""" SooSeF Web Frontend Flask application factory that unifies Stegasoo (steganography) and Verisoo (provenance attestation) into a single web UI with fieldkit security features. Built on Stegasoo's production-grade web UI patterns: - Subprocess isolation for crash-safe stegasoo operations - Async jobs with progress polling for large images - Context processors for global template variables - File-based temp storage with auto-expiry BLUEPRINT STRUCTURE =================== / → index (dashboard) /login, /logout → auth (adapted from stegasoo) /setup → first-run wizard /encode, /decode, /generate, /tools → stego blueprint /attest, /verify → attest blueprint /fieldkit/* → fieldkit blueprint /keys/* → keys blueprint /admin/* → admin blueprint """ import os import secrets import sys from pathlib import Path from flask import Flask, redirect, render_template, url_for import soosef from soosef.config import SoosefConfig from soosef.paths import AUTH_DB, INSTANCE_DIR, SECRET_KEY_FILE, TEMP_DIR, ensure_dirs # Suppress numpy/scipy warnings in subprocesses os.environ["NUMPY_MADVISE_HUGEPAGE"] = "0" os.environ["OMP_NUM_THREADS"] = "1" # Maximum upload size (50 MB default) MAX_FILE_SIZE = 50 * 1024 * 1024 def create_app(config: SoosefConfig | None = None) -> Flask: """Application factory.""" config = config or SoosefConfig.load() ensure_dirs() app = Flask( __name__, instance_path=str(INSTANCE_DIR), template_folder=str(Path(__file__).parent / "templates"), static_folder=str(Path(__file__).parent / "static"), ) app.config["MAX_CONTENT_LENGTH"] = config.max_upload_mb * 1024 * 1024 app.config["AUTH_ENABLED"] = config.auth_enabled app.config["HTTPS_ENABLED"] = config.https_enabled app.config["SOOSEF_CONFIG"] = config # Persist secret key so sessions survive restarts _load_secret_key(app) # ── Register blueprints ─────────────────────────────────────── from frontends.web.blueprints.stego import bp as stego_bp from frontends.web.blueprints.attest import bp as attest_bp from frontends.web.blueprints.fieldkit import bp as fieldkit_bp from frontends.web.blueprints.keys import bp as keys_bp from frontends.web.blueprints.admin import bp as admin_bp app.register_blueprint(stego_bp) app.register_blueprint(attest_bp) app.register_blueprint(fieldkit_bp) app.register_blueprint(keys_bp) app.register_blueprint(admin_bp) # ── Context processor (injected into ALL templates) ─────────── @app.context_processor def inject_globals(): from soosef.keystore import KeystoreManager ks = KeystoreManager() ks_status = ks.status() # Check fieldkit alert level fieldkit_status = "ok" if config.deadman_enabled: from soosef.fieldkit.deadman import DeadmanSwitch dm = DeadmanSwitch() if dm.should_fire(): fieldkit_status = "alarm" elif dm.is_overdue(): fieldkit_status = "warn" # Check stegasoo capabilities try: from stegasoo import has_dct_support, HAS_AUDIO_SUPPORT has_dct = has_dct_support() has_audio = HAS_AUDIO_SUPPORT except ImportError: has_dct = False has_audio = False # Check verisoo availability try: import verisoo # noqa: F401 has_verisoo = True except ImportError: has_verisoo = False return { "version": soosef.__version__, "has_dct": has_dct, "has_audio": has_audio, "has_verisoo": has_verisoo, "has_fieldkit": config.killswitch_enabled or config.deadman_enabled, "fieldkit_status": fieldkit_status, "channel_configured": ks_status.has_channel_key, "channel_fingerprint": ks_status.channel_fingerprint or "", "identity_configured": ks_status.has_identity, "identity_fingerprint": ks_status.identity_fingerprint or "", "auth_enabled": app.config["AUTH_ENABLED"], "is_authenticated": _is_authenticated(), "is_admin": _is_admin(), "username": _get_username(), } # ── Root routes ─────────────────────────────────────────────── @app.route("/") def index(): return render_template("index.html") return app def _load_secret_key(app: Flask) -> None: """Load or generate persistent secret key for Flask sessions.""" SECRET_KEY_FILE.parent.mkdir(parents=True, exist_ok=True) if SECRET_KEY_FILE.exists(): app.secret_key = SECRET_KEY_FILE.read_bytes() else: key = secrets.token_bytes(32) SECRET_KEY_FILE.write_bytes(key) SECRET_KEY_FILE.chmod(0o600) app.secret_key = key def _is_authenticated() -> bool: """Check if current request has an authenticated session.""" # TODO: Wire up auth.py from stegasoo return True def _is_admin() -> bool: """Check if current user is an admin.""" # TODO: Wire up auth.py from stegasoo return True def _get_username() -> str: """Get current user's username.""" # TODO: Wire up auth.py from stegasoo return "admin"