Automates the Blancco parts of the onsite-support CMMC playbook:
- ENT-056/158 evidence pack: /reports/evidence?month=YYYY-MM returns
ENT-056_<Site>_<YYYY-MM>.zip (summary.csv, README, each report's XML
and PDF). pxe-blancco-evidence.timer saves last month's pack to the
reports share's evidence/ folder on the 1st (Persistent).
- ENT-045/159 ServiceNow tick list: /reports/servicenow lists recent
reports as "Wiped" or "Blancco Wipe failed" with a pre-written
destruction note, copy buttons and Done (CSRF-protected).
- Cloud upload: blancco-progress.py posts each report's upload result
("Sending report document id" -> "Report sent to MC") to
/reports/cloud-status (CSRF-exempt like /imaging/status); the Reports
page and the CSVs show it, so a wipe missing from BMP is visible.
- CSV gains failure_reason (exception messages, failed steps, error
counts), business_location and cloud_upload.
- Preferences: business_location "West Jefferson" (config.BLANCCO_SITE)
and pdf+xml reports; the report copier now copies the PDF too, named
after its XML. .part and hidden files are not listed as reports.
State (cloud confirmations, ServiceNow ticks) is a JSON file at
/var/lib/pxe-webapp/blancco-state.json, off the report share.
39 lines
1.2 KiB
Python
39 lines
1.2 KiB
Python
"""Session-based CSRF token: generate per-session, double-submit on POST."""
|
|
|
|
import secrets
|
|
|
|
from flask import abort, request, session
|
|
|
|
# Endpoint paths exempt from CSRF (machine-to-machine POSTs from PXE clients
|
|
# that have no browser session to carry a token). Air-gapped LAN; treated as
|
|
# trust-by-network. Keep the list short and explicit.
|
|
CSRF_EXEMPT_PATHS = {
|
|
"/imaging/status",
|
|
"/reports/cloud-status",
|
|
}
|
|
|
|
|
|
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
|
|
if request.path in CSRF_EXEMPT_PATHS:
|
|
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}
|