diff --git a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py index 31703a11..552dbcb5 100644 --- a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py +++ b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py @@ -1360,15 +1360,17 @@ def _weknora_embed_target_path(weknora_id: str, tab: str) -> str: def _set_weknora_embed_cookie(request: Request, response: Response, payload: dict[str, Any]) -> None: secure = is_secure_request(request) - response.set_cookie( - _WEKNORA_EMBED_COOKIE, - _sign_embed_payload(payload), - max_age=_WEKNORA_EMBED_TTL_SECONDS, - httponly=True, - secure=secure, - samesite="none" if secure else "lax", - path="/", - ) + signed = _sign_embed_payload(payload) + for path in ("/", _WEKNORA_PUBLIC_PREFIX): + response.set_cookie( + _WEKNORA_EMBED_COOKIE, + signed, + max_age=_WEKNORA_EMBED_TTL_SECONDS, + httponly=True, + secure=secure, + samesite="none" if secure else "lax", + path=path, + ) response.headers["Cache-Control"] = "no-store" diff --git a/offline-backend-20260512/backend/app/gateway/weknora_embed.py b/offline-backend-20260512/backend/app/gateway/weknora_embed.py index 6de5e448..9fc26c8e 100644 --- a/offline-backend-20260512/backend/app/gateway/weknora_embed.py +++ b/offline-backend-20260512/backend/app/gateway/weknora_embed.py @@ -14,10 +14,11 @@ 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_PROXY_SECRET = os.getenv("DEERFLOW_LLMWIKI_PROXY_SECRET") or secrets.token_urlsafe(48) WEKNORA_ROOT_ASSET_PATHS: frozenset[str] = frozenset( { "/favicon.ico", @@ -29,6 +30,31 @@ WEKNORA_ROOT_ASSET_PATHS: frozenset[str] = frozenset( ) +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 diff --git a/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py b/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py index a0e3480e..c670605e 100644 --- a/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py +++ b/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py @@ -234,6 +234,13 @@ async def test_weknora_session_endpoint_sets_cookie_and_returns_platform_path(mo assert "deerflow_weknora_embed=" in cookie assert "Secure" in cookie assert "SameSite=none" in cookie + set_cookie_headers = [ + value.decode("latin-1") + for key, value in response.raw_headers + if key.lower() == b"set-cookie" + ] + assert any("Path=/" in value for value in set_cookie_headers) + assert any("Path=/deerflow" in value for value in set_cookie_headers) raw = cookie.split("deerflow_weknora_embed=", 1)[1].split(";", 1)[0] ctx = llmwiki_router._verify_embed_cookie(raw) assert ctx.mapping_id == "local-kb"