Fix scanner probes returning 200 via SPA catch-all
The 404 handler was unconditionally serving index.html (200) for all non-API, non-static paths, including scanner probes for .php, .asp, .cgi etc. Added _SPA_EXTENSIONS set so paths with unknown extensions get a real 404 instead of a misleading 200. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -238,17 +238,34 @@ def create_app() -> Quart:
|
|||||||
resp.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
resp.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
# File extensions that belong to the SPA or its assets.
|
||||||
|
# Anything else with an extension is not a valid app path and gets a hard 404.
|
||||||
|
_SPA_EXTENSIONS = {
|
||||||
|
"", ".html", ".js", ".css", ".ico", ".png", ".jpg", ".jpeg",
|
||||||
|
".svg", ".webp", ".woff", ".woff2", ".ttf", ".otf", ".map", ".json",
|
||||||
|
}
|
||||||
|
|
||||||
@app.errorhandler(404)
|
@app.errorhandler(404)
|
||||||
async def handle_404(error):
|
async def handle_404(error):
|
||||||
# Return JSON 404 for API routes
|
# Return JSON 404 for API routes
|
||||||
if request.path.startswith("/api/"):
|
if request.path.startswith("/api/"):
|
||||||
return jsonify({"error": "Not found"}), 404
|
return jsonify({"error": "Not found"}), 404
|
||||||
# Try to serve static file
|
|
||||||
|
# Try to serve a real static file first
|
||||||
path = request.path.lstrip("/")
|
path = request.path.lstrip("/")
|
||||||
file_path = STATIC_DIR / path
|
file_path = STATIC_DIR / path
|
||||||
if path and file_path.is_file():
|
if path and file_path.is_file():
|
||||||
return await send_from_directory(STATIC_DIR, path)
|
return await send_from_directory(STATIC_DIR, path)
|
||||||
# SPA fallback
|
|
||||||
|
# Reject paths with file extensions the app doesn't serve.
|
||||||
|
# This turns scanner probes (.php, .asp, .cgi, etc.) into honest 404s
|
||||||
|
# instead of serving them the Vue SPA with a misleading 200.
|
||||||
|
from pathlib import PurePosixPath
|
||||||
|
suffix = PurePosixPath(request.path).suffix.lower()
|
||||||
|
if suffix not in _SPA_EXTENSIONS:
|
||||||
|
return "", 404
|
||||||
|
|
||||||
|
# SPA fallback for clean client-side routes (/notes/123, /chat, etc.)
|
||||||
resp = await make_response(
|
resp = await make_response(
|
||||||
await send_from_directory(STATIC_DIR, "index.html")
|
await send_from_directory(STATIC_DIR, "index.html")
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user