diff --git a/versioned_docs/version-v1.5/about.md b/versioned_docs/version-v1.5/about.md new file mode 100644 index 00000000..1f8b4c75 --- /dev/null +++ b/versioned_docs/version-v1.5/about.md @@ -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; +``` diff --git a/versioned_docs/version-v1.5/best-practices/best-practices.md b/versioned_docs/version-v1.5/best-practices/best-practices.md new file mode 100644 index 00000000..9e94985d --- /dev/null +++ b/versioned_docs/version-v1.5/best-practices/best-practices.md @@ -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** diff --git a/versioned_docs/version-v1.5/configuration/_category_.json b/versioned_docs/version-v1.5/configuration/_category_.json new file mode 100644 index 00000000..c2b07d5b --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Configuration", + "position": 5 +} diff --git a/versioned_docs/version-v1.5/configuration/api-tokens.md b/versioned_docs/version-v1.5/configuration/api-tokens.md new file mode 100644 index 00000000..23c762fd --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/api-tokens.md @@ -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 diff --git a/versioned_docs/version-v1.5/configuration/auth.md b/versioned_docs/version-v1.5/configuration/auth.md new file mode 100644 index 00000000..a5440865 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/auth.md @@ -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),
`token4` and `token5` on the other hand only allow for being used with **Body** auth. diff --git a/versioned_docs/version-v1.5/configuration/endpoints.md b/versioned_docs/version-v1.5/configuration/endpoints.md new file mode 100644 index 00000000..6e5a057f --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/endpoints.md @@ -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 diff --git a/versioned_docs/version-v1.5/configuration/examples/config.yml b/versioned_docs/version-v1.5/configuration/examples/config.yml new file mode 100644 index 00000000..ac569362 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/examples/config.yml @@ -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 diff --git a/versioned_docs/version-v1.5/configuration/examples/message-template.yml b/versioned_docs/version-v1.5/configuration/examples/message-template.yml new file mode 100644 index 00000000..74f40e37 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/examples/message-template.yml @@ -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 }} diff --git a/versioned_docs/version-v1.5/configuration/examples/token.yml b/versioned_docs/version-v1.5/configuration/examples/token.yml new file mode 100644 index 00000000..acfee731 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/examples/token.yml @@ -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 diff --git a/versioned_docs/version-v1.5/configuration/field-mappings.md b/versioned_docs/version-v1.5/configuration/field-mappings.md new file mode 100644 index 00000000..264ee3cb --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/field-mappings.md @@ -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. + +
+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 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 | +> | ------------- | -------- | ----------- | +> | βœ… | βœ… | ❌ | diff --git a/versioned_docs/version-v1.5/configuration/field-policies.md b/versioned_docs/version-v1.5/configuration/field-policies.md new file mode 100644 index 00000000..97c4bee5 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/field-policies.md @@ -0,0 +1,55 @@ +--- +title: Field Policies +--- + +# Field Policies + +An extra layer of security for ensuring no unwanted values are passed through a request. + +**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: + +```yaml +settings: + access: + fieldPolicies: + "@number": + - value: "+123400002" + action: block + - value: "+123400003" + action: allow +``` + +Set the wanted action on encounter, available options are `block` and `allow`. + +> [!IMPORTANT] +> String fields always try to use +> +> 1. [Regex matching](https://regex101.com) +> 2. On compile error exact match is used as fallback + +> [!NOTE] +> Supported [placeholder types](../usage/advanced#placeholders): +> +> | `.` Variables | `@` Body | `#` Headers | +> | ------------- | -------- | ----------- | +> | ❌ | βœ… | βœ… | + +## Behavior + +| Allow | Block | Result | +| ------------------- | ----------------------- | --------------------------------------------------------------------------- | +| `number=+123400003` | β€” | `number` may **only** be `+123400003` | +| β€” | `number=+123400002` | `number` may **not** be `+123400002` | +| `message=hello` | `number=+123400002` | `number` may **not** be `+123400002`
`message` may **only** be `hello` | +| `number=+123400003` | `number=+12340000[2-9]` | `number` may **not** be `+123400002` through `9` **except** `123400003` | + +### Rules + +- **Field-scoped** (policies for `a` don't affect policies for `b`) + +* Default: **allow all** +* Allow rules exist: default **block** +* Only block rules exist: default **allow** +* Explicit allow **overrides** block diff --git a/versioned_docs/version-v1.5/configuration/hostnames.md b/versioned_docs/version-v1.5/configuration/hostnames.md new file mode 100644 index 00000000..4732dc21 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/hostnames.md @@ -0,0 +1,21 @@ +--- +title: Hostnames +--- + +# Hostnames + +Hostnames can be set to create isolated realms or to restrict access by limiting to a only a small subset of hostnames. + +Add hostnames, that are allowed to be used in `service.hostnames`. (default: all) + +```yaml +service: + hostnames: + - mydomain.com +``` + +## Usage behind Proxy + +For clients behind proxies IPs cannot be reliably determined without using the `X-Forwarded-Proto`, `X-Forwarded-Host` and `X-Forwarded-Port` HTTP headers. + +For **Secured Signal API** to trust a proxy it must be added to the trusted proxies, read more [here](./trusted-proxies). diff --git a/versioned_docs/version-v1.5/configuration/index.md b/versioned_docs/version-v1.5/configuration/index.md new file mode 100644 index 00000000..a3be1003 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/index.md @@ -0,0 +1,55 @@ +--- +sidebar_position: 1 +title: Configuration +--- + +# Configuration + +Here is how you configure **Secured Signal API** + +## Environment Variables + +Whilst being a bit **restrictive** environment variables are a great way to configure Secured Signal API. + +Suppose you want to set a new [placeholder](./usage/advanced#placeholders) `NUMBER` in your environment… + +```yaml +environment: + SETTINGS__MESSAGE__VARIABLES__NUMBER: "+123400001" +``` + +This would internally be converted into `settings.message.variables.number` matching the config formatting. + +> [!IMPORTANT] +> Single underscores `_` are removed during conversion, whereas double underscores `__` convert the variable into a nested object (with `__` replaced by `.`) + +## Config Files + +Config files are the **recommended** way to configure and use **Secured Signal API**, +they are **flexible**, **extensible** and really **easy to use**. + +Config files allow **YAML** formatting and additionally `${ENV}` to get environment variables. + +> [!NOTE] +> To change the internal config file location set `CONFIG_PATH` in your **environment** to an absolute path (default: `/config/config.yml`) + +This example config shows all the individual settings that can be applied: + +```yaml +{{{ #://./examples/config.yml }}} +``` + +### Token Configs + +> But wait! There is more… 😁 + +Token configs can be used to create **per-token** defined **overrides** and settings. + +> [!NOTE] +> Create them under `TOKENS_PATH` (default: `config/tokens/`) + +Here is an example: + +```yaml +{{{ #://./examples/token.yml }}} +``` diff --git a/versioned_docs/version-v1.5/configuration/ip-filter.md b/versioned_docs/version-v1.5/configuration/ip-filter.md new file mode 100644 index 00000000..a9da4995 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/ip-filter.md @@ -0,0 +1,64 @@ +--- +title: IP Filter +--- + +# IP Filter + +Restrict access to your **Secured Signal API** based on client IP addresses. + +IP filtering allows you to explicitly **allow** or **block** requests originating from specific IPs or CIDR ranges. + +## Default + +By default, **all IP addresses are allowed**. + +No IP-based restrictions are applied unless `access.ipFilter` is configured. + +## Customize + +You can modify IP access rules by configuring `access.ipFilter` in your config: + +```yaml +settings: + access: + ipFilter: + - "!123.456.78.9" + - "!234.567.89.0/24" + - 192.168.1.10 + - 10.0.0.0/24 +``` + +By default, adding an IP or range explicitly allows it, use `!` to block it instead. + +> [!NOTE] +> When using `!` to block an IP or range, you must enclose it in quotes + +**Supports:** + +- Single IPv4 / IPv6 addresses +- CIDR notation (`10.0.0.0/24`, `2001:db8::/32`) + +## Behavior + +| Allow | Block | Result | +| -------------- | ------------------------ | --------------------------------------------- | +| `192.168.1.10` | β€” | **Only** `192.168.1.10` allowed | +| β€” | `!123.456.78.9` | **All** allowed, **except** `123.456.78.9` | +| `10.0.0.0/24` | `!10.0.0.10` | `10.0.0.0/24` allowed, **except** `10.0.0.10` | +| β€” | `!0.0.0.0/0`
`!::/0` | All IPv4 & IPv6 blocked | + +### Rules + +- Default: **allow all** +- Allow rules exist: default **block** +- Only block rules exist: default **allow** +- Explicit allow **overrides** block + +* IPv4 and IPv6 rules may be mixed + +## Clients behind Proxies + +For clients behind proxies, IPs cannot be reliably determined without trusting the `X-Forwarded-For` HTTP header. +In order for **Secured Signal API** to trust the _XFF_ header it has to trust the request's originating proxy. + +Read more about trusted proxies [here](./trusted-proxies). diff --git a/versioned_docs/version-v1.5/configuration/log-level.md b/versioned_docs/version-v1.5/configuration/log-level.md new file mode 100644 index 00000000..0a516a08 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/log-level.md @@ -0,0 +1,42 @@ +--- +title: Log Level +--- + +# Log Level + +Log levels help to filter or explicitly allow certain information from the logs. + +To change the log level set `service.logLevel` to one of the following levels… (default: `info`) + +**Levels:** + +- `info` +- `debug` (verbose) +- `warn` (**only** warnings and errors) +- `error` (**only** errors) +- `fatal` (**only** fatal errors) + +> [!CAUTION] +> The log level `dev` **can leak data in the logs** +> and must only be used for testing during development + +## Per-Token Logger + +Each token config can define its **own log level**, independent of the global logger. + +This allows fine-grained control, for example: + +- verbose logging for one integration +- minimal logging for another + +If `service.logLevel` is not set, the global log level is used. + +### Logger Naming + +Each token logger is automatically named using the [`name` attribute](./name) to make log output easier to identify. + +**Example output:** + +```log +11.11 11:11 INFO middlewares/log.go:60 abc GET /v2/send +``` diff --git a/versioned_docs/version-v1.5/configuration/message-template.md b/versioned_docs/version-v1.5/configuration/message-template.md new file mode 100644 index 00000000..45efd77f --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/message-template.md @@ -0,0 +1,24 @@ +--- +title: Message Template +--- + +# Message Template + +**Message Templates** are the best way to **structure** and **customize** your messages and can be very useful for **compatibility** between different services. + +Configure them by using the `message.template` attribute in you config. + +These support Go templates (see [Formatting](../usage/formatting#templates)) and work by templating the `message` field in the request's body. + +Here is an example: + +```yaml +{{{ #://./examples/message-template.yml }}} +``` + +> [!NOTE] +> Supported [placeholder types](../usage/advanced#placeholders): +> +> | `.` Variables | `@` Body | `#` Headers | +> | ------------- | -------- | ----------- | +> | βœ… | βœ… | βœ… | diff --git a/versioned_docs/version-v1.5/configuration/name.md b/versioned_docs/version-v1.5/configuration/name.md new file mode 100644 index 00000000..ea228d7d --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/name.md @@ -0,0 +1,13 @@ +--- +title: Name +--- + +# Name + +Each token config can be explicitly named by setting the `name` field. + +```yaml +name: abc +``` + +If `name` is not set, the name is automatically derived from the configuration filename (without extension). diff --git a/versioned_docs/version-v1.5/configuration/port.md b/versioned_docs/version-v1.5/configuration/port.md new file mode 100644 index 00000000..ba8d707a --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/port.md @@ -0,0 +1,35 @@ +--- +title: Port +--- + +# Port + +To change the port which **Secured Signal API** uses, you need to set `service.port` in your config. (default: `8880`) + +## Token-specific ports (port realms) + +You can additionally define a port per Token config. + +> [!NOTE] +> Each port spawns a separate listener, beware that this _can_ affect performance + +When a token specifies a port, a new **realm** is created for that port. +Only tokens that explicitly belong to the same realm are accepted on that port. + +### Example + +- `TOKEN_1` β†’ port `8880` +- `TOKEN_2` β†’ port `8890` + +Requests behave as follows: + +| Token | Port | Result | +| :-------- | :----- | :----: | +| `TOKEN_1` | `8880` | βœ… | +| `TOKEN_2` | `8880` | ⛔️ | +| `TOKEN_1` | `8890` | ⛔️ | +| `TOKEN_2` | `8890` | βœ… | + +If a token config does not specify a port, it automatically gets assigned to the default realm. + +This allows strict separation of access by port without running multiple instances. diff --git a/versioned_docs/version-v1.5/configuration/rate-limiting.md b/versioned_docs/version-v1.5/configuration/rate-limiting.md new file mode 100644 index 00000000..be6d288a --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/rate-limiting.md @@ -0,0 +1,27 @@ +--- +title: Rate Limiting +--- + +# Rate Limiting + +Rate limiting is used to control how many requests or actions a token or client can perform within a given period. +This helps prevent abuse, protect downstream services, and ensure fair usage. + +Rate limits can be defined in `settings.access.rateLimiting`: + +```yaml +settings: + access: + rateLimiting: + limit: 100 + period: 1m +``` + +- `limit`: The maximum number of allowed requests in the given period +- `period`: The duration over which the limit is measured (supports Go duration format like `1m`, `10s`, `1h`) + +When a request exceeds the configured rate limit the server responds with `429` `Too Many Requests`. + +> [!NOTE] +> +> [Trusted clients](./trusted-ips.md) are allowed to bypass rate limits diff --git a/versioned_docs/version-v1.5/configuration/trusted-ips.md b/versioned_docs/version-v1.5/configuration/trusted-ips.md new file mode 100644 index 00000000..63a925d1 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/trusted-ips.md @@ -0,0 +1,17 @@ +--- +title: Trusted IPs +--- + +# Trusted IPs + +Trusted clients can bypass some security features and are often local or internal IPs. + +To trust IPs or ranges add them to `access.trustedIPs`. + +```yaml +settings: + access: + trustedIPs: + - 192.168.1.10 + - 192.168.2.0/24 +``` diff --git a/versioned_docs/version-v1.5/configuration/trusted-proxies.md b/versioned_docs/version-v1.5/configuration/trusted-proxies.md new file mode 100644 index 00000000..82868806 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/trusted-proxies.md @@ -0,0 +1,27 @@ +--- +title: Trusted Proxies +--- + +# Trusted Proxies + +Proxies can be marked as trusted. + +Add proxies to be trusted in `access.trustedProxies`. + +```yaml +settings: + access: + trustedProxies: + - 172.20.0.100 +``` + +## `X-Forwarded-*` Headers + +HTTP listeners only get the `proto://host:port/uri` from the incoming request, but proxies often redirect requests causing modified request URLs +`http://sec-signal-api:8880`. + +To get the origin URL you have to use the `X-Forwarded-*` headers, but as you might know anyone can set headers (spoofing possible). +This means you should only trust _XF_ headers from trusted sources, +otherwise, malicious actors can change any `X-Forwarded-*` headers to be able to bypass block list, rate limits, hostname restrictions, … . + +This also applies to determining the IP of a client behind a proxy, so it is extremely important to allow for using the _XF_ headers when a proxy is trusted. diff --git a/versioned_docs/version-v1.5/configuration/variables.md b/versioned_docs/version-v1.5/configuration/variables.md new file mode 100644 index 00000000..996539f6 --- /dev/null +++ b/versioned_docs/version-v1.5/configuration/variables.md @@ -0,0 +1,23 @@ +--- +title: Variables +--- + +# Variables + +The most common type of [placeholders](../usage/advanced#placeholders) are **variables**. +These can be set under `message.variables` in your config. + +> [!NOTE] +> Variables are always converted into an **uppercase** string. +> Example: `number` β‡’ `NUMBER` in `{{.NUMBER}}` +> (See [Formatting](../usage/formatting#templates)) + +Here is an example: + +```yaml +settings: + message: + variables: + number: "+123400001", + recipients: ["+123400002", "group.id", "user.id"] +``` diff --git a/versioned_docs/version-v1.5/examples/backend.sec-signal-api.yml b/versioned_docs/version-v1.5/examples/backend.sec-signal-api.yml new file mode 100644 index 00000000..83d39da8 --- /dev/null +++ b/versioned_docs/version-v1.5/examples/backend.sec-signal-api.yml @@ -0,0 +1,13 @@ + 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]" + restart: unless-stopped + networks: + backend: + aliases: + - secured-signal-api diff --git a/versioned_docs/version-v1.5/examples/frontend.sec-signal-api.yml b/versioned_docs/version-v1.5/examples/frontend.sec-signal-api.yml new file mode 100644 index 00000000..a8d81d49 --- /dev/null +++ b/versioned_docs/version-v1.5/examples/frontend.sec-signal-api.yml @@ -0,0 +1,15 @@ + 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 diff --git a/versioned_docs/version-v1.5/features/features.md b/versioned_docs/version-v1.5/features/features.md new file mode 100644 index 00000000..213e33ee --- /dev/null +++ b/versioned_docs/version-v1.5/features/features.md @@ -0,0 +1,70 @@ +--- +sidebar_position: 2 +title: Features +--- + +# Features + +Here are some of the highlights of using **Secured Signal API**. + +## Message Template + +> _Structure your messages_ + +**Message Templates** can be used to customize your final message after preprocessing. +Look at this complex template for example: + +```yaml +{{{ #://../configuration/examples/message-template.yml }}} +``` + +It can extract needed data from the body and headers to then process them using Go's templating library +and finally output a message packed with so much information. + +Head to [Configuration](./configuration/message-template) to see how-to use. + +## Placeholders + +> _Time saving and flexible_ + +**Placeholders** are one of the highlights of Secured Signal API, +these have saved me, and will save many others, much time by, for example, not having to change your phone number in every service separately. + +Take a look at the [usage](./usage/advanced). + +## Field Mappings + +> _Standardize output_ + +**Field Mappings** are very useful for when your favorite service does not officially support **Secured Signal API** (or Signal CLI REST API). +With this feature you have the power to do it yourself, just extract what's needed and then integrate with any of the other features. + +Interested? [Take a look](./configuration/field-mappings). + +## Field Policies + +**Field Policies** are a great way to disallow specific fields or even disallowing fields with unwanted values. +This is really helpful when trying to block certain numbers from using certain tokens, and therefor mitigating risks of unwanted use of a token. + +Find more about this feature [here](./configuration/field-policies). + +## Rate Limiting + +**Rate Limiting** is used for limiting requests and to stop server overload, because of DDoS attacks, malconfigured clients, or malicious actors. +It ensures fair usage per token by controlling how many requests can be processed within a defined period. + +Limit those rates [here](./configuration/rate-limiting). + +## Endpoints + +> _Block unwanted access_ + +**Endpoints** are used for restricting unauthorized access and for ensuring least privilege. + +[Let's start blocking then!](./configuration/endpoints) + +## IP Filters + +**IP Filters** are used for restricting access to **Secured Signal API** by blocking or specifically allowing IPs and CIDR ranges. + +Configure your _mini firewall_ [here](./configuration/ip-filter). diff --git a/versioned_docs/version-v1.5/getting-started/_category_.json b/versioned_docs/version-v1.5/getting-started/_category_.json new file mode 100644 index 00000000..4af1367c --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Getting Started", + "position": 3 +} diff --git a/versioned_docs/version-v1.5/getting-started/examples/.prettierignore b/versioned_docs/version-v1.5/getting-started/examples/.prettierignore new file mode 100644 index 00000000..f59ec20a --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/examples/.prettierignore @@ -0,0 +1 @@ +* \ No newline at end of file diff --git a/versioned_docs/version-v1.5/getting-started/examples/docker-compose.yaml b/versioned_docs/version-v1.5/getting-started/examples/docker-compose.yaml new file mode 100644 index 00000000..b9383de6 --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/examples/docker-compose.yaml @@ -0,0 +1,18 @@ +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 + + {{{ \\#://../../examples/frontend.sec-signal-api.yml }}} + +networks: + backend: diff --git a/versioned_docs/version-v1.5/getting-started/installation.md b/versioned_docs/version-v1.5/getting-started/installation.md new file mode 100644 index 00000000..e0ce4a87 --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/installation.md @@ -0,0 +1,23 @@ +--- +sidebar_position: 2 +title: Installation +--- + +# Installation + +Get the latest version of the `docker-compose.yaml` file: + +```yaml +{{{ #://./examples/docker-compose.yaml }}} +``` + +> [!IMPORTANT] +> In this documentation, we'll be using `sec-signal-api:8880` as the host for simplicity, +> please replace it with your actual container/host IP, port, or hostname + +## API Tokens + +Now head to [configuration](../configuration/api-tokens) and define some **API tokens**. + +> [!TIP] +> This recommendation is part of the [**best practices**](../best-practices) diff --git a/versioned_docs/version-v1.5/getting-started/prerequisites.md b/versioned_docs/version-v1.5/getting-started/prerequisites.md new file mode 100644 index 00000000..43959683 --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/prerequisites.md @@ -0,0 +1,13 @@ +--- +sidebar_position: 1 +title: Prerequisites +--- + +# Prerequisites + +To be able to install and run **Secured Signal API** you will need + +- **Docker** (>=20.x) and **Docker Compose** +- On average **1.50 CPU cores** (Signal CLI REST API) +- [Signal CLI REST API](https://github.com/bbernhard/signal-cli-rest-api) behind Secured Signal API +- Probably a [**tls-enabled reverse proxy**](../reverse-proxy) diff --git a/versioned_docs/version-v1.5/getting-started/setup.md b/versioned_docs/version-v1.5/getting-started/setup.md new file mode 100644 index 00000000..3e1fa07d --- /dev/null +++ b/versioned_docs/version-v1.5/getting-started/setup.md @@ -0,0 +1,74 @@ +--- +sidebar_position: 3 +title: Setup +--- + +# Setup + +> [!WARNING] +> These instructions are for **personal or educational use only**.
+> Using multiple accounts, automated messaging, or any activity that violates **Signal's Terms of Service** may result in **account suspension** or **legal action**.
+> We **do not** endorse **spam or fraudulent activity**!
+> Furthermore, we are **not in any way affiliated** with the **Signal Foundation**. + +To use **Secured Signal API** for the first time you will need to set up and link your **signal account**. +In this section we'll take you quickly through what's needed. + +> [!IMPORTANT] +> Run setup directly with Signal CLI REST API. +> Setup requests via Secured Signal API will be [blocked by default](../configuration/endpoints#default) + +## Register + +To be able to send messages via **Secured Signal API** you must first set up Signal CLI REST API. +Here we'll be registering a new signal account. + +### SMS Verification + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + 'http://signal-cli-rest-api:8080/v1/register/' +``` + +Example: + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + 'http://signal-cli-rest-api:8080/v1/register/+431212131491291' +``` + +### Voice Verification + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -d '{"use_voice": true}' \ + 'http://signal-cli-rest-api:8080/v1/register/' +``` + +Example: + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -d '{"use_voice": true}' \ + 'http://signal-cli-rest-api:8080/v1/register/+431212131491291' +``` + +## Link + +If you don't want to register a new account you can link Secured Signal API to one instead. + +```bash +curl -X GET \ + -H "Content-Type: application/json" \ + 'http://signal-cli-rest-api:8080/v1/qrcodelink?device_name=' +``` + +This will show you a QR-Code which you will be able to use for linking. + +## Troubleshooting + +If you encounter any issues in the steps above look at the [examples](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) provided by [@bbernhard](https://github.com/bbernhard/signal-cli-rest-api) diff --git a/versioned_docs/version-v1.5/integrations/_category_.json b/versioned_docs/version-v1.5/integrations/_category_.json new file mode 100644 index 00000000..33adc79c --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Integrations", + "position": 8 +} diff --git a/versioned_docs/version-v1.5/integrations/authentik/authentik.md b/versioned_docs/version-v1.5/integrations/authentik/authentik.md new file mode 100644 index 00000000..ee2a746c --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/authentik/authentik.md @@ -0,0 +1,94 @@ +--- +title: Authentik +--- + +# Authentik + +This guide will show you how to use **Secured Signal API** as an authenticator in [Authentik](https://github.com/goauthentik/authentik). + +## Setup + +### 1. Stage + +First you need to create the `SMS Authenticator Setup` stage. + +Go to `Flows and Stages > Stage > Create`. + +![Stage 1](/integrations/authentik/stage_1.png) + +Then you need to fill in your **API token** and your **sender number** (make sure to use the `Generic` provider). +Point the **API URL** to your Secured Signal API (`/v2/send`). + +![Stage 2](/integrations/authentik/stage_2.png) + +### 2. Flow + +Go to `Flows and Stages > Flows > Create`. + +After you have created the stage you need to use it in a setup flow. +Create one like in the screenshot below. + +![Flow](/integrations/authentik/flow.png) + +Note down your slug, you will need it later… + +Once you've done that you will have to bind the previously created stage to the flow like so: + +![Binding](/integrations/authentik/binding.png) + +### 3. Webhook Mapping + +Now we have to create a custom **webhook mapping**. + +Go to `Customization > Property Mappings > Create`. +And select `Webhook Mapping`. + +#### Simple + +![Webhook Mapping](/integrations/authentik/mapping.png) + +#### Advanced + +For advanced setups or if you want to manage message content with Secured Signal API you may use this webhook mapping instead. + +
+ Click to see screenshot + + ![Advanced Webhook Mapping](/integrations/authentik/advanced-mapping.png) + +
+ +```python +return { + "recipients": [device.phone_number], + "token": f"{token}", + "number": f"stage.from_number}" +} +``` + +> [!TIP] +> Take a look at Authentik's [expression documentation](https://next.goauthentik.io/add-secure-apps/providers/property-mappings/expression) for all the available variables. + +Since you have decided to go the advanced way, you will have to use [**Message Templates**](../configuration/message-template), here is an example: + +```yaml +{{{ #://./message-template.yml }}} +``` + +### 4. Enable SMS-Verification + +To be able to use the newly created authenticator you need to enable `SMS-based Authenticators` in `default-authentication-mfa-validation`. + +Go to `Flows and Stages > Stages` and edit the `default-authentication-mfa-validation` stage. + +![MFA Settings](/integrations/authentik/mfa_stage.png) + +Check `SMS-based Authenticators` and add your `signal-authentication-setup` stage. + +## Register + +After completing the setup, you can finally go to `https://authentik.domain.com/if/flow/` and finish the `SMS Authenticator` setup. + +## Sources + +- https://docs.goauthentik.io/add-secure-apps/flows-stages/stages/authenticator_sms diff --git a/versioned_docs/version-v1.5/integrations/authentik/message-template.yml b/versioned_docs/version-v1.5/integrations/authentik/message-template.yml new file mode 100644 index 00000000..a948fb29 --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/authentik/message-template.yml @@ -0,0 +1,12 @@ +settings: + message: + # prettier-ignore + template: | + **Your Verification Code** + + Use the verification code below to complete your sign-in: + + {{ @token }} + + This code expires in 5 minutes⏱️. + If you didn't request it, you can ignore this message. diff --git a/versioned_docs/version-v1.5/integrations/gitea/gitea.md b/versioned_docs/version-v1.5/integrations/gitea/gitea.md new file mode 100644 index 00000000..5d1cef7c --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/gitea/gitea.md @@ -0,0 +1,47 @@ +--- +title: Gitea +--- + +# Gitea + +Here's how you can use **Secured Signal API** as a notification service for [Gitea](https://github.com/go-gitea/gitea). + +## Setup + +### 1. Message Template + +Because Gitea's webhook data is very _clustered_, we need to use [**Message Templates**](../configuration/message-template) to ensure correct message rendering. + +Here is an example: + +```yaml +{{{ #://./message-template.yml }}} +``` + +Add this to your token config and modify it to your needs. + +### 2. Webhook + +Head to your Gitea repository (or user settings) and go to `Settings > Webhooks` and create a new Gitea webhook. + +![Webhook](/integrations/gitea/webhook.png) + +## Testing + +After you've completed the setup you can try out your new notification integration: + +![Example Issue](/integrations/gitea/issue.png) + +```markdown +πŸ“ **#1 Very Important Issue** +🟒 | πŸ‘€ User +πŸ”— https://gitea.domain.com/user/repo/issues/1 +``` + +## Features + +The provided Message Template currently supports: + +- Gitea issues +- Git commits +- Gitea pull requests diff --git a/versioned_docs/version-v1.5/integrations/gitea/message-template.yml b/versioned_docs/version-v1.5/integrations/gitea/message-template.yml new file mode 100644 index 00000000..cbcf6ca5 --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/gitea/message-template.yml @@ -0,0 +1,38 @@ +settings: + message: + # prettier-ignore + template: | + {{- /* === ISSUE === */ - }} + {{- if and @issue (ne @issue nil) (not @is_pull) -}} + πŸ“ **#{{@issue.number}} {{@issue.title}}** + {{ if eq @issue.state "open" -}}🟒{{- else if eq @issue.state "closed" -}}πŸ”΄{{- else -}}{{@issue.state}}{{- end }} | πŸ‘€ {{@sender.full_name}} + πŸ”— {{@issue.html_url}} + {{- end -}} + + {{- /* === PULL REQUEST === */ - }} + {{- if and @pull_request (ne @pull_request nil) -}} + πŸš€ **#{{@pull_request.number}} {{@pull_request.title}}** + {{ if eq @pull_request.state "open" -}}🟒{{- else if eq @pull_request.state "closed" -}}πŸ”΄{{- else if eq @pull_request.state "merged" -}}🟣{{- else -}}{{@pull_request.state}}{{- end }} | πŸ‘€ {{@sender.full_name}} + πŸ”— {{@pull_request.html_url}} + {{- end -}} + + {{- /* === COMMIT === */ - }} + {{- if and @commits (gt (len @commits) 0) }} + πŸ“₯️ **Push** β†’ *{{@ref}}* + πŸ“ {{@repository.full_name}} | πŸ‘€ {{@pusher.full_name}} | πŸ”’ {{@total_commits}} + {{- range @commits }} + - 🧾 *{{.message}}* + {{- if .added }} + {{- range .added }}βž• {{.}} {{- end }} + {{- end -}} + {{- if .modified }} + {{- range .modified }} ✏️ {{.}} {{- end }} + {{- end -}} + {{- if .removed }} + {{- range .removed }} ❌ {{.}} {{- end }} + {{- end }} + πŸ”— {{.url}} + {{- end }} + + πŸ”Ž Compare: {{@compare_url}} + {{- end -}} diff --git a/versioned_docs/version-v1.5/integrations/home-assistant/configuration.yml b/versioned_docs/version-v1.5/integrations/home-assistant/configuration.yml new file mode 100644 index 00000000..c2a84331 --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/home-assistant/configuration.yml @@ -0,0 +1,7 @@ +notify: + - name: signal + platform: signal_messenger + url: "http://sec-signal-api:8880/@auth=API_TOKEN" + number: "{{.NUMBER}}" + recipients: + - "+123400002" # tip: use a placeholder instead diff --git a/versioned_docs/version-v1.5/integrations/home-assistant/home-assistant.md b/versioned_docs/version-v1.5/integrations/home-assistant/home-assistant.md new file mode 100644 index 00000000..a13ccd5d --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/home-assistant/home-assistant.md @@ -0,0 +1,37 @@ +--- +title: Home Assistant +--- + +# Home Assistant + +Instructions on how you can use **Secured Signal API** as a notification service for [Home Assistant](https://github.com/home-assistant/core). + +## Setup + +### 1. Home Assistant Configuration + +To be able to use the Signal Messenger integration in Home Assistant you need to modify or add the following to your `configuration.yml` file: + +```yaml +{{{ #://./configuration.yml }}} +``` + +Here we are taking advantage of the `url` field for adding `/@auth=API_TOKEN` in order to use [Path Auth](../usage#auth). + +For more detailed configuration instructions read the [official Home Assistant docs](https://www.home-assistant.io/integrations/signal_messenger/). + +### 2. Enabling Path Auth + +By default, [Path Auth](../usage#auth) is disabled, so we first need to enable it in the config by adding `path` to [`auth.methods`](../configuration/auth): + +```yaml +api: + auth: + methods: [bearer, basic, body, path] +``` + +And that's basically it, have fun! + +## Sources + +- https://www.home-assistant.io/integrations/signal_messenger/ diff --git a/versioned_docs/version-v1.5/integrations/index.md b/versioned_docs/version-v1.5/integrations/index.md new file mode 100644 index 00000000..9097f57e --- /dev/null +++ b/versioned_docs/version-v1.5/integrations/index.md @@ -0,0 +1,35 @@ +--- +sidebar_position: 1 +title: Compatibility +--- + +# Compatibility + +## The Problem + +**Secured Signal API** is only of use when compatible with programs. +Even tho it keeps the underlying Signal CLI REST API you'd still need your services to support Signal CLI REST API. + +## The Solution + +**Secured Signal API** implements enough features to technically support any and all services. +But with one flaw: + +> _manual configuration_ + +In order for **Secured Signal API** to be compatible and integratable with a service, you still need to manually define [**Field Mappings**](./configuration/field-mappings) and [**Message Templates**](./configuration/message-template). + +This process is straightforward, provided you know what the service uses as its payload β€” for example, you can test by sending a request to a debugging endpoint. + +> _Now wouldn't it be great if someone had already done that?_ + +If you are using a common and popular service or programs there is probably someone who already configured everything and was willing to share it on +[our GitHub discussions](https://github.com/codeshelldev/secured-signal-api/discussions) (**Thank you!**). + +## How to Help + +You successfully integrated a service and want to share it? + +> Well, that's nice of you πŸ€©πŸ‘οΈ + +Then create a [discussion](https://github.com/CodeShellDev/secured-signal-api/discussions/categories/integrations) and share your configs or if you want you can submit a [pull request](https://github.com/codeshelldev/secured-signal-api/pulls) to add your integration to the **integrations section** in the official documentation. diff --git a/versioned_docs/version-v1.5/reverse-proxy/_category_.json b/versioned_docs/version-v1.5/reverse-proxy/_category_.json new file mode 100644 index 00000000..8f223218 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Reverse Proxy", + "position": 7 +} diff --git a/versioned_docs/version-v1.5/reverse-proxy/apache/apache.md b/versioned_docs/version-v1.5/reverse-proxy/apache/apache.md new file mode 100644 index 00000000..5ad5c14f --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/apache/apache.md @@ -0,0 +1,52 @@ +--- +title: Apache +--- + +# Apache + +Want to use [**Apache**](https://github.com/apache/apache) as your **reverse proxy**? +Then your in luck you've come to the right place! + +## Prerequisites + +Before moving on you must have + +- some knowledge of **Apache** +- valid **SSL certificates** + +## Installation + +To implement Apache in front of **Secured Signal API** you need to update your `docker-compose.yaml` file. + +```yaml +{{{ #://./examples/apache.docker-compose.yaml }}} +``` + +## Setup + +Create a `apache.conf` file in the `docker-compose.yaml` folder and mount it to `/usr/local/apache2/conf.d` in your Apache container. + +```apacheconf +{{{ #://./examples/apache.conf }}} +``` + +Add your `cert.key` and `cert.crt` into your `certs/` folder and mount it to `/etc/ssl`. + +## Configuration + +Now you can switch over to **Secured Signal API** and add Apache to your [trusted proxies](../../configuration/trusted-proxies.md): + +```yaml +settings: + access: + trustedProxies: + - 172.20.0.100 +``` + +Lastly spin up your stack: + +```bash +docker compose up -d +``` + +And you are ready to go! diff --git a/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.conf b/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.conf new file mode 100644 index 00000000..c129c28f --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.conf @@ -0,0 +1,21 @@ + + ServerName domain.com + + # SSL Configuration + SSLEngine on + SSLCertificateFile /etc/ssl/cert.crt + SSLCertificateKeyFile /etc/ssl/cert.key + + # Proxy settings + ProxyPreserveHost On + + # Use whatever network alias you set in the docker-compose file + ProxyPass / http://sec-signal-api:8880 + ProxyPassReverse / http://sec-signal-api:8880 + + +# Redirect HTTP to HTTPS + + ServerName domain.com + Redirect permanent / https://domain.com/ + diff --git a/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.docker-compose.yaml b/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.docker-compose.yaml new file mode 100644 index 00000000..3069cfea --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/apache/examples/apache.docker-compose.yaml @@ -0,0 +1,20 @@ +services: + {{{ \\#://../../../examples/backend.sec-signal-api.yml }}} + + apache: + image: httpd:latest + container_name: apache + ports: + - "80:80" + - "443:443" + volumes: + - ./apache.conf:/usr/local/apache2/conf/httpd.conf:ro + - ./certs:/etc/ssl + networks: + proxy: + backend: + ipv4_address: 172.20.0.100 + +networks: + backend: + proxy: \ No newline at end of file diff --git a/versioned_docs/version-v1.5/reverse-proxy/caddy/caddy.md b/versioned_docs/version-v1.5/reverse-proxy/caddy/caddy.md new file mode 100644 index 00000000..e507e6a8 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/caddy/caddy.md @@ -0,0 +1,50 @@ +--- +title: Caddy +--- + +# Caddy + +Want to use [**Caddy**](https://github.com/caddyserver/caddy) as your **reverse proxy**? +These instructions will take you through the steps. + +## Prerequisites + +Before moving on you must have + +- some knowledge of **Caddy** +- already deployed **Caddy** + +## Installation + +Add Caddy to your `docker-compose.yaml` file. + +```yaml +{{{ #://./examples/caddy.docker-compose.yaml }}} +``` + +## Setup + +Create a `Caddyfile` in your `docker-compose.yaml` folder and mount it to `/etc/caddy/Caddyfile` in your Caddy container. + +```nginx +{{{ #://./examples/Caddyfile }}} +``` + +## Configuration + +Now you can switch over to **Secured Signal API** and add Caddy to your [trusted proxies](../../configuration/trusted-proxies.md): + +```yaml +settings: + access: + trustedProxies: + - 172.20.0.100 +``` + +Then spin up your stack: + +```bash +docker compose up -d +``` + +And you are ready to go! diff --git a/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/Caddyfile b/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/Caddyfile new file mode 100644 index 00000000..afcc2b8b --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/Caddyfile @@ -0,0 +1,18 @@ +# Replace with your actual domain +domain.com { + # Use whatever network alias you set in the docker-compose file + reverse_proxy secured-signal-api:8880 + + # Optional: basic security headers + header { + Strict-Transport-Security "max-age=31536000;" + X-Content-Type-Options "nosniff" + X-Frame-Options "DENY" + Referrer-Policy "no-referrer" + } +} + +# HTTP redirect to HTTPS +http://domain.com { + redir https://{host}{uri} permanent +} diff --git a/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/caddy.docker-compose.yaml b/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/caddy.docker-compose.yaml new file mode 100644 index 00000000..852a801f --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/caddy/examples/caddy.docker-compose.yaml @@ -0,0 +1,26 @@ +services: + {{{ \\#://../../../examples/backend.sec-signal-api.yml }}} + + caddy: + image: caddy:latest + container_name: caddy + ports: + - "80:80" + - "443:443" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - data:/data + depends_on: + - secured-signal + restart: unless-stopped + networks: + proxy: + backend: + ipv4_address: 172.20.0.100 + +networks: + backend: + proxy: + +volumes: + data: diff --git a/versioned_docs/version-v1.5/reverse-proxy/index.md b/versioned_docs/version-v1.5/reverse-proxy/index.md new file mode 100644 index 00000000..b6c6b157 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/index.md @@ -0,0 +1,26 @@ +--- +sidebar_position: 1 +title: Reverse Proxy +--- + +# Reverse Proxy + +In this section we will be explaining why a **tls-enabled reverse proxy** is a must-have. + +## Why another Proxy + +**Secured Signal API** itself is already a **reverse proxy**, lacking one important feature: **SSL certificates**. + +### SSL Certificates + +When deploying anything on the internet an **SSL certificate** is almost a necessity. +Same goes for **Secured Signal API**, even if you don't plan on exposing your instance to the internet it is always good to have an extra layer of **security**. + +### Port Forwarding + +Furthermore, if you want to have multiple services **on the same port** using **HTTP** you'd also need a **tls-enabled reverse proxy**, +to route requests to the correct backend based on hostnames and routing rules. + +### Not Convinced? + +And if you are still not convinced then look at this [article](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy) online. diff --git a/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.conf b/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.conf new file mode 100644 index 00000000..f8c7c6d5 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.conf @@ -0,0 +1,29 @@ +server { + # Allow SSL on Port 443 + listen 443 ssl; + + # Add allowed hostnames which nginx should respond to + # `_` for any + server_name domain.com; + + # SSL Configuration + ssl_certificate /etc/nginx/ssl/cert.crt; + ssl_certificate_key /etc/nginx/ssl/cert.key; + + location / { + # Use whatever network alias you set in the docker-compose file + proxy_pass http://secured-signal-api:8880; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Fowarded-Proto $scheme; + } +} + +# Redirect HTTP to HTTPs +server { + listen 80; + server_name domain.com; + return 301 https://$host$request_uri; +} \ No newline at end of file diff --git a/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.docker-compose.yaml b/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.docker-compose.yaml new file mode 100644 index 00000000..14415657 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/nginx/examples/nginx.docker-compose.yaml @@ -0,0 +1,24 @@ +services: + {{{ \\#://../../../examples/backend.sec-signal-api.yml }}} + + nginx: + image: nginx:latest + container_name: secured-signal-proxy + volumes: + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + # Load SSL certificates: cert.key, cert.crt + - ./certs:/etc/nginx/ssl + ports: + - "80:80" + - "443:443" + depends_on: + - secured-signal + restart: unless-stopped + networks: + proxy: + backend: + ipv4_address: 172.20.0.100 + +networks: + backend: + proxy: diff --git a/versioned_docs/version-v1.5/reverse-proxy/nginx/nginx.md b/versioned_docs/version-v1.5/reverse-proxy/nginx/nginx.md new file mode 100644 index 00000000..7966623e --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/nginx/nginx.md @@ -0,0 +1,52 @@ +--- +title: NGINX +--- + +# NGINX + +Want to use [**Nginx**](https://github.com/nginx/nginx) as your **reverse proxy**? +No problem here are the instructions… + +## Prerequisites + +Before moving on you must have + +- some knowledge of **Nginx** +- valid **SSL certificates** + +## Installation + +To implement Nginx in front of **Secured Signal API** you need to update your `docker-compose.yaml` file. + +```yaml +{{{ #://./examples/nginx.docker-compose.yaml }}} +``` + +## Setup + +Create a `nginx.conf` file in the `docker-compose.yaml` folder and mount it to `/etc/nginx/conf.d/default.conf` in your Nginx container. + +```nginx +{{{ #://./examples/nginx.conf }}} +``` + +Add your `cert.key` and `cert.crt` into your `certs/` folder and mount it to `/etc/nginx/ssl`. + +## Configuration + +Now you can switch over to **Secured Signal API** and add Nginx to your [trusted proxies](../../configuration/trusted-proxies.md): + +```yaml +settings: + access: + trustedProxies: + - 172.20.0.100 +``` + +Lastly spin up your stack: + +```bash +docker compose up -d +``` + +And you are ready to go! diff --git a/versioned_docs/version-v1.5/reverse-proxy/traefik/examples/traefik.docker-compose.yaml b/versioned_docs/version-v1.5/reverse-proxy/traefik/examples/traefik.docker-compose.yaml new file mode 100644 index 00000000..e7e0d700 --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/traefik/examples/traefik.docker-compose.yaml @@ -0,0 +1,22 @@ +services: + {{{ \\#://../../../examples/backend.sec-signal-api.yml }}} + + traefik: + image: traefik:latest + container_name: traefik + ports: + - "80:80" + - "443:443" + volumes: + - /var/run/docker.sock:/var/run/docker.sock + - ./config/traefik.yaml:/etc/traefik/traefik.yaml:ro + - certs:/var/traefik/certs/:rw + - logs:/var/log/traefik + restart: unless-stopped + networks: + proxy: + ipv4_address: 172.20.0.100 + +networks: + backend: + proxy: diff --git a/versioned_docs/version-v1.5/reverse-proxy/traefik/traefik.md b/versioned_docs/version-v1.5/reverse-proxy/traefik/traefik.md new file mode 100644 index 00000000..9f2734db --- /dev/null +++ b/versioned_docs/version-v1.5/reverse-proxy/traefik/traefik.md @@ -0,0 +1,45 @@ +--- +title: Traefik +--- + +# Traefik + +Want to use [**Traefik**](https://github.com/traefik/traefik) as your **reverse proxy**? +Then look no further, we'll take you through how to integrate Traefik with **Secured Signal API**. + +## Prerequisites + +Before moving on you must have + +- already **configured** **Traefik** +- some knowledge of Traefik +- valid **SSL certificates** + +## Installation + +To implement Traefik in front of **Secured Signal API** you need to update your `docker-compose.yaml` file. + +```yaml +{{{ #://./examples/traefik.docker-compose.yaml }}} +``` + +To include the Traefik router and service labels. + +## Configuration + +Now you can switch over to **Secured Signal API** and add Traefik to your [trusted proxies](../../configuration/trusted-proxies.md): + +```yaml +settings: + access: + trustedProxies: + - 172.20.0.100 +``` + +Then restart **Secured Signal API**: + +```bash +docker compose down && docker compose up -d +``` + +That's it, have fun! diff --git a/versioned_docs/version-v1.5/usage/_category_.json b/versioned_docs/version-v1.5/usage/_category_.json new file mode 100644 index 00000000..3a46cad4 --- /dev/null +++ b/versioned_docs/version-v1.5/usage/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "Usage", + "position": 4 +} diff --git a/versioned_docs/version-v1.5/usage/advanced.md b/versioned_docs/version-v1.5/usage/advanced.md new file mode 100644 index 00000000..08788154 --- /dev/null +++ b/versioned_docs/version-v1.5/usage/advanced.md @@ -0,0 +1,74 @@ +--- +sidebar_position: 2 +title: Advanced +--- + +# Advanced + +Here you will be explained all the neat tricks and quirks for **Secured Signal API** + +## placeholders + +Placeholders do exactly what you think they do: They **replace** actual values. +These can be especially **helpful** when managing **variables** across multiple services. + +### How to Use + +| Scope | Example | +| :------------------------------------- | :------------------ | +| Body | `{{@data.key}}` | +| Header (except `Authorization`) | `{{#Content_Type}}` | +| [Variable](../configuration/variables) | `{{.VAR}}` | + +> [!NOTE] +> Formatting rules (capitalization, escaping, and typing) are defined in [Formatting](./formatting) + +### 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}}` | + +**Combine them:** + +```json +"message": "{{.NUMBER}} -> {{.RECIPIENTS}}" +``` + +**Mix and match:** + +```json +"message": "{{#X_Forwarded_For}} just send from {{.NUMBER}}" +``` + +> [!NOTE] +> Placeholders follow strict formatting rules ([See Formatting](./formatting#templates)) + +## URL-to-Body Injection + +> _Sounds scary… but it really isn't._ 🫣 + +**URL-to-Body Injection** is a powerful feature designed for **restricted or inflexible environments**. + +In some setups, webhook configuration is extremely limited. +For example, you may **only** be able to define a webhook URL, without any control over the **request body**. +This becomes a problem when every receiving service is expected to support the **Signal CLI REST API** format. +In such cases, using a simple, generic webhook is not possible. + +**URL-to-Body Injection** solves this by allowing you to inject values directly into the request body via query parameters or seperated path parameters. + +`http://sec-signal-api:8880/@key2=value2/?@key=value` + +> [!IMPORTANT] +> +> - Supported value types include **strings**, **integers**, **arrays**, and **JSON objects** +> - See [Formatting](./formatting#string-to-type) for details on supported structures and syntax + +> [!NOTE] +> Supported [placeholder types](./advanced#placeholders): +> +> | `.` Variables | `@` Body | `#` Headers | +> | ------------- | -------- | ----------- | +> | ❌ | βœ… | ❌ | diff --git a/versioned_docs/version-v1.5/usage/formatting.md b/versioned_docs/version-v1.5/usage/formatting.md new file mode 100644 index 00000000..de8873c8 --- /dev/null +++ b/versioned_docs/version-v1.5/usage/formatting.md @@ -0,0 +1,47 @@ +--- +sidebar_position: 3 +title: Formatting +--- + +# Formatting + +**Secured Signal API** has some specific formatting rules to ensure for correct parsing. + +## Templates + +**Secured Signal API** is built with Go and therefore uses Go’s [standard templating library](https://pkg.go.dev/text/template). +As a result, any valid Go template string works in Secured Signal API. + +> [!NOTE] +> The following features use Go’s templating library: +> +> - [URL Templates](../configuration/message-template) +> - [URL-to-Body Injection](./advanced#url-to-body-injection) +> - [Placeholders](./advanced#placeholders) + +| Scope | Example | Note | +| :-------------------------------------- | :------------------ | :--------------- | +| Body | `{{@data.key}}` | | +| Headers | `{{#Content_Type}}` | `-` becomes `_` | +| [Variables](../configuration/variables) | `{{.VAR}}` | Always uppercase | + +## String to Type + +> [!TIP] +> This formatting applies to **almost every situation** where the only (allowed) **input type is a string** and **other output types are needed** + +If you are using environment variables for example there would be no way of using arrays or even dictionaries as values, for these cases we have **String to Type** conversion shown below. + +| Type | Example | +| :------------ | :----------- | +| string | abc | +| string | +123 | +| int | 123 | +| int | -123 | +| JSON | \{"a": "b"\} | +| array(int) | [1, 2, 3] | +| array(string) | [a, b, c] | + +> [!TIP] +> Escape type denotations such as `[]`, `{}`, or `-` by prefixing them with a **backslash** (`\`). +> An **odd number** of backslashes will **escape** the character immediately following them diff --git a/versioned_docs/version-v1.5/usage/index.md b/versioned_docs/version-v1.5/usage/index.md new file mode 100644 index 00000000..8401ec25 --- /dev/null +++ b/versioned_docs/version-v1.5/usage/index.md @@ -0,0 +1,46 @@ +--- +sidebar_position: 1 +title: Usage +--- + +# Usage + +In this section we'll be taking a look at how to use **Secured Signal API**. + +## Basic + +Here is a quick command to see if you've correctly followed the [setup instructions](./getting-started/setup): + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -d '{"message":"Hello, World!", "number":"", "recipients":[""]}' \ + 'http://sec-signal-api:8880/v2/send' +``` + +This will send `Hello, World!` to `` from ``. + +## Auth + +**Secured Signal API** implements 5 auth methods: + +| 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](../configuration/auth.md) + +**Example:** + +```bash +curl -X POST \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer API_TOKEN" \ + -d '{"message":"Hello, World!", "number":"", "recipients":[""]}' \ + 'http://sec-signal-api:8880/v2/send' +``` diff --git a/versioned_sidebars/version-v1.5-sidebars.json b/versioned_sidebars/version-v1.5-sidebars.json new file mode 100644 index 00000000..5f41a72e --- /dev/null +++ b/versioned_sidebars/version-v1.5-sidebars.json @@ -0,0 +1,8 @@ +{ + "documentationSidebar": [ + { + "type": "autogenerated", + "dirName": "." + } + ] +} diff --git a/versions.json b/versions.json index a6a6446e..dc2d72a2 100644 --- a/versions.json +++ b/versions.json @@ -1,3 +1,4 @@ [ + "v1.5", "v1.4" ]