diff --git a/.dockerignore b/.dockerignore index 8abd962..3587155 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,8 +1 @@ -.gitignore -.git -.github -.env -docker-compose.yaml -LICENSE -*.md -.venv \ No newline at end of file +!*.py \ No newline at end of file diff --git a/.github/templates/README.template.md b/.github/templates/README.template.md index bf5236c..6cfa70a 100644 --- a/.github/templates/README.template.md +++ b/.github/templates/README.template.md @@ -10,16 +10,65 @@ Get the latest version of the `docker-compose.yaml` file: { { file.docker-compose.yaml } } ``` +### Reverse proxy + +Take a look at traefik implementation: + +```yaml +{ { file.examples/traefik.docker-compose.yaml } } +``` + +## Setup + +Before you can send messages via `secured-signal-api` you must first setup [`signal-api`](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md), + +to send messages you have to either: + +- register a Signal Account + +OR + +- link Signal Api to a already registered Signal Device + ## Usage To send a message to `number`: `1234567`: ```bash -curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api/v2/send +curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api:8880/v2/send +``` + +### Configuration + +Because `secured-signal-api` is just a secure proxy you can use all of the [Signal REST Api](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: + +```python +DEFAULT_BLOCKED_ENDPOINTS = [ + "/v1/about", + "/v1/configuration", + "/v1/devices", + "/v1/register", + "/v1/unregister", + "/v1/qrcodelink", + "/v1/accounts", + "/v1/contacts" +] +``` + +Which are blocked by default to increase Security, but you these can be modified by setting the `BLOCKED_ENDPOINTS` environment variable as a valid json array + +```yaml +environment: + BLOCKED_ENDPOINTS: '[ "/v1/register","/v1/unregister","/v1/qrcodelink","/v1/contacts" ]' ``` ## Contributing +Found a bug? Want to change or add something? +Feel free to open up an issue or create a Pull Request! + +_This is a small project so don't expect any huge changes in the future_ + ## License [MIT](https://choosealicense.com/licenses/mit/) diff --git a/.github/workflows/readme-update.yml b/.github/workflows/readme-update.yml index ad79409..cb7edb3 100644 --- a/.github/workflows/readme-update.yml +++ b/.github/workflows/readme-update.yml @@ -5,6 +5,7 @@ on: paths: - "docker-compose.yaml" - ".github/templates/README.template.md" + - "examples/*" jobs: update-readme: diff --git a/README.md b/README.md index 5951dc0..7e48462 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,125 @@ Get the latest version of the `docker-compose.yaml` file: ```yaml --- services: - myservice: - container_name: myservice + signal-api: + image: bbernhard/signal-cli-rest-api + container_name: signal-api + environment: + - MODE=normal + volumes: + - ./data:/home/.local/share/signal-cli + networks: + backend: + aliases: + - signal-api + restart: unless-stopped + + secured-signal: + image: ghcr.io/codeshelldev/secured-signal-api + container_name: secured-signal + networks: + backend: + aliases: + - secured-signal-api + environment: + SIGNAL_API_URL: http://signal-api:8080 + DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' + SENDER: 123456789 + ports: + - "8880:8880" + restart: unless-stopped + +networks: + backend: ``` +### Reverse proxy + +Take a look at traefik implementation: + +```yaml +services: + # ... + secured-signal: + image: ghcr.io/codeshelldev/secured-signal-api + container_name: secured-signal + networks: + proxy: + backend: + aliases: + - secured-signal-api + environment: + SIGNAL_API_URL: http://signal-api:8080 + DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' + SENDER: 123456789 + labels: + - traefik.enable=true + - traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`) + - traefik.http.routers.signal-api.entrypoints=websecure + - traefik.http.routers.signal-api.tls=true + - traefik.http.routers.signal-api.tls.certresolver=cloudflare + - traefik.http.routers.signal-api.service=signal-api-svc + - traefik.http.services.signal-api-svc.loadbalancer.server.port=8880 + - traefik.docker.network=proxy + restart: unless-stopped + +networks: + backend: + proxy: + external: true +``` + +## Setup + +Before you can send messages via `secured-signal-api` you must first setup [`signal-api`](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md), + +to send messages you have to either: + +- register a Signal Account + +OR + +- link Signal Api to a already registered Signal Device + ## Usage To send a message to `number`: `1234567`: ```bash -curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api/v2/send +curl -X POST -H "Content-Type: application/json" -H "Authorization: Bearer TOKEN" -d '{"message": "Hello World!", "recipients": ["1234567"]}' http://signal-api:8880/v2/send +``` + +### Configuration + +Because `secured-signal-api` is just a secure proxy you can use all of the [Signal REST Api](https://github.com/bbernhard/signal-cli-rest-api/blob/master/doc/EXAMPLES.md) endpoints with an Exception of: + +```python +DEFAULT_BLOCKED_ENDPOINTS = [ + "/v1/about", + "/v1/configuration", + "/v1/devices", + "/v1/register", + "/v1/unregister", + "/v1/qrcodelink", + "/v1/accounts", + "/v1/contacts" +] +``` + +Which are blocked by default to increase Security, but you these can be modified by setting the `BLOCKED_ENDPOINTS` environment variable as a valid json array + +```yaml +environment: + BLOCKED_ENDPOINTS: '[ "/v1/register","/v1/unregister","/v1/qrcodelink","/v1/contacts" ]' ``` ## Contributing +Found a bug? Want to change or add something? +Feel free to open up an issue or create a Pull Request! + +_This is a small project so don't expect any huge changes in the future_ + ## License [MIT](https://choosealicense.com/licenses/mit/) diff --git a/app.py b/app.py index 5f5f6aa..35a0a81 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,8 @@ import requests import re import base64 -import logging +import logging +from urllib.parse import unquote app = Flask("Secured Signal Api") @@ -39,7 +40,7 @@ def fillInVars(obj): for i in range(len(obj)): obj[i] = fillInVars(obj[i]) elif isinstance(obj, str): - matches = re.findall(r"\${(.*?)}", obj) + matches = re.findall(r"\${(.*?)}", obj) for match in matches: if match in VARIABLES: value = VARIABLES[match] @@ -75,15 +76,20 @@ def middlewares(): auth_header = request.headers.get("Authorization", "") if auth_header.startswith("Bearer "): - token = auth_header.split(" ", 1)[1] - if token != API_TOKEN: + token = auth_header.split(" ", 1)[1] + + token = unquote(token) + if token != API_TOKEN: infoLog(f"Client failed Bearer Auth [token: {token}]") return UnauthorizedResponse() - elif auth_header.startswith("Basic "): - try: - decoded = base64.b64decode(auth_header.split(" ", 1)[1]).decode() - username, password = decoded.split(":", 1) - if username != "api" or password != API_TOKEN: + elif auth_header.startswith("Basic "): + try: + decoded = base64.b64decode(auth_header.split(" ", 1)[1]).decode() + username, password = decoded.split(":", 1) + + username = unquote(username) + password = unquote(password) + if username != "api" or password != API_TOKEN: infoLog(f"Client failed Basic Auth [user: {username}, pw:{password}]") return UnauthorizedResponse() except Exception as error: diff --git a/docker-compose.yaml b/docker-compose.yaml index ab85f8d..14fa642 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,4 +1,32 @@ --- services: - myservice: - container_name: myservice + signal-api: + image: bbernhard/signal-cli-rest-api + container_name: signal-api + environment: + - MODE=normal + volumes: + - ./data:/home/.local/share/signal-cli + networks: + backend: + aliases: + - signal-api + restart: unless-stopped + + secured-signal: + image: ghcr.io/codeshelldev/secured-signal-api + container_name: secured-signal + networks: + backend: + aliases: + - secured-signal-api + environment: + SIGNAL_API_URL: http://signal-api:8080 + DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' + SENDER: 123456789 + ports: + - "8880:8880" + restart: unless-stopped + +networks: + backend: diff --git a/examples/traefik.docker-compose.yaml b/examples/traefik.docker-compose.yaml new file mode 100644 index 0000000..21d2bf2 --- /dev/null +++ b/examples/traefik.docker-compose.yaml @@ -0,0 +1,29 @@ +services: + # ... + secured-signal: + image: ghcr.io/codeshelldev/secured-signal-api + container_name: secured-signal + networks: + proxy: + backend: + aliases: + - secured-signal-api + environment: + SIGNAL_API_URL: http://signal-api:8080 + DEFAULT_RECIPIENTS: '[ "000", "001", "002" ]' + SENDER: 123456789 + labels: + - traefik.enable=true + - traefik.http.routers.signal-api.rule=Host(`signal-api.mydomain.com`) + - traefik.http.routers.signal-api.entrypoints=websecure + - traefik.http.routers.signal-api.tls=true + - traefik.http.routers.signal-api.tls.certresolver=cloudflare + - traefik.http.routers.signal-api.service=signal-api-svc + - traefik.http.services.signal-api-svc.loadbalancer.server.port=8880 + - traefik.docker.network=proxy + restart: unless-stopped + +networks: + backend: + proxy: + external: true