mirror of
https://github.com/bbernhard/signal-cli-rest-api.git
synced 2026-05-20 13:44:17 +00:00
Compare commits
33 Commits
1129e5a7be
...
cbefcb2ecd
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbefcb2ecd | ||
|
|
76511ae14f | ||
|
|
fcc62a7fe7 | ||
|
|
f1c7525292 | ||
|
|
05235bd7ae | ||
|
|
d7ffe54883 | ||
|
|
2760fe0b70 | ||
|
|
4fb1be6657 | ||
|
|
bb8c0efcac | ||
|
|
1543997e02 | ||
|
|
b527cba584 | ||
|
|
877bc9e845 | ||
|
|
808bad21ab | ||
|
|
53cd2dc014 | ||
|
|
ddc5aa55df | ||
|
|
00bbfca878 | ||
|
|
884582a71e | ||
|
|
e3d503c746 | ||
|
|
af34a0881c | ||
|
|
c7cb9ab13e | ||
|
|
af18c7aea8 | ||
|
|
ab30ba5bba | ||
|
|
ed3626fa77 | ||
|
|
6257fa754d | ||
|
|
dd6d763618 | ||
|
|
1ea89705d5 | ||
|
|
9e5d73b5c0 | ||
|
|
d080e8d478 | ||
|
|
a9c367a5b1 | ||
|
|
8d13f5f383 | ||
|
|
bd9e648739 | ||
|
|
24513e9cf3 | ||
|
|
3a36a04b09 |
90
Dockerfile
90
Dockerfile
@ -1,14 +1,15 @@
|
|||||||
ARG SIGNAL_CLI_VERSION=0.13.24
|
ARG SIGNAL_CLI_VERSION=0.14.0
|
||||||
ARG LIBSIGNAL_CLIENT_VERSION=0.87.0
|
ARG LIBSIGNAL_CLIENT_VERSION=0.87.4
|
||||||
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.13.24+morph027+2
|
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.14.0+morph027+5
|
||||||
|
|
||||||
ARG SWAG_VERSION=1.16.4
|
ARG SWAG_VERSION=1.16.4
|
||||||
ARG GRAALVM_VERSION=21.0.0
|
ARG GRAALVM_VERSION=25.0.2
|
||||||
#ARG GRAALVM_VERSION=25.0.2
|
|
||||||
|
ARG S6_OVERLAY_VERSION=v3.2.2.0
|
||||||
|
|
||||||
ARG BUILD_VERSION_ARG=unset
|
ARG BUILD_VERSION_ARG=unset
|
||||||
|
|
||||||
FROM golang:1.24-bookworm AS buildcontainer
|
FROM golang:1.26-trixie AS buildcontainer
|
||||||
|
|
||||||
ARG SIGNAL_CLI_VERSION
|
ARG SIGNAL_CLI_VERSION
|
||||||
ARG LIBSIGNAL_CLIENT_VERSION
|
ARG LIBSIGNAL_CLIENT_VERSION
|
||||||
@ -32,8 +33,8 @@ RUN arch="$(uname -m)"; \
|
|||||||
RUN dpkg-reconfigure debconf --frontend=noninteractive \
|
RUN dpkg-reconfigure debconf --frontend=noninteractive \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get -y install --no-install-recommends \
|
&& apt-get -y install --no-install-recommends \
|
||||||
wget software-properties-common git locales zip unzip \
|
wget git locales zip unzip \
|
||||||
file build-essential libz-dev zlib1g-dev \
|
file build-essential libz-dev zlib1g-dev binutils \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
||||||
@ -42,7 +43,7 @@ RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
|||||||
|
|
||||||
ENV JAVA_OPTS="-Djdk.lang.Process.launchMechanism=vfork"
|
ENV JAVA_OPTS="-Djdk.lang.Process.launchMechanism=vfork"
|
||||||
|
|
||||||
ENV LANG en_US.UTF-8
|
ENV LANG=en_US.UTF-8
|
||||||
|
|
||||||
#RUN cd /tmp/ \
|
#RUN cd /tmp/ \
|
||||||
# && git clone https://github.com/swaggo/swag.git swag-${SWAG_VERSION} \
|
# && git clone https://github.com/swaggo/swag.git swag-${SWAG_VERSION} \
|
||||||
@ -91,8 +92,8 @@ RUN if [ "$(uname -m)" = "x86_64" ]; then \
|
|||||||
&& ./gradlew -q nativeCompile; \
|
&& ./gradlew -q nativeCompile; \
|
||||||
elif [ "$(uname -m)" = "aarch64" ] ; then \
|
elif [ "$(uname -m)" = "aarch64" ] ; then \
|
||||||
echo "Use native image from @morph027 (https://packaging.gitlab.io/signal-cli/) for arm64 - many thanks to @morph027" \
|
echo "Use native image from @morph027 (https://packaging.gitlab.io/signal-cli/) for arm64 - many thanks to @morph027" \
|
||||||
&& curl -fsSL https://packaging.gitlab.io/signal-cli/gpg.key | apt-key add - \
|
&& curl -fsSL https://packaging.gitlab.io/signal-cli/gpg.key | gpg -o /usr/share/keyrings/signal-cli-native.pgp --dearmor \
|
||||||
&& echo "deb https://packaging.gitlab.io/signal-cli focal main" > /etc/apt/sources.list.d/morph027-signal-cli.list \
|
&& echo "deb [signed-by=/usr/share/keyrings/signal-cli-native.pgp] https://packaging.gitlab.io/signal-cli signalcli main" > /etc/apt/sources.list.d/morph027-signal-cli.list \
|
||||||
&& mkdir -p /tmp/signal-cli-native \
|
&& mkdir -p /tmp/signal-cli-native \
|
||||||
&& cd /tmp/signal-cli-native \
|
&& cd /tmp/signal-cli-native \
|
||||||
#&& wget https://gitlab.com/packaging/signal-cli/-/jobs/3716873649/artifacts/download?file_type=archive -O /tmp/signal-cli-native/archive.zip \
|
#&& wget https://gitlab.com/packaging/signal-cli/-/jobs/3716873649/artifacts/download?file_type=archive -O /tmp/signal-cli-native/archive.zip \
|
||||||
@ -154,42 +155,63 @@ RUN cd /tmp/signal-cli-rest-api-src/scripts && go build -o jsonrpc2-helper
|
|||||||
RUN cd /tmp/signal-cli-rest-api-src && go build -buildmode=plugin -o signal-cli-rest-api_plugin_loader.so plugin_loader.go
|
RUN cd /tmp/signal-cli-rest-api-src && go build -buildmode=plugin -o signal-cli-rest-api_plugin_loader.so plugin_loader.go
|
||||||
|
|
||||||
# Start a fresh container for release container
|
# Start a fresh container for release container
|
||||||
|
FROM debian:trixie-slim
|
||||||
|
|
||||||
# eclipse-temurin doesn't provide a OpenJDK 21 image for armv7 (see https://github.com/adoptium/containers/issues/502). Until this
|
ARG TARGETARCH # set by buildx
|
||||||
# is fixed we use the standard ubuntu image
|
|
||||||
#FROM eclipse-temurin:21-jre-jammy
|
|
||||||
|
|
||||||
FROM ubuntu:jammy
|
|
||||||
|
|
||||||
ENV GIN_MODE=release
|
|
||||||
|
|
||||||
ENV PORT=8080
|
|
||||||
|
|
||||||
ARG SIGNAL_CLI_VERSION
|
ARG SIGNAL_CLI_VERSION
|
||||||
ARG BUILD_VERSION_ARG
|
ARG BUILD_VERSION_ARG
|
||||||
|
ARG S6_OVERLAY_VERSION
|
||||||
|
ENV GIN_MODE=release
|
||||||
|
|
||||||
|
# Set environment variables to keep the image clean
|
||||||
|
ENV DEBIAN_FRONTEND=noninteractive
|
||||||
|
|
||||||
|
ENV PORT=8080
|
||||||
|
|
||||||
ENV BUILD_VERSION=$BUILD_VERSION_ARG
|
ENV BUILD_VERSION=$BUILD_VERSION_ARG
|
||||||
ENV SIGNAL_CLI_REST_API_PLUGIN_SHARED_OBJ_DIR=/usr/bin/
|
ENV SIGNAL_CLI_REST_API_PLUGIN_SHARED_OBJ_DIR=/usr/bin/
|
||||||
|
|
||||||
RUN dpkg-reconfigure debconf --frontend=noninteractive \
|
RUN dpkg-reconfigure debconf --frontend=noninteractive \
|
||||||
&& apt-get update \
|
&& apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends util-linux supervisor netcat openjdk-21-jre curl locales \
|
&& apt-get install -y --no-install-recommends util-linux openjdk-25-jre curl locales xz-utils \
|
||||||
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
RUN if [ -z "$TARGETARCH" ]; then \
|
||||||
|
# Fallback for older Docker versions not using BuildKit
|
||||||
|
TARGETARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/'); \
|
||||||
|
else \
|
||||||
|
echo "Building for architecture: $TARGETARCH"; \
|
||||||
|
fi;
|
||||||
|
|
||||||
|
# install s6-overlay as service control system
|
||||||
|
RUN curl -fL -o /tmp/s6-overlay-noarch.tar.xz \
|
||||||
|
"https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-noarch.tar.xz" && \
|
||||||
|
tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz && \
|
||||||
|
if [ "$TARGETARCH" = "amd64" ]; then S6_ARCH="x86_64"; \
|
||||||
|
elif [ "$TARGETARCH" = "arm64" ]; then S6_ARCH="aarch64"; \
|
||||||
|
elif [ "$TARGETARCH" = "arm" ]; then S6_ARCH="arm"; \
|
||||||
|
else S6_ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/'); fi;\
|
||||||
|
curl -fL -o /tmp/s6-overlay-bin.tar.xz \
|
||||||
|
"https://github.com/just-containers/s6-overlay/releases/download/${S6_OVERLAY_VERSION}/s6-overlay-${S6_ARCH}.tar.xz" && \
|
||||||
|
tar -C / -Jxpf /tmp/s6-overlay-bin.tar.xz && \
|
||||||
|
rm /tmp/s6-overlay-*.tar.xz
|
||||||
|
|
||||||
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api /usr/bin/signal-cli-rest-api
|
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api /usr/bin/signal-cli-rest-api
|
||||||
COPY --from=buildcontainer /opt/signal-cli-${SIGNAL_CLI_VERSION} /opt/signal-cli-${SIGNAL_CLI_VERSION}
|
COPY --from=buildcontainer /opt/signal-cli-${SIGNAL_CLI_VERSION} /opt/signal-cli-${SIGNAL_CLI_VERSION}
|
||||||
COPY --from=buildcontainer /tmp/signal-cli-${SIGNAL_CLI_VERSION}-source/build/native/nativeCompile/signal-cli /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native
|
COPY --from=buildcontainer /tmp/signal-cli-${SIGNAL_CLI_VERSION}-source/build/native/nativeCompile/signal-cli /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native
|
||||||
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/scripts/jsonrpc2-helper /usr/bin/jsonrpc2-helper
|
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/scripts/jsonrpc2-helper /usr/bin/jsonrpc2-helper
|
||||||
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api_plugin_loader.so /usr/bin/signal-cli-rest-api_plugin_loader.so
|
COPY --from=buildcontainer /tmp/signal-cli-rest-api-src/signal-cli-rest-api_plugin_loader.so /usr/bin/signal-cli-rest-api_plugin_loader.so
|
||||||
COPY entrypoint.sh /entrypoint.sh
|
|
||||||
|
|
||||||
|
|
||||||
RUN groupadd -g 1000 signal-api \
|
RUN groupadd -g 1000 signal-api \
|
||||||
&& useradd --no-log-init -M -d /home -s /bin/bash -u 1000 -g 1000 signal-api \
|
&& useradd --no-log-init -M -d /home -s /bin/bash -u 1000 -g 1000 signal-api \
|
||||||
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/bin/signal-cli \
|
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli /usr/bin/signal-cli \
|
||||||
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native /usr/bin/signal-cli-native \
|
&& ln -s /opt/signal-cli-${SIGNAL_CLI_VERSION}/bin/signal-cli-native /usr/bin/signal-cli-native \
|
||||||
&& mkdir -p /signal-cli-config/ \
|
&& mkdir -p /home/.local/share/signal-cli \
|
||||||
&& mkdir -p /home/.local/share/signal-cli
|
&& chown -R signal-api:signal-api /home
|
||||||
|
|
||||||
|
COPY --chmod=755 ./s6-services/ /etc/s6-overlay/s6-rc.d/
|
||||||
|
|
||||||
# remove the temporary created signal-cli-native on armv7, as GRAALVM doesn't support 32bit
|
# remove the temporary created signal-cli-native on armv7, as GRAALVM doesn't support 32bit
|
||||||
RUN arch="$(uname -m)"; \
|
RUN arch="$(uname -m)"; \
|
||||||
@ -201,16 +223,24 @@ RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
|
|||||||
dpkg-reconfigure --frontend=noninteractive locales && \
|
dpkg-reconfigure --frontend=noninteractive locales && \
|
||||||
update-locale LANG=en_US.UTF-8
|
update-locale LANG=en_US.UTF-8
|
||||||
|
|
||||||
ENV LANG en_US.UTF-8
|
ENV LANG=en_US.UTF-8
|
||||||
|
|
||||||
EXPOSE ${PORT}
|
EXPOSE ${PORT}
|
||||||
|
|
||||||
ENV SIGNAL_CLI_CONFIG_DIR=/home/.local/share/signal-cli
|
ENV SIGNAL_CLI_CONFIG_DIR=/home/.local/share/signal-cli
|
||||||
ENV SIGNAL_CLI_UID=1000
|
|
||||||
ENV SIGNAL_CLI_GID=1000
|
|
||||||
ENV SIGNAL_CLI_CHOWN_ON_STARTUP=true
|
|
||||||
|
|
||||||
ENTRYPOINT ["/entrypoint.sh"]
|
RUN mkdir -p /tmp/s6-runtime && chown -R signal-api:signal-api /tmp/s6-runtime /etc/s6-overlay
|
||||||
|
|
||||||
|
USER signal-api
|
||||||
|
|
||||||
|
# Mandatory ENV for non-root s6
|
||||||
|
ENV S6_RUNTIME_PATH=/tmp/s6-runtime
|
||||||
|
ENV S6_READ_ONLY_ROOT=1
|
||||||
|
ENV S6_VERBOSITY=2
|
||||||
|
|
||||||
|
WORKDIR /home
|
||||||
|
|
||||||
|
ENTRYPOINT ["/init"]
|
||||||
|
|
||||||
HEALTHCHECK --interval=20s --timeout=10s --retries=3 \
|
HEALTHCHECK --interval=20s --timeout=10s --retries=3 \
|
||||||
CMD curl -f http://localhost:${PORT}/v1/health || exit 1
|
CMD curl -f http://localhost:${PORT}/v1/health || exit 1
|
||||||
|
|||||||
@ -156,4 +156,6 @@ There are a bunch of environmental variables that can be set inside the docker c
|
|||||||
|
|
||||||
* `JSON_RPC_IGNORE_ATTACHMENTS`: When set to `true`, attachments are not automatically downloaded in json-rpc mode (default: `false`)
|
* `JSON_RPC_IGNORE_ATTACHMENTS`: When set to `true`, attachments are not automatically downloaded in json-rpc mode (default: `false`)
|
||||||
* `JSON_RPC_IGNORE_STORIES`: When set to `true`, stories are not automatically downloaded in json-rpc mode (default: `false`)
|
* `JSON_RPC_IGNORE_STORIES`: When set to `true`, stories are not automatically downloaded in json-rpc mode (default: `false`)
|
||||||
|
* `JSON_RPC_IGNORE_AVATARS`: When set to `true`, avatars are not automatically downloaded in json-rpc mode (default: `false`)
|
||||||
|
* `JSON_RPC_IGNORE_STICKERS`: When set to `true`, sticker packs are not automatically downloaded in json-rpc mode (default: `false`)
|
||||||
* `JSON_RPC_TRUST_NEW_IDENTITIES`: Choose how to trust new identities in json-rpc mode. Supported values: `on-first-use`, `always`, `never`. (default: `on-first-use`)
|
* `JSON_RPC_TRUST_NEW_IDENTITIES`: Choose how to trust new identities in json-rpc mode. Supported values: `on-first-use`, `always`, `never`. (default: `on-first-use`)
|
||||||
|
|||||||
@ -4,6 +4,8 @@ This can be done by putting the docker container into debug mode with the follow
|
|||||||
|
|
||||||
```curl -X POST -H "Content-Type: application/json" -d '{"logging": {"level": "debug"}}' 'http://127.0.0.1:8080/v1/configuration'```
|
```curl -X POST -H "Content-Type: application/json" -d '{"logging": {"level": "debug"}}' 'http://127.0.0.1:8080/v1/configuration'```
|
||||||
|
|
||||||
|
Alternatively, you can set the `LOG_LEVEL` environment variable.
|
||||||
|
|
||||||
Once the docker container is in debug mode, execute the REST API command you want to debug.
|
Once the docker container is in debug mode, execute the REST API command you want to debug.
|
||||||
|
|
||||||
e.g Let's assume we are experiencing some problems with sending messages. So, let's send a Signal message with
|
e.g Let's assume we are experiencing some problems with sending messages. So, let's send a Signal message with
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
version: "3"
|
|
||||||
services:
|
services:
|
||||||
signal-cli-rest-api:
|
signal-cli-rest-api:
|
||||||
image: bbernhard/signal-cli-rest-api:latest
|
image: bbernhard/signal-cli-rest-api:latest
|
||||||
@ -9,3 +8,4 @@ services:
|
|||||||
- "8080:8080" #map docker port 8080 to host port 8080.
|
- "8080:8080" #map docker port 8080 to host port 8080.
|
||||||
volumes:
|
volumes:
|
||||||
- "./signal-cli-config:/home/.local/share/signal-cli" #map "signal-cli-config" folder on host system into docker container. the folder contains the password and cryptographic keys when a new number is registered
|
- "./signal-cli-config:/home/.local/share/signal-cli" #map "signal-cli-config" folder on host system into docker container. the folder contains the password and cryptographic keys when a new number is registered
|
||||||
|
|
||||||
|
|||||||
43
entrypoint.old.sh
Executable file
43
entrypoint.old.sh
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -x
|
||||||
|
set -e
|
||||||
|
|
||||||
|
[ -z "${SIGNAL_CLI_CONFIG_DIR}" ] && echo "SIGNAL_CLI_CONFIG_DIR environmental variable needs to be set! Aborting!" && exit 1;
|
||||||
|
|
||||||
|
usermod -u ${SIGNAL_CLI_UID} signal-api
|
||||||
|
groupmod -o -g ${SIGNAL_CLI_GID} signal-api
|
||||||
|
|
||||||
|
# Fix permissions to ensure backward compatibility if SIGNAL_CLI_CHOWN_ON_STARTUP is not set to "false"
|
||||||
|
if [ "$SIGNAL_CLI_CHOWN_ON_STARTUP" != "false" ]; then
|
||||||
|
echo "Changing ownership of ${SIGNAL_CLI_CONFIG_DIR} to ${SIGNAL_CLI_UID}:${SIGNAL_CLI_GID}"
|
||||||
|
chown ${SIGNAL_CLI_UID}:${SIGNAL_CLI_GID} -R ${SIGNAL_CLI_CONFIG_DIR}
|
||||||
|
else
|
||||||
|
echo "Skipping chown on startup since SIGNAL_CLI_CHOWN_ON_STARTUP is set to 'false'"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show warning on docker exec
|
||||||
|
cat <<EOF >> /root/.bashrc
|
||||||
|
echo "WARNING: signal-cli-rest-api runs as signal-api (not as root!)"
|
||||||
|
echo "Run 'su signal-api' before using signal-cli!"
|
||||||
|
echo "If you want to use signal-cli directly, don't forget to specify the config directory. e.g: \"signal-cli --config ${SIGNAL_CLI_CONFIG_DIR}\""
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cap_prefix="-cap_"
|
||||||
|
caps="$cap_prefix$(seq -s ",$cap_prefix" 0 $(cat /proc/sys/kernel/cap_last_cap))"
|
||||||
|
|
||||||
|
# TODO: check mode
|
||||||
|
if [ "$MODE" = "json-rpc" ]
|
||||||
|
then
|
||||||
|
/usr/bin/jsonrpc2-helper
|
||||||
|
if [ -n "$JAVA_OPTS" ] ; then
|
||||||
|
echo "export JAVA_OPTS='$JAVA_OPTS'" >> /etc/default/supervisor
|
||||||
|
fi
|
||||||
|
service supervisor start
|
||||||
|
supervisorctl start all
|
||||||
|
fi
|
||||||
|
|
||||||
|
export HOST_IP=$(hostname -I | awk '{print $1}')
|
||||||
|
|
||||||
|
# Start API as signal-api user
|
||||||
|
exec setpriv --reuid=${SIGNAL_CLI_UID} --regid=${SIGNAL_CLI_GID} --init-groups --inh-caps=$caps signal-cli-rest-api -signal-cli-config=${SIGNAL_CLI_CONFIG_DIR}
|
||||||
@ -1,23 +1,22 @@
|
|||||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
diff --git a/build.gradle.kts b/build.gradle.kts
|
||||||
index f51d9f1c..6357f590 100644
|
index d8e36ea4..dba4dae3 100644
|
||||||
--- a/build.gradle.kts
|
--- a/build.gradle.kts
|
||||||
+++ b/build.gradle.kts
|
+++ b/build.gradle.kts
|
||||||
@@ -55,6 +55,7 @@ dependencies {
|
@@ -91,6 +91,7 @@ dependencies {
|
||||||
implementation(libs.slf4j.jul)
|
|
||||||
implementation(libs.logback)
|
implementation(libs.logback)
|
||||||
|
implementation(libs.zxing)
|
||||||
implementation(project(":libsignal-cli"))
|
implementation(project(":libsignal-cli"))
|
||||||
+ implementation(files("/tmp/libsignal-client.jar"))
|
+ implementation(files("/tmp/libsignal-client.jar"))
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
@@ -63,6 +64,10 @@ configurations {
|
@@ -99,6 +100,9 @@ configurations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
+configurations.all {
|
+configurations.all {
|
||||||
+ exclude(group = "org.signal", module = "libsignal-client")
|
+ exclude(group = "org.signal", module = "libsignal-client")
|
||||||
+}
|
+}
|
||||||
+
|
|
||||||
|
|
||||||
tasks.withType<AbstractArchiveTask>().configureEach {
|
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||||
isPreserveFileTimestamps = false
|
isPreserveFileTimestamps = false
|
||||||
|
|||||||
BIN
ext/libraries/libsignal-client/v0.87.4/arm64/libsignal_jni.so
Normal file
BIN
ext/libraries/libsignal-client/v0.87.4/arm64/libsignal_jni.so
Normal file
Binary file not shown.
BIN
ext/libraries/libsignal-client/v0.87.4/armv7/libsignal_jni.so
Normal file
BIN
ext/libraries/libsignal-client/v0.87.4/armv7/libsignal_jni.so
Normal file
Binary file not shown.
BIN
ext/libraries/libsignal-client/v0.87.4/x86-64/libsignal_jni.so
Normal file
BIN
ext/libraries/libsignal-client/v0.87.4/x86-64/libsignal_jni.so
Normal file
Binary file not shown.
3
s6-services/signal-api/run
Normal file
3
s6-services/signal-api/run
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#!/command/with-contenv sh
|
||||||
|
# Use with-contenv to import environment variables like SIGNAL_CLI_CONFIG_DIR
|
||||||
|
exec signal-cli-rest-api -signal-cli-config="${SIGNAL_CLI_CONFIG_DIR}"
|
||||||
1
s6-services/signal-api/type
Normal file
1
s6-services/signal-api/type
Normal file
@ -0,0 +1 @@
|
|||||||
|
longrun
|
||||||
10
s6-services/signal-json-rpc/run
Normal file
10
s6-services/signal-json-rpc/run
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/command/with-contenv sh
|
||||||
|
# File: /etc/s6-overlay/s6-rc.d/signal-json-rpc/run
|
||||||
|
|
||||||
|
if [ "$MODE" != "json-rpc" ]; then
|
||||||
|
echo "Running as mode: $MODE - skipping json-rpc setup"
|
||||||
|
sleep infinity # do nothing, but keep service running
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
exec jsonrpc2-helper
|
||||||
1
s6-services/signal-json-rpc/type
Normal file
1
s6-services/signal-json-rpc/type
Normal file
@ -0,0 +1 @@
|
|||||||
|
longrun
|
||||||
0
s6-services/user/contents.d/signal-api
Normal file
0
s6-services/user/contents.d/signal-api
Normal file
0
s6-services/user/contents.d/signal-json-rpc
Normal file
0
s6-services/user/contents.d/signal-json-rpc
Normal file
1
s6-services/user/type
Normal file
1
s6-services/user/type
Normal file
@ -0,0 +1 @@
|
|||||||
|
bundle
|
||||||
@ -215,7 +215,7 @@ type RemoteDeleteRequest struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DeleteLocalAccountDataRequest struct {
|
type DeleteLocalAccountDataRequest struct {
|
||||||
IgnoreRegistered bool `json:"ignore_registered" example:"false"`
|
IgnoreRegistered bool `json:"ignore_registered" example:"false"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeviceLinkUriResponse struct {
|
type DeviceLinkUriResponse struct {
|
||||||
@ -364,30 +364,30 @@ func (a *Api) UnregisterNumber(c *gin.Context) {
|
|||||||
// @Failure 400 {object} Error
|
// @Failure 400 {object} Error
|
||||||
// @Router /v1/devices/{number}/local-data [delete]
|
// @Router /v1/devices/{number}/local-data [delete]
|
||||||
func (a *Api) DeleteLocalAccountData(c *gin.Context) {
|
func (a *Api) DeleteLocalAccountData(c *gin.Context) {
|
||||||
number, err := url.PathUnescape(c.Param("number"))
|
number, err := url.PathUnescape(c.Param("number"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(400, Error{Msg: "Couldn't process request - malformed number"})
|
c.JSON(400, Error{Msg: "Couldn't process request - malformed number"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if number == "" {
|
if number == "" {
|
||||||
c.JSON(400, Error{Msg: "Couldn't process request - number missing"})
|
c.JSON(400, Error{Msg: "Couldn't process request - number missing"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
req := DeleteLocalAccountDataRequest{}
|
req := DeleteLocalAccountDataRequest{}
|
||||||
if c.Request.Body != nil && c.Request.ContentLength != 0 {
|
if c.Request.Body != nil && c.Request.ContentLength != 0 {
|
||||||
if err := c.BindJSON(&req); err != nil {
|
if err := c.BindJSON(&req); err != nil {
|
||||||
c.JSON(400, Error{Msg: "Couldn't process request - invalid request"})
|
c.JSON(400, Error{Msg: "Couldn't process request - invalid request"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := a.signalClient.DeleteLocalAccountData(number, req.IgnoreRegistered); err != nil {
|
if err := a.signalClient.DeleteLocalAccountData(number, req.IgnoreRegistered); err != nil {
|
||||||
c.JSON(400, Error{Msg: err.Error()})
|
c.JSON(400, Error{Msg: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Status(http.StatusNoContent)
|
c.Status(http.StatusNoContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary Verify a registered phone number.
|
// @Summary Verify a registered phone number.
|
||||||
@ -670,6 +670,8 @@ func StringToBool(input string) bool {
|
|||||||
// @Param timeout query string false "Receive timeout in seconds (default: 1)"
|
// @Param timeout query string false "Receive timeout in seconds (default: 1)"
|
||||||
// @Param ignore_attachments query string false "Specify whether the attachments of the received message should be ignored" (default: false)"
|
// @Param ignore_attachments query string false "Specify whether the attachments of the received message should be ignored" (default: false)"
|
||||||
// @Param ignore_stories query string false "Specify whether stories should be ignored when receiving messages" (default: false)"
|
// @Param ignore_stories query string false "Specify whether stories should be ignored when receiving messages" (default: false)"
|
||||||
|
// @Param ignore_avatars query string false "Specify whether avatar downloads should be ignored when receiving messages" (default: false)"
|
||||||
|
// @Param ignore_stickers query string false "Specify whether sticker pack downloads should be ignored when receiving messages" (default: false)"
|
||||||
// @Param max_messages query string false "Specify the maximum number of messages to receive (default: unlimited)". Not available in json-rpc mode.
|
// @Param max_messages query string false "Specify the maximum number of messages to receive (default: unlimited)". Not available in json-rpc mode.
|
||||||
// @Param send_read_receipts query string false "Specify whether read receipts should be sent when receiving messages" (default: false)"
|
// @Param send_read_receipts query string false "Specify whether read receipts should be sent when receiving messages" (default: false)"
|
||||||
// @Router /v1/receive/{number} [get]
|
// @Router /v1/receive/{number} [get]
|
||||||
@ -718,13 +720,25 @@ func (a *Api) Receive(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignoreAvatars := c.DefaultQuery("ignore_avatars", "false")
|
||||||
|
if ignoreAvatars != "true" && ignoreAvatars != "false" {
|
||||||
|
c.JSON(400, Error{Msg: "Couldn't process request - ignore_avatars parameter needs to be either 'true' or 'false'"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreStickers := c.DefaultQuery("ignore_stickers", "false")
|
||||||
|
if ignoreStickers != "true" && ignoreStickers != "false" {
|
||||||
|
c.JSON(400, Error{Msg: "Couldn't process request - ignore_stickers parameter needs to be either 'true' or 'false'"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sendReadReceipts := c.DefaultQuery("send_read_receipts", "false")
|
sendReadReceipts := c.DefaultQuery("send_read_receipts", "false")
|
||||||
if sendReadReceipts != "true" && sendReadReceipts != "false" {
|
if sendReadReceipts != "true" && sendReadReceipts != "false" {
|
||||||
c.JSON(400, Error{Msg: "Couldn't process request - send_read_receipts parameter needs to be either 'true' or 'false'"})
|
c.JSON(400, Error{Msg: "Couldn't process request - send_read_receipts parameter needs to be either 'true' or 'false'"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonStr, err := a.signalClient.Receive(number, timeoutInt, StringToBool(ignoreAttachments), StringToBool(ignoreStories), maxMessagesInt, StringToBool(sendReadReceipts))
|
jsonStr, err := a.signalClient.Receive(number, timeoutInt, StringToBool(ignoreAttachments), StringToBool(ignoreStories), StringToBool(ignoreAvatars), StringToBool(ignoreStickers), maxMessagesInt, StringToBool(sendReadReceipts))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(400, Error{Msg: err.Error()})
|
c.JSON(400, Error{Msg: err.Error()})
|
||||||
return
|
return
|
||||||
@ -1174,19 +1188,19 @@ func (a *Api) GetQrCodeLink(c *gin.Context) {
|
|||||||
// @Failure 400 {object} Error
|
// @Failure 400 {object} Error
|
||||||
// @Router /v1/qrcodelink/raw [get]
|
// @Router /v1/qrcodelink/raw [get]
|
||||||
func (a *Api) GetQrCodeLinkUri(c *gin.Context) {
|
func (a *Api) GetQrCodeLinkUri(c *gin.Context) {
|
||||||
deviceName := c.Query("device_name")
|
deviceName := c.Query("device_name")
|
||||||
if deviceName == "" {
|
if deviceName == "" {
|
||||||
c.JSON(400, Error{Msg: "Please provide a name for the device"})
|
c.JSON(400, Error{Msg: "Please provide a name for the device"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
deviceLinkUri, err := a.signalClient.GetDeviceLinkUri(deviceName)
|
deviceLinkUri, err := a.signalClient.GetDeviceLinkUri(deviceName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(400, Error{Msg: err.Error()})
|
c.JSON(400, Error{Msg: err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(200, DeviceLinkUriResponse{DeviceLinkUri: deviceLinkUri})
|
c.JSON(200, DeviceLinkUriResponse{DeviceLinkUri: deviceLinkUri})
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Summary List all accounts
|
// @Summary List all accounts
|
||||||
@ -2080,7 +2094,7 @@ func (a *Api) RemoveDevice(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
deviceIdStr := c.Param("deviceId")
|
deviceIdStr := c.Param("deviceId")
|
||||||
deviceId, err := strconv.ParseInt(deviceIdStr, 10, 64)
|
deviceId, err := strconv.ParseInt(deviceIdStr, 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(400, Error{Msg: "deviceId must be numeric"})
|
c.JSON(400, Error{Msg: "deviceId must be numeric"})
|
||||||
return
|
return
|
||||||
|
|||||||
@ -410,7 +410,7 @@ func (s *SignalClient) GetSignalCliMode() SignalCliMode {
|
|||||||
return s.signalCliMode
|
return s.signalCliMode
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SignalClient) Init() error {
|
func (s *SignalClient) Init(maxRetries int) error {
|
||||||
s.signalCliApiConfig = utils.NewSignalCliApiConfig()
|
s.signalCliApiConfig = utils.NewSignalCliApiConfig()
|
||||||
err := s.signalCliApiConfig.Load(s.signalCliApiConfigPath)
|
err := s.signalCliApiConfig.Load(s.signalCliApiConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -427,7 +427,7 @@ func (s *SignalClient) Init() error {
|
|||||||
tcpPortsNumberMapping := s.jsonRpc2ClientConfig.GetTcpPortsForNumbers()
|
tcpPortsNumberMapping := s.jsonRpc2ClientConfig.GetTcpPortsForNumbers()
|
||||||
for number, tcpPort := range tcpPortsNumberMapping {
|
for number, tcpPort := range tcpPortsNumberMapping {
|
||||||
s.jsonRpc2Clients[number] = NewJsonRpc2Client(s.signalCliApiConfig, number)
|
s.jsonRpc2Clients[number] = NewJsonRpc2Client(s.signalCliApiConfig, number)
|
||||||
err := s.jsonRpc2Clients[number].Dial("127.0.0.1:" + strconv.FormatInt(tcpPort, 10))
|
err := s.jsonRpc2Clients[number].Dial("127.0.0.1:"+strconv.FormatInt(tcpPort, 10), maxRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -993,7 +993,7 @@ func (s *SignalClient) SendV2(number string, message string, recps []string, bas
|
|||||||
return ×tamps, nil
|
return ×tamps, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SignalClient) Receive(number string, timeout int64, ignoreAttachments bool, ignoreStories bool, maxMessages int64, sendReadReceipts bool) (string, error) {
|
func (s *SignalClient) Receive(number string, timeout int64, ignoreAttachments bool, ignoreStories bool, ignoreAvatars bool, ignoreStickers bool, maxMessages int64, sendReadReceipts bool) (string, error) {
|
||||||
if s.signalCliMode == JsonRpc {
|
if s.signalCliMode == JsonRpc {
|
||||||
return "", errors.New("Not implemented")
|
return "", errors.New("Not implemented")
|
||||||
} else {
|
} else {
|
||||||
@ -1007,6 +1007,14 @@ func (s *SignalClient) Receive(number string, timeout int64, ignoreAttachments b
|
|||||||
command = append(command, "--ignore-stories")
|
command = append(command, "--ignore-stories")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ignoreAvatars {
|
||||||
|
command = append(command, "--ignore-avatars")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ignoreStickers {
|
||||||
|
command = append(command, "--ignore-stickers")
|
||||||
|
}
|
||||||
|
|
||||||
if maxMessages > 0 {
|
if maxMessages > 0 {
|
||||||
command = append(command, "--max-messages")
|
command = append(command, "--max-messages")
|
||||||
command = append(command, strconv.FormatInt(maxMessages, 10))
|
command = append(command, strconv.FormatInt(maxMessages, 10))
|
||||||
@ -1349,7 +1357,7 @@ func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) {
|
|||||||
}
|
}
|
||||||
pendingMembers = append(pendingMembers, identifier)
|
pendingMembers = append(pendingMembers, identifier)
|
||||||
}
|
}
|
||||||
groupEntry.PendingRequests = pendingMembers
|
groupEntry.PendingInvites = pendingMembers
|
||||||
|
|
||||||
requestingMembers := []string{}
|
requestingMembers := []string{}
|
||||||
for _, val := range signalCliGroupEntry.RequestingMembers {
|
for _, val := range signalCliGroupEntry.RequestingMembers {
|
||||||
@ -1359,7 +1367,7 @@ func (s *SignalClient) GetGroups(number string) ([]GroupEntry, error) {
|
|||||||
}
|
}
|
||||||
requestingMembers = append(requestingMembers, identifier)
|
requestingMembers = append(requestingMembers, identifier)
|
||||||
}
|
}
|
||||||
groupEntry.PendingInvites = requestingMembers
|
groupEntry.PendingRequests = requestingMembers
|
||||||
|
|
||||||
admins := []string{}
|
admins := []string{}
|
||||||
for _, val := range signalCliGroupEntry.Admins {
|
for _, val := range signalCliGroupEntry.Admins {
|
||||||
@ -2634,8 +2642,8 @@ func (s *SignalClient) ListContacts(number string, allRecipients bool, recipient
|
|||||||
|
|
||||||
if s.signalCliMode == JsonRpc {
|
if s.signalCliMode == JsonRpc {
|
||||||
type Request struct {
|
type Request struct {
|
||||||
AllRecipients bool `json:"allRecipients,omitempty"`
|
AllRecipients bool `json:"allRecipients,omitempty"`
|
||||||
Recipient string `json:"recipient,omitempty"`
|
Recipient string `json:"recipient,omitempty"`
|
||||||
}
|
}
|
||||||
req := Request{}
|
req := Request{}
|
||||||
if allRecipients {
|
if allRecipients {
|
||||||
@ -2705,7 +2713,6 @@ func (s *SignalClient) ListContacts(number string, allRecipients bool, recipient
|
|||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *SignalClient) SetPin(number string, registrationLockPin string) error {
|
func (s *SignalClient) SetPin(number string, registrationLockPin string) error {
|
||||||
if s.signalCliMode == JsonRpc {
|
if s.signalCliMode == JsonRpc {
|
||||||
type Request struct {
|
type Request struct {
|
||||||
|
|||||||
@ -2,14 +2,14 @@ package client
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"net"
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"net/http"
|
|
||||||
"bytes"
|
|
||||||
"strconv"
|
|
||||||
|
|
||||||
"github.com/bbernhard/signal-cli-rest-api/utils"
|
"github.com/bbernhard/signal-cli-rest-api/utils"
|
||||||
uuid "github.com/gofrs/uuid"
|
uuid "github.com/gofrs/uuid"
|
||||||
@ -60,11 +60,11 @@ type JsonRpc2Client struct {
|
|||||||
conn net.Conn
|
conn net.Conn
|
||||||
receivedResponsesById map[string]chan JsonRpc2MessageResponse
|
receivedResponsesById map[string]chan JsonRpc2MessageResponse
|
||||||
receivedMessagesChannels map[string]chan JsonRpc2ReceivedMessage
|
receivedMessagesChannels map[string]chan JsonRpc2ReceivedMessage
|
||||||
lastTimeErrorMessageSent time.Time
|
|
||||||
signalCliApiConfig *utils.SignalCliApiConfig
|
signalCliApiConfig *utils.SignalCliApiConfig
|
||||||
number string
|
number string
|
||||||
receivedMessagesMutex sync.Mutex
|
receivedMessagesMutex sync.Mutex
|
||||||
receivedResponsesMutex sync.Mutex
|
receivedResponsesMutex sync.Mutex
|
||||||
|
address string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewJsonRpc2Client(signalCliApiConfig *utils.SignalCliApiConfig, number string) *JsonRpc2Client {
|
func NewJsonRpc2Client(signalCliApiConfig *utils.SignalCliApiConfig, number string) *JsonRpc2Client {
|
||||||
@ -76,10 +76,24 @@ func NewJsonRpc2Client(signalCliApiConfig *utils.SignalCliApiConfig, number stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *JsonRpc2Client) Dial(address string) error {
|
func (r *JsonRpc2Client) Dial(address string, maxRetries int) error {
|
||||||
var err error
|
var err error
|
||||||
r.conn, err = net.Dial("tcp", address)
|
r.address = address
|
||||||
if err != nil {
|
connected := false
|
||||||
|
for i := 0; i < maxRetries; i++ {
|
||||||
|
r.conn, err = net.Dial("tcp", address)
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Waiting for signal-cli to start up in daemon mode...")
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
connected = true
|
||||||
|
log.Info("Successfully connected to signal-cli in daemon mode")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if !connected {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,11 +221,14 @@ func (r *JsonRpc2Client) ReceiveData(number string, receiveWebhookUrl string) {
|
|||||||
for {
|
for {
|
||||||
str, err := connbuf.ReadString('\n')
|
str, err := connbuf.ReadString('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
elapsed := time.Since(r.lastTimeErrorMessageSent)
|
log.Error("Lost connection to signal-cli...attempting to reconnect (", err.Error(), ")")
|
||||||
if (elapsed) > time.Duration(5*time.Minute) { //avoid spamming the log file and only log the message at max every 5 minutes
|
r.conn.Close()
|
||||||
log.Error("Couldn't read data for number ", number, ": ", err.Error(), ". Is the number properly registered?")
|
err = r.Dial(r.address, 15)
|
||||||
r.lastTimeErrorMessageSent = time.Now()
|
if err != nil {
|
||||||
|
log.Fatal("Unable to reconnect to signal-cli: ", err.Error(), "...aborting")
|
||||||
}
|
}
|
||||||
|
connbuf = bufio.NewReader(r.conn)
|
||||||
|
log.Info("Successfully reconnected to signal-cli")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
log.Debug("json-rpc received data: ", str)
|
log.Debug("json-rpc received data: ", str)
|
||||||
@ -248,7 +265,7 @@ func (r *JsonRpc2Client) ReceiveData(number string, receiveWebhookUrl string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.Error("Received unparsable message: ", str)
|
log.Warn("Received unparsable message: ", str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2043,6 +2043,18 @@ const docTemplate = `{
|
|||||||
"name": "ignore_stories",
|
"name": "ignore_stories",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specify whether avatar downloads should be ignored when receiving messages",
|
||||||
|
"name": "ignore_avatars",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specify whether sticker pack downloads should be ignored when receiving messages",
|
||||||
|
"name": "ignore_stickers",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specify the maximum number of messages to receive (default: unlimited)",
|
"description": "Specify the maximum number of messages to receive (default: unlimited)",
|
||||||
|
|||||||
@ -2040,6 +2040,18 @@
|
|||||||
"name": "ignore_stories",
|
"name": "ignore_stories",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specify whether avatar downloads should be ignored when receiving messages",
|
||||||
|
"name": "ignore_avatars",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Specify whether sticker pack downloads should be ignored when receiving messages",
|
||||||
|
"name": "ignore_stickers",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specify the maximum number of messages to receive (default: unlimited)",
|
"description": "Specify the maximum number of messages to receive (default: unlimited)",
|
||||||
|
|||||||
@ -1916,6 +1916,16 @@ paths:
|
|||||||
in: query
|
in: query
|
||||||
name: ignore_stories
|
name: ignore_stories
|
||||||
type: string
|
type: string
|
||||||
|
- description: Specify whether avatar downloads should be ignored when receiving
|
||||||
|
messages
|
||||||
|
in: query
|
||||||
|
name: ignore_avatars
|
||||||
|
type: string
|
||||||
|
- description: Specify whether sticker pack downloads should be ignored when
|
||||||
|
receiving messages
|
||||||
|
in: query
|
||||||
|
name: ignore_stickers
|
||||||
|
type: string
|
||||||
- description: 'Specify the maximum number of messages to receive (default:
|
- description: 'Specify the maximum number of messages to receive (default:
|
||||||
unlimited)'
|
unlimited)'
|
||||||
in: query
|
in: query
|
||||||
|
|||||||
@ -163,7 +163,7 @@ func main() {
|
|||||||
jsonRpc2ClientConfigPathPath := *signalCliConfig + "/jsonrpc2.yml"
|
jsonRpc2ClientConfigPathPath := *signalCliConfig + "/jsonrpc2.yml"
|
||||||
signalCliApiConfigPath := *signalCliConfig + "/api-config.yml"
|
signalCliApiConfigPath := *signalCliConfig + "/api-config.yml"
|
||||||
signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir, signalCliMode, jsonRpc2ClientConfigPathPath, signalCliApiConfigPath, webhookUrl)
|
signalClient := client.NewSignalClient(*signalCliConfig, *attachmentTmpDir, *avatarTmpDir, signalCliMode, jsonRpc2ClientConfigPathPath, signalCliApiConfigPath, webhookUrl)
|
||||||
err = signalClient.Init()
|
err = signalClient.Init(15)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Couldn't init Signal Client: ", err.Error())
|
log.Fatal("Couldn't init Signal Client: ", err.Error())
|
||||||
}
|
}
|
||||||
@ -395,6 +395,8 @@ func main() {
|
|||||||
autoReceiveScheduleReceiveTimeout := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_RECEIVE_TIMEOUT", "10")
|
autoReceiveScheduleReceiveTimeout := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_RECEIVE_TIMEOUT", "10")
|
||||||
autoReceiveScheduleIgnoreAttachments := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_ATTACHMENTS", "false")
|
autoReceiveScheduleIgnoreAttachments := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_ATTACHMENTS", "false")
|
||||||
autoReceiveScheduleIgnoreStories := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_STORIES", "false")
|
autoReceiveScheduleIgnoreStories := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_STORIES", "false")
|
||||||
|
autoReceiveScheduleIgnoreAvatars := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_AVATARS", "false")
|
||||||
|
autoReceiveScheduleIgnoreStickers := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_IGNORE_STICKERS", "false")
|
||||||
autoReceiveScheduleSendReadReceipts := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_SEND_READ_RECEIPTS", "false")
|
autoReceiveScheduleSendReadReceipts := utils.GetEnv("AUTO_RECEIVE_SCHEDULE_SEND_READ_RECEIPTS", "false")
|
||||||
|
|
||||||
c := cron.New()
|
c := cron.New()
|
||||||
@ -424,6 +426,8 @@ func main() {
|
|||||||
q.Add("timeout", autoReceiveScheduleReceiveTimeout)
|
q.Add("timeout", autoReceiveScheduleReceiveTimeout)
|
||||||
q.Add("ignore_attachments", autoReceiveScheduleIgnoreAttachments)
|
q.Add("ignore_attachments", autoReceiveScheduleIgnoreAttachments)
|
||||||
q.Add("ignore_stories", autoReceiveScheduleIgnoreStories)
|
q.Add("ignore_stories", autoReceiveScheduleIgnoreStories)
|
||||||
|
q.Add("ignore_avatars", autoReceiveScheduleIgnoreAvatars)
|
||||||
|
q.Add("ignore_stickers", autoReceiveScheduleIgnoreStickers)
|
||||||
q.Add("send_read_receipts", autoReceiveScheduleSendReadReceipts)
|
q.Add("send_read_receipts", autoReceiveScheduleSendReadReceipts)
|
||||||
req.URL.RawQuery = q.Encode()
|
req.URL.RawQuery = q.Encode()
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,15 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/bbernhard/signal-cli-rest-api/utils"
|
"github.com/bbernhard/signal-cli-rest-api/utils"
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
const supervisorctlConfigTemplate = `
|
|
||||||
[program:%s]
|
|
||||||
process_name=%s
|
|
||||||
command=bash -c "nc -l -p %d <%s | signal-cli --output=json --config %s%s jsonRpc%s%s >%s"
|
|
||||||
autostart=true
|
|
||||||
autorestart=true
|
|
||||||
startretries=10
|
|
||||||
user=signal-api
|
|
||||||
directory=/usr/bin/
|
|
||||||
redirect_stderr=true
|
|
||||||
stdout_logfile=/var/log/%s/out.log
|
|
||||||
stderr_logfile=/var/log/%s/err.log
|
|
||||||
stdout_logfile_maxbytes=50MB
|
|
||||||
stdout_logfile_backups=10
|
|
||||||
numprocs=1
|
|
||||||
`
|
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
signalCliConfigDir := "/home/.local/share/signal-cli/"
|
signalCliConfigDir := "/home/.local/share/signal-cli/"
|
||||||
signalCliConfigDirEnv := utils.GetEnv("SIGNAL_CLI_CONFIG_DIR", "")
|
signalCliConfigDirEnv := utils.GetEnv("SIGNAL_CLI_CONFIG_DIR", "")
|
||||||
@ -41,72 +23,57 @@ func main() {
|
|||||||
jsonRpc2ClientConfig := utils.NewJsonRpc2ClientConfig()
|
jsonRpc2ClientConfig := utils.NewJsonRpc2ClientConfig()
|
||||||
|
|
||||||
var tcpPort int64 = 6001
|
var tcpPort int64 = 6001
|
||||||
fifoPathname := "/tmp/sigsocket1"
|
jsonRpc2ClientConfig.AddEntry(utils.MULTI_ACCOUNT_NUMBER, utils.JsonRpc2ClientConfigEntry{TcpPort: tcpPort})
|
||||||
|
|
||||||
jsonRpc2ClientConfig.AddEntry(utils.MULTI_ACCOUNT_NUMBER, utils.JsonRpc2ClientConfigEntry{TcpPort: tcpPort, FifoPathname: fifoPathname})
|
args := []string{"--output=json", "--config", signalCliConfigDir}
|
||||||
|
|
||||||
os.Remove(fifoPathname) //remove any existing named pipe
|
|
||||||
|
|
||||||
_, err := exec.Command("mkfifo", fifoPathname).Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't create fifo with name ", fifoPathname, ": ", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
uid := utils.GetEnv("SIGNAL_CLI_UID", "1000")
|
|
||||||
gid := utils.GetEnv("SIGNAL_CLI_GID", "1000")
|
|
||||||
_, err = exec.Command("chown", uid+":"+gid, fifoPathname).Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't change permissions of fifo with name ", fifoPathname, ": ", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
signalCliIgnoreAttachments := ""
|
|
||||||
ignoreAttachments := utils.GetEnv("JSON_RPC_IGNORE_ATTACHMENTS", "")
|
|
||||||
if ignoreAttachments == "true" {
|
|
||||||
signalCliIgnoreAttachments = " --ignore-attachments"
|
|
||||||
}
|
|
||||||
|
|
||||||
signalCliIgnoreStories := ""
|
|
||||||
ignoreStories := utils.GetEnv("JSON_RPC_IGNORE_STORIES", "")
|
|
||||||
if ignoreStories == "true" {
|
|
||||||
signalCliIgnoreStories = " --ignore-stories"
|
|
||||||
}
|
|
||||||
|
|
||||||
supervisorctlProgramName := "signal-cli-json-rpc-1"
|
|
||||||
supervisorctlLogFolder := "/var/log/" + supervisorctlProgramName
|
|
||||||
_, err = exec.Command("mkdir", "-p", supervisorctlLogFolder).Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't create log folder ", supervisorctlLogFolder, ": ", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
trustNewIdentities := ""
|
|
||||||
trustNewIdentitiesEnv := utils.GetEnv("JSON_RPC_TRUST_NEW_IDENTITIES", "")
|
trustNewIdentitiesEnv := utils.GetEnv("JSON_RPC_TRUST_NEW_IDENTITIES", "")
|
||||||
if trustNewIdentitiesEnv == "on-first-use" {
|
if trustNewIdentitiesEnv == "on-first-use" {
|
||||||
trustNewIdentities = " --trust-new-identities on-first-use"
|
args = append(args, []string{"--trust-new-identities", "on-first-use"}...)
|
||||||
} else if trustNewIdentitiesEnv == "always" {
|
} else if trustNewIdentitiesEnv == "always" {
|
||||||
trustNewIdentities = " --trust-new-identities always"
|
args = append(args, []string{"--trust-new-identities", "always"}...)
|
||||||
} else if trustNewIdentitiesEnv == "never" {
|
} else if trustNewIdentitiesEnv == "never" {
|
||||||
trustNewIdentities = " --trust-new-identities never"
|
args = append(args, []string{"--trust-new-identities", "never"}...)
|
||||||
} else if trustNewIdentitiesEnv != "" {
|
} else if trustNewIdentitiesEnv != "" {
|
||||||
log.Fatal("Invalid JSON_RPC_TRUST_NEW_IDENTITIES environment variable set!")
|
log.Fatal("Invalid JSON_RPC_TRUST_NEW_IDENTITIES environment variable set!")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info("Updated jsonrpc2.yml")
|
args = append(args, "daemon")
|
||||||
|
|
||||||
//write supervisorctl config
|
ignoreAttachments := utils.GetEnv("JSON_RPC_IGNORE_ATTACHMENTS", "")
|
||||||
supervisorctlConfigFilename := "/etc/supervisor/conf.d/" + "signal-cli-json-rpc-1.conf"
|
if ignoreAttachments == "true" {
|
||||||
|
args = append(args, "--ignore-attachments")
|
||||||
supervisorctlConfig := fmt.Sprintf(supervisorctlConfigTemplate, supervisorctlProgramName, supervisorctlProgramName,
|
|
||||||
tcpPort, fifoPathname, signalCliConfigDir, trustNewIdentities, signalCliIgnoreAttachments, signalCliIgnoreStories, fifoPathname,
|
|
||||||
supervisorctlProgramName, supervisorctlProgramName)
|
|
||||||
|
|
||||||
err = ioutil.WriteFile(supervisorctlConfigFilename, []byte(supervisorctlConfig), 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatal("Couldn't write ", supervisorctlConfigFilename, ": ", err.Error())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ignoreStories := utils.GetEnv("JSON_RPC_IGNORE_STORIES", "")
|
||||||
|
if ignoreStories == "true" {
|
||||||
|
args = append(args, "--ignore-stories")
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreAvatars := utils.GetEnv("JSON_RPC_IGNORE_AVATARS", "")
|
||||||
|
if ignoreAvatars == "true" {
|
||||||
|
args = append(args, "--ignore-avatars")
|
||||||
|
}
|
||||||
|
|
||||||
|
ignoreStickers := utils.GetEnv("JSON_RPC_IGNORE_STICKERS", "")
|
||||||
|
if ignoreStickers == "true" {
|
||||||
|
args = append(args, "--ignore-stickers")
|
||||||
|
}
|
||||||
|
|
||||||
|
args = append(args, []string{"--tcp", "127.0.0.1:" + strconv.FormatInt(tcpPort, 10)}...)
|
||||||
|
|
||||||
// write jsonrpc.yml config file
|
// write jsonrpc.yml config file
|
||||||
err = jsonRpc2ClientConfig.Persist(signalCliConfigDir + "jsonrpc2.yml")
|
err := jsonRpc2ClientConfig.Persist(signalCliConfigDir + "jsonrpc2.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("Couldn't persist jsonrpc2.yaml: ", err.Error())
|
log.Fatal("Couldn't persist jsonrpc2.yaml: ", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Info("Updated jsonrpc2.yml")
|
||||||
|
|
||||||
|
env := os.Environ()
|
||||||
|
|
||||||
|
err = syscall.Exec("/usr/bin/signal-cli", args, env)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("Couldn't start signal-cli in json-rpc mode: ", err.Error())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,15 +2,15 @@ package utils
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const MULTI_ACCOUNT_NUMBER string = "<multi-account>"
|
const MULTI_ACCOUNT_NUMBER string = "<multi-account>"
|
||||||
|
|
||||||
type JsonRpc2ClientConfigEntry struct {
|
type JsonRpc2ClientConfigEntry struct {
|
||||||
TcpPort int64 `yaml:"tcp_port"`
|
TcpPort int64 `yaml:"tcp_port"`
|
||||||
FifoPathname string `yaml:"fifo_pathname"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type JsonRpc2ClientConfigEntries struct {
|
type JsonRpc2ClientConfigEntries struct {
|
||||||
@ -47,14 +47,6 @@ func (c *JsonRpc2ClientConfig) GetTcpPortForNumber(number string) (int64, error)
|
|||||||
return 0, errors.New("Number " + number + " not found in local map")
|
return 0, errors.New("Number " + number + " not found in local map")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *JsonRpc2ClientConfig) GetFifoPathnameForNumber(number string) (string, error) {
|
|
||||||
if val, ok := c.config.Entries[number]; ok {
|
|
||||||
return val.FifoPathname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", errors.New("Number " + number + " not found in local map")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *JsonRpc2ClientConfig) GetTcpPortsForNumbers() map[string]int64 {
|
func (c *JsonRpc2ClientConfig) GetTcpPortsForNumbers() map[string]int64 {
|
||||||
mapping := make(map[string]int64)
|
mapping := make(map[string]int64)
|
||||||
for number, val := range c.config.Entries {
|
for number, val := range c.config.Entries {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user