From 9599ce66a72426e4db51392e055f4cc11d00a02a Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:05:31 +0200 Subject: [PATCH 01/10] Update app.py --- app.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/app.py b/app.py index 0589274..03bc46b 100644 --- a/app.py +++ b/app.py @@ -4,7 +4,7 @@ import requests import re import base64 -import logging +import logging from urllib.parse import unquote app = Flask("Secured Signal Api") @@ -76,18 +76,18 @@ def middlewares(): auth_header = request.headers.get("Authorization", "") if auth_header.startswith("Bearer "): - token = auth_header.split(" ", 1)[1] - + token = auth_header.split(" ", 1)[1] + token = unquote(token) if token != API_TOKEN: infoLog(f"Client failed Bearer Auth [token: {token}]") - return UnauthorizedResponse() + return UnauthorizedResponse() elif auth_header.startswith("Basic "): try: decoded = base64.b64decode(auth_header.split(" ", 1)[1]).decode() - username, password = decoded.split(":", 1) - - username = unquote(username) + 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}]") @@ -169,4 +169,4 @@ def errorLog(msg): "RECIPIENTS": DEFAULT_RECIPIENTS } - app.run(debug=False, port=8880, host='0.0.0.0') \ No newline at end of file + app.run(debug=False, port=8880, host='0.0.0.0') From e9137f4989758e81809308d9321827ebec74736c Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:16:10 +0200 Subject: [PATCH 02/10] fixing indentation --- app.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/app.py b/app.py index 03bc46b..b2bb2c3 100644 --- a/app.py +++ b/app.py @@ -32,24 +32,24 @@ secure = False -def fillInVars(obj): - if isinstance(obj, dict): - for key, value in obj.items(): - obj[key] = fillInVars(value) - elif isinstance(obj, list): - for i in range(len(obj)): - obj[i] = fillInVars(obj[i]) - elif isinstance(obj, str): - matches = re.findall(r"\${(.*?)}", obj) - for match in matches: - if match in VARIABLES: - value = VARIABLES[match] - - if isinstance(value, str): - newValue = obj.replace(f"${{{match}}}", str(value)) - return newValue - else: - return value +def fillInVars(obj): + if isinstance(obj, dict): + for key, value in obj.items(): + obj[key] = fillInVars(value) + elif isinstance(obj, list): + for i in range(len(obj)): + obj[i] = fillInVars(obj[i]) + elif isinstance(obj, str): + matches = re.findall(r"\${(.*?)}", obj) + for match in matches: + if match in VARIABLES: + value = VARIABLES[match] + + if isinstance(value, str): + newValue = obj.replace(f"${{{match}}}", str(value)) + return newValue + else: + return value return obj def UnauthorizedResponse(prompt=None): From 22d669361c1b8dc29bc9734395fc3c7bb1f51d23 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 18:22:08 +0200 Subject: [PATCH 03/10] app.py fix --- app.py | 314 ++++++++++++++++++++++++++++----------------------------- 1 file changed, 157 insertions(+), 157 deletions(-) diff --git a/app.py b/app.py index b2bb2c3..f3c97af 100644 --- a/app.py +++ b/app.py @@ -1,47 +1,47 @@ -from flask import Flask, Response, request, jsonify, make_response -import os -import json -import requests -import re -import base64 -import logging -from urllib.parse import unquote - -app = Flask("Secured Signal Api") - -app.logger.setLevel(logging.INFO) - -DEFAULT_BLOCKED_ENDPOINTS = [ - "/v1/about", - "/v1/configuration", - "/v1/devices", - "/v1/register", - "/v1/unregister", - "/v1/qrcodelink", - "/v1/accounts", - "/v1/contacts" -] - -SENDER = os.getenv("SENDER") -DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS") -SIGNAL_API_URL = os.getenv("SIGNAL_API_URL") -API_TOKEN = os.getenv("API_TOKEN") - -BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS") -VARIABLES = os.getenv("VARIABLES") - -secure = False - +from flask import Flask, Response, request, jsonify, make_response +import os +import json +import requests +import re +import base64 +import logging +from urllib.parse import unquote + +app = Flask("Secured Signal Api") + +app.logger.setLevel(logging.INFO) + +DEFAULT_BLOCKED_ENDPOINTS = [ + "/v1/about", + "/v1/configuration", + "/v1/devices", + "/v1/register", + "/v1/unregister", + "/v1/qrcodelink", + "/v1/accounts", + "/v1/contacts" +] + +SENDER = os.getenv("SENDER") +DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS") +SIGNAL_API_URL = os.getenv("SIGNAL_API_URL") +API_TOKEN = os.getenv("API_TOKEN") + +BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS") +VARIABLES = os.getenv("VARIABLES") + +secure = False + def fillInVars(obj): - if isinstance(obj, dict): + if isinstance(obj, dict): for key, value in obj.items(): obj[key] = fillInVars(value) elif isinstance(obj, list): for i in range(len(obj)): obj[i] = fillInVars(obj[i]) elif isinstance(obj, str): - matches = re.findall(r"\${(.*?)}", obj) - for match in matches: + matches = re.findall(r"\${(.*?)}", obj) + for match in matches: if match in VARIABLES: value = VARIABLES[match] @@ -50,123 +50,123 @@ def fillInVars(obj): return newValue else: return value - return obj - -def UnauthorizedResponse(prompt=None): - headers = {} - - if prompt: - headers = { - "WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"' - } - - return Response( - "Unauthorized", 401, - headers - ) - -@app.before_request -def middlewares(): - for blockedPath in BLOCKED_ENDPOINTS: - if request.path.startswith(blockedPath): - infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]") - return Response("Forbidden", 401) - - if secure: - auth_header = request.headers.get("Authorization", "") - - if auth_header.startswith("Bearer "): - 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) - - 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: - errorLog(f"Unexpected Error during Basic Auth: {error}") - return UnauthorizedResponse() - else: - infoLog(f"Client did not provide any Auth Method") - return UnauthorizedResponse(True) - - -@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT']) -@app.route('/', methods=['GET', 'POST', 'PUT']) -def proxy(path): - method = request.method - incomingJSON = request.get_json(force=True, silent=True) - jsonData = incomingJSON - headers = {k: v for k, v in request.headers if k.lower() != 'host'} - - if incomingJSON: - jsonData = fillInVars(incomingJSON) - - if "${NUMBER}" in path: - path = path.replace("${NUMBER}", SENDER) - - query_string = request.query_string.decode() - - if request.query_string.decode(): - query_string= "?" + request.query_string.decode() - - targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" - - infoLog(json.dumps(jsonData)) - - resp = requests.request( - method=method, - url=targetURL, - headers=headers, - json=jsonData - ) - - infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]") - - # return Response(resp.content, status=resp.status_code, headers=dict(resp.headers)) - - response = make_response(resp.json()) - response.status_code = resp.status_code - - return response - -def infoLog(msg): - app.logger.info(msg) - -def errorLog(msg): - app.logger.error(msg) - -if __name__ == '__main__': - if SENDER and SIGNAL_API_URL: - if API_TOKEN == None or API_TOKEN == "": - infoLog("No API Token set (API_TOKEN), this is not recommended!") - else: - secure = True - infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication") - - if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "": - DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS) - - if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "": - BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS) - else: - BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS - - if VARIABLES != None and VARIABLES != "": - VARIABLES = json.loads(VARIABLES) - else: - VARIABLES = { - "NUMBER": SENDER, - "RECIPIENTS": DEFAULT_RECIPIENTS - } - - app.run(debug=False, port=8880, host='0.0.0.0') + return obj + +def UnauthorizedResponse(prompt=None): + headers = {} + + if prompt: + headers = { + "WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"' + } + + return Response( + "Unauthorized", 401, + headers + ) + +@app.before_request +def middlewares(): + for blockedPath in BLOCKED_ENDPOINTS: + if request.path.startswith(blockedPath): + infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]") + return Response("Forbidden", 401) + + if secure: + auth_header = request.headers.get("Authorization", "") + + if auth_header.startswith("Bearer "): + 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) + + 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: + errorLog(f"Unexpected Error during Basic Auth: {error}") + return UnauthorizedResponse() + else: + infoLog(f"Client did not provide any Auth Method") + return UnauthorizedResponse(True) + + +@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT']) +@app.route('/', methods=['GET', 'POST', 'PUT']) +def proxy(path): + method = request.method + incomingJSON = request.get_json(force=True, silent=True) + jsonData = incomingJSON + headers = {k: v for k, v in request.headers if k.lower() != 'host'} + + if incomingJSON: + jsonData = fillInVars(incomingJSON) + + if "${NUMBER}" in path: + path = path.replace("${NUMBER}", SENDER) + + query_string = request.query_string.decode() + + if request.query_string.decode(): + query_string= "?" + request.query_string.decode() + + targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" + + infoLog(json.dumps(jsonData)) + + resp = requests.request( + method=method, + url=targetURL, + headers=headers, + json=jsonData + ) + + infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]") + + # return Response(resp.content, status=resp.status_code, headers=dict(resp.headers)) + + response = make_response(resp.json()) + response.status_code = resp.status_code + + return response + +def infoLog(msg): + app.logger.info(msg) + +def errorLog(msg): + app.logger.error(msg) + +if __name__ == '__main__': + if SENDER and SIGNAL_API_URL: + if API_TOKEN == None or API_TOKEN == "": + infoLog("No API Token set (API_TOKEN), this is not recommended!") + else: + secure = True + infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication") + + if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "": + DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS) + + if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "": + BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS) + else: + BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS + + if VARIABLES != None and VARIABLES != "": + VARIABLES = json.loads(VARIABLES) + else: + VARIABLES = { + "NUMBER": SENDER, + "RECIPIENTS": DEFAULT_RECIPIENTS + } + + app.run(debug=False, port=8880, host='0.0.0.0') From 0c2380ea6f95050c0dd74d427889e1da729d9f14 Mon Sep 17 00:00:00 2001 From: codeshelldev <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 19:08:13 +0200 Subject: [PATCH 04/10] fix --- app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.py b/app.py index f3c97af..220d05c 100644 --- a/app.py +++ b/app.py @@ -40,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] From e57d6a47af4c870e465cbdc547b5a97660d1bebe Mon Sep 17 00:00:00 2001 From: codeshelldev <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 22:55:11 +0200 Subject: [PATCH 05/10] revert changes --- app.py | 346 +++++++++++++++++++++++++++++---------------------------- 1 file changed, 174 insertions(+), 172 deletions(-) diff --git a/app.py b/app.py index 220d05c..b1bd5e6 100644 --- a/app.py +++ b/app.py @@ -1,172 +1,174 @@ -from flask import Flask, Response, request, jsonify, make_response -import os -import json -import requests -import re -import base64 -import logging -from urllib.parse import unquote - -app = Flask("Secured Signal Api") - -app.logger.setLevel(logging.INFO) - -DEFAULT_BLOCKED_ENDPOINTS = [ - "/v1/about", - "/v1/configuration", - "/v1/devices", - "/v1/register", - "/v1/unregister", - "/v1/qrcodelink", - "/v1/accounts", - "/v1/contacts" -] - -SENDER = os.getenv("SENDER") -DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS") -SIGNAL_API_URL = os.getenv("SIGNAL_API_URL") -API_TOKEN = os.getenv("API_TOKEN") - -BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS") -VARIABLES = os.getenv("VARIABLES") - -secure = False - -def fillInVars(obj): - if isinstance(obj, dict): - for key, value in obj.items(): - obj[key] = fillInVars(value) - elif isinstance(obj, list): - for i in range(len(obj)): - obj[i] = fillInVars(obj[i]) - elif isinstance(obj, str): - matches = re.findall(r"\${(.*?)}", obj) - for match in matches: - if match in VARIABLES: - value = VARIABLES[match] - - if isinstance(value, str): - newValue = obj.replace(f"${{{match}}}", str(value)) - return newValue - else: - return value - return obj - -def UnauthorizedResponse(prompt=None): - headers = {} - - if prompt: - headers = { - "WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"' - } - - return Response( - "Unauthorized", 401, - headers - ) - -@app.before_request -def middlewares(): - for blockedPath in BLOCKED_ENDPOINTS: - if request.path.startswith(blockedPath): - infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]") - return Response("Forbidden", 401) - - if secure: - auth_header = request.headers.get("Authorization", "") - - if auth_header.startswith("Bearer "): - 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) - - 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: - errorLog(f"Unexpected Error during Basic Auth: {error}") - return UnauthorizedResponse() - else: - infoLog(f"Client did not provide any Auth Method") - return UnauthorizedResponse(True) - - -@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT']) -@app.route('/', methods=['GET', 'POST', 'PUT']) -def proxy(path): - method = request.method - incomingJSON = request.get_json(force=True, silent=True) - jsonData = incomingJSON - headers = {k: v for k, v in request.headers if k.lower() != 'host'} - - if incomingJSON: - jsonData = fillInVars(incomingJSON) - - if "${NUMBER}" in path: - path = path.replace("${NUMBER}", SENDER) - - query_string = request.query_string.decode() - - if request.query_string.decode(): - query_string= "?" + request.query_string.decode() - - targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" - - infoLog(json.dumps(jsonData)) - - resp = requests.request( - method=method, - url=targetURL, - headers=headers, - json=jsonData - ) - - infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]") - - # return Response(resp.content, status=resp.status_code, headers=dict(resp.headers)) - - response = make_response(resp.json()) - response.status_code = resp.status_code - - return response - -def infoLog(msg): - app.logger.info(msg) - -def errorLog(msg): - app.logger.error(msg) - -if __name__ == '__main__': - if SENDER and SIGNAL_API_URL: - if API_TOKEN == None or API_TOKEN == "": - infoLog("No API Token set (API_TOKEN), this is not recommended!") - else: - secure = True - infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication") - - if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "": - DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS) - - if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "": - BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS) - else: - BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS - - if VARIABLES != None and VARIABLES != "": - VARIABLES = json.loads(VARIABLES) - else: - VARIABLES = { - "NUMBER": SENDER, - "RECIPIENTS": DEFAULT_RECIPIENTS - } - - app.run(debug=False, port=8880, host='0.0.0.0') +from flask import Flask, Response, request, jsonify, make_response +import os +import json +import requests +import re +import base64 +import logging +from urllib.parse import unquote + +app = Flask("Secured Signal Api") + +app.logger.setLevel(logging.INFO) + +DEFAULT_BLOCKED_ENDPOINTS = [ + "/v1/about", + "/v1/configuration", + "/v1/devices", + "/v1/register", + "/v1/unregister", + "/v1/qrcodelink", + "/v1/accounts", + "/v1/contacts" +] + +SENDER = os.getenv("SENDER") +DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS") +SIGNAL_API_URL = os.getenv("SIGNAL_API_URL") +API_TOKEN = os.getenv("API_TOKEN") + +BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS") +VARIABLES = os.getenv("VARIABLES") + +secure = False + +def fillInVars(obj): + if isinstance(obj, dict): + for key, value in obj.items(): + obj[key] = fillInVars(value) + elif isinstance(obj, list): + for i in range(len(obj)): + obj[i] = fillInVars(obj[i]) + elif isinstance(obj, str): + matches = re.findall(r"\${(.*?)}", obj) + for match in matches: + if match in VARIABLES: + value = VARIABLES[match] + + if isinstance(value, str): + newValue = obj.replace(f"${{{match}}}", str(value)) + return newValue + else: + return value + return obj + +def UnauthorizedResponse(prompt=None): + headers = {} + + if prompt: + headers = { + "WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"' + } + + return Response( + "Unauthorized", 401, + headers + ) + +@app.before_request +def middlewares(): + for blockedPath in BLOCKED_ENDPOINTS: + if request.path.startswith(blockedPath): + infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]") + return Response("Forbidden", 401) + + if secure: + auth_header = request.headers.get("Authorization", "") + + if auth_header.startswith("Bearer "): + 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) + + 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: + errorLog(f"Unexpected Error during Basic Auth: {error}") + return UnauthorizedResponse() + else: + infoLog(f"Client did not provide any Auth Method") + return UnauthorizedResponse(True) + + +@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT']) +@app.route('/', methods=['GET', 'POST', 'PUT']) +def proxy(path): + method = request.method + incomingJSON = request.get_json(force=True, silent=True) + jsonData = incomingJSON + headers = {k: v for k, v in request.headers if k.lower() != 'host'} + + if incomingJSON: + jsonData = fillInVars(incomingJSON) + + if "${NUMBER}" in path: + path = path.replace("${NUMBER}", SENDER) + + query_string = request.query_string.decode() + + if request.query_string.decode(): + query_string= "?" + request.query_string.decode() + + targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" + + infoLog(json.dumps(jsonData)) + + resp = requests.request( + method=method, + url=targetURL, + headers=headers, + json=jsonData + ) + + infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]") + + # return Response(resp.content, status=resp.status_code, headers=dict(resp.headers)) + + response = make_response(resp.json()) + response.status_code = resp.status_code + + return response + +def infoLog(msg): + app.logger.info(msg) + +def errorLog(msg): + app.logger.error(msg) + +if __name__ == '__main__': + if SENDER and SIGNAL_API_URL: + if API_TOKEN == None or API_TOKEN == "": + infoLog("No API Token set (API_TOKEN), this is not recommended!") + else: + secure = True + infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication") + + if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "": + DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS) + + if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "": + BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS) + else: + BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS + + if VARIABLES != None and VARIABLES != "": + VARIABLES = json.loads(VARIABLES) + else: + VARIABLES = { + "NUMBER": SENDER, + "RECIPIENTS": DEFAULT_RECIPIENTS + } + + app.run(debug=False, port=8880, host='0.0.0.0') \ No newline at end of file From 121a2291126582ae211863b06dff1b830ec6fd2c Mon Sep 17 00:00:00 2001 From: codeshelldev <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 23:10:40 +0200 Subject: [PATCH 06/10] remove debug --- app.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app.py b/app.py index b1bd5e6..620828a 100644 --- a/app.py +++ b/app.py @@ -79,7 +79,7 @@ def middlewares(): token = auth_header.split(" ", 1)[1] token = unquote(token) - + if token != API_TOKEN: infoLog(f"Client failed Bearer Auth [token: {token}]") return UnauthorizedResponse() @@ -123,8 +123,6 @@ def proxy(path): targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" - infoLog(json.dumps(jsonData)) - resp = requests.request( method=method, url=targetURL, From aa72bd096c3ffb3469b8852e54690a6af45675b6 Mon Sep 17 00:00:00 2001 From: codeshelldev <122738806+CodeShellDev@users.noreply.github.com> Date: Thu, 19 Jun 2025 23:55:52 +0200 Subject: [PATCH 07/10] added Query Auth --- app.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/app.py b/app.py index 620828a..704cbab 100644 --- a/app.py +++ b/app.py @@ -5,7 +5,7 @@ import re import base64 import logging -from urllib.parse import unquote +from urllib.parse import unquote, urlencode, parse_qs app = Flask("Secured Signal Api") @@ -72,6 +72,8 @@ def middlewares(): infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]") return Response("Forbidden", 401) + query_string = request.query_string.decode() + if secure: auth_header = request.headers.get("Authorization", "") @@ -97,10 +99,24 @@ def middlewares(): except Exception as error: errorLog(f"Unexpected Error during Basic Auth: {error}") return UnauthorizedResponse() + elif request.args.get("authorization", None): + token = request.args.get("authorization", "") + + token = unquote(token) + + if token != API_TOKEN: + infoLog(f"Client failed Query Auth [query: {token}]") + return UnauthorizedResponse() + + args = parse_qs(query_string) + + args.pop('authorization', None) + query_string = urlencode(args, doseq=True) else: infoLog(f"Client did not provide any Auth Method") return UnauthorizedResponse(True) - + + g.query_string = query_string @app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT']) @app.route('/', methods=['GET', 'POST', 'PUT']) @@ -116,10 +132,10 @@ def proxy(path): if "${NUMBER}" in path: path = path.replace("${NUMBER}", SENDER) - query_string = request.query_string.decode() + query_string = g.query_string - if request.query_string.decode(): - query_string= "?" + request.query_string.decode() + if query_string: + query_string = "?" + query_string targetURL = f"{SIGNAL_API_URL}/{path}{query_string}" From 334959efeef769e3f34e77024055398c8b5c111b Mon Sep 17 00:00:00 2001 From: codeshelldev <122738806+CodeShellDev@users.noreply.github.com> Date: Fri, 20 Jun 2025 00:02:54 +0200 Subject: [PATCH 08/10] import g from flask --- app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app.py b/app.py index 704cbab..a3826fa 100644 --- a/app.py +++ b/app.py @@ -1,4 +1,4 @@ -from flask import Flask, Response, request, jsonify, make_response +from flask import Flask, Response, request, jsonify, make_response, g import os import json import requests From 38534802386e2fcf95ccca47426eed639ae1c2eb Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 22 Jun 2025 21:28:22 +0200 Subject: [PATCH 09/10] update workflow --- .github/workflows/docker-image-dev.yml | 54 ++++++-------------------- .github/workflows/docker-image.yml | 50 +++--------------------- .github/workflows/readme-update.yml | 34 +++------------- 3 files changed, 23 insertions(+), 115 deletions(-) diff --git a/.github/workflows/docker-image-dev.yml b/.github/workflows/docker-image-dev.yml index c1740eb..03e2292 100644 --- a/.github/workflows/docker-image-dev.yml +++ b/.github/workflows/docker-image-dev.yml @@ -4,48 +4,18 @@ on: push: branches: - dev - -env: - USERNAME: ${{ github.repository_owner }} - IMAGE_NAME: ${{ github.repository }} - REGISTRY: ghcr.io + paths-ignore: + - ".**" jobs: update: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Login to Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ env.USERNAME }} - password: ${{ secrets.GH_PCKG_TOKEN }} - - - name: Setup QEMU - uses: docker/setup-qemu-action@v3 - - - name: Setup Buildx - uses: docker/setup-buildx-action@v3 - - - name: Extract Labels and Tags - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - flavor: | - latest=false - tags: | - type=raw,value=latest-dev - - - name: Build and Push Image - uses: docker/build-push-action@v6 - with: - context: . - platforms: linux/amd64, linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - push: true + uses: codeshelldev/gh-actions/.github/workflows/docker-image.yml@main + with: + registry: ghcr.io + flavor: | + latest=false + tags: | + type=sha + type=raw,value=latest-dev + secrets: + GH_PCKG_TOKEN: ${{ secrets.GH_PCKG_TOKEN }} diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 4c61d4a..d0c694f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -4,50 +4,10 @@ on: release: types: [published] -env: - USERNAME: ${{ github.repository_owner }} - IMAGE_NAME: ${{ github.repository }} - REGISTRY: ghcr.io - jobs: update: - runs-on: ubuntu-latest - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Login to Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ env.USERNAME }} - password: ${{ secrets.GH_PCKG_TOKEN }} - - - name: Setup QEMU - uses: docker/setup-qemu-action@v3 - - - name: Setup Buildx - uses: docker/setup-buildx-action@v3 - - - name: Extract Labels and Tags - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - flavor: | - latest=false - tags: | - type=semver,pattern=v{{major}} - type=semver,pattern=v{{version}} - type=semver,pattern=v{{major}}.{{minor}} - type=semver,pattern=latest - - - name: Build and Push Image - uses: docker/build-push-action@v6 - with: - context: . - platforms: linux/amd64, linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - push: true + uses: codeshelldev/gh-actions/.github/workflows/docker-image.yml@main + with: + registry: ghcr.io + secrets: + GH_PCKG_TOKEN: ${{ secrets.GH_PCKG_TOKEN }} diff --git a/.github/workflows/readme-update.yml b/.github/workflows/readme-update.yml index cb7edb3..2f6b272 100644 --- a/.github/workflows/readme-update.yml +++ b/.github/workflows/readme-update.yml @@ -3,33 +3,11 @@ name: Update README on: push: paths: - - "docker-compose.yaml" - - ".github/templates/README.template.md" - - "examples/*" + - docker-compose.yaml + - .github/templates/README.template.md jobs: - update-readme: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Replace File Placeholders in README - run: | - bash .github/helper-scripts/replace_placeholders.sh .github/templates/README.template.md README.md - - - name: Commit & Push README.md - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - - git add README.md - if git diff --cached --quiet; then - echo "No changes to commit." - else - git commit -m "Update README.md" - git push - fi + update: + uses: codeshelldev/gh-actions/.github/workflows/readme-update.yml@main + secrets: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 75b5de64a5ddfe71c48903ebbb274b5035c2d3d8 Mon Sep 17 00:00:00 2001 From: CodeShell <122738806+CodeShellDev@users.noreply.github.com> Date: Sun, 22 Jun 2025 21:28:35 +0200 Subject: [PATCH 10/10] cleaned up app.py --- app.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app.py b/app.py index a3826fa..02494d2 100644 --- a/app.py +++ b/app.py @@ -80,8 +80,6 @@ def middlewares(): if auth_header.startswith("Bearer "): token = auth_header.split(" ", 1)[1] - token = unquote(token) - if token != API_TOKEN: infoLog(f"Client failed Bearer Auth [token: {token}]") return UnauthorizedResponse() @@ -90,9 +88,6 @@ def middlewares(): 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()