secured-signal-api

command module
v1.5.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2026 License: MIT Imports: 8 Imported by: 0

README ΒΆ

Secure Proxy for Signal CLI REST API

Secure Proxy for Signal CLI REST API

token-based authentication, endpoint restrictions, placeholders, flexible configuration

πŸ”’ Secure Β· ⭐️ Configurable Β· πŸš€ Easy to Deploy with Docker

Contents

[!IMPORTANT] Check out the Official Documentation for up-to-date instructions and additional content!

[!WARNING] We are slowly moving away from this README and instead are trying to make the Official Documentation the only source of truth

Getting Started

Prerequisites: You need Docker and Docker Compose installed.

Get the latest version of the docker-compose.yaml file:

services:
  signal-api:
    image: bbernhard/signal-cli-rest-api:latest
    container_name: signal-api
    environment:
      - MODE=normal
    volumes:
      - ./data:/home/.local/share/signal-cli
    restart: unless-stopped
    networks:
      backend:
        aliases:
          - signal-api

  secured-signal:
    image: ghcr.io/codeshelldev/secured-signal-api:latest
    container_name: secured-signal
    environment:
      API__URL: http://signal-api:8080
      SETTINGS__MESSAGE__VARIABLES__RECIPIENTS: "[+123400002, +123400003, +123400004]"
      SETTINGS__MESSAGE__VARIABLES__NUMBER: "+123400001"
      API__TOKENS: "[LOOOOOONG_STRING]"
    ports:
      - "8880:8880"
    restart: unless-stopped
    networks:
      backend:
        aliases:
          - secured-signal-api

networks:
  backend:

And add secure tokens to api.tokens. See API Tokens.

[!IMPORTANT] Here we'll use sec-signal-api:8880 as the host, but replace it with your actual container/host IP, port, or hostname

Setup

Before you can send messages via Secured Signal API you must first set up Signal CLI REST API

  1. Register or link a Signal account with signal-cli-rest-api

  2. Deploy secured-signal-api with at least one API token

  3. Confirm you can send a test message (See Usage)

[!IMPORTANT] Run setup directly with Signal CLI REST API. Setup requests via Secured Signal API are blocked by default

Usage

Secured Signal API provides 5 ways to authenticate

Auth

Method Example
Bearer Auth Add Authorization: Bearer API_TOKEN to headers
Basic Auth Add Authorization: Basic BASE64_STRING (api:API_TOKEN)
Query Auth Append @auth=API_TOKEN to request URL
Path Auth Prepend request path with /@auth=API_TOKEN/
Body Auth Set auth to API_TOKEN in the request body

[!WARNING] Query and Path auth are disabled by default and must be enabled in the config

Example

To send a message to +123400002:

curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer API_TOKEN" -d '{"message": "Hello World!", "recipients": ["+123400002"]}' http://sec-signal-api:8880/v2/send

Advanced

Placeholders

If you are not comfortable / don't want to hard-code your number for example and/or recipients in you, may use placeholders in your request.

How to use:

Scope Example Note
Body {{@data.key}}
Header {{#Content_Type}} - becomes _
Variable {{.VAR}} always uppercase

Where to use:

Scope Example
Body {"number": "{{ .NUMBER }}", "recipients": "{{ .RECIPIENTS }}"}
Query http://sec-signal-api:8880/v1/receive/?@number={{.NUMBER}}
Path http://sec-signal-api:8880/v1/receive/{{.NUMBER}}

You can also combine them:

{
	"content": "{{.NUMBER}} -> {{.RECIPIENTS}}"
}
URL-to-Body Injection

In some cases you may not be able to access / modify the request body, in that case specify needed values in the request query or path:

http://sec-signal-api:8880/@key2=value2/?@key=value

[!IMPORTANT] To differentiate injection queries from regular queries, prefix the key with @. Only keys starting with @ are injected into the request body.

[!NOTE]

  • Supported value types include strings, integers, arrays, and JSON objects
  • See Formatting for details on supported structures and syntax

Supported placeholder types:

. Variables @ Body # Headers
❌ βœ… ❌

Configuration

There are multiple ways to configure Secured Signal API, you can optionally use config.yml as well as environment variables to override the config.

Config Files

Config files allow YAML formatting and ${ENV} to get environment variables.

To change the internal config file location set CONFIG_PATH in your environment. (default: /config/config.yml)

This example config shows all the individual settings that can be applied:

# Example Config (all configurations shown)
service:
  logLevel: info
  port: 8880
  hostnames:
    - mydomain.com

api:
  url: http://signal-api:8080
  tokens: [token1, token2]
  auth:
    methods: [bearer, basic, body]
    tokens:
      - set: [pathToken1, pathToken2]
        methods: [path]
      - set: [queryAndBodyToken]
        methods: [body, query]

settings:
  message:
    template: |
      You've got a Notification:
      {{@message}} 
      At {{@data.timestamp}} on {{@data.date}}.
      Send using {{.NUMBER}}.

    variables:
      number: "+123400001"
      recipients: ["+123400002", "group.id", "user.id"]

    fieldMappings:
      "@message": [{ field: "msg", score: 100 }]

  access:
    trustedIPs:
      - 192.168.1.10

    trustedProxies:
      - 172.20.0.100

    ipFilter:
      - 192.168.1.10
      - 192.168.2.0/24
      - "!192.168.2.44"

    endpoints:
      - "!/v1/about"
      - /v2/send

    rateLimiting:
      limit: 100
      period: 1h

    fieldPolicies:
      "@number":
        - value: "+123400003"
          action: block
        - value: "+123400004"
          action: block
Token Configs

You can also override the config.yml file for each individual token by adding configs under TOKENS_PATH (default: config/tokens/)

Here is an example:

# Example Token Config (overwrites)
service:
  logLevel: info
  port: 8880
  hostnames:
    - mydomain.com

api:
  tokens: [token1, token2]
  auth:
    methods: [bearer, basic, body, path] # add path auth

settings:
  message:
    template: # disable
    variables: # overwrite main config variables
      number: "+123400010"
      recipients: ["+123400020", "group.id", "user.id"]

    fieldMappings: # overwrite @message from main config
      "@message": [{ field: "msg", score: 100 }]

  access:
    trustedIPs: # disable
    trustedProxies: # disable
    ipFilter: # disable

    endpoints: # overwrite main config endpoints
      - "!/v1/about"
      - /v1/receive
      - /v2/send

    rateLimiting:
      limit: 100
      period: 10h # overwrite main config period

    fieldPolicies: # disable

API Tokens

During authentication Secured Signal API will try to match the given token against the list of tokens inside of the api.tokens (or api.auth.tokens) attribute.

api:
  tokens: [token1, token2, token3]

[!IMPORTANT] Using API tokens is highly recommended, but not mandatory. Some important security features won't be available (for example the default blocked endpoints)

[!NOTE] Blocked endpoints can be reactivated by manually configuring them

Endpoints

Since Secured Signal API is just a proxy you can use all the Signal CLI REST API endpoints except for…

Endpoint
/v1/configuration /v1/unregister
/v1/devices /v1/contacts
/v1/register /v1/accounts
/v1/qrcodelink

These endpoints are blocked by default due to security risks.

[!IMPORTANT]

  1. Matching uses regex
  2. On compile error exact match is used instead

[!WARNING] Remember that some symbols have special meanings in regex, a good rule of thumb is:

  • If it is a special character, it probably needs to be escaped (/) if you are not looking to use regex
  • Otherwise test your pattern on a regex testing site

You can modify endpoints by configuring access.endpoints in your config:

settings:
  access:
    endpoints:
      - "!/v1/receive"
      - /v2/send

By default adding an endpoint explicitly allows access to it, use ! to block it instead.

[!IMPORTANT] When using ! to block you must enclose the endpoint with quotes, like in the example above

Allow Block Result
/v2/send β€” Only /v2/send allowed
β€” !/v1/receive All allowed, except /v1/receive
/v2/send !/v2/.* Only /v2/send allowed

Variables

Variables can be added under variables and can then be referenced in the body, query, or path. See Placeholders.

[!NOTE] Variables are always converted into an uppercase string. Example: number β‡’ NUMBER in {{.NUMBER}}

settings:
  message:
    variables:
      number: "+123400001",
      recipients: ["+123400002", "group.id", "user.id"]

Message Templates

To customize the message attribute you can use Message Templates to build your message by using other body keys and variables. Use message.template to configure:

settings:
  message:
    template: |
      Your Message:
      {{@message}}.
      Sent with Secured Signal API.

Supported placeholder types:

. Variables @ Body # Headers
βœ… βœ… βœ…

Field Policies

Field Policies allow for blocking or specifically allowing certain fields with set values from being used in the requests body or headers.

Configure them by using access.fieldPolicies like so:

settings:
  access:
    fieldPolicies:
      "@number":
        - value: "+123400002"
          action: block
        - value: "+123400003"
          action: block

Set the wanted action on encounter, available options are block and allow.

[!IMPORTANT] String fields always try to use

  1. Regex matching
  2. On compile error exact match is used as fallback

[!WARNING] Remember that some symbols have special meanings in regex, a good rule of thumb is:

  • If it is a special, it probably needs to be escaped (/) if you are not looking to use regex
  • Otherwise test your pattern on a regex testing site

Supported placeholder types:

. Variables @ Body # Headers
❌ βœ… βœ…

Field Mappings

To improve compatibility with other services Secured Signal API provides Field Mappings and a built-in message mapping.

Default `message` mapping
Field Score Field Score
msg 100 data.content 9
content 99 data.description 8
description 98 data.text 7
text 20 data.summary 6
summary 15 data.details 5
details 14 body 2
data.message 10 data 1

Secured Signal API will pick the best scoring field (if available) to set the key to the correct value from the request body.

Field Mappings can be added by setting message.fieldMappings in your config:

settings:
  message:
    fieldMappings:
      "@message":
        [
          { field: "msg", score: 80 },
          { field: "data.message", score: 79 },
          { field: "array[0].message", score: 78 },
        ]
      ".NUMBER": [{ field: "phone_number", score: 100 }]

Supported placeholder types:

. Variables @ Body # Headers
βœ… βœ… ❌

Contributing

Found a bug? Want to change or add something? Feel free to open up an issue or create a pull request!

Support

Has this Repo been helpful πŸ‘οΈ to you? Then consider ⭐️'ing this Project.

:)

Help

Are you having problems setting up Secured Signal API?
No worries check out the discussions tab and ask for help.

We are all volunteers, so please be friendly and patient.

License

This Project is licensed under the MIT License.

Logo designed by @CodeShellDev, All Rights Reserved.

This Project is not affiliated with the Signal Foundation.

Documentation ΒΆ

The Go Gopher

There is no documentation for this package.

Directories ΒΆ

Path Synopsis
internals
utils
mockserver command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL