hueta
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/python3
|
||||
from flask import Flask, make_response, request, redirect
|
||||
import os
|
||||
import requests as r
|
||||
app = Flask(__name__)
|
||||
database_node_port = 5002
|
||||
@@ -7,6 +8,8 @@ logic_node_port = 5003
|
||||
database_node = "database:" + str(database_node_port)
|
||||
|
||||
IMG_MIN, IMG_MAX = 1, 16
|
||||
INTERNAL = os.environ.get("RUSGRAM_INTERNAL", "e9b2f6d14a8c7035e1d0a6b8c4f2e7a9")
|
||||
DBH = {"X-Internal": INTERNAL}
|
||||
|
||||
|
||||
def bad_request(status="error", code=400):
|
||||
@@ -31,9 +34,16 @@ def valid_username(username):
|
||||
return False # имя юзера = имя файла в db/users/
|
||||
if username.lower().endswith((".html", ".htm")):
|
||||
return False # имя, которое content мог бы отрендерить как шаблон
|
||||
if "{{" in username or "{%" in username or "{#" in username:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def clean_value(value):
|
||||
"""Не даём записать Jinja-конструкции в поля, которые когда-то рендерились как шаблон."""
|
||||
return isinstance(value, str) and "{{" not in value and "{%" not in value and "{#" not in value
|
||||
|
||||
|
||||
def current_user():
|
||||
"""Возвращает имя авторизованного юзера или None. Не бросает исключений."""
|
||||
session = request.cookies.get("session")
|
||||
@@ -46,7 +56,8 @@ def current_user():
|
||||
if not username:
|
||||
return None
|
||||
try:
|
||||
resp = r.get(f"http://{database_node}/users/{username}/password", timeout=5)
|
||||
resp = r.get(f"http://{database_node}/users/{username}/password",
|
||||
headers=DBH, timeout=5)
|
||||
if resp.status_code != 200: # PATCH V8: несуществующий юзер -> KeyError -> 500
|
||||
return None
|
||||
if resp.json().get("data") != password:
|
||||
@@ -70,7 +81,8 @@ def login():
|
||||
if not isinstance(username, str) or not isinstance(password, str):
|
||||
return bad_request()
|
||||
try:
|
||||
resp = r.get(f"http://{database_node}/users/{username}/password", timeout=5)
|
||||
resp = r.get(f"http://{database_node}/users/{username}/password",
|
||||
headers=DBH, timeout=5)
|
||||
correct_password = resp.json()["data"] if resp.status_code == 200 else None
|
||||
except (r.RequestException, ValueError, KeyError):
|
||||
return bad_request()
|
||||
@@ -96,7 +108,8 @@ def register():
|
||||
# его пароль (остальные поля, включая флаг, сохранялись) => полный захват
|
||||
# чужого аккаунта без единого запроса на аутентификацию.
|
||||
try:
|
||||
exists = r.get(f"http://{database_node}/users/{username}/password", timeout=5)
|
||||
exists = r.get(f"http://{database_node}/users/{username}/password",
|
||||
headers=DBH, timeout=5)
|
||||
if exists.status_code == 200:
|
||||
return make_response({"status": "user_exists"}, 409)
|
||||
except r.RequestException:
|
||||
@@ -104,7 +117,7 @@ def register():
|
||||
|
||||
try:
|
||||
resp = r.post(f"http://{database_node}/users/{username}/password",
|
||||
json={"value": password}, timeout=5)
|
||||
json={"value": password}, headers=DBH, timeout=5)
|
||||
except r.RequestException:
|
||||
return bad_request()
|
||||
if resp.status_code == 200:
|
||||
@@ -123,12 +136,12 @@ def update_personal():
|
||||
if data is None:
|
||||
return bad_request()
|
||||
for field in ("first_name", "second_name", "email"):
|
||||
if field not in data or not isinstance(data[field], str):
|
||||
if field not in data or not clean_value(data[field]):
|
||||
return bad_request()
|
||||
try:
|
||||
for field in ("first_name", "second_name", "email"):
|
||||
r.post(f"http://{database_node}/users/{username}/{field}",
|
||||
json={"value": data[field]}, timeout=5)
|
||||
json={"value": data[field]}, headers=DBH, timeout=5)
|
||||
except r.RequestException:
|
||||
return bad_request()
|
||||
return make_response({"status": "ok"}, 200)
|
||||
@@ -140,11 +153,11 @@ def send_msg():
|
||||
if username is None:
|
||||
return unauthorized()
|
||||
data = json_body()
|
||||
if data is None or not isinstance(data.get("msg"), str):
|
||||
if data is None or not clean_value(data.get("msg")):
|
||||
return bad_request()
|
||||
try:
|
||||
r.post(f"http://{database_node}/users/{username}/msg",
|
||||
json={"value": data["msg"]}, timeout=5)
|
||||
json={"value": data["msg"]}, headers=DBH, timeout=5)
|
||||
except r.RequestException:
|
||||
return bad_request()
|
||||
return make_response({"status": "ok"}, 200)
|
||||
@@ -156,7 +169,7 @@ def post_comment():
|
||||
if username is None:
|
||||
return unauthorized()
|
||||
data = json_body()
|
||||
if data is None or not isinstance(data.get("msg"), str):
|
||||
if data is None or not clean_value(data.get("msg")):
|
||||
return bad_request()
|
||||
# PATCH V8: img_id раньше уходил в URL внутреннего запроса как есть
|
||||
try:
|
||||
@@ -167,7 +180,7 @@ def post_comment():
|
||||
return bad_request()
|
||||
try:
|
||||
r.post(f"http://{database_node}/images/{img_id}",
|
||||
json={"value": [username, data["msg"]]}, timeout=5)
|
||||
json={"value": [username, data["msg"]]}, headers=DBH, timeout=5)
|
||||
except r.RequestException:
|
||||
return bad_request()
|
||||
return make_response({"status": "ok"}, 200)
|
||||
|
||||
Reference in New Issue
Block a user