"""Shared helpers for WeKnora iframe proxy sessions.""" from __future__ import annotations import base64 import hashlib import hmac import json import os import secrets import time from dataclasses import dataclass from typing import Any from fastapi import HTTPException from deerflow.config.runtime_paths import runtime_home WEKNORA_EMBED_COOKIE = "deerflow_weknora_embed" WEKNORA_EMBED_TTL_SECONDS = 15 * 60 WEKNORA_EMBED_API_PREFIX = "/api/llmwiki/weknora-embed" WEKNORA_ROOT_ASSET_PATHS: frozenset[str] = frozenset( { "/favicon.ico", "/favicon.svg", "/config.js", "/logo.svg", "/manifest.webmanifest", } ) WEKNORA_STATIC_PATH_PREFIXES: tuple[str, ...] = ( "/assets/", "/css/", "/fonts/", "/img/", "/images/", "/js/", "/locales/", "/media/", "/static/", "/tdesign-icons/", ) def _load_weknora_proxy_secret() -> str: if secret := os.getenv("DEERFLOW_LLMWIKI_PROXY_SECRET"): return secret secret_path = runtime_home() / "weknora_embed_secret" try: if secret_path.is_file(): secret = secret_path.read_text(encoding="utf-8").strip() if secret: return secret secret_path.parent.mkdir(parents=True, exist_ok=True) secret = secrets.token_urlsafe(48) try: fd = os.open(str(secret_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600) except FileExistsError: return secret_path.read_text(encoding="utf-8").strip() with os.fdopen(fd, "w", encoding="utf-8") as handle: handle.write(secret) return secret except OSError: return secrets.token_urlsafe(48) WEKNORA_PROXY_SECRET = _load_weknora_proxy_secret() @dataclass(frozen=True) class WeKnoraEmbedContext: mapping_id: str weknora_id: str user_id: str is_admin: bool can_write: bool exp: int is_conversation_deposit: bool = False def is_weknora_embed_proxy_path(path: str) -> bool: path = path.removeprefix("/deerflow") return ( path == "/platform" or path.startswith("/platform/") or path.startswith(WEKNORA_STATIC_PATH_PREFIXES) or path in WEKNORA_ROOT_ASSET_PATHS or path.startswith(f"{WEKNORA_EMBED_API_PREFIX}/api/v1/") or (path.startswith("/api/v1/") and not path.startswith("/api/v1/auth/")) ) def _b64url_encode(data: bytes) -> str: return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=") def _b64url_decode(data: str) -> bytes: padded = data + ("=" * (-len(data) % 4)) return base64.urlsafe_b64decode(padded.encode("ascii")) def sign_weknora_embed_payload(payload: dict[str, Any]) -> str: body = _b64url_encode(json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")) sig = hmac.new(WEKNORA_PROXY_SECRET.encode("utf-8"), body.encode("ascii"), hashlib.sha256).digest() return f"{body}.{_b64url_encode(sig)}" def verify_weknora_embed_cookie(raw: str | None) -> WeKnoraEmbedContext: if not raw or "." not in raw: raise HTTPException(status_code=401, detail="WeKnora iframe session is missing") body, sig = raw.rsplit(".", 1) expected = _b64url_encode( hmac.new(WEKNORA_PROXY_SECRET.encode("utf-8"), body.encode("ascii"), hashlib.sha256).digest() ) if not hmac.compare_digest(sig, expected): raise HTTPException(status_code=401, detail="WeKnora iframe session is invalid") try: payload = json.loads(_b64url_decode(body)) except (ValueError, TypeError, json.JSONDecodeError): raise HTTPException(status_code=401, detail="WeKnora iframe session is invalid") from None if int(payload.get("exp") or 0) < int(time.time()): raise HTTPException(status_code=401, detail="WeKnora iframe session has expired") return WeKnoraEmbedContext( mapping_id=str(payload.get("mapping_id") or ""), weknora_id=str(payload.get("weknora_id") or ""), user_id=str(payload.get("user_id") or ""), is_admin=bool(payload.get("is_admin")), can_write=bool(payload.get("can_write")), exp=int(payload.get("exp") or 0), is_conversation_deposit=bool(payload.get("is_conversation_deposit")), ) def has_valid_weknora_embed_cookie(raw: str | None) -> bool: try: verify_weknora_embed_cookie(raw) except HTTPException: return False return True