UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

90 lines (89 loc) 4.35 kB
import { s as BoardValidationError } from "./github-actions-capability-rN2d0K3V.js"; import { a as resolveBoardWidgetContentKindResourceUrls, i as resolveBoardWidgetContentKindByPluginKind } from "./board-widget-content-kinds-BzUrqFWH.js"; import { r as buildSandboxHostPath } from "./sandbox-host-BttkEpCR.js"; import { t as buildWidgetDocument } from "./wrap-B4s_WVbg.js"; import { c as verifyBoardViewTicket, o as requireBoardViewTicketAuthority } from "./board-view-ticket-B5Cj1xmB.js"; //#region src/gateway/board-sandbox.ts function grantedConnectOrigins(document) { if (document.grantState !== "granted") return; const origins = document.declared?.netOrigins; return origins?.length ? origins : void 0; } function buildBoardWidgetSandboxPath(document) { const connectDomains = grantedConnectOrigins(document); return buildSandboxHostPath({ blockDescendantFrames: true, ...document.resourceOrigins?.length ? { resourceDomains: [...document.resourceOrigins] } : {}, ...connectDomains ? { connectDomains } : {} }); } /** Defense in depth for direct/legacy widget document loads outside the proxy host. */ function buildBoardWidgetContentSecurityPolicy(document) { const connectSources = grantedConnectOrigins(document)?.join(" ") ?? "'none'"; const resourceSources = document.resourceOrigins?.join(" ") ?? ""; return [ "default-src 'none'", `script-src 'unsafe-inline' ${resourceSources}`.trim(), "style-src 'unsafe-inline'", `img-src data: ${resourceSources}`.trim(), `media-src data: ${resourceSources}`.trim(), `connect-src ${connectSources}`, "webrtc 'block'", "base-uri 'none'", "object-src 'none'", "form-action 'none'", "frame-src 'none'", "sandbox allow-scripts" ].join("; "); } //#endregion //#region src/gateway/board-widget-view.ts function resolveAuthorizedBoardWidgetView(store, ticket, options = {}) { const claims = verifyBoardViewTicket(ticket, options); if (!claims) throw new BoardValidationError("invalid_operation", "board widget view ticket is invalid"); const authority = requireBoardViewTicketAuthority(claims, options.gatewayContext); const session = { sessionKey: claims.sessionKey, agentId: claims.agentId }; const document = claims.pluginFrame ? store.readWidgetRegistered(session, claims.name) : store.readWidgetHtml(session, claims.name); if (!document || document.grantState !== "none" && document.grantState !== "granted" || document.revision !== claims.revision || document.viewGeneration !== claims.viewGeneration) throw new BoardValidationError("invalid_operation", "board widget view ticket is stale"); if (claims.pluginFrame) { if (!("source" in document) || document.pluginKind !== claims.pluginFrame.pluginKind) throw new BoardValidationError("invalid_operation", "board widget view ticket is stale"); const registration = resolveBoardWidgetContentKindByPluginKind(authority.pluginRegistry, document.pluginKind); const resourceUrls = registration ? resolveBoardWidgetContentKindResourceUrls(registration, claims.pluginFrame.scopedHostUrl) : void 0; if (!registration || !resourceUrls) throw new BoardValidationError("invalid_operation", "board widget content kind is unavailable"); const resourceOrigins = [...new Set(Object.values(resourceUrls).map((url) => new URL(url).origin))]; const body = registration.definition.composeDocument({ source: document.source, title: document.title ?? claims.name, resourceUrls, promptGranted: document.grantState === "granted" && document.declared?.tools?.includes("prompt") === true }); const composed = { html: buildWidgetDocument(document.title ?? claims.name, body, { connectOrigins: document.declared?.netOrigins, scriptOrigins: resourceOrigins }), revision: document.revision, sha256: document.sha256, viewGeneration: document.viewGeneration, grantState: document.grantState, ...document.declared ? { declared: document.declared } : {}, resourceOrigins }; return { ...session, name: claims.name, document: composed }; } if (!("html" in document)) throw new BoardValidationError("invalid_operation", "board widget view ticket is stale"); return { ...session, name: claims.name, document }; } //#endregion export { buildBoardWidgetContentSecurityPolicy as n, buildBoardWidgetSandboxPath as r, resolveAuthorizedBoardWidgetView as t };