diff --git a/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx b/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx index 2f4610e2..e733ae3a 100644 --- a/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx +++ b/frontend-web/src/strategy-components/components/resource-management/llmwiki/WeKnoraKnowledgeDetailPage.tsx @@ -51,7 +51,15 @@ function collectThemePayload(): DeerFlowThemePayload { function postThemeToFrame(frame: HTMLIFrameElement | null) { if (!frame?.contentWindow) return; const src = frame.getAttribute("src") || ""; + if (!src) return; const targetOrigin = new URL(src, window.location.href).origin; + try { + const currentUrl = frame.contentWindow.location.href; + if (!currentUrl || currentUrl === "about:blank") return; + if (new URL(currentUrl, window.location.href).origin !== targetOrigin) return; + } catch { + // Reading location throws once the iframe has reached the cross-origin backend. + } frame.contentWindow.postMessage(collectThemePayload(), targetOrigin); } diff --git a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py index 2b86e743..024328fe 100644 --- a/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py +++ b/offline-backend-20260512/backend/app/gateway/routers/llmwiki.py @@ -479,6 +479,9 @@ async def _authorize_weknora_api_proxy( if read_method and tail == ["me", "invitations", "pending-count"]: return + if read_method and tail == ["tenants", "kv", "retrieval-config"]: + return + if tail[:1] == ["knowledge-bases"]: if len(tail) == 1: if method == "GET": diff --git a/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py b/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py index ff358381..313b36a4 100644 --- a/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py +++ b/offline-backend-20260512/backend/tests/test_llmwiki_weknora.py @@ -1425,3 +1425,49 @@ async def test_weknora_iframe_proxy_blocks_other_knowledge_bases() -> None: ) assert exc_info.value.status_code == 403 + + +@pytest.mark.asyncio +async def test_weknora_iframe_proxy_only_reads_tenant_retrieval_config() -> None: + from app.gateway.routers import llmwiki as llmwiki_router + + class FakeRequest: + headers = Headers({}) + query_params = QueryParams("") + + def __init__(self, method: str) -> None: + self.method = method + + ctx = llmwiki_router.WeKnoraEmbedContext( + mapping_id="local-kb", + weknora_id="remote-kb", + user_id="admin-a", + is_admin=True, + can_write=True, + exp=4_102_444_800, + ) + + await llmwiki_router._authorize_weknora_api_proxy( + FakeRequest("GET"), + ctx, + object(), + "/api/v1/tenants/kv/retrieval-config", + b"", + "token", + ) + + for method, path in ( + ("GET", "/api/v1/tenants/kv/other-setting"), + ("PUT", "/api/v1/tenants/kv/retrieval-config"), + ): + with pytest.raises(HTTPException) as exc_info: + await llmwiki_router._authorize_weknora_api_proxy( + FakeRequest(method), + ctx, + object(), + path, + b"{}", + "token", + ) + + assert exc_info.value.status_code == 403