From b251fc4b89d7e80c96108423b5374db1756f453c Mon Sep 17 00:00:00 2001 From: RockChinQ Date: Thu, 14 May 2026 15:38:55 +0800 Subject: [PATCH] fix(plugin): resolve plugin page asset origin --- .../pkg/api/http/controller/groups/plugins.py | 12 +++++++++++- web/src/app/infra/http/BackendClient.ts | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/langbot/pkg/api/http/controller/groups/plugins.py b/src/langbot/pkg/api/http/controller/groups/plugins.py index 5a565997..cc327b8d 100644 --- a/src/langbot/pkg/api/http/controller/groups/plugins.py +++ b/src/langbot/pkg/api/http/controller/groups/plugins.py @@ -39,6 +39,16 @@ def _normalize_plugin_asset_path(filepath: str) -> str | None: return f'assets/{normalized}' +def _get_request_origin() -> str: + """Return the public request origin, respecting reverse-proxy headers.""" + forwarded_proto = quart.request.headers.get('X-Forwarded-Proto', '').split(',')[0].strip() + forwarded_host = quart.request.headers.get('X-Forwarded-Host', '').split(',')[0].strip() + + scheme = forwarded_proto or quart.request.scheme + host = forwarded_host or quart.request.host + return f'{scheme}://{host}' + + @group.group_class('plugins', '/api/v1/plugins') class PluginsRouterGroup(group.RouterGroup): async def _check_extensions_limit(self) -> str | None: @@ -189,7 +199,7 @@ class PluginsRouterGroup(group.RouterGroup): # CSP for HTML pages served to sandboxed iframes (opaque origin). # 'self' doesn't work in sandboxed iframes — use actual server origin. if mime_type and mime_type.startswith('text/html'): - origin = f'{quart.request.scheme}://{quart.request.host}' + origin = _get_request_origin() resp.headers['Content-Security-Policy'] = ( f'default-src {origin}; ' f"script-src {origin} 'unsafe-inline'; " diff --git a/web/src/app/infra/http/BackendClient.ts b/web/src/app/infra/http/BackendClient.ts index c27e4870..c26a6d68 100644 --- a/web/src/app/infra/http/BackendClient.ts +++ b/web/src/app/infra/http/BackendClient.ts @@ -590,6 +590,9 @@ export class BackendClient extends BaseHttpClient { name: string, filepath: string, ): string { + if (this.instance.defaults.baseURL === '/') { + return `${window.location.origin}/api/v1/plugins/${author}/${name}/assets/${filepath}`; + } return ( this.instance.defaults.baseURL + `/api/v1/plugins/${author}/${name}/assets/${filepath}`