@xopcai/xopc 0.0.270 → 0.0.272
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser-ext/dist/assets/{auth-cwEj8rFb.js → auth-C1QI-uMG.js} +65 -14
- package/dist/browser-ext/dist/background.js +23 -2
- package/dist/browser-ext/dist/pairing-handoff.js +51 -0
- package/dist/browser-ext/dist/sidepanel.html +1 -1
- package/dist/browser-ext/dist/sidepanel.js +39 -27
- package/dist/browser-ext/manifest.json +12 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-D_0FmdRj.js → activity-store-DffqjeqQ.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-IZvEXak_.js → agent-avatar-dicebear-Cwj4HCYY.js} +1 -1
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-6CLfLxVc.js +1 -0
- package/dist/gateway/static/root/assets/agents-B6mu64fY.js +1 -0
- package/dist/gateway/static/root/assets/{api-O3TTQ4qN.js → api-CGLdye4i.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-Cqqsbzri.js → app-management-settings-panel-BLujSbaw.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-DaJyf32s.js → appearance-settings-BXMcueb8.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-BEgy4hY3.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-kDPnDTJI.js → archive-plugin-D4bUampf.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CJ3VceKS.js → attachment-load-CBGNA2Ys.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-JwMtU8XB.js → automations-page-dQyolNmy.js} +1 -1
- package/dist/gateway/static/root/assets/automations-workspace-DxRFrmrV.js +6 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DzyZXLBX.js → binary-plugins-bbvp81h2.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-kTt3gYIJ.js → block-editor-C8e6Wri4.js} +3 -3
- package/dist/gateway/static/root/assets/{browser-automation-inputs-BKohPYR4.js → browser-automation-inputs-oJWJtQa6.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-ktQfFPk-.js → browser-automations-page-CAcJQSjN.js} +2 -2
- package/dist/gateway/static/root/assets/browser-settings-page-TLAlqcPo.js +8 -0
- package/dist/gateway/static/root/assets/capabilities-settings-panel-z-K_jrZz.js +8 -0
- package/dist/gateway/static/root/assets/channels-settings-Dzrk33aB.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-DrqzYmDr.js → channels-status-swr-CfOPNnVr.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-CIFGGLGa.js → chat-terminal-dock-9ZOl92kh.js} +2 -2
- package/dist/gateway/static/root/assets/clock-3-DnrAnuyZ.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-B1dIoRNi.js +2 -0
- package/dist/gateway/static/root/assets/cron-expression-C26e13YU.js +2 -0
- package/dist/gateway/static/root/assets/date-picker-Dj6FRLF9.js +1 -0
- package/dist/gateway/static/root/assets/{dependency-picker-D3vNIjRI.js → dependency-picker-D1q89tVc.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-fQwRb_3p.js → desktop-pet-DfqZBvhp.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-DfOJ-GvT.js → desktop-pet-settings-HCEh2MOm.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-CPth92s6.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-Cn53jB5-.js → extension-debug-page-C8cAWVoK.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-IDpLCxpC.js → extension-page-5N87Vaym.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-D85SAUFP.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-config-swr-B7dcmP7Q.js → gateway-config-swr-BjsDnB_n.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-Dqx8PmcT.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-JGhGMhVZ.js → gateway-startup-retry-BIf0eLWX.js} +1 -1
- package/dist/gateway/static/root/assets/git-branch-Dh9uxTot.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-BpDWGE1a.js +1 -0
- package/dist/gateway/static/root/assets/home-page-DJaqpC8-.js +1 -0
- package/dist/gateway/static/root/assets/{image-generation-api-BJLX7Qrh.js → image-generation-api-1m8xTVS_.js} +1 -1
- package/dist/gateway/static/root/assets/index-C6PmD0cK.js +74 -0
- package/dist/gateway/static/root/assets/index-DKy1Qn1_.css +2 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CBvMTFFx.js → keyboard-shortcuts-settings-Byy8mCSq.js} +1 -1
- package/dist/gateway/static/root/assets/local-app-workbench-page-l2AEiG2C.js +2 -0
- package/dist/gateway/static/root/assets/{local-apps-page-APCMNDvU.js → local-apps-page-BPo0wBgM.js} +1 -1
- package/dist/gateway/static/root/assets/locale-store-CRNble2Z.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-X5FdLlXK.js +2 -0
- package/dist/gateway/static/root/assets/management-settings-DT6NoIjm.js +1 -0
- package/dist/gateway/static/root/assets/{markdown-view-BwjpJVPs.js → markdown-view-AglreSOj.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-C10byeaa.js → media-plugins-Bzka9qXu.js} +1 -1
- package/dist/gateway/static/root/assets/message-circle-Badhj-4D.js +1 -0
- package/dist/gateway/static/root/assets/message-square-fVE7Ghj1.js +1 -0
- package/dist/gateway/static/root/assets/{messages-D0V_bgRP.js → messages-DH_HCgmw.js} +3 -3
- package/dist/gateway/static/root/assets/note-detail-panel-BUJPoaGZ.js +5 -0
- package/dist/gateway/static/root/assets/notes-page-BwFpWRuo.js +8 -0
- package/dist/gateway/static/root/assets/{page-tabs-qQ36zncF.js → page-tabs-Ys0p65Lt.js} +1 -1
- package/dist/gateway/static/root/assets/popover-select-Dz_Qis2R.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BiAJvvCo.js → preview-open-alternatives-iknB5xEp.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-card-CcNBqHoH.js → proactive-card-BPZDgNNR.js} +1 -1
- package/dist/gateway/static/root/assets/{proactive-page-C3K61jve.js → proactive-page-CxdZR-p2.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CunnDP4w.js → product-open-page-W1o3f-kz.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-BU1RKAcy.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-z0X0tL8G.js +1 -0
- package/dist/gateway/static/root/assets/{registry-api-0JSegbNl.js → registry-api-DmYFpjsH.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-NNTut2I8.js +1 -0
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bu_mwBTr.js → runtime-tools-settings-panel-DP1XyYO8.js} +2 -2
- package/dist/gateway/static/root/assets/{schema-form-BE0sgZyz.js → schema-form-BMYKdzsH.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-B6SsHlz5.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BQu8bAcN.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-CBo517lV.js → settings-form-section-2LGjz7bu.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-DBPimx93.js → settings-page-7DjpC9_C.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Dj9jFWJt.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-DdV75VTe.js → share-preview-page-BxYdSi8c.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CMqE0KuK.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BXqSJymN.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-Cn_-nvRo.js → skills-page-DNEScMZH.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page.utils-q88l65YU.js +1 -0
- package/dist/gateway/static/root/assets/system-settings-panel-8NIssGKj.js +1 -0
- package/dist/gateway/static/root/assets/task-detail-page-L6dp9v2y.js +1 -0
- package/dist/gateway/static/root/assets/{theme-store-1wryLgBQ.js → theme-store-BXZG3S25.js} +1 -1
- package/dist/gateway/static/root/assets/tunnel-api-CWsRPM84.js +1 -0
- package/dist/gateway/static/root/assets/{use-autosave-N_lm4FdD.js → use-autosave-BwQuoTQU.js} +1 -1
- package/dist/gateway/static/root/assets/user-model-page-D4BucMrZ.js +2 -0
- package/dist/gateway/static/root/assets/{voice-api-key-field-DMsyVfri.js → voice-api-key-field-Bd03Ic0s.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-config-api-QWVmiAp3.js → voice-config-api-gggUp3u9.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-BC0vAxp1.js → work-discovery-overlay-DF8PR_pK.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Cz9jQIlP.js → workflow-run-setup-panel-BiAAWlir.js} +2 -2
- package/dist/gateway/static/root/assets/workflows-page-DryKUMfA.js +6 -0
- package/dist/gateway/static/root/index.html +15 -11
- package/dist/package.js +1 -1
- package/dist/packages/gateway-contract/src/device-pairing.js +2 -1
- package/dist/packages/gateway-contract/src/session-identity.js +37 -0
- package/dist/src/agent/memory/compaction-chunks.d.ts +18 -0
- package/dist/src/agent/memory/compaction-chunks.js +53 -0
- package/dist/src/agent/memory/compaction-request.d.ts +12 -0
- package/dist/src/agent/memory/compaction-request.js +72 -0
- package/dist/src/agent/memory/compaction.d.ts +3 -0
- package/dist/src/agent/memory/compaction.js +166 -118
- package/dist/src/agent/service.js +1 -0
- package/dist/src/browser/native-messaging-host.js +3 -1
- package/dist/src/cli/bin.js +2 -2
- package/dist/src/cli/commands/agent.js +2 -2
- package/dist/src/cli/commands/auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/cli/commands/gateway-ssh-tunnel.js +1 -1
- package/dist/src/cli/commands/models.js +2 -2
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/platform.js +1 -1
- package/dist/src/cli/commands/profile.js +1 -1
- package/dist/src/cli/commands/tunnel.js +6 -1
- package/dist/src/cli/commands/update.js +1 -1
- package/dist/src/cli/extension-cli-register.js +1 -1
- package/dist/src/config/index.js +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/app.js +1 -0
- package/dist/src/gateway/hono/middleware/auth.d.ts +1 -2
- package/dist/src/gateway/hono/middleware/auth.js +49 -31
- package/dist/src/gateway/hono/middleware/strict-rate-limit.js +11 -15
- package/dist/src/gateway/hono/routes/browser-session.d.ts +3 -0
- package/dist/src/gateway/hono/routes/browser-session.js +43 -0
- package/dist/src/gateway/hono/routes/devices.js +61 -96
- package/dist/src/gateway/hono/routes/exposure.js +3 -7
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/models.js +60 -1
- package/dist/src/gateway/hono/routes/notes.js +3 -7
- package/dist/src/gateway/hono/routes/sessions.js +11 -0
- package/dist/src/gateway/hono/routes/shares.js +8 -20
- package/dist/src/gateway/hono/routes/site-shares.js +4 -8
- package/dist/src/gateway/hono/routes/tunnel.js +13 -13
- package/dist/src/gateway/image-generation-setup.d.ts +17 -0
- package/dist/src/gateway/image-generation-setup.js +30 -21
- package/dist/src/gateway/rate-limit/buckets.d.ts +3 -0
- package/dist/src/gateway/rate-limit/buckets.js +10 -0
- package/dist/src/gateway/run-loop.js +1 -1
- package/dist/src/gateway/runtime-config.js +2 -0
- package/dist/src/gateway/security/browser-session.d.ts +5 -0
- package/dist/src/gateway/security/browser-session.js +45 -0
- package/dist/src/gateway/security/gateway-principal.d.ts +1 -0
- package/dist/src/gateway/server.js +1 -1
- package/dist/src/gateway/service.d.ts +1 -0
- package/dist/src/gateway/service.js +11 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/rate-limit/keyed-store.d.ts +3 -0
- package/dist/src/infra/rate-limit/keyed-store.js +9 -2
- package/dist/src/proactive/policy/service.d.ts +1 -1
- package/dist/src/realtime/runtime.d.ts +2 -1
- package/dist/src/realtime/runtime.js +9 -3
- package/dist/src/realtime/tickets.d.ts +1 -0
- package/dist/src/realtime/tickets.js +3 -0
- package/dist/src/session/store.d.ts +2 -0
- package/dist/src/session/store.js +17 -2
- package/dist/src/session/types.d.ts +2 -1
- package/dist/src/storage/sqlite/browser-session-repository.d.ts +17 -0
- package/dist/src/storage/sqlite/browser-session-repository.js +54 -0
- package/dist/src/storage/sqlite/device-pairing-approval.js +2 -1
- package/dist/src/storage/sqlite/device-pairing-repository.d.ts +4 -10
- package/dist/src/storage/sqlite/device-pairing-repository.js +10 -62
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/storage/sqlite/migrations/164_browser_sessions.sql +8 -0
- package/dist/src/storage/sqlite/migrations/165_device_pairing_target.sql +40 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/storage/sqlite/session-identity-sql.d.ts +2 -0
- package/dist/src/storage/sqlite/session-identity-sql.js +18 -0
- package/dist/src/storage/sqlite/session-repository.js +26 -22
- package/dist/src/tunnel/auth-policy.d.ts +3 -0
- package/dist/src/tunnel/auth-policy.js +8 -0
- package/dist/src/tunnel/broker-client.d.ts +5 -15
- package/dist/src/tunnel/broker-client.js +37 -49
- package/dist/src/tunnel/frpc-binary.d.ts +8 -6
- package/dist/src/tunnel/frpc-binary.js +76 -88
- package/dist/src/tunnel/frpc-config.d.ts +2 -1
- package/dist/src/tunnel/frpc-config.js +29 -12
- package/dist/src/tunnel/frpc-release.d.ts +27 -0
- package/dist/src/tunnel/frpc-release.js +30 -0
- package/dist/src/tunnel/gateway-lifecycle.js +8 -2
- package/dist/src/tunnel/index.js +2 -1
- package/dist/src/tunnel/registration-proof.d.ts +19 -0
- package/dist/src/tunnel/registration-proof.js +37 -0
- package/dist/src/tunnel/tunnel-persist.js +3 -1
- package/dist/src/tunnel/tunnel-service.d.ts +1 -0
- package/dist/src/tunnel/tunnel-service.js +35 -8
- package/dist/src/tunnel/tunnel-state.js +11 -5
- package/dist/src/tunnel/tunnel-types.d.ts +2 -0
- package/dist/src/tunnel/well-known.js +5 -1
- package/dist/src/user-context/config.js +2 -2
- package/dist/src/utils/logger/redact.js +4 -0
- package/dist/src/voice/realtime/runtime.d.ts +1 -0
- package/dist/src/voice/realtime/runtime.js +17 -1
- package/dist/src/voice/realtime/runtime.types.d.ts +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +2 -0
- package/dist/src/workflows/service/workflow-session-bridge.d.ts +1 -0
- package/dist/src/workflows/service/workflow-session-bridge.js +1 -0
- package/package.json +4 -4
- package/dist/gateway/static/root/assets/agent-defaults-settings-panel-CE3ygr3l.js +0 -1
- package/dist/gateway/static/root/assets/agents-DzG2qw-c.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-B4lX6yoT.js +0 -1
- package/dist/gateway/static/root/assets/automations-workspace-BiNBewg0.js +0 -6
- package/dist/gateway/static/root/assets/browser-settings-page-Dgdt5uVL.js +0 -8
- package/dist/gateway/static/root/assets/capabilities-settings-panel-BpDW-R9f.js +0 -7
- package/dist/gateway/static/root/assets/channels-settings-DU4EQnR0.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CfJqy284.js +0 -2
- package/dist/gateway/static/root/assets/cron-expression-BNwbnrEb.js +0 -2
- package/dist/gateway/static/root/assets/date-picker-DKyirU4K.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B1dds2bP.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-pp9jN0wl.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-B8_zTyev.js +0 -1
- package/dist/gateway/static/root/assets/home-page-g1KdAdLb.js +0 -1
- package/dist/gateway/static/root/assets/index-1zRt56Zt.css +0 -2
- package/dist/gateway/static/root/assets/index-OMnem2nr.js +0 -74
- package/dist/gateway/static/root/assets/local-app-workbench-page-bj75v2ZE.js +0 -2
- package/dist/gateway/static/root/assets/locale-store-BThkG0W5.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-BX7n39zV.js +0 -2
- package/dist/gateway/static/root/assets/management-settings-CM62j8ZX.js +0 -1
- package/dist/gateway/static/root/assets/mobile-pairing-wizard-BCWfwVx3.js +0 -1
- package/dist/gateway/static/root/assets/note-detail-panel-koOqb0gX.js +0 -5
- package/dist/gateway/static/root/assets/notes-page-BH54rY3B.js +0 -8
- package/dist/gateway/static/root/assets/popover-select-CKBYnT3c.js +0 -1
- package/dist/gateway/static/root/assets/project-detail-page-SL2g8MZY.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-BtxazT5J.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BSb7b67A.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-ljcS2KVz.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CR9Y9LQm.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-J3AnooPW.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-AAm4Iwcp.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-pRCjP5sm.js +0 -1
- package/dist/gateway/static/root/assets/skills-page.utils-CfVAc_lu.js +0 -1
- package/dist/gateway/static/root/assets/system-settings-panel-B-pzalp-.js +0 -1
- package/dist/gateway/static/root/assets/task-detail-page-CmrLy3PO.js +0 -1
- package/dist/gateway/static/root/assets/tunnel-api-Cgpnm2fL.js +0 -1
- package/dist/gateway/static/root/assets/user-model-page-u3QLDX6L.js +0 -2
- package/dist/gateway/static/root/assets/workflows-page-DA6OOK6X.js +0 -6
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { createDevice, issueDeviceTokenPair, listDevices, revokeDevice, rotateDeviceRefreshToken } from "../../../storage/sqlite/device-access-repository.js";
|
|
1
|
+
import { devicePairingTargetKindSchema } from "../../../../packages/gateway-contract/src/device-pairing.js";
|
|
2
|
+
import { listDevices, revokeDevice, rotateDeviceRefreshToken } from "../../../storage/sqlite/device-access-repository.js";
|
|
4
3
|
import { getGatewayIdentityPublicKeyRaw, getOrCreateGatewayIdentity, signGatewayPayload } from "../../../storage/sqlite/gateway-identity-repository.js";
|
|
5
|
-
import {
|
|
4
|
+
import { createDevicePairingSetup, isDevicePairingSetupActive } from "../../../storage/sqlite/device-pairing-repository.js";
|
|
6
5
|
import { resolveSecureDeviceRoutes } from "../../device-routes.js";
|
|
6
|
+
import { buckets } from "../../rate-limit/buckets.js";
|
|
7
|
+
import "../../rate-limit/index.js";
|
|
7
8
|
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
8
9
|
import { registerPairingApprovalAdminRoutes, registerPairingApprovalPublicRoutes } from "./device-pairing-approval.js";
|
|
9
10
|
import os from "node:os";
|
|
10
11
|
import { z } from "zod";
|
|
12
|
+
import { bodyLimit } from "hono/body-limit";
|
|
11
13
|
//#region src/gateway/hono/routes/devices.ts
|
|
12
14
|
const refreshRequestSchema = z.strictObject({
|
|
13
15
|
refreshToken: z.string().min(1).max(256),
|
|
@@ -17,40 +19,33 @@ const refreshRequestSchema = z.strictObject({
|
|
|
17
19
|
nextRefreshToken: z.string().min(80).max(256),
|
|
18
20
|
signature: z.string().min(1).max(256)
|
|
19
21
|
});
|
|
20
|
-
const pairingExchangeSchema = z.strictObject({
|
|
21
|
-
pairingToken: z.string().min(1).max(256),
|
|
22
|
-
device: z.strictObject({
|
|
23
|
-
displayName: z.string().trim().min(1).max(80),
|
|
24
|
-
platform: z.enum([
|
|
25
|
-
"ios",
|
|
26
|
-
"android",
|
|
27
|
-
"chrome"
|
|
28
|
-
]),
|
|
29
|
-
extensionId: z.string().regex(/^[a-p]{32}$/).optional(),
|
|
30
|
-
publicKeyJwk: z.strictObject({
|
|
31
|
-
kty: z.literal("EC"),
|
|
32
|
-
crv: z.literal("P-256"),
|
|
33
|
-
x: z.string().min(40).max(64),
|
|
34
|
-
y: z.string().min(40).max(64)
|
|
35
|
-
})
|
|
36
|
-
})
|
|
37
|
-
}).superRefine((value, context) => {
|
|
38
|
-
if (value.device.platform === "chrome" && !value.device.extensionId) context.addIssue({
|
|
39
|
-
code: "custom",
|
|
40
|
-
path: ["device", "extensionId"],
|
|
41
|
-
message: "Chrome devices require an extension id"
|
|
42
|
-
});
|
|
43
|
-
if (value.device.platform !== "chrome" && value.device.extensionId) context.addIssue({
|
|
44
|
-
code: "custom",
|
|
45
|
-
path: ["device", "extensionId"],
|
|
46
|
-
message: "Only Chrome devices may set an extension id"
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
22
|
const pairingProbeSchema = z.strictObject({ pairingId: z.string().uuid() });
|
|
23
|
+
const pairingSetupSchema = z.strictObject({ targetKind: devicePairingTargetKindSchema });
|
|
50
24
|
function pairingLinkPayload(input) {
|
|
51
25
|
return Buffer.from(JSON.stringify(input)).toString("base64url");
|
|
52
26
|
}
|
|
53
27
|
function registerDeviceAuthPublicRoutes(app) {
|
|
28
|
+
app.post("/api/gateway-identity/challenge", bodyLimit({ maxSize: 512 }), async (c) => {
|
|
29
|
+
const budget = buckets.identityChallenge().consume("gateway");
|
|
30
|
+
if (!budget.allowed) {
|
|
31
|
+
c.header("Retry-After", String(Math.ceil(budget.retryAfterMs / 1e3)));
|
|
32
|
+
return c.json({ error: "Too many identity challenges" }, 429);
|
|
33
|
+
}
|
|
34
|
+
const parsed = z.strictObject({ nonce: z.string().regex(/^[A-Za-z0-9_-]{32,64}$/) }).safeParse(await c.req.json().catch(() => null));
|
|
35
|
+
if (!parsed.success) return c.json({ error: "Invalid identity challenge" }, 400);
|
|
36
|
+
const identity = getOrCreateGatewayIdentity();
|
|
37
|
+
const signedPayload = Buffer.from(JSON.stringify({
|
|
38
|
+
purpose: "gateway-route-v1",
|
|
39
|
+
gatewayId: identity.id,
|
|
40
|
+
nonce: parsed.data.nonce,
|
|
41
|
+
expiresAt: Date.now() + 3e4
|
|
42
|
+
})).toString("base64url");
|
|
43
|
+
c.header("Cache-Control", "no-store");
|
|
44
|
+
return c.json({
|
|
45
|
+
signedPayload,
|
|
46
|
+
signature: signGatewayPayload(signedPayload)
|
|
47
|
+
});
|
|
48
|
+
});
|
|
54
49
|
registerPairingApprovalPublicRoutes(app);
|
|
55
50
|
app.post("/api/device-auth/refresh", async (c) => {
|
|
56
51
|
const parsed = refreshRequestSchema.safeParse(await c.req.json().catch(() => null));
|
|
@@ -62,9 +57,19 @@ function registerDeviceAuthPublicRoutes(app) {
|
|
|
62
57
|
}
|
|
63
58
|
}, 400);
|
|
64
59
|
try {
|
|
60
|
+
const tokens = rotateDeviceRefreshToken(parsed.data);
|
|
61
|
+
const signedPayload = Buffer.from(JSON.stringify({
|
|
62
|
+
purpose: "device-refresh-v3",
|
|
63
|
+
gatewayId: getOrCreateGatewayIdentity().id,
|
|
64
|
+
requestId: parsed.data.requestId,
|
|
65
|
+
nonce: parsed.data.nonce,
|
|
66
|
+
expiresAt: Date.now() + 3e4,
|
|
67
|
+
tokens
|
|
68
|
+
})).toString("base64url");
|
|
65
69
|
return c.json({
|
|
66
70
|
ok: true,
|
|
67
|
-
|
|
71
|
+
signedPayload,
|
|
72
|
+
signature: signGatewayPayload(signedPayload)
|
|
68
73
|
});
|
|
69
74
|
} catch (error) {
|
|
70
75
|
return c.json({
|
|
@@ -97,61 +102,6 @@ function registerDeviceAuthPublicRoutes(app) {
|
|
|
97
102
|
signature: signGatewayPayload(payload)
|
|
98
103
|
});
|
|
99
104
|
});
|
|
100
|
-
app.post("/api/device-pairing/exchange", async (c) => {
|
|
101
|
-
const parsed = pairingExchangeSchema.safeParse(await c.req.json().catch(() => null));
|
|
102
|
-
if (!parsed.success) return c.json({
|
|
103
|
-
ok: false,
|
|
104
|
-
error: {
|
|
105
|
-
code: "BAD_REQUEST",
|
|
106
|
-
message: "Invalid pairing request"
|
|
107
|
-
}
|
|
108
|
-
}, 400);
|
|
109
|
-
const completed = runSqliteWriteTransaction(() => {
|
|
110
|
-
const pairing = consumeDevicePairingToken(parsed.data.pairingToken);
|
|
111
|
-
if (!pairing.ok && "reason" in pairing) return {
|
|
112
|
-
success: false,
|
|
113
|
-
reason: pairing.reason
|
|
114
|
-
};
|
|
115
|
-
const device = createDevice({
|
|
116
|
-
displayName: parsed.data.device.displayName,
|
|
117
|
-
platform: parsed.data.device.platform,
|
|
118
|
-
publicKeyJwk: parsed.data.device.publicKeyJwk,
|
|
119
|
-
extensionId: parsed.data.device.extensionId,
|
|
120
|
-
scopes: parsed.data.device.platform === "chrome" ? DEFAULT_BROWSER_EXTENSION_SCOPES : DEFAULT_MOBILE_SCOPES
|
|
121
|
-
});
|
|
122
|
-
return {
|
|
123
|
-
success: true,
|
|
124
|
-
device,
|
|
125
|
-
routes: pairing.routes,
|
|
126
|
-
tokens: issueDeviceTokenPair(device.id)
|
|
127
|
-
};
|
|
128
|
-
});
|
|
129
|
-
if ("reason" in completed) return c.json({
|
|
130
|
-
ok: false,
|
|
131
|
-
error: {
|
|
132
|
-
code: "PAIRING_DENIED",
|
|
133
|
-
message: `Pairing ${completed.reason}`
|
|
134
|
-
}
|
|
135
|
-
}, 401);
|
|
136
|
-
const identity = getOrCreateGatewayIdentity();
|
|
137
|
-
const payload = Buffer.from(JSON.stringify({
|
|
138
|
-
gateway: {
|
|
139
|
-
id: identity.id,
|
|
140
|
-
name: os.hostname()
|
|
141
|
-
},
|
|
142
|
-
device: {
|
|
143
|
-
id: completed.device.id,
|
|
144
|
-
scopes: completed.device.scopes
|
|
145
|
-
},
|
|
146
|
-
routes: completed.routes,
|
|
147
|
-
tokens: completed.tokens
|
|
148
|
-
})).toString("base64url");
|
|
149
|
-
return c.json({
|
|
150
|
-
ok: true,
|
|
151
|
-
signedPayload: payload,
|
|
152
|
-
signature: signGatewayPayload(payload)
|
|
153
|
-
}, 201);
|
|
154
|
-
});
|
|
155
105
|
}
|
|
156
106
|
function registerDeviceRoutes(authenticated, deps) {
|
|
157
107
|
registerPairingApprovalAdminRoutes(authenticated);
|
|
@@ -161,14 +111,21 @@ function registerDeviceRoutes(authenticated, deps) {
|
|
|
161
111
|
ok: true,
|
|
162
112
|
ready: routes.length > 0,
|
|
163
113
|
routes,
|
|
164
|
-
|
|
114
|
+
protocolVersion: 3,
|
|
165
115
|
routeState: routes.length > 0 ? "configured" : "missing",
|
|
166
116
|
nextAction: routes.length > 0 ? "scan" : "configure-route",
|
|
167
117
|
serverTime: Date.now()
|
|
168
118
|
});
|
|
169
119
|
});
|
|
170
120
|
authenticated.post("/api/device-pairing/setups", async (c) => {
|
|
171
|
-
const
|
|
121
|
+
const parsed = pairingSetupSchema.safeParse(await c.req.json().catch(() => null));
|
|
122
|
+
if (!parsed.success) return c.json({
|
|
123
|
+
ok: false,
|
|
124
|
+
error: {
|
|
125
|
+
code: "BAD_REQUEST",
|
|
126
|
+
message: "Choose a device type"
|
|
127
|
+
}
|
|
128
|
+
}, 400);
|
|
172
129
|
const routes = resolveSecureDeviceRoutes(deps.service.currentConfig);
|
|
173
130
|
if (routes.length === 0) return c.json({
|
|
174
131
|
ok: false,
|
|
@@ -177,15 +134,16 @@ function registerDeviceRoutes(authenticated, deps) {
|
|
|
177
134
|
message: "Configure XOPC Secure Link, Tailscale Serve, or an HTTPS public URL first"
|
|
178
135
|
}
|
|
179
136
|
}, 409);
|
|
180
|
-
const setup = createDevicePairingSetup(routes, Date.now(),
|
|
137
|
+
const setup = createDevicePairingSetup(routes, Date.now(), { targetKind: parsed.data.targetKind });
|
|
181
138
|
const identity = getOrCreateGatewayIdentity();
|
|
182
139
|
const encoded = pairingLinkPayload({
|
|
183
|
-
version,
|
|
140
|
+
version: 3,
|
|
184
141
|
pairingToken: setup.token,
|
|
185
142
|
gatewayId: identity.id,
|
|
186
143
|
gatewayName: os.hostname(),
|
|
187
144
|
gatewayPublicKey: getGatewayIdentityPublicKeyRaw(identity),
|
|
188
145
|
routes,
|
|
146
|
+
targetKind: setup.targetKind,
|
|
189
147
|
expiresAt: setup.expiresAt
|
|
190
148
|
});
|
|
191
149
|
return c.json({
|
|
@@ -195,7 +153,8 @@ function registerDeviceRoutes(authenticated, deps) {
|
|
|
195
153
|
universalLink: `https://link.xopc.ai/connect#p=${encoded}`,
|
|
196
154
|
expiresAt: setup.expiresAt,
|
|
197
155
|
routes,
|
|
198
|
-
protocolVersion:
|
|
156
|
+
protocolVersion: 3,
|
|
157
|
+
targetKind: setup.targetKind
|
|
199
158
|
}
|
|
200
159
|
}, 201);
|
|
201
160
|
});
|
|
@@ -234,7 +193,10 @@ function registerDeviceRoutes(authenticated, deps) {
|
|
|
234
193
|
}
|
|
235
194
|
}, 403);
|
|
236
195
|
const revoked = revokeDevice(principal.deviceId);
|
|
237
|
-
if (revoked)
|
|
196
|
+
if (revoked) {
|
|
197
|
+
deps.service.realtime.disconnectPrincipal(principal.deviceId);
|
|
198
|
+
deps.service.voiceRealtime.disconnectPrincipal(principal.deviceId);
|
|
199
|
+
}
|
|
238
200
|
return c.json({
|
|
239
201
|
ok: true,
|
|
240
202
|
revoked
|
|
@@ -243,7 +205,10 @@ function registerDeviceRoutes(authenticated, deps) {
|
|
|
243
205
|
authenticated.delete("/api/devices/:deviceId", (c) => {
|
|
244
206
|
const deviceId = c.req.param("deviceId");
|
|
245
207
|
const revoked = revokeDevice(deviceId);
|
|
246
|
-
if (revoked)
|
|
208
|
+
if (revoked) {
|
|
209
|
+
deps.service.realtime.disconnectPrincipal(deviceId);
|
|
210
|
+
deps.service.voiceRealtime.disconnectPrincipal(deviceId);
|
|
211
|
+
}
|
|
247
212
|
return c.json({
|
|
248
213
|
ok: true,
|
|
249
214
|
revoked
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import { extractToken } from "../../auth.js";
|
|
2
1
|
import { getExposureManager } from "../../../remote-access/exposure-manager.js";
|
|
2
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
3
3
|
import { consumeTunnelMutationLimit } from "../../../tunnel/tunnel-rate-limit.js";
|
|
4
4
|
//#region src/gateway/hono/routes/exposure.ts
|
|
5
|
-
function requireGatewayToken(c) {
|
|
6
|
-
return extractToken({ authorization: c.req.header("authorization") ?? void 0 }) ?? null;
|
|
7
|
-
}
|
|
8
5
|
function createExposureMutationRateLimitMiddleware() {
|
|
9
6
|
return async (c, next) => {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
const result = consumeTunnelMutationLimit(token);
|
|
7
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
8
|
+
const result = consumeTunnelMutationLimit(principalId);
|
|
13
9
|
if (!result.allowed) {
|
|
14
10
|
const retryAfterSec = Math.ceil(result.retryAfterMs / 1e3);
|
|
15
11
|
c.header("Retry-After", String(retryAfterSec));
|
|
@@ -3,6 +3,14 @@ function startsWithAny(path, prefixes) {
|
|
|
3
3
|
return prefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));
|
|
4
4
|
}
|
|
5
5
|
const AUTHENTICATED_LAZY_ROUTE_BUNDLES = [
|
|
6
|
+
{
|
|
7
|
+
id: "browser-session",
|
|
8
|
+
match: (path) => path === "/api/browser-session",
|
|
9
|
+
load: async () => {
|
|
10
|
+
const { registerBrowserSessionRoutes } = await import("./browser-session.js");
|
|
11
|
+
return { register: registerBrowserSessionRoutes };
|
|
12
|
+
}
|
|
13
|
+
},
|
|
6
14
|
{
|
|
7
15
|
id: "proactive",
|
|
8
16
|
match: (path) => startsWithAny(path, [
|
|
@@ -13,7 +13,7 @@ import { getImageGenerationProvider, reloadImageGenerationProviders, resolveImag
|
|
|
13
13
|
import { SessionConfigStore } from "../../../session/config-store.js";
|
|
14
14
|
import { getModelThinking } from "../../../providers/model-thinking.js";
|
|
15
15
|
import { deleteCustomImageProvider, listCustomImageProviders, upsertCustomImageProvider } from "../../custom-image-providers.js";
|
|
16
|
-
import { getAgentImageGenerationConfig, getImageGenerationCatalog, prepareImageGenerationSetup, verifyImageGenerationCredential } from "../../image-generation-setup.js";
|
|
16
|
+
import { getAgentImageGenerationConfig, getDefaultImageGenerationConfig, getImageGenerationCatalog, prepareDefaultImageGenerationSetup, prepareImageGenerationSetup, verifyImageGenerationCredential } from "../../image-generation-setup.js";
|
|
17
17
|
import { discoverProviderModels, isProviderApiDiscoverable } from "../../../providers/model-discovery.js";
|
|
18
18
|
import { getXopcCloudCatalogCoordinator } from "../../../providers/xopc-cloud-catalog-coordinator.js";
|
|
19
19
|
import { respondStartupUnavailable } from "../lib/startup-unavailable.js";
|
|
@@ -505,6 +505,65 @@ function registerModelsRoutes(authenticated, deps) {
|
|
|
505
505
|
}, 502);
|
|
506
506
|
}
|
|
507
507
|
});
|
|
508
|
+
authenticated.get("/api/image-generation/default", (c) => c.json({
|
|
509
|
+
ok: true,
|
|
510
|
+
payload: getDefaultImageGenerationConfig(service.currentConfig)
|
|
511
|
+
}));
|
|
512
|
+
authenticated.post("/api/image-generation/default/setup", strictRateLimitMiddleware, async (c) => {
|
|
513
|
+
const body = await c.req.json().catch(() => null);
|
|
514
|
+
if (!body || typeof body.providerId !== "string") return c.json({
|
|
515
|
+
ok: false,
|
|
516
|
+
error: { message: "providerId is required" }
|
|
517
|
+
}, 400);
|
|
518
|
+
const prepared = prepareDefaultImageGenerationSetup(service.currentConfig, {
|
|
519
|
+
providerId: body.providerId,
|
|
520
|
+
...typeof body.modelId === "string" ? { modelId: body.modelId } : {},
|
|
521
|
+
...body.providerConfig && typeof body.providerConfig === "object" && !Array.isArray(body.providerConfig) ? { providerConfig: body.providerConfig } : {}
|
|
522
|
+
});
|
|
523
|
+
if (prepared.ok === false) return c.json({
|
|
524
|
+
ok: false,
|
|
525
|
+
error: { message: prepared.error }
|
|
526
|
+
}, 400);
|
|
527
|
+
const resolver = new CredentialResolver();
|
|
528
|
+
const usesApiKey = resolveImageGenerationCredentialMode(getImageGenerationProvider(prepared.providerId)) === "api-key";
|
|
529
|
+
const previousKey = usesApiKey ? await resolver.revealGatewayStoredApiKey(prepared.providerId) : void 0;
|
|
530
|
+
const suppliedKey = typeof body.apiKey === "string" ? body.apiKey.trim() : "";
|
|
531
|
+
const effectiveKey = usesApiKey ? suppliedKey || await resolver.resolveApiKey(prepared.providerId) : void 0;
|
|
532
|
+
if (usesApiKey && !effectiveKey) return c.json({
|
|
533
|
+
ok: false,
|
|
534
|
+
error: { message: "API key is required" }
|
|
535
|
+
}, 400);
|
|
536
|
+
const verification = usesApiKey && suppliedKey ? await verifyImageGenerationCredential({
|
|
537
|
+
providerId: prepared.providerId,
|
|
538
|
+
apiKey: suppliedKey,
|
|
539
|
+
baseUrl: typeof body.providerConfig?.baseUrl === "string" ? body.providerConfig.baseUrl : void 0
|
|
540
|
+
}) : {
|
|
541
|
+
verified: false,
|
|
542
|
+
supported: false
|
|
543
|
+
};
|
|
544
|
+
if (verification.supported && !verification.verified) return c.json({
|
|
545
|
+
ok: false,
|
|
546
|
+
error: { message: verification.message ?? "Credential verification failed" }
|
|
547
|
+
}, 400);
|
|
548
|
+
if (usesApiKey && suppliedKey) await resolver.saveApiKey(prepared.providerId, suppliedKey, { profileName: "default" });
|
|
549
|
+
const saved = await service.saveConfig(prepared.config);
|
|
550
|
+
if (!saved.saved) {
|
|
551
|
+
if (usesApiKey && suppliedKey) if (previousKey) await resolver.saveApiKey(prepared.providerId, previousKey, { profileName: "default" });
|
|
552
|
+
else await resolver.deleteProfile(`${prepared.providerId}:default`);
|
|
553
|
+
return c.json({
|
|
554
|
+
ok: false,
|
|
555
|
+
error: { message: saved.error ?? "Failed to save configuration" }
|
|
556
|
+
}, 500);
|
|
557
|
+
}
|
|
558
|
+
return c.json({
|
|
559
|
+
ok: true,
|
|
560
|
+
payload: {
|
|
561
|
+
default: getDefaultImageGenerationConfig(service.currentConfig),
|
|
562
|
+
providers: getImageGenerationCatalog(service.currentConfig),
|
|
563
|
+
verification
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
});
|
|
508
567
|
authenticated.get("/api/agents/:agentId/image-generation", (c) => {
|
|
509
568
|
try {
|
|
510
569
|
return c.json({
|
|
@@ -5,7 +5,7 @@ import { resolveGatewayEffectiveHost } from "../../../config/gateway-bind.js";
|
|
|
5
5
|
import { getShareStore } from "../../../share/share-store.js";
|
|
6
6
|
import { resolveShareUrl } from "../../../share/share-url.js";
|
|
7
7
|
import { resolveReverseProxyPublicUrl } from "../../public-url.js";
|
|
8
|
-
import {
|
|
8
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
9
9
|
import { NoteShareService, NoteShareVersionConflictError } from "../../../share/note-share-service.js";
|
|
10
10
|
import { createReadStream } from "node:fs";
|
|
11
11
|
import { createHash } from "node:crypto";
|
|
@@ -412,11 +412,7 @@ function registerNotesRoutes(authenticated, deps) {
|
|
|
412
412
|
});
|
|
413
413
|
});
|
|
414
414
|
authenticated.post("/api/notes/:id/shares", async (c) => {
|
|
415
|
-
const
|
|
416
|
-
if (!gatewayToken) return c.json({
|
|
417
|
-
ok: false,
|
|
418
|
-
error: { message: "Token required" }
|
|
419
|
-
}, 401);
|
|
415
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
420
416
|
const body = await c.req.json().catch(() => ({}));
|
|
421
417
|
const shares = noteShares();
|
|
422
418
|
try {
|
|
@@ -426,7 +422,7 @@ function registerNotesRoutes(authenticated, deps) {
|
|
|
426
422
|
ttlMs: typeof body.ttlMs === "number" ? body.ttlMs : void 0,
|
|
427
423
|
maxViews: body.maxViews === null ? null : typeof body.maxViews === "number" ? body.maxViews : void 0,
|
|
428
424
|
description: typeof body.description === "string" ? body.description.trim() || void 0 : void 0,
|
|
429
|
-
gatewayTokenHash: createHash("sha256").update(
|
|
425
|
+
gatewayTokenHash: createHash("sha256").update(principalId, "utf8").digest("hex").slice(0, 12)
|
|
430
426
|
});
|
|
431
427
|
const resolved = resolveShareUrl(record.token, shareUrlContext());
|
|
432
428
|
return c.json({
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { deleteBrowserTabBinding } from "../../../storage/sqlite/browser-tab-binding-repository.js";
|
|
2
|
+
import { SessionDiscoveryQuerySchema } from "../../../../packages/gateway-contract/src/session-identity.js";
|
|
2
3
|
import { buildSessionKey, init_session_key } from "../../../routing/session-key.js";
|
|
3
4
|
import { resolveProjectAgentId } from "../../../projects/project-agent.js";
|
|
4
5
|
import "../../../projects/index.js";
|
|
@@ -259,8 +260,18 @@ function registerSessionsRoutes(authenticated, deps) {
|
|
|
259
260
|
const blocked = ensureGatewayReadyForSessions(c, service, "sessions.list");
|
|
260
261
|
if (blocked) return blocked;
|
|
261
262
|
const query = c.req.query();
|
|
263
|
+
const discovery = SessionDiscoveryQuerySchema.safeParse({
|
|
264
|
+
sources: query.sources?.split(","),
|
|
265
|
+
purposes: query.purposes?.split(","),
|
|
266
|
+
activity: query.activity,
|
|
267
|
+
agentId: query.agentId,
|
|
268
|
+
excludeArchived: query.excludeArchived === "true"
|
|
269
|
+
});
|
|
270
|
+
if (!discovery.success) return c.json({ error: "Invalid session filters" }, 400);
|
|
271
|
+
if (query.updatedAfter && !Number.isFinite(Number(query.updatedAfter))) return c.json({ error: "Invalid session time filter" }, 400);
|
|
262
272
|
const sessionTypes = query.types?.split(",").map((value) => value.trim()).filter(isSessionType);
|
|
263
273
|
const result = await service.sessions.listSessions({
|
|
274
|
+
...discovery.data,
|
|
264
275
|
status: query.status,
|
|
265
276
|
search: query.search,
|
|
266
277
|
channel: query.channel,
|
|
@@ -15,10 +15,10 @@ import { publishHostedStaticSite } from "../../../share/hosted-static-site-publi
|
|
|
15
15
|
import { resolveReverseProxyPublicUrl } from "../../public-url.js";
|
|
16
16
|
import { audienceDefaults, cleanupStagedSite, decideShareKind, forgetStagedSite, makeDescription, makeTitle, probeShareTarget, rememberStagedSite, stageSingleHtmlAsSite } from "../../../share/share-auto.js";
|
|
17
17
|
import { deleteThumbnail, placeholderSvg, readThumbnail, scheduleThumbnail, thumbnailContentType, thumbnailExists } from "../../../share/share-thumbnail.js";
|
|
18
|
-
import { extractToken } from "../../auth.js";
|
|
19
18
|
import { getGatewayFileSpaceService } from "../../file-space-service.js";
|
|
20
19
|
import { getClientIpFromHeaders } from "../../security/loopback.js";
|
|
21
20
|
import { SHARED_HTML_CSP } from "../../security/csp.js";
|
|
21
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
22
22
|
import { renderFolderLandingPage, renderShareExpiredPage, renderShareLandingPage, renderSnapshotShareLandingPage } from "../../../share/share-landing.js";
|
|
23
23
|
import { resolveScopedMediaReference } from "../../media-access.js";
|
|
24
24
|
import { NoteShareService } from "../../../share/note-share-service.js";
|
|
@@ -56,7 +56,7 @@ function resolveShareConfig(service) {
|
|
|
56
56
|
if (!raw || typeof raw !== "object") return {};
|
|
57
57
|
return raw;
|
|
58
58
|
}
|
|
59
|
-
function
|
|
59
|
+
function hashPrincipal(token) {
|
|
60
60
|
return createHash("sha256").update(token, "utf8").digest("hex").slice(0, 12);
|
|
61
61
|
}
|
|
62
62
|
const MAX_CONCURRENT_DOWNLOADS_PER_TOKEN = 5;
|
|
@@ -594,11 +594,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
594
594
|
});
|
|
595
595
|
});
|
|
596
596
|
authenticated.post("/api/sessions/:key/shares", async (c) => {
|
|
597
|
-
const
|
|
598
|
-
if (!gatewayToken) return c.json({
|
|
599
|
-
ok: false,
|
|
600
|
-
error: { message: "Token required" }
|
|
601
|
-
}, 401);
|
|
597
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
602
598
|
const body = await c.req.json().catch(() => ({}));
|
|
603
599
|
if (typeof body.expectedSessionId !== "string" || typeof body.expectedCutoffSeq !== "number" || typeof body.expectedMetadataUpdatedAt !== "string") return c.json({
|
|
604
600
|
ok: false,
|
|
@@ -614,7 +610,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
614
610
|
description: typeof body.description === "string" ? body.description.trim() || void 0 : void 0,
|
|
615
611
|
includeToolActivities: body.includeToolActivities === true,
|
|
616
612
|
attachmentIds: Array.isArray(body.attachmentIds) ? body.attachmentIds.filter((id) => typeof id === "string") : void 0,
|
|
617
|
-
gatewayTokenHash:
|
|
613
|
+
gatewayTokenHash: hashPrincipal(principalId)
|
|
618
614
|
});
|
|
619
615
|
const resolved = resolveShareUrl(record.token, getShareUrlContext(service));
|
|
620
616
|
return c.json({
|
|
@@ -1130,11 +1126,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
1130
1126
|
}
|
|
1131
1127
|
});
|
|
1132
1128
|
authenticated.post("/api/shares", async (c) => {
|
|
1133
|
-
const
|
|
1134
|
-
if (!gatewayToken) return c.json({
|
|
1135
|
-
ok: false,
|
|
1136
|
-
error: { message: "Token required" }
|
|
1137
|
-
}, 401);
|
|
1129
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
1138
1130
|
let body;
|
|
1139
1131
|
try {
|
|
1140
1132
|
body = await c.req.json();
|
|
@@ -1201,7 +1193,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
1201
1193
|
sessionKey,
|
|
1202
1194
|
agentId,
|
|
1203
1195
|
workspaceRoot,
|
|
1204
|
-
gatewayTokenHash:
|
|
1196
|
+
gatewayTokenHash: hashPrincipal(principalId),
|
|
1205
1197
|
kind,
|
|
1206
1198
|
directoryMode,
|
|
1207
1199
|
followSymlinks,
|
|
@@ -1242,11 +1234,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
1242
1234
|
* reachability) in a single round-trip.
|
|
1243
1235
|
*/
|
|
1244
1236
|
authenticated.post("/api/shares/auto", async (c) => {
|
|
1245
|
-
const
|
|
1246
|
-
if (!gatewayToken) return c.json({
|
|
1247
|
-
ok: false,
|
|
1248
|
-
error: { message: "Token required" }
|
|
1249
|
-
}, 401);
|
|
1237
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
1250
1238
|
let body;
|
|
1251
1239
|
try {
|
|
1252
1240
|
body = await c.req.json();
|
|
@@ -1309,7 +1297,7 @@ function registerShareRoutes(authenticated, deps) {
|
|
|
1309
1297
|
const defaults = audienceDefaults(audience);
|
|
1310
1298
|
const ttlMs = ttlOverride ?? defaults.ttlMs;
|
|
1311
1299
|
const maxViews = maxViewsOverride !== void 0 ? maxViewsOverride : defaults.maxViews;
|
|
1312
|
-
const tokenHash =
|
|
1300
|
+
const tokenHash = hashPrincipal(principalId);
|
|
1313
1301
|
const urlCtx = getShareUrlContext(service);
|
|
1314
1302
|
try {
|
|
1315
1303
|
if (decision.kind === "site") {
|
|
@@ -3,10 +3,10 @@ import { resolveSiteShareConfig } from "../../../share/site-share-config.js";
|
|
|
3
3
|
import { getSiteShareStore } from "../../../share/site-share-store.js";
|
|
4
4
|
import { resolveSiteShareUrl } from "../../../share/share-url.js";
|
|
5
5
|
import { resolveReverseProxyPublicUrl } from "../../public-url.js";
|
|
6
|
-
import {
|
|
6
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
7
7
|
import { createHash } from "node:crypto";
|
|
8
8
|
//#region src/gateway/hono/routes/site-shares.ts
|
|
9
|
-
function
|
|
9
|
+
function hashPrincipal(token) {
|
|
10
10
|
return createHash("sha256").update(token, "utf8").digest("hex").slice(0, 12);
|
|
11
11
|
}
|
|
12
12
|
function buildShareUrls(record, publicHostSuffix, service) {
|
|
@@ -42,11 +42,7 @@ function registerSiteShareRoutes(authenticated, deps) {
|
|
|
42
42
|
return resolveAgentWorkspaceDir(cfg, resolveDefaultAgentId(cfg));
|
|
43
43
|
}
|
|
44
44
|
authenticated.post("/api/site-shares", async (c) => {
|
|
45
|
-
const
|
|
46
|
-
if (!gatewayToken) return c.json({
|
|
47
|
-
ok: false,
|
|
48
|
-
error: { message: "Token required" }
|
|
49
|
-
}, 401);
|
|
45
|
+
const principalId = getGatewayPrincipal(c).principalId;
|
|
50
46
|
let body;
|
|
51
47
|
try {
|
|
52
48
|
body = await c.req.json();
|
|
@@ -96,7 +92,7 @@ function registerSiteShareRoutes(authenticated, deps) {
|
|
|
96
92
|
sessionKey,
|
|
97
93
|
agentId,
|
|
98
94
|
workspaceRoot,
|
|
99
|
-
gatewayTokenHash:
|
|
95
|
+
gatewayTokenHash: hashPrincipal(principalId)
|
|
100
96
|
});
|
|
101
97
|
const urls = buildShareUrls(record, store.getConfig().publicHostSuffix, service);
|
|
102
98
|
return c.json({
|
|
@@ -2,10 +2,11 @@ import { init_public_url, validatePublicUrl } from "../../../config/public-url.j
|
|
|
2
2
|
import { TUNNEL_REGISTRATION_SECRET_REQUIRED_CODE, TunnelRegistrationSecretError, getTunnelRegistrationSecretMeta, readTunnelRegistrationSecretFromConfigOnly, resolveTunnelBrokerUrl } from "../../../tunnel/env.js";
|
|
3
3
|
import { logTunnelAudit } from "../../../tunnel/tunnel-audit.js";
|
|
4
4
|
import { getTunnelService, hashGatewayToken } from "../../../tunnel/tunnel-service.js";
|
|
5
|
-
import {
|
|
5
|
+
import { requireTunnelGatewayToken } from "../../../tunnel/auth-policy.js";
|
|
6
6
|
import { TUNNEL_CONSENT_REQUIRED_CODE, TunnelConsentError, assertTunnelMayStart, getTunnelConsentState } from "../../../tunnel/consent.js";
|
|
7
7
|
import { configureTunnelFromGatewayConfig } from "../../../tunnel/gateway-lifecycle.js";
|
|
8
8
|
import { applyTunnelConsentToConfig, mergeTunnelConfigPatch, setTunnelEnabledInConfig } from "../../../tunnel/tunnel-config.js";
|
|
9
|
+
import { getGatewayPrincipal } from "../../security/gateway-principal.js";
|
|
9
10
|
import { consumeTunnelMutationLimit } from "../../../tunnel/tunnel-rate-limit.js";
|
|
10
11
|
import "../../../tunnel/index.js";
|
|
11
12
|
import { provisionTunnelRegistrationKey } from "../../../tunnel/xopc-cloud-registration.js";
|
|
@@ -36,14 +37,9 @@ function enrichTunnelStatus(config, status) {
|
|
|
36
37
|
registrationSecret
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
|
-
function requireGatewayToken(c) {
|
|
40
|
-
return extractToken({ authorization: c.req.header("authorization") ?? void 0 }) ?? null;
|
|
41
|
-
}
|
|
42
40
|
function createTunnelMutationRateLimitMiddleware() {
|
|
43
41
|
return async (c, next) => {
|
|
44
|
-
const
|
|
45
|
-
if (!token) return c.json({ error: "Gateway token required" }, 401);
|
|
46
|
-
const result = consumeTunnelMutationLimit(token);
|
|
42
|
+
const result = consumeTunnelMutationLimit(getGatewayPrincipal(c).principalId);
|
|
47
43
|
if (!result.allowed) {
|
|
48
44
|
c.header("Retry-After", String(Math.ceil(result.retryAfterMs / 1e3)));
|
|
49
45
|
return c.json({
|
|
@@ -66,7 +62,6 @@ function registerTunnelRoutes(authenticated, deps) {
|
|
|
66
62
|
* the UI can render targeted hints (TLS / DNS / wrong service / blocked path).
|
|
67
63
|
*/
|
|
68
64
|
authenticated.post("/api/tunnel/probe-public", tunnelMutationLimit, async (c) => {
|
|
69
|
-
if (!requireGatewayToken(c)) return c.json({ error: "Gateway token required" }, 401);
|
|
70
65
|
let body;
|
|
71
66
|
try {
|
|
72
67
|
body = await c.req.json();
|
|
@@ -142,8 +137,6 @@ function registerTunnelRoutes(authenticated, deps) {
|
|
|
142
137
|
return c.json(enrichTunnelStatus(config, tunnel.getStatus()));
|
|
143
138
|
});
|
|
144
139
|
authenticated.post("/api/tunnel/consent", tunnelMutationLimit, async (c) => {
|
|
145
|
-
const token = requireGatewayToken(c);
|
|
146
|
-
if (!token) return c.json({ error: "Gateway token required" }, 401);
|
|
147
140
|
const config = deps.service.currentConfig;
|
|
148
141
|
applyTunnelConsentToConfig(config);
|
|
149
142
|
const result = await deps.service.saveConfig(config);
|
|
@@ -154,7 +147,7 @@ function registerTunnelRoutes(authenticated, deps) {
|
|
|
154
147
|
const consent = getTunnelConsentState(config);
|
|
155
148
|
logTunnelAudit("tunnel.consent", {
|
|
156
149
|
consentVersion: consent.currentVersion,
|
|
157
|
-
|
|
150
|
+
principalId: getGatewayPrincipal(c).principalId
|
|
158
151
|
}, "Remote access security consent recorded");
|
|
159
152
|
return c.json({
|
|
160
153
|
ok: true,
|
|
@@ -190,10 +183,17 @@ function registerTunnelRoutes(authenticated, deps) {
|
|
|
190
183
|
}
|
|
191
184
|
});
|
|
192
185
|
authenticated.post("/api/tunnel/start", tunnelMutationLimit, async (c) => {
|
|
186
|
+
let token;
|
|
187
|
+
try {
|
|
188
|
+
token = requireTunnelGatewayToken(deps.service.getResolvedAuth());
|
|
189
|
+
} catch (error) {
|
|
190
|
+
return c.json({
|
|
191
|
+
error: error.message,
|
|
192
|
+
code: "TUNNEL_AUTH_REQUIRED"
|
|
193
|
+
}, 403);
|
|
194
|
+
}
|
|
193
195
|
await configureTunnelFromService(deps, { force: true });
|
|
194
196
|
const config = deps.service.currentConfig;
|
|
195
|
-
const token = requireGatewayToken(c);
|
|
196
|
-
if (!token) return c.json({ error: "Gateway token required" }, 401);
|
|
197
197
|
try {
|
|
198
198
|
assertTunnelMayStart(config);
|
|
199
199
|
} catch (err) {
|
|
@@ -19,6 +19,23 @@ export declare function getAgentImageGenerationConfig(config: Config, agentIdRaw
|
|
|
19
19
|
timeoutMs?: number;
|
|
20
20
|
};
|
|
21
21
|
};
|
|
22
|
+
export declare function getDefaultImageGenerationConfig(config: Config): {
|
|
23
|
+
model: {
|
|
24
|
+
primary: string;
|
|
25
|
+
fallbacks: string[];
|
|
26
|
+
autoProviderFallback: boolean;
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export declare function prepareDefaultImageGenerationSetup(config: Config, input: ImageGenerationSetupInput): {
|
|
31
|
+
ok: true;
|
|
32
|
+
config: Config;
|
|
33
|
+
providerId: string;
|
|
34
|
+
modelId: string;
|
|
35
|
+
} | {
|
|
36
|
+
ok: false;
|
|
37
|
+
error: string;
|
|
38
|
+
};
|
|
22
39
|
export declare function prepareImageGenerationSetup(config: Config, agentIdRaw: string, input: ImageGenerationSetupInput): {
|
|
23
40
|
ok: true;
|
|
24
41
|
config: Config;
|