Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions versioned_docs/version-v1.5/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
---
sidebar_position: 1
title: About
---

# About

**Secured Signal API** is a secure, configurable proxy for [Signal CLI REST API](https://github.com/bbernhard/signal-cli-rest-api).
It does **not** replace or modify the original API — it sits in front of it, adding a layer of control, authentication, and flexibility for production use.

## What it Is

The [Signal CLI REST API](https://github.com/bbernhard/signal-cli-rest-api) provides a robust HTTP interface to the Signal Messenger service.
**Secured Signal API** works as a **reverse proxy**, forwarding approved requests to your existing Signal CLI REST API instance, while managing access and configuration.

It's designed for developers who want to:

- **Restrict** or **log** certain API calls
- Enforce **authentication**
- Add **templating** or **request preprocessing**
- And deploy everything neatly via **Docker**

## Key Features

- 🔒 **Access Control** — Protect your Signal API with [**token-based authentication**](./usage#auth), [**endpoint restrictions**](./features#endpoints) and [**IP filters**](./features#ip-filter).
- 🧩 **Full Compatibility** — 100% protocol-compatible; all requests are still handled by your existing Signal CLI REST API.
- ⚙️ **Configurable Proxy Behavior** — Define templates and limits via YAML or environment variables.
- 🧠 **Message Templates** — Use [**variables**](./configuration/variables) and [**placeholders**](./features#placeholders) to standardize common message formats.
- 🐳 **Docker-Ready** — Comes packaged for containerized environments, deployable in seconds.
- [And much more…](./features)

## Architecture

Secured Signal API acts purely as a **gateway** — it never bypasses or replaces your existing Signal CLI REST API:

```mermaid
flowchart TD
A[Client App / Script]
B[TLS Reverse Proxy]
C[Secured Signal API]
D[Signal CLI REST API]
E[Signal Servers]

A -. HTTP Request .-> B
B -. HTTPS .-> C
C -- Forwarded Request --> D
D -. Encrypted Signal .-> E

classDef gateway fill:#1e3a8a,stroke:#93c5fd,stroke-width:1.5px,color:#ffffff;
class C gateway;

classDef external fill:#374151,stroke:#9ca3af,stroke-width:1.5px,color:#ffffff;
class A,E external;
```
23 changes: 23 additions & 0 deletions versioned_docs/version-v1.5/best-practices/best-practices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
sidebar_position: 5
title: Best Practices
---

# Best Practices

Here are some common best practices for running **Secured Signal API**, but these generally apply for any service.

## Usage

- Create **separate configs** for each service
- Use [**placeholders**](./usage/advanced#placeholders) extensively
- Always keep your stack **up-to-date**

## Security

- Always use **API tokens** in production
- Run behind a [**tls-enabled reverse proxy**](./reverse-proxy)
- Be cautious when overriding [**blocked endpoints**](./features#endpoints)
- Use per-token overrides to **enforce least privilege**
- Always allow the least possible [**endpoints**](./features#endpoints)
- Only allow access from [**IPs**](./features#ip-filter) **you trust**
4 changes: 4 additions & 0 deletions versioned_docs/version-v1.5/configuration/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"label": "Configuration",
"position": 5
}
21 changes: 21 additions & 0 deletions versioned_docs/version-v1.5/configuration/api-tokens.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: API Tokens
---

# API Tokens

> [!IMPORTANT]
> Using API tokens is highly **recommended**, but not mandatory.
> Some important Security Features won't be available (for example the default [blocked endpoints](./endpoints#default))

Define API tokens for accessing **Secured Signal API**.

```yaml
api:
tokens: [token1, token2, token3]
```

See [Auth](./auth) for possible auth methods and how to activate additional ones.

> [!NOTE]
> Blocked endpoints can be reactivated by manually configuring them
22 changes: 22 additions & 0 deletions versioned_docs/version-v1.5/configuration/auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
---
title: Auth
---

# Auth

The `auth` setting under `api` is used for configuring auth methods and setting API tokens.
(default methods: `bearer, basic, body`)

**Example:**

```yaml
api:
auth:
methods: [query, path]
tokens:
- set: [token4, token5]
methods: [body]
```

In the example above **Query** and **Path** auth have been enabled in favor of **Bearer**, **Basic** and **Body** auth.
This applies to any token defined in [`api.tokens`](./api-tokens), <br/>`token4` and `token5` on the other hand only allow for being used with **Body** auth.
59 changes: 59 additions & 0 deletions versioned_docs/version-v1.5/configuration/endpoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
---
title: Endpoints
---

# Endpoints

Restrict access to your **Secured Signal API**.

## Default

Secured Signal API is just a proxy, which means any and all the **Signal CLI REST API** **endpoints are available**,
because of security concerns the following endpoints are blocked:

| Endpoint | |
| :-------------------- | ------------------ |
| **/v1/configuration** | **/v1/unregister** |
| **/v1/devices** | **/v1/contacts** |
| **/v1/register** | **/v1/accounts** |
| **/v1/qrcodelink** | |

## Customize

> [!IMPORTANT]
>
> 1. Matching uses [regex](https://regex101.com)
> 2. On compile error exact match is used instead

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

```yaml
settings:
access:
endpoints:
- "!/v1/register"
- "!/v1/unregister"
- "!/v1/qrcodelink"
- "!/v1/contacts"
- /v2/send
```

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

> [!NOTE]
> When using `!` to block you must enclose the endpoint in quotes, like in the example above

## Behavior

| Allow | Block | Result |
| ---------- | -------------- | ----------------------------------------- |
| `/v2/send` | — | **Only** `/v2/send` allowed |
| — | `!/v1/receive` | **All** allowed, **except** `/v1/receive` |
| `/v2/send` | `!/v2/.*` | **Only** `/v2/send` allowed |

### Rules

- Default: **allow all**
- Allow rules exist: default **block**
- Only block rules exist: default **allow**
- Explicit allow **overrides** block
59 changes: 59 additions & 0 deletions versioned_docs/version-v1.5/configuration/examples/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
settings:
message:
template: |
{{- $greeting := "Hello" -}}
{{ $greeting }}, {{ @name }}!
{{ if @age -}}
You are {{ @age }} years old.
{{- else -}}
Age unknown.
{{- end }}
Your friends:
{{- range @friends }}
- {{ . }}
{{- else }}
You have no friends.
{{- end }}
Profile details:
{{- range $key, $value := @profile }}
- {{ $key }}: {{ $value }}
{{- end }}
{{ define "footer" -}}
This is the footer for {{ @name }}.
{{- end }}
{{ template "footer" . -}}
------------------------------------
Content-Type: {{ #Content_Type }}
Redacted Auth Header: {{ #Authorization }}
37 changes: 37 additions & 0 deletions versioned_docs/version-v1.5/configuration/examples/token.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# 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
48 changes: 48 additions & 0 deletions versioned_docs/version-v1.5/configuration/field-mappings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Field Mappings
---

# Field Mappings

A compatibility layer for **Secured Signal API**.

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

<details>
<summary><strong>Default `message` mapping</strong></summary>

| 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 |

</details>

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

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

```yaml
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 }]
```

> [!NOTE]
> Supported [placeholder types](../usage/advanced#placeholders):
>
> | `.` Variables | `@` Body | `#` Headers |
> | ------------- | -------- | ----------- |
> | ✅ | ✅ | ❌ |
Loading