From 57706988474ee882e03e0e72cfa6ce0fd439c699 Mon Sep 17 00:00:00 2001 From: Username Date: Sat, 20 Dec 2025 04:43:36 +0100 Subject: [PATCH] add URL_PREFIX config for reverse proxy path support --- app/api/routes.py | 33 +++++++++++++++++++++------------ app/config.py | 3 +++ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/app/api/routes.py b/app/api/routes.py index 5f1505b..3389454 100644 --- a/app/api/routes.py +++ b/app/api/routes.py @@ -17,6 +17,12 @@ from app.database import check_content_hash, get_db # Valid paste ID pattern (hexadecimal only) PASTE_ID_PATTERN = re.compile(r"^[a-f0-9]+$") + +def _url(path: str) -> str: + """Generate URL with configured prefix for reverse proxy deployments.""" + prefix = current_app.config.get("URL_PREFIX", "") + return f"{prefix}{path}" + # Runtime-generated PoW secret (used if not configured) _pow_secret_cache = None @@ -273,22 +279,25 @@ def index(): if request.method == "POST": return create_paste() + prefix = current_app.config.get("URL_PREFIX", "") return _json_response( { "name": "FlaskPaste", "version": VERSION, + "prefix": prefix or "/", "endpoints": { - "GET /": "API information", - "GET /health": "Health check", - "POST /": "Create paste", - "GET /": "Retrieve paste metadata", - "GET //raw": "Retrieve raw paste content", - "DELETE /": "Delete paste", + f"GET {_url('/')}": "API information", + f"GET {_url('/health')}": "Health check", + f"GET {_url('/challenge')}": "Get PoW challenge", + f"POST {_url('/')}": "Create paste", + f"GET {_url('/')}": "Retrieve paste metadata", + f"GET {_url('//raw')}": "Retrieve raw paste content", + f"DELETE {_url('/')}": "Delete paste", }, "usage": { - "raw": "curl --data-binary @file.txt http://host/", - "pipe": "cat file.txt | curl --data-binary @- http://host/", - "json": "curl -H 'Content-Type: application/json' -d '{\"content\":\"...\"}' http://host/", + "raw": f"curl --data-binary @file.txt http://host{_url('/')}", + "pipe": f"cat file.txt | curl --data-binary @- http://host{_url('/')}", + "json": f"curl -H 'Content-Type: application/json' -d '{{\"content\":\"...\"}}' http://host{_url('/')}", }, "note": "Use --data-binary (not -d) to preserve newlines", } @@ -382,8 +391,8 @@ def create_paste(): response_data = { "id": paste_id, - "url": f"/{paste_id}", - "raw": f"/{paste_id}/raw", + "url": _url(f"/{paste_id}"), + "raw": _url(f"/{paste_id}/raw"), "mime_type": mime_type, "created_at": now, } @@ -420,7 +429,7 @@ def get_paste(paste_id: str): "mime_type": row["mime_type"], "size": row["size"], "created_at": row["created_at"], - "raw": f"/{paste_id}/raw", + "raw": _url(f"/{paste_id}/raw"), }) diff --git a/app/config.py b/app/config.py index 94bf071..44c26b0 100644 --- a/app/config.py +++ b/app/config.py @@ -44,6 +44,9 @@ class Config: # Secret key for signing challenges (auto-generated if not set) POW_SECRET = os.environ.get("FLASKPASTE_POW_SECRET", "") + # URL prefix for reverse proxy deployments (e.g., "/paste" for mymx.me/paste) + URL_PREFIX = os.environ.get("FLASKPASTE_URL_PREFIX", "").rstrip("/") + class DevelopmentConfig(Config): """Development configuration."""