mirror of
https://github.com/bbernhard/signal-cli-rest-api.git
synced 2026-05-24 14:24:15 +00:00
Compare commits
11 Commits
edc7f461ae
...
1d928bfe5a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d928bfe5a | ||
|
|
ed3626fa77 | ||
|
|
6257fa754d | ||
|
|
dd6d763618 | ||
|
|
1ea89705d5 | ||
|
|
9e5d73b5c0 | ||
|
|
d080e8d478 | ||
|
|
a9c367a5b1 | ||
|
|
8d13f5f383 | ||
|
|
3a36a04b09 | ||
|
|
a6b4392fd7 |
12
Dockerfile
12
Dockerfile
@ -1,13 +1,13 @@
|
|||||||
ARG SIGNAL_CLI_VERSION=0.14.0
|
ARG SIGNAL_CLI_VERSION=0.14.0
|
||||||
ARG LIBSIGNAL_CLIENT_VERSION=0.87.4
|
ARG LIBSIGNAL_CLIENT_VERSION=0.87.4
|
||||||
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.14.0+morph027+1
|
ARG SIGNAL_CLI_NATIVE_PACKAGE_VERSION=0.14.0+morph027+3
|
||||||
|
|
||||||
ARG SWAG_VERSION=1.16.4
|
ARG SWAG_VERSION=1.16.4
|
||||||
ARG GRAALVM_VERSION=25.0.2
|
ARG GRAALVM_VERSION=25.0.2
|
||||||
|
|
||||||
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
|
||||||
@ -31,8 +31,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 && \
|
||||||
@ -90,8 +90,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 \
|
||||||
|
|||||||
@ -1,11 +1,22 @@
|
|||||||
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-dev
|
||||||
|
build: "."
|
||||||
environment:
|
environment:
|
||||||
- MODE=normal #supported modes: json-rpc, native, normal
|
- MODE=normal #supported modes: json-rpc, json-rpc-native, native, normal
|
||||||
|
- ENABLE_PLUGINS=true
|
||||||
|
- DEFAULT_SIGNAL_TEXT_MODE=styled
|
||||||
|
- SWAGGER_IP=127.0.0.1
|
||||||
|
- PODMAN_USERNS=keep-id
|
||||||
|
#- JSON_RPC_IGNORE_ATTACHMENTS=true
|
||||||
|
#- JSON_RPC_IGNORE_STORIES=true
|
||||||
|
#- RECEIVE_WEBHOOK_URL=http://127.0.0.1:8089/webhook
|
||||||
|
#- JSON_RPC_TRUST_NEW_IDENTITIES=always
|
||||||
|
#- RECEIVE_WEBHOOK_URL=http://127.0.0.1:8080/v1/plugins/abc
|
||||||
#- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below)
|
#- AUTO_RECEIVE_SCHEDULE=0 22 * * * #enable this parameter on demand (see description below)
|
||||||
|
#network_mode: host
|
||||||
ports:
|
ports:
|
||||||
- "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
|
||||||
|
- "./plugins:/plugins"
|
||||||
|
|||||||
@ -4,40 +4,57 @@ set -x
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
[ -z "${SIGNAL_CLI_CONFIG_DIR}" ] && echo "SIGNAL_CLI_CONFIG_DIR environmental variable needs to be set! Aborting!" && exit 1;
|
[ -z "${SIGNAL_CLI_CONFIG_DIR}" ] && echo "SIGNAL_CLI_CONFIG_DIR environmental variable needs to be set! Aborting!" && exit 1;
|
||||||
|
[ -z "${SIGNAL_CLI_UID}" ] && echo "SIGNAL_CLI_UID environmental variable needs to be set! Aborting!" && exit 1;
|
||||||
|
[ -z "${SIGNAL_CLI_GID}" ] && echo "SIGNAL_CLI_GID environmental variable needs to be set! Aborting!" && exit 1;
|
||||||
|
|
||||||
usermod -u ${SIGNAL_CLI_UID} signal-api
|
# Check if we are already running as the target user and group
|
||||||
groupmod -o -g ${SIGNAL_CLI_GID} signal-api
|
RUNNING_AS_TARGET_USER=false
|
||||||
|
if [ "$(id -u)" -eq "${SIGNAL_CLI_UID}" ] && [ "$(id -g)" -eq "${SIGNAL_CLI_GID}" ]; then
|
||||||
# Fix permissions to ensure backward compatibility if SIGNAL_CLI_CHOWN_ON_STARTUP is not set to "false"
|
RUNNING_AS_TARGET_USER=true
|
||||||
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
|
fi
|
||||||
|
|
||||||
# Show warning on docker exec
|
if [ "$RUNNING_AS_TARGET_USER" = "true" ]; then
|
||||||
cat <<EOF >> /root/.bashrc
|
echo "Already running as UID ${SIGNAL_CLI_UID} and GID ${SIGNAL_CLI_GID}. Skipping privileged operations."
|
||||||
|
else
|
||||||
|
echo "Adjusting user and group IDs to ${SIGNAL_CLI_UID}:${SIGNAL_CLI_GID}"
|
||||||
|
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 "WARNING: signal-cli-rest-api runs as signal-api (not as root!)"
|
||||||
echo "Run 'su signal-api' before using signal-cli!"
|
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}\""
|
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
|
EOF
|
||||||
|
fi
|
||||||
cap_prefix="-cap_"
|
|
||||||
caps="$cap_prefix$(seq -s ",$cap_prefix" 0 $(cat /proc/sys/kernel/cap_last_cap))"
|
|
||||||
|
|
||||||
# TODO: check mode
|
# TODO: check mode
|
||||||
if [ "$MODE" = "json-rpc" ]
|
if [ "$MODE" = "json-rpc" ]; then
|
||||||
then
|
/usr/bin/jsonrpc2-helper
|
||||||
/usr/bin/jsonrpc2-helper
|
if [ -n "$JAVA_OPTS" ]; then
|
||||||
if [ -n "$JAVA_OPTS" ] ; then
|
echo "export JAVA_OPTS='$JAVA_OPTS'" >> /etc/default/supervisor
|
||||||
echo "export JAVA_OPTS='$JAVA_OPTS'" >> /etc/default/supervisor
|
fi
|
||||||
fi
|
service supervisor start
|
||||||
service supervisor start
|
supervisorctl start all
|
||||||
supervisorctl start all
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export HOST_IP=$(hostname -I | awk '{print $1}')
|
export HOST_IP=$(hostname -I | awk '{print $1}')
|
||||||
|
|
||||||
# Start API as signal-api user
|
# 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}
|
if [ "$RUNNING_AS_TARGET_USER" = "true" ]; then
|
||||||
|
# Already running as the target user, start directly
|
||||||
|
exec signal-cli-rest-api -signal-cli-config="${SIGNAL_CLI_CONFIG_DIR}"
|
||||||
|
else
|
||||||
|
# Use setpriv to switch to target user
|
||||||
|
cap_prefix="-cap_"
|
||||||
|
caps="$cap_prefix$(seq -s ",$cap_prefix" 0 $(cat /proc/sys/kernel/cap_last_cap))"
|
||||||
|
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}"
|
||||||
|
fi
|
||||||
|
|||||||
@ -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.
|
||||||
@ -843,6 +843,7 @@ func (a *Api) AddMembersToGroup(c *gin.Context) {
|
|||||||
|
|
||||||
err = a.signalClient.AddMembersToGroup(number, groupId, req.Members)
|
err = a.signalClient.AddMembersToGroup(number, groupId, req.Members)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
log.Info("ERR NOT NULL")
|
||||||
switch err.(type) {
|
switch err.(type) {
|
||||||
case *client.NotFoundError:
|
case *client.NotFoundError:
|
||||||
c.JSON(404, Error{Msg: err.Error()})
|
c.JSON(404, Error{Msg: err.Error()})
|
||||||
@ -1174,19 +1175,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 +2081,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
|
||||||
|
|||||||
@ -1349,7 +1349,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 +1359,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 +2634,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 +2705,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 {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user