webapp: extract service layer (config.py + services/) from app.py
Phase 1a of a multi-session refactor toward a clean blueprint
structure. Pulls the helper code that lived alongside the routes in
the 1621-line app.py into focused modules. app.py is now 625 lines
of mostly routes plus a small Flask wiring header. Behaviour is
unchanged: smoke-tested against the 8 main GET routes (200 OK).
New modules:
- config.py env vars + IMAGE_TYPES + FRIENDLY_NAMES +
SHARED_DEPLOY_* taxonomy + unattend XML
namespaces.
- services/audit.py audit log file handler + audit() helper.
- services/csrf.py session CSRF token + before_request validator
wired via init_csrf(app).
- services/fs.py image_root / deploy_path / unattend_path /
control_path / tools_path + load_json /
save_json + resolve_destination.
- services/system.py service_status / find_usb_mounts /
find_upload_sources.
- services/images.py image_status + load_image_config.
- services/deploy.py import_deploy + _merge_tree +
_replace_with_symlink + allowed_import_source.
- services/unattend.py parse_unattend / build_unattend_xml /
extract_form_data and the qn / qwcm / settings
pass helpers.
- services/wim.py extract_startnet / update_startnet / list_files
wrapping wimextract / wimupdate / wimdir.
Endpoint names kept stable (dashboard, clonezilla_backups, etc.) so
existing url_for(...) calls in templates are unchanged. Phase 1b
(Flask blueprints with ".endpoint" naming) deferred to a future
session because it requires updating ~30 url_for sites in templates
and is mostly cosmetic.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
28
webapp/services/csrf.py
Normal file
28
webapp/services/csrf.py
Normal file
@@ -0,0 +1,28 @@
|
||||
"""Session-based CSRF token: generate per-session, double-submit on POST."""
|
||||
|
||||
import secrets
|
||||
|
||||
from flask import abort, request, session
|
||||
|
||||
|
||||
def generate_csrf_token():
|
||||
"""Return the CSRF token for the current session, creating one if needed."""
|
||||
if "_csrf_token" not in session:
|
||||
session["_csrf_token"] = secrets.token_hex(32)
|
||||
return session["_csrf_token"]
|
||||
|
||||
|
||||
def init_csrf(app):
|
||||
"""Wire CSRF protection into a Flask app: validator + template helper."""
|
||||
|
||||
@app.before_request
|
||||
def _validate_csrf():
|
||||
if request.method != "POST":
|
||||
return
|
||||
token = request.form.get("_csrf_token") or request.headers.get("X-CSRF-Token")
|
||||
if not token or token != generate_csrf_token():
|
||||
abort(403)
|
||||
|
||||
@app.context_processor
|
||||
def _inject_csrf_token():
|
||||
return {"csrf_token": generate_csrf_token}
|
||||
Reference in New Issue
Block a user