Skip to content

Commit e57d6a4

Browse files
committed
revert changes
1 parent 0c2380e commit e57d6a4

File tree

1 file changed

+174
-172
lines changed

1 file changed

+174
-172
lines changed

app.py

Lines changed: 174 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,174 @@
1-
from flask import Flask, Response, request, jsonify, make_response
2-
import os
3-
import json
4-
import requests
5-
import re
6-
import base64
7-
import logging
8-
from urllib.parse import unquote
9-
10-
app = Flask("Secured Signal Api")
11-
12-
app.logger.setLevel(logging.INFO)
13-
14-
DEFAULT_BLOCKED_ENDPOINTS = [
15-
"/v1/about",
16-
"/v1/configuration",
17-
"/v1/devices",
18-
"/v1/register",
19-
"/v1/unregister",
20-
"/v1/qrcodelink",
21-
"/v1/accounts",
22-
"/v1/contacts"
23-
]
24-
25-
SENDER = os.getenv("SENDER")
26-
DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS")
27-
SIGNAL_API_URL = os.getenv("SIGNAL_API_URL")
28-
API_TOKEN = os.getenv("API_TOKEN")
29-
30-
BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS")
31-
VARIABLES = os.getenv("VARIABLES")
32-
33-
secure = False
34-
35-
def fillInVars(obj):
36-
if isinstance(obj, dict):
37-
for key, value in obj.items():
38-
obj[key] = fillInVars(value)
39-
elif isinstance(obj, list):
40-
for i in range(len(obj)):
41-
obj[i] = fillInVars(obj[i])
42-
elif isinstance(obj, str):
43-
matches = re.findall(r"\${(.*?)}", obj)
44-
for match in matches:
45-
if match in VARIABLES:
46-
value = VARIABLES[match]
47-
48-
if isinstance(value, str):
49-
newValue = obj.replace(f"${{{match}}}", str(value))
50-
return newValue
51-
else:
52-
return value
53-
return obj
54-
55-
def UnauthorizedResponse(prompt=None):
56-
headers = {}
57-
58-
if prompt:
59-
headers = {
60-
"WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"'
61-
}
62-
63-
return Response(
64-
"Unauthorized", 401,
65-
headers
66-
)
67-
68-
@app.before_request
69-
def middlewares():
70-
for blockedPath in BLOCKED_ENDPOINTS:
71-
if request.path.startswith(blockedPath):
72-
infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]")
73-
return Response("Forbidden", 401)
74-
75-
if secure:
76-
auth_header = request.headers.get("Authorization", "")
77-
78-
if auth_header.startswith("Bearer "):
79-
token = auth_header.split(" ", 1)[1]
80-
81-
token = unquote(token)
82-
if token != API_TOKEN:
83-
infoLog(f"Client failed Bearer Auth [token: {token}]")
84-
return UnauthorizedResponse()
85-
elif auth_header.startswith("Basic "):
86-
try:
87-
decoded = base64.b64decode(auth_header.split(" ", 1)[1]).decode()
88-
username, password = decoded.split(":", 1)
89-
90-
username = unquote(username)
91-
password = unquote(password)
92-
if username != "api" or password != API_TOKEN:
93-
infoLog(f"Client failed Basic Auth [user: {username}, pw:{password}]")
94-
return UnauthorizedResponse()
95-
except Exception as error:
96-
errorLog(f"Unexpected Error during Basic Auth: {error}")
97-
return UnauthorizedResponse()
98-
else:
99-
infoLog(f"Client did not provide any Auth Method")
100-
return UnauthorizedResponse(True)
101-
102-
103-
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT'])
104-
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT'])
105-
def proxy(path):
106-
method = request.method
107-
incomingJSON = request.get_json(force=True, silent=True)
108-
jsonData = incomingJSON
109-
headers = {k: v for k, v in request.headers if k.lower() != 'host'}
110-
111-
if incomingJSON:
112-
jsonData = fillInVars(incomingJSON)
113-
114-
if "${NUMBER}" in path:
115-
path = path.replace("${NUMBER}", SENDER)
116-
117-
query_string = request.query_string.decode()
118-
119-
if request.query_string.decode():
120-
query_string= "?" + request.query_string.decode()
121-
122-
targetURL = f"{SIGNAL_API_URL}/{path}{query_string}"
123-
124-
infoLog(json.dumps(jsonData))
125-
126-
resp = requests.request(
127-
method=method,
128-
url=targetURL,
129-
headers=headers,
130-
json=jsonData
131-
)
132-
133-
infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]")
134-
135-
# return Response(resp.content, status=resp.status_code, headers=dict(resp.headers))
136-
137-
response = make_response(resp.json())
138-
response.status_code = resp.status_code
139-
140-
return response
141-
142-
def infoLog(msg):
143-
app.logger.info(msg)
144-
145-
def errorLog(msg):
146-
app.logger.error(msg)
147-
148-
if __name__ == '__main__':
149-
if SENDER and SIGNAL_API_URL:
150-
if API_TOKEN == None or API_TOKEN == "":
151-
infoLog("No API Token set (API_TOKEN), this is not recommended!")
152-
else:
153-
secure = True
154-
infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication")
155-
156-
if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "":
157-
DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS)
158-
159-
if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "":
160-
BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS)
161-
else:
162-
BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS
163-
164-
if VARIABLES != None and VARIABLES != "":
165-
VARIABLES = json.loads(VARIABLES)
166-
else:
167-
VARIABLES = {
168-
"NUMBER": SENDER,
169-
"RECIPIENTS": DEFAULT_RECIPIENTS
170-
}
171-
172-
app.run(debug=False, port=8880, host='0.0.0.0')
1+
from flask import Flask, Response, request, jsonify, make_response
2+
import os
3+
import json
4+
import requests
5+
import re
6+
import base64
7+
import logging
8+
from urllib.parse import unquote
9+
10+
app = Flask("Secured Signal Api")
11+
12+
app.logger.setLevel(logging.INFO)
13+
14+
DEFAULT_BLOCKED_ENDPOINTS = [
15+
"/v1/about",
16+
"/v1/configuration",
17+
"/v1/devices",
18+
"/v1/register",
19+
"/v1/unregister",
20+
"/v1/qrcodelink",
21+
"/v1/accounts",
22+
"/v1/contacts"
23+
]
24+
25+
SENDER = os.getenv("SENDER")
26+
DEFAULT_RECIPIENTS = os.getenv("DEFAULT_RECIPIENTS")
27+
SIGNAL_API_URL = os.getenv("SIGNAL_API_URL")
28+
API_TOKEN = os.getenv("API_TOKEN")
29+
30+
BLOCKED_ENDPOINTS = os.getenv("BLOCKED_ENDPOINTS")
31+
VARIABLES = os.getenv("VARIABLES")
32+
33+
secure = False
34+
35+
def fillInVars(obj):
36+
if isinstance(obj, dict):
37+
for key, value in obj.items():
38+
obj[key] = fillInVars(value)
39+
elif isinstance(obj, list):
40+
for i in range(len(obj)):
41+
obj[i] = fillInVars(obj[i])
42+
elif isinstance(obj, str):
43+
matches = re.findall(r"\${(.*?)}", obj)
44+
for match in matches:
45+
if match in VARIABLES:
46+
value = VARIABLES[match]
47+
48+
if isinstance(value, str):
49+
newValue = obj.replace(f"${{{match}}}", str(value))
50+
return newValue
51+
else:
52+
return value
53+
return obj
54+
55+
def UnauthorizedResponse(prompt=None):
56+
headers = {}
57+
58+
if prompt:
59+
headers = {
60+
"WWW-Authenticate": 'Basic realm="Login Required", Bearer realm="Access Token Required"'
61+
}
62+
63+
return Response(
64+
"Unauthorized", 401,
65+
headers
66+
)
67+
68+
@app.before_request
69+
def middlewares():
70+
for blockedPath in BLOCKED_ENDPOINTS:
71+
if request.path.startswith(blockedPath):
72+
infoLog(f"Client tried to access Blocked Endpoint [{blockedPath}]")
73+
return Response("Forbidden", 401)
74+
75+
if secure:
76+
auth_header = request.headers.get("Authorization", "")
77+
78+
if auth_header.startswith("Bearer "):
79+
token = auth_header.split(" ", 1)[1]
80+
81+
token = unquote(token)
82+
83+
if token != API_TOKEN:
84+
infoLog(f"Client failed Bearer Auth [token: {token}]")
85+
return UnauthorizedResponse()
86+
elif auth_header.startswith("Basic "):
87+
try:
88+
decoded = base64.b64decode(auth_header.split(" ", 1)[1]).decode()
89+
username, password = decoded.split(":", 1)
90+
91+
username = unquote(username)
92+
password = unquote(password)
93+
94+
if username != "api" or password != API_TOKEN:
95+
infoLog(f"Client failed Basic Auth [user: {username}, pw:{password}]")
96+
return UnauthorizedResponse()
97+
except Exception as error:
98+
errorLog(f"Unexpected Error during Basic Auth: {error}")
99+
return UnauthorizedResponse()
100+
else:
101+
infoLog(f"Client did not provide any Auth Method")
102+
return UnauthorizedResponse(True)
103+
104+
105+
@app.route('/', defaults={'path': ''}, methods=['GET', 'POST', 'PUT'])
106+
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT'])
107+
def proxy(path):
108+
method = request.method
109+
incomingJSON = request.get_json(force=True, silent=True)
110+
jsonData = incomingJSON
111+
headers = {k: v for k, v in request.headers if k.lower() != 'host'}
112+
113+
if incomingJSON:
114+
jsonData = fillInVars(incomingJSON)
115+
116+
if "${NUMBER}" in path:
117+
path = path.replace("${NUMBER}", SENDER)
118+
119+
query_string = request.query_string.decode()
120+
121+
if request.query_string.decode():
122+
query_string= "?" + request.query_string.decode()
123+
124+
targetURL = f"{SIGNAL_API_URL}/{path}{query_string}"
125+
126+
infoLog(json.dumps(jsonData))
127+
128+
resp = requests.request(
129+
method=method,
130+
url=targetURL,
131+
headers=headers,
132+
json=jsonData
133+
)
134+
135+
infoLog(f"Forwarded {resp.text} to {targetURL} [{method}]")
136+
137+
# return Response(resp.content, status=resp.status_code, headers=dict(resp.headers))
138+
139+
response = make_response(resp.json())
140+
response.status_code = resp.status_code
141+
142+
return response
143+
144+
def infoLog(msg):
145+
app.logger.info(msg)
146+
147+
def errorLog(msg):
148+
app.logger.error(msg)
149+
150+
if __name__ == '__main__':
151+
if SENDER and SIGNAL_API_URL:
152+
if API_TOKEN == None or API_TOKEN == "":
153+
infoLog("No API Token set (API_TOKEN), this is not recommended!")
154+
else:
155+
secure = True
156+
infoLog("API Token set, use Bearer or Basic Auth (user: api) for authentication")
157+
158+
if DEFAULT_RECIPIENTS != None and DEFAULT_RECIPIENTS != "":
159+
DEFAULT_RECIPIENTS = json.loads(DEFAULT_RECIPIENTS)
160+
161+
if BLOCKED_ENDPOINTS != None and BLOCKED_ENDPOINTS != "":
162+
BLOCKED_ENDPOINTS = json.loads(BLOCKED_ENDPOINTS)
163+
else:
164+
BLOCKED_ENDPOINTS = DEFAULT_BLOCKED_ENDPOINTS
165+
166+
if VARIABLES != None and VARIABLES != "":
167+
VARIABLES = json.loads(VARIABLES)
168+
else:
169+
VARIABLES = {
170+
"NUMBER": SENDER,
171+
"RECIPIENTS": DEFAULT_RECIPIENTS
172+
}
173+
174+
app.run(debug=False, port=8880, host='0.0.0.0')

0 commit comments

Comments
 (0)