diff --git a/berretin.py b/berretin.py index b10e4e8..39784e5 100644 --- a/berretin.py +++ b/berretin.py @@ -4,45 +4,68 @@ import json import requests import subprocess from datetime import datetime, timedelta -from flask import Flask, jsonify, Response, request +from flask import Flask, jsonify, Response, request, abort BASE_API = "https://ws1.smn.gob.ar" CACHE_DIR = "json.api.cache" -CACHE_TTL = timedelta(minutes=30) +CACHE_TTL = timedelta(minutes=60) SMN_TOKEN_FILE = "token.txt" ACCESS_TOKEN = "i.hate.smn" +TIMEOUT = 10 app = Flask(__name__) +app.config["JSONIFY_PRETTYPRINT_REGULAR"] = False + +@app.after_request +def remove_server_header(response): + response.headers["Server"] = "" + response.headers["X-Powered-By"] = "" + return response + def get_cache_filename(url: str) -> str: h = hashlib.sha256(url.encode()).hexdigest() return os.path.join(CACHE_DIR, f"{h}.json") def load_cache(url: str): - path = get_cache_filename(url) - if not os.path.exists(path): + try: + path = get_cache_filename(url) + if not os.path.exists(path): + return None + mtime = datetime.fromtimestamp(os.path.getmtime(path)) + if datetime.now() - mtime > CACHE_TTL: + return None + with open(path, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: return None - mtime = datetime.fromtimestamp(os.path.getmtime(path)) - if datetime.now() - mtime > CACHE_TTL: - return None - with open(path, "r", encoding="utf-8") as f: - return json.load(f) def save_cache(url: str, data: dict): - os.makedirs(CACHE_DIR, exist_ok=True) - path = get_cache_filename(url) - with open(path, "w", encoding="utf-8") as f: - json.dump(data, f, indent=2, ensure_ascii=False) + try: + os.makedirs(CACHE_DIR, exist_ok=True) + path = get_cache_filename(url) + with open(path, "w", encoding="utf-8") as f: + json.dump(data, f, ensure_ascii=False) + except Exception as e: + print(f"[CACHE] Failed to save cache: {e}") + def load_smn_token(): - with open(SMN_TOKEN_FILE, "r") as f: - return f.read().strip() + try: + with open(SMN_TOKEN_FILE, "r", encoding="utf-8") as f: + token = f.read().strip() + if not token: + raise ValueError("Empty token file.") + return token + except Exception as e: + print(f"[TOKEN] Error loading token: {e}") + return "" def refresh_smn_token(): print("[TOKEN] Refreshing SMN token...") try: result = subprocess.run( - ["python3", "tokenext.py"], # cheap as fuck, fixing later + ["python3", "tokenext.py"], capture_output=True, text=True, timeout=60 @@ -50,13 +73,16 @@ def refresh_smn_token(): if result.returncode == 0: print("[TOKEN] Token refreshed successfully.") else: - print("[TOKEN] Failed to refresh token:", result.stderr) + print(f"[TOKEN] Refresh failed: {result.stderr.strip()}") except Exception as e: - print("[TOKEN] Error running tokenext.py:", e) + print(f"[TOKEN] Error running tokenext.py: {e}") + def check_access_token(): header_token = request.headers.get("Authorization", "").strip() - return header_token == ACCESS_TOKEN + if not header_token or header_token != ACCESS_TOKEN: + abort(401) # immediately reject unauthorized access + def fetch_from_smn(url: str, retry: bool = True): token = load_smn_token() @@ -66,23 +92,27 @@ def fetch_from_smn(url: str, retry: bool = True): "User-Agent": "Mozilla/5.0" } - resp = requests.get(url, headers=headers) + try: + resp = requests.get(url, headers=headers, timeout=TIMEOUT) + except requests.RequestException as e: + print(f"[ERROR] Request failed: {e}") + return None if resp.status_code == 401 and retry: - print("[AUTH] SMN token expired, trying to refresh...") + print("[AUTH] SMN token expired, refreshing...") refresh_smn_token() return fetch_from_smn(url, retry=False) return resp + @app.route("/smn/") def smn_proxy(subpath): - if not check_access_token(): - return jsonify({"error": "Unauthorized"}), 401 + check_access_token() url = f"{BASE_API}/{subpath}" - # Check cache + # Cache check cached = load_cache(url) if cached: print(f"[CACHE] Loaded {subpath}") @@ -90,18 +120,23 @@ def smn_proxy(subpath): print(f"[FETCH] {url}") resp = fetch_from_smn(url) + if not resp: + return Response("", status=502) - if resp.status_code != 200: - return Response( - resp.text, - status=resp.status_code, - content_type=resp.headers.get("Content-Type", "text/plain") - ) + if resp.status_code >= 400: + print(f"[WARN] {resp.status_code} for {url}") + return Response("", status=resp.status_code) + + try: + data = resp.json() + except Exception: + print("[ERROR] Invalid JSON response.") + return Response("", status=502) - data = resp.json() save_cache(url, data) return jsonify(data) + if __name__ == "__main__": os.makedirs(CACHE_DIR, exist_ok=True) - app.run(host="0.0.0.0", port=6942, debug=False) + app.run(host="0.0.0.0", port=6942, debug=False, use_reloader=False)