"""VoxIP Kiosk Manager — Flask application factory.""" from __future__ import annotations import os import secrets from dataclasses import dataclass from datetime import timedelta from typing import Any from flask import Flask from ..cdp import CDP from ..config import load_config from ..helper_client import HelperClient from ..paths import Paths, load_paths, read_version from .auth import CredentialStore, LoginThrottle @dataclass class Services: paths: Paths credentials: CredentialStore throttle: LoginThrottle helper: Any cdp: Any version: str def _secret_key(paths: Paths) -> bytes: path = paths.secret_key_file try: key = path.read_bytes() if len(key) >= 32: return key except FileNotFoundError: pass key = secrets.token_bytes(64) fd = os.open(str(path), os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) with os.fdopen(fd, "wb") as fh: fh.write(key) return key def create_app(paths: Paths | None = None, *, helper: Any = None, cdp: Any = None) -> Flask: paths = paths or load_paths() config = load_config(paths.config_file) app = Flask(__name__) app.secret_key = _secret_key(paths) app.config.update( SESSION_COOKIE_NAME="voxip_session", SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SAMESITE="Strict", SESSION_COOKIE_SECURE=config["admin_https"], PERMANENT_SESSION_LIFETIME=timedelta(hours=12), MAX_CONTENT_LENGTH=64 * 1024, TEMPLATES_AUTO_RELOAD=False, ) credentials = CredentialStore(paths.admin_file, paths.setup_code_file) credentials.ensure_setup_code() app.extensions["voxip"] = Services( paths=paths, credentials=credentials, throttle=LoginThrottle(), helper=helper or HelperClient(paths.helper), cdp=cdp or CDP(timeout=5), version=read_version(paths), ) from .views import bp app.register_blueprint(bp) return app