UNPKG

openclaw

Version:

Multi-channel AI gateway with extensible messaging integrations

135 lines (134 loc) • 7.55 kB
import { n as normalizeDeviceAuthScopes, t as normalizeDeviceAuthRole } from "./device-auth-DIR2dK9a.mjs"; //#region src/shared/device-bootstrap-profile.ts /** Operator scopes allowed to cross the short-lived bootstrap handoff boundary. */ const BOOTSTRAP_HANDOFF_OPERATOR_SCOPES = [ "operator.approvals", "operator.questions", "operator.read", "operator.talk.secrets", "operator.write" ]; const BOOTSTRAP_HANDOFF_OPERATOR_SCOPE_SET = new Set(BOOTSTRAP_HANDOFF_OPERATOR_SCOPES); /** Full browser-owner scopes allowed only by the host-issued Control UI profile. */ const CONTROL_UI_OWNER_BOOTSTRAP_OPERATOR_SCOPES = [ "operator.admin", "operator.approvals", "operator.pairing", "operator.questions", "operator.read", "operator.talk.secrets", "operator.write" ]; const CONTROL_UI_OWNER_BOOTSTRAP_OPERATOR_SCOPE_SET = new Set(CONTROL_UI_OWNER_BOOTSTRAP_OPERATOR_SCOPES); /** Full native-mobile operator scopes allowed only by the closed mobile setup profile. */ const MOBILE_FULL_ACCESS_OPERATOR_SCOPES = ["operator.admin", ...BOOTSTRAP_HANDOFF_OPERATOR_SCOPES]; const MOBILE_FULL_ACCESS_OPERATOR_SCOPE_SET = new Set(MOBILE_FULL_ACCESS_OPERATOR_SCOPES); const VOICE_NODE_OPERATOR_SCOPE_SET = /* @__PURE__ */ new Set(["operator.read", "operator.talk"]); /** Existing least-privilege setup-code/QR profile. */ const PAIRING_SETUP_BOOTSTRAP_PROFILE = { roles: ["node", "operator"], scopes: [...BOOTSTRAP_HANDOFF_OPERATOR_SCOPES] }; /** Full browser-owner profile issued only by dashboard and graphical onboarding. */ const CONTROL_UI_OWNER_BOOTSTRAP_PROFILE = { roles: ["operator"], scopes: [...CONTROL_UI_OWNER_BOOTSTRAP_OPERATOR_SCOPES], purpose: "control-ui-owner" }; /** Full native-mobile setup profile for explicitly authorized setup surfaces. */ const FULL_ACCESS_PAIRING_SETUP_BOOTSTRAP_PROFILE = { roles: ["node", "operator"], scopes: [...MOBILE_FULL_ACCESS_OPERATOR_SCOPES], purpose: "mobile-full" }; /** Node-only setup profile for companions that never act as operators. */ const NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE = { roles: ["node"], scopes: [] }; /** Environment-owned node profile removed when its cloud lease is released. */ const CLOUD_WORKER_PAIRING_SETUP_BOOTSTRAP_PROFILE = { roles: ["node"], scopes: [], purpose: "cloud-worker" }; /** Room/embedded voice profile: node capabilities plus least-privilege Talk RPCs. */ const VOICE_NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE = { roles: ["node", "operator"], scopes: ["operator.read", "operator.talk"], purpose: "voice-node" }; /** Compare normalized bootstrap profiles, including their closed purpose. */ function deviceBootstrapProfilesEqual(left, right) { const profile = normalizeDeviceBootstrapProfile(left); const expected = normalizeDeviceBootstrapProfile(right); return profile.purpose === expected.purpose && profile.roles.length === expected.roles.length && profile.scopes.length === expected.scopes.length && profile.roles.every((role, index) => role === expected.roles[index]) && profile.scopes.every((scope, index) => scope === expected.scopes[index]); } /** Return whether an input matches either supported native-mobile setup profile. */ function isMobilePairingSetupBootstrapProfile(input) { return deviceBootstrapProfilesEqual(input, PAIRING_SETUP_BOOTSTRAP_PROFILE) || deviceBootstrapProfilesEqual(input, FULL_ACCESS_PAIRING_SETUP_BOOTSTRAP_PROFILE); } /** Return whether an input exactly matches the node-only companion setup profile. */ function isNodePairingSetupBootstrapProfile(input) { return deviceBootstrapProfilesEqual(input, NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE) || deviceBootstrapProfilesEqual(input, CLOUD_WORKER_PAIRING_SETUP_BOOTSTRAP_PROFILE); } function resolvePairingSetupAccess(input) { if (deviceBootstrapProfilesEqual(input, FULL_ACCESS_PAIRING_SETUP_BOOTSTRAP_PROFILE)) return "full"; if (isNodePairingSetupBootstrapProfile(input)) return "node"; return "limited"; } /** Return whether an input exactly matches the embedded voice-node setup profile. */ function isVoiceNodePairingSetupBootstrapProfile(input) { return deviceBootstrapProfilesEqual(input, VOICE_NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE); } /** Resolve the subset of requested scopes a bootstrap profile may carry for one role. */ function resolveBootstrapProfileScopesForRole(role, scopes, purpose) { const normalizedRole = normalizeDeviceAuthRole(role); const normalizedScopes = normalizeDeviceAuthScopes(Array.from(scopes)); if (normalizedRole === "operator") { const allowedScopes = purpose === "control-ui-owner" ? CONTROL_UI_OWNER_BOOTSTRAP_OPERATOR_SCOPE_SET : purpose === "mobile-full" ? MOBILE_FULL_ACCESS_OPERATOR_SCOPE_SET : purpose === "voice-node" ? VOICE_NODE_OPERATOR_SCOPE_SET : BOOTSTRAP_HANDOFF_OPERATOR_SCOPE_SET; return normalizedScopes.filter((scope) => allowedScopes.has(scope)); } return []; } /** Resolve bounded bootstrap handoff scopes across a role set. */ function resolveBootstrapProfileScopesForRoles(roles, scopes, purpose) { return normalizeDeviceAuthScopes(roles.flatMap((role) => resolveBootstrapProfileScopesForRole(role, scopes, purpose))); } /** Resolve one role's scopes directly from a normalized bootstrap profile. */ function resolveDeviceProfileRoleScopes(profile, role, scopes = profile.scopes) { return resolveBootstrapProfileScopesForRole(role, scopes, profile.purpose); } /** Resolve role-set scopes directly from a normalized bootstrap profile. */ function resolveDeviceProfileScopes(profile, roles, scopes = profile.scopes) { return resolveBootstrapProfileScopesForRoles(roles, scopes, profile.purpose); } /** Normalize a requested bootstrap profile and strip scopes outside the handoff allowlist. */ function normalizeDeviceBootstrapHandoffProfile(input) { const profile = normalizeDeviceBootstrapProfile(input); return { roles: profile.roles, scopes: resolveBootstrapProfileScopesForRoles(profile.roles, profile.scopes, profile.purpose), ...profile.purpose ? { purpose: profile.purpose } : {} }; } function normalizeBootstrapRoles(roles) { if (!Array.isArray(roles)) return []; const out = /* @__PURE__ */ new Set(); for (const role of roles) { const normalized = normalizeDeviceAuthRole(role); if (normalized) out.add(normalized); } return [...out].toSorted(); } /** Normalize caller-provided bootstrap roles/scopes without applying handoff bounds. */ function normalizeDeviceBootstrapProfile(input) { const purpose = input?.purpose === "control-ui" || input?.purpose === "control-ui-owner" || input?.purpose === "mobile-full" || input?.purpose === "voice-node" || input?.purpose === "cloud-worker" ? input.purpose : void 0; return { roles: normalizeBootstrapRoles(input?.roles), scopes: normalizeDeviceAuthScopes(input?.scopes ? [...input.scopes] : []), ...purpose ? { purpose } : {} }; } //#endregion export { resolveDeviceProfileScopes as _, NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE as a, deviceBootstrapProfilesEqual as c, isVoiceNodePairingSetupBootstrapProfile as d, normalizeDeviceBootstrapHandoffProfile as f, resolveDeviceProfileRoleScopes as g, resolveBootstrapProfileScopesForRoles as h, FULL_ACCESS_PAIRING_SETUP_BOOTSTRAP_PROFILE as i, isMobilePairingSetupBootstrapProfile as l, resolveBootstrapProfileScopesForRole as m, CLOUD_WORKER_PAIRING_SETUP_BOOTSTRAP_PROFILE as n, PAIRING_SETUP_BOOTSTRAP_PROFILE as o, normalizeDeviceBootstrapProfile as p, CONTROL_UI_OWNER_BOOTSTRAP_PROFILE as r, VOICE_NODE_PAIRING_SETUP_BOOTSTRAP_PROFILE as s, BOOTSTRAP_HANDOFF_OPERATOR_SCOPES as t, isNodePairingSetupBootstrapProfile as u, resolvePairingSetupAccess as v };