@raybase/core 0.0.2 → 0.3.3
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/LICENSE +21 -0
- package/dist/.admin-build/AdminApp.css +2 -0
- package/dist/.admin-build/AdminApp.js +77 -0
- package/dist/.admin-docs-build/AdminDocsApp.css +2 -0
- package/dist/.admin-docs-build/AdminDocsApp.js +45 -0
- package/dist/actions.d.ts +347 -0
- package/dist/actions.d.ts.map +1 -0
- package/dist/actions.js +661 -0
- package/dist/actions.js.map +1 -0
- package/dist/admin-assets/admin.7738f50720a8ed7b.css +2 -0
- package/dist/admin-assets/admin.8678cb61db34dc81.js +77 -0
- package/dist/admin-boot.d.ts +94 -0
- package/dist/admin-boot.d.ts.map +1 -0
- package/dist/admin-boot.js +139 -0
- package/dist/admin-boot.js.map +1 -0
- package/dist/admin-docs-content.d.ts +95 -0
- package/dist/admin-docs-content.d.ts.map +1 -0
- package/dist/admin-docs-content.js +463 -0
- package/dist/admin-docs-content.js.map +1 -0
- package/dist/admin-docs-ui.d.ts +11 -0
- package/dist/admin-docs-ui.d.ts.map +1 -0
- package/dist/admin-docs-ui.js +23 -0
- package/dist/admin-docs-ui.js.map +1 -0
- package/dist/admin-kit.d.ts +29 -0
- package/dist/admin-kit.js +1557 -0
- package/dist/admin-role.d.ts +8 -0
- package/dist/admin-role.d.ts.map +1 -0
- package/dist/admin-role.js +22 -0
- package/dist/admin-role.js.map +1 -0
- package/dist/admin-ui.d.ts +3 -0
- package/dist/admin-ui.d.ts.map +1 -0
- package/dist/admin-ui.js +16 -0
- package/dist/admin-ui.js.map +1 -0
- package/dist/agent-ai-chat.d.ts +127 -0
- package/dist/agent-ai-chat.d.ts.map +1 -0
- package/dist/agent-ai-chat.js +5975 -0
- package/dist/agent-ai-chat.js.map +1 -0
- package/dist/agent-chapter-archive.d.ts +214 -0
- package/dist/agent-chapter-archive.d.ts.map +1 -0
- package/dist/agent-chapter-archive.js +696 -0
- package/dist/agent-chapter-archive.js.map +1 -0
- package/dist/agent-chapter-search.d.ts +116 -0
- package/dist/agent-chapter-search.d.ts.map +1 -0
- package/dist/agent-chapter-search.js +605 -0
- package/dist/agent-chapter-search.js.map +1 -0
- package/dist/agent-chapter-tools.d.ts +45 -0
- package/dist/agent-chapter-tools.d.ts.map +1 -0
- package/dist/agent-chapter-tools.js +344 -0
- package/dist/agent-chapter-tools.js.map +1 -0
- package/dist/agent-chapters.d.ts +228 -0
- package/dist/agent-chapters.d.ts.map +1 -0
- package/dist/agent-chapters.js +737 -0
- package/dist/agent-chapters.js.map +1 -0
- package/dist/agent-data-parts.d.ts +167 -0
- package/dist/agent-data-parts.d.ts.map +1 -0
- package/dist/agent-data-parts.js +68 -0
- package/dist/agent-data-parts.js.map +1 -0
- package/dist/agent-errors.d.ts +41 -0
- package/dist/agent-errors.d.ts.map +1 -0
- package/dist/agent-errors.js +191 -0
- package/dist/agent-errors.js.map +1 -0
- package/dist/agent-follow-up-store.d.ts +273 -0
- package/dist/agent-follow-up-store.d.ts.map +1 -0
- package/dist/agent-follow-up-store.js +703 -0
- package/dist/agent-follow-up-store.js.map +1 -0
- package/dist/agent-follow-ups.d.ts +314 -0
- package/dist/agent-follow-ups.d.ts.map +1 -0
- package/dist/agent-follow-ups.js +840 -0
- package/dist/agent-follow-ups.js.map +1 -0
- package/dist/agent-memory.d.ts +323 -0
- package/dist/agent-memory.d.ts.map +1 -0
- package/dist/agent-memory.js +1270 -0
- package/dist/agent-memory.js.map +1 -0
- package/dist/agent-message-parts.d.ts +58 -0
- package/dist/agent-message-parts.d.ts.map +1 -0
- package/dist/agent-message-parts.js +163 -0
- package/dist/agent-message-parts.js.map +1 -0
- package/dist/agent-remote-mcp-credentials.d.ts +154 -0
- package/dist/agent-remote-mcp-credentials.d.ts.map +1 -0
- package/dist/agent-remote-mcp-credentials.js +287 -0
- package/dist/agent-remote-mcp-credentials.js.map +1 -0
- package/dist/agent-remote-mcp-crypto.d.ts +32 -0
- package/dist/agent-remote-mcp-crypto.d.ts.map +1 -0
- package/dist/agent-remote-mcp-crypto.js +101 -0
- package/dist/agent-remote-mcp-crypto.js.map +1 -0
- package/dist/agent-remote-mcp-install.d.ts +299 -0
- package/dist/agent-remote-mcp-install.d.ts.map +1 -0
- package/dist/agent-remote-mcp-install.js +785 -0
- package/dist/agent-remote-mcp-install.js.map +1 -0
- package/dist/agent-remote-mcp-oauth.d.ts +73 -0
- package/dist/agent-remote-mcp-oauth.d.ts.map +1 -0
- package/dist/agent-remote-mcp-oauth.js +344 -0
- package/dist/agent-remote-mcp-oauth.js.map +1 -0
- package/dist/agent-remote-mcp-transport.d.ts +46 -0
- package/dist/agent-remote-mcp-transport.d.ts.map +1 -0
- package/dist/agent-remote-mcp-transport.js +225 -0
- package/dist/agent-remote-mcp-transport.js.map +1 -0
- package/dist/agent-remote-mcp.d.ts +147 -0
- package/dist/agent-remote-mcp.d.ts.map +1 -0
- package/dist/agent-remote-mcp.js +681 -0
- package/dist/agent-remote-mcp.js.map +1 -0
- package/dist/agent-room-redaction.d.ts +66 -0
- package/dist/agent-room-redaction.d.ts.map +1 -0
- package/dist/agent-room-redaction.js +264 -0
- package/dist/agent-room-redaction.js.map +1 -0
- package/dist/agent-rooms.d.ts +209 -0
- package/dist/agent-rooms.d.ts.map +1 -0
- package/dist/agent-rooms.js +244 -0
- package/dist/agent-rooms.js.map +1 -0
- package/dist/agent-runtime.d.ts +541 -0
- package/dist/agent-runtime.d.ts.map +1 -0
- package/dist/agent-runtime.js +4260 -0
- package/dist/agent-runtime.js.map +1 -0
- package/dist/agent-skill-archive.d.ts +20 -0
- package/dist/agent-skill-archive.d.ts.map +1 -0
- package/dist/agent-skill-archive.js +316 -0
- package/dist/agent-skill-archive.js.map +1 -0
- package/dist/agent-skill-discovery.d.ts +96 -0
- package/dist/agent-skill-discovery.d.ts.map +1 -0
- package/dist/agent-skill-discovery.js +464 -0
- package/dist/agent-skill-discovery.js.map +1 -0
- package/dist/agent-skill-format.d.ts +57 -0
- package/dist/agent-skill-format.d.ts.map +1 -0
- package/dist/agent-skill-format.js +238 -0
- package/dist/agent-skill-format.js.map +1 -0
- package/dist/agent-skill-import.d.ts +64 -0
- package/dist/agent-skill-import.d.ts.map +1 -0
- package/dist/agent-skill-import.js +295 -0
- package/dist/agent-skill-import.js.map +1 -0
- package/dist/agent-skill-publish.d.ts +51 -0
- package/dist/agent-skill-publish.d.ts.map +1 -0
- package/dist/agent-skill-publish.js +136 -0
- package/dist/agent-skill-publish.js.map +1 -0
- package/dist/agent-skill-store.d.ts +252 -0
- package/dist/agent-skill-store.d.ts.map +1 -0
- package/dist/agent-skill-store.js +514 -0
- package/dist/agent-skill-store.js.map +1 -0
- package/dist/agent-skills.d.ts +85 -0
- package/dist/agent-skills.d.ts.map +1 -0
- package/dist/agent-skills.js +291 -0
- package/dist/agent-skills.js.map +1 -0
- package/dist/agent-transcript-pager.d.ts +77 -0
- package/dist/agent-transcript-pager.d.ts.map +1 -0
- package/dist/agent-transcript-pager.js +210 -0
- package/dist/agent-transcript-pager.js.map +1 -0
- package/dist/agent-user-data-parts.d.ts +20 -0
- package/dist/agent-user-data-parts.d.ts.map +1 -0
- package/dist/agent-user-data-parts.js +161 -0
- package/dist/agent-user-data-parts.js.map +1 -0
- package/dist/agent-user-transcript.d.ts +46 -0
- package/dist/agent-user-transcript.d.ts.map +1 -0
- package/dist/agent-user-transcript.js +106 -0
- package/dist/agent-user-transcript.js.map +1 -0
- package/dist/agent-voice-notes.d.ts +15 -0
- package/dist/agent-voice-notes.d.ts.map +1 -0
- package/dist/agent-voice-notes.js +17 -0
- package/dist/agent-voice-notes.js.map +1 -0
- package/dist/agent-wakes.d.ts +213 -0
- package/dist/agent-wakes.d.ts.map +1 -0
- package/dist/agent-wakes.js +534 -0
- package/dist/agent-wakes.js.map +1 -0
- package/dist/agent.d.ts +1780 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +3123 -0
- package/dist/agent.js.map +1 -0
- package/dist/ai.d.ts +583 -0
- package/dist/ai.d.ts.map +1 -0
- package/dist/ai.js +1858 -0
- package/dist/ai.js.map +1 -0
- package/dist/app-manifest.d.ts +255 -0
- package/dist/app-manifest.d.ts.map +1 -0
- package/dist/app-manifest.js +372 -0
- package/dist/app-manifest.js.map +1 -0
- package/dist/app-users.d.ts +30 -0
- package/dist/app-users.d.ts.map +1 -0
- package/dist/app-users.js +91 -0
- package/dist/app-users.js.map +1 -0
- package/dist/audit-archive.d.ts +85 -0
- package/dist/audit-archive.d.ts.map +1 -0
- package/dist/audit-archive.js +178 -0
- package/dist/audit-archive.js.map +1 -0
- package/dist/audit.d.ts +54 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +95 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth-logger.d.ts +28 -0
- package/dist/auth-logger.d.ts.map +1 -0
- package/dist/auth-logger.js +53 -0
- package/dist/auth-logger.js.map +1 -0
- package/dist/auth-password-secret.d.ts +59 -0
- package/dist/auth-password-secret.d.ts.map +1 -0
- package/dist/auth-password-secret.js +409 -0
- package/dist/auth-password-secret.js.map +1 -0
- package/dist/auth-schema.d.ts +120 -0
- package/dist/auth-schema.d.ts.map +1 -0
- package/dist/auth-schema.js +285 -0
- package/dist/auth-schema.js.map +1 -0
- package/dist/auth.d.ts +321 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +1562 -0
- package/dist/auth.js.map +1 -0
- package/dist/backup-archive.d.ts +257 -0
- package/dist/backup-archive.d.ts.map +1 -0
- package/dist/backup-archive.js +2068 -0
- package/dist/backup-archive.js.map +1 -0
- package/dist/backup-crypto.d.ts +313 -0
- package/dist/backup-crypto.d.ts.map +1 -0
- package/dist/backup-crypto.js +693 -0
- package/dist/backup-crypto.js.map +1 -0
- package/dist/backup-format.d.ts +200 -0
- package/dist/backup-format.d.ts.map +1 -0
- package/dist/backup-format.js +1247 -0
- package/dist/backup-format.js.map +1 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +15 -0
- package/dist/cli.js.map +1 -0
- package/dist/clock.d.ts +35 -0
- package/dist/clock.d.ts.map +1 -0
- package/dist/clock.js +83 -0
- package/dist/clock.js.map +1 -0
- package/dist/data-client.d.ts +187 -0
- package/dist/data-client.d.ts.map +1 -0
- package/dist/data-client.js +590 -0
- package/dist/data-client.js.map +1 -0
- package/dist/data-secrets.d.ts +164 -0
- package/dist/data-secrets.d.ts.map +1 -0
- package/dist/data-secrets.js +383 -0
- package/dist/data-secrets.js.map +1 -0
- package/dist/db.d.ts +453 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +324 -0
- package/dist/db.js.map +1 -0
- package/dist/dev-activity.d.ts +48 -0
- package/dist/dev-activity.d.ts.map +1 -0
- package/dist/dev-activity.js +50 -0
- package/dist/dev-activity.js.map +1 -0
- package/dist/do.d.ts +429 -0
- package/dist/do.d.ts.map +1 -0
- package/dist/do.js +4526 -0
- package/dist/do.js.map +1 -0
- package/dist/email.d.ts +137 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +527 -0
- package/dist/email.js.map +1 -0
- package/dist/generated/admin-assets.d.ts +16 -0
- package/dist/generated/admin-assets.d.ts.map +1 -0
- package/dist/generated/admin-assets.js +16 -0
- package/dist/generated/admin-assets.js.map +1 -0
- package/dist/generated/admin-docs-assets.d.ts +3 -0
- package/dist/generated/admin-docs-assets.d.ts.map +1 -0
- package/dist/generated/admin-docs-assets.js +3 -0
- package/dist/generated/admin-docs-assets.js.map +1 -0
- package/dist/handoff-consumer.d.ts +79 -0
- package/dist/handoff-consumer.d.ts.map +1 -0
- package/dist/handoff-consumer.js +300 -0
- package/dist/handoff-consumer.js.map +1 -0
- package/dist/handoff.d.ts +70 -0
- package/dist/handoff.d.ts.map +1 -0
- package/dist/handoff.js +228 -0
- package/dist/handoff.js.map +1 -0
- package/dist/host-auth.d.ts +47 -0
- package/dist/host-auth.d.ts.map +1 -0
- package/dist/host-auth.js +59 -0
- package/dist/host-auth.js.map +1 -0
- package/dist/host-user.d.ts +15 -0
- package/dist/host-user.d.ts.map +1 -0
- package/dist/host-user.js +23 -0
- package/dist/host-user.js.map +1 -0
- package/dist/html.d.ts +35 -0
- package/dist/html.d.ts.map +1 -0
- package/dist/html.js +634 -0
- package/dist/html.js.map +1 -0
- package/dist/http-error.d.ts +13 -0
- package/dist/http-error.d.ts.map +1 -0
- package/dist/http-error.js +15 -0
- package/dist/http-error.js.map +1 -0
- package/dist/imports.d.ts +219 -0
- package/dist/imports.d.ts.map +1 -0
- package/dist/imports.js +571 -0
- package/dist/imports.js.map +1 -0
- package/dist/index.d.ts +78 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/inference-tape.d.ts +64 -0
- package/dist/inference-tape.d.ts.map +1 -0
- package/dist/inference-tape.js +278 -0
- package/dist/inference-tape.js.map +1 -0
- package/dist/internal.d.ts +15 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +48 -0
- package/dist/internal.js.map +1 -0
- package/dist/jobs.d.ts +796 -0
- package/dist/jobs.d.ts.map +1 -0
- package/dist/jobs.js +538 -0
- package/dist/jobs.js.map +1 -0
- package/dist/json-schema.d.ts +91 -0
- package/dist/json-schema.d.ts.map +1 -0
- package/dist/json-schema.js +884 -0
- package/dist/json-schema.js.map +1 -0
- package/dist/knowledge.d.ts +33 -0
- package/dist/knowledge.d.ts.map +1 -0
- package/dist/knowledge.js +348 -0
- package/dist/knowledge.js.map +1 -0
- package/dist/local-dev-chrome.d.ts +29 -0
- package/dist/local-dev-chrome.d.ts.map +1 -0
- package/dist/local-dev-chrome.js +514 -0
- package/dist/local-dev-chrome.js.map +1 -0
- package/dist/local-dev-personas.d.ts +15 -0
- package/dist/local-dev-personas.d.ts.map +1 -0
- package/dist/local-dev-personas.js +46 -0
- package/dist/local-dev-personas.js.map +1 -0
- package/dist/mcp.d.ts +567 -0
- package/dist/mcp.d.ts.map +1 -0
- package/dist/mcp.js +2480 -0
- package/dist/mcp.js.map +1 -0
- package/dist/modules.d.ts +145 -0
- package/dist/modules.d.ts.map +1 -0
- package/dist/modules.js +164 -0
- package/dist/modules.js.map +1 -0
- package/dist/notification-client.d.ts +94 -0
- package/dist/notification-client.d.ts.map +1 -0
- package/dist/notification-client.js +127 -0
- package/dist/notification-client.js.map +1 -0
- package/dist/notifications.d.ts +447 -0
- package/dist/notifications.d.ts.map +1 -0
- package/dist/notifications.js +1625 -0
- package/dist/notifications.js.map +1 -0
- package/dist/operator-data-query.d.ts +117 -0
- package/dist/operator-data-query.d.ts.map +1 -0
- package/dist/operator-data-query.js +431 -0
- package/dist/operator-data-query.js.map +1 -0
- package/dist/operator-mcp.d.ts +63 -0
- package/dist/operator-mcp.d.ts.map +1 -0
- package/dist/operator-mcp.js +2828 -0
- package/dist/operator-mcp.js.map +1 -0
- package/dist/outbound-https.d.ts +24 -0
- package/dist/outbound-https.d.ts.map +1 -0
- package/dist/outbound-https.js +172 -0
- package/dist/outbound-https.js.map +1 -0
- package/dist/pitr.d.ts +60 -0
- package/dist/pitr.d.ts.map +1 -0
- package/dist/pitr.js +94 -0
- package/dist/pitr.js.map +1 -0
- package/dist/platform.d.ts +199 -0
- package/dist/platform.d.ts.map +1 -0
- package/dist/platform.js +196 -0
- package/dist/platform.js.map +1 -0
- package/dist/policies.d.ts +115 -0
- package/dist/policies.d.ts.map +1 -0
- package/dist/policies.js +158 -0
- package/dist/policies.js.map +1 -0
- package/dist/principal.d.ts +143 -0
- package/dist/principal.d.ts.map +1 -0
- package/dist/principal.js +174 -0
- package/dist/principal.js.map +1 -0
- package/dist/realtime.d.ts +280 -0
- package/dist/realtime.d.ts.map +1 -0
- package/dist/realtime.js +578 -0
- package/dist/realtime.js.map +1 -0
- package/dist/retrieval.d.ts +263 -0
- package/dist/retrieval.d.ts.map +1 -0
- package/dist/retrieval.js +602 -0
- package/dist/retrieval.js.map +1 -0
- package/dist/runtime-error-client.d.ts +10 -0
- package/dist/runtime-error-client.d.ts.map +1 -0
- package/dist/runtime-error-client.js +70 -0
- package/dist/runtime-error-client.js.map +1 -0
- package/dist/runtime-errors.d.ts +180 -0
- package/dist/runtime-errors.d.ts.map +1 -0
- package/dist/runtime-errors.js +572 -0
- package/dist/runtime-errors.js.map +1 -0
- package/dist/schema.d.ts +434 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +232 -0
- package/dist/schema.js.map +1 -0
- package/dist/search.d.ts +216 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +785 -0
- package/dist/search.js.map +1 -0
- package/dist/settings.d.ts +191 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +478 -0
- package/dist/settings.js.map +1 -0
- package/dist/sql.d.ts +7 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +30 -0
- package/dist/sql.js.map +1 -0
- package/dist/storage-client.d.ts +69 -0
- package/dist/storage-client.d.ts.map +1 -0
- package/dist/storage-client.js +469 -0
- package/dist/storage-client.js.map +1 -0
- package/dist/storage.d.ts +21 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +82 -0
- package/dist/storage.js.map +1 -0
- package/dist/subject-domains.d.ts +15 -0
- package/dist/subject-domains.d.ts.map +1 -0
- package/dist/subject-domains.js +38 -0
- package/dist/subject-domains.js.map +1 -0
- package/dist/support.d.ts +132 -0
- package/dist/support.d.ts.map +1 -0
- package/dist/support.js +483 -0
- package/dist/support.js.map +1 -0
- package/dist/system-tables.d.ts +12 -0
- package/dist/system-tables.d.ts.map +1 -0
- package/dist/system-tables.js +225 -0
- package/dist/system-tables.js.map +1 -0
- package/dist/test.d.ts +57 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +454 -0
- package/dist/test.js.map +1 -0
- package/dist/vite.d.ts +82 -0
- package/dist/vite.d.ts.map +1 -0
- package/dist/vite.js +82 -0
- package/dist/vite.js.map +1 -0
- package/dist/webpush-crypto.d.ts +39 -0
- package/dist/webpush-crypto.d.ts.map +1 -0
- package/dist/webpush-crypto.js +213 -0
- package/dist/webpush-crypto.js.map +1 -0
- package/dist/webpush-private.d.ts +11 -0
- package/dist/webpush-private.d.ts.map +1 -0
- package/dist/webpush-private.js +11 -0
- package/dist/webpush-private.js.map +1 -0
- package/dist/webpush.d.ts +86 -0
- package/dist/webpush.d.ts.map +1 -0
- package/dist/webpush.js +375 -0
- package/dist/webpush.js.map +1 -0
- package/dist/worker.d.ts +185 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +13021 -0
- package/dist/worker.js.map +1 -0
- package/package.json +161 -8
- package/README.md +0 -3
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `kind` claim. The hub mints `sso`/`pass`; a resource owner's own signer
|
|
3
|
+
* mints `link` (a signed right, no person) and `machine` (a link-shaped pass
|
|
4
|
+
* held by an automated lease). This module owns the vocabulary because it
|
|
5
|
+
* imports nothing from Core; `handoff.ts` takes the type from here.
|
|
6
|
+
*/
|
|
7
|
+
export type RaybaseHandoffTokenKind = "sso" | "pass" | "link" | "machine";
|
|
8
|
+
/** What a verified token turns into: a person, or a signed right. */
|
|
9
|
+
export type RaybaseHandoffPrincipalKind = "identity" | "link" | "machine";
|
|
10
|
+
export type RaybaseHandoffIssuer = {
|
|
11
|
+
issuer: string;
|
|
12
|
+
/** Defaults to `${issuer}/.well-known/jwks.json`. */
|
|
13
|
+
jwks?: string;
|
|
14
|
+
/** Pin a single public key instead of fetching a key set. */
|
|
15
|
+
publicJwk?: JsonWebKey;
|
|
16
|
+
/**
|
|
17
|
+
* Which kinds this issuer may mint. Defaults to `["sso", "pass"]` for the
|
|
18
|
+
* first issuer (the hub) and `["link", "machine"]` for every later one, so a
|
|
19
|
+
* second signer cannot mint memberships unless the resource says it may.
|
|
20
|
+
*/
|
|
21
|
+
kinds?: RaybaseHandoffTokenKind[];
|
|
22
|
+
};
|
|
23
|
+
export type RaybaseHandoffConsumerConfig = {
|
|
24
|
+
resource: string;
|
|
25
|
+
/** Origin of the authorize endpoint the bounce sends strangers to. */
|
|
26
|
+
hub: string;
|
|
27
|
+
/** The hub is normally issuers[0]; a resource owner's own signer is another. */
|
|
28
|
+
issuers: RaybaseHandoffIssuer[];
|
|
29
|
+
cookieName?: string;
|
|
30
|
+
returnTo?: string;
|
|
31
|
+
clockToleranceSeconds?: number;
|
|
32
|
+
};
|
|
33
|
+
export type RaybaseHandoffPrincipal = {
|
|
34
|
+
kind: RaybaseHandoffPrincipalKind;
|
|
35
|
+
sub: string;
|
|
36
|
+
email?: string;
|
|
37
|
+
emailVerified?: boolean;
|
|
38
|
+
name?: string;
|
|
39
|
+
/** Only ever present on an identity principal minted from an sso handoff. */
|
|
40
|
+
roles?: string[];
|
|
41
|
+
appId?: string;
|
|
42
|
+
resource: string;
|
|
43
|
+
issuer: string;
|
|
44
|
+
exp: number;
|
|
45
|
+
jti: string;
|
|
46
|
+
};
|
|
47
|
+
/** The nonce that binds a consume URL to the browser that started the bounce. */
|
|
48
|
+
export declare const handoffStateCookieName = "raybase_handoff_state";
|
|
49
|
+
/** A bearer beats a cookie: a caller that names its token means it. */
|
|
50
|
+
export declare function extractHandoffToken(request: Request, cookieName?: string): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* Verify a handoff token against the configured issuers. The unverified `iss`
|
|
53
|
+
* claim only selects which configured key to verify against; an issuer that is
|
|
54
|
+
* not listed is rejected before any signature check.
|
|
55
|
+
*/
|
|
56
|
+
export declare function verifyHandoffToken(token: string, cfg: RaybaseHandoffConsumerConfig): Promise<RaybaseHandoffPrincipal>;
|
|
57
|
+
/** The request's principal, or null when it carries no usable handoff token. */
|
|
58
|
+
export declare function verifyHandoff(request: Request, cfg: RaybaseHandoffConsumerConfig): Promise<RaybaseHandoffPrincipal | null>;
|
|
59
|
+
export declare function serializeHandoffCookie(value: string, options: {
|
|
60
|
+
cookieName?: string;
|
|
61
|
+
requestUrl: string | URL;
|
|
62
|
+
maxAgeSeconds: number;
|
|
63
|
+
}): string;
|
|
64
|
+
export declare function handoffAuthorizeUrl(request: Request, cfg: RaybaseHandoffConsumerConfig, state?: string): string;
|
|
65
|
+
/** A top-level navigation, which can be bounced; anything else gets JSON. */
|
|
66
|
+
export declare function isHandoffNavigation(request: Request): boolean;
|
|
67
|
+
/**
|
|
68
|
+
* The consume route handler: verify the token the hub redirected with, set the
|
|
69
|
+
* resource's own cookie, and send the visitor on to where they were going.
|
|
70
|
+
*/
|
|
71
|
+
export declare function consumeHandoff(request: Request, cfg: RaybaseHandoffConsumerConfig, hooks?: {
|
|
72
|
+
onPrincipal?(principal: RaybaseHandoffPrincipal): Promise<string | void>;
|
|
73
|
+
}): Promise<Response>;
|
|
74
|
+
/**
|
|
75
|
+
* The gate: null admits the request, a Response refuses it. Navigations bounce
|
|
76
|
+
* to the hub's authorize endpoint; everything else gets a 401 naming it.
|
|
77
|
+
*/
|
|
78
|
+
export declare function requireHandoff(request: Request, cfg: RaybaseHandoffConsumerConfig): Promise<Response | null>;
|
|
79
|
+
//# sourceMappingURL=handoff-consumer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-consumer.d.ts","sourceRoot":"","sources":["../src/handoff-consumer.ts"],"names":[],"mappings":"AAOA;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,qEAAqE;AACrE,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,uBAAuB,EAAE,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,4BAA4B,GAAG;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,gFAAgF;IAChF,OAAO,EAAE,oBAAoB,EAAE,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qBAAqB,CAAC,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,IAAI,EAAE,2BAA2B,CAAC;IAClC,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAeF,iFAAiF;AACjF,eAAO,MAAM,sBAAsB,0BAA0B,CAAC;AAyG9D,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,SAAoB,GAAG,MAAM,GAAG,IAAI,CAGnG;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAmD3H;AAED,gFAAgF;AAChF,wBAAsB,aAAa,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAIhI;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,GAAG,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAE,GAChF,MAAM,CAaR;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,4BAA4B,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAM/G;AAUD,6EAA6E;AAC7E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAK7D;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,4BAA4B,EACjC,KAAK,CAAC,EAAE;IAAE,WAAW,CAAC,CAAC,SAAS,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;CAAE,GACnF,OAAO,CAAC,QAAQ,CAAC,CAkCnB;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,4BAA4B,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAkBlH"}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// The resource side of the handoff. This module runs inside arbitrary Workers
|
|
2
|
+
// (an Astro site, a preview deploy, a third party's edge worker), so it imports
|
|
3
|
+
// `jose` and nothing else — no other Core module, no Node API. `jose` is a
|
|
4
|
+
// direct dependency of @raybase/core precisely so JWS/JWK correctness is
|
|
5
|
+
// amortized across every consumer instead of re-implemented per resource.
|
|
6
|
+
import { createRemoteJWKSet, customFetch, decodeJwt, importJWK, jwtVerify } from "jose";
|
|
7
|
+
const defaultCookieName = "raybase_handoff";
|
|
8
|
+
/** The nonce that binds a consume URL to the browser that started the bounce. */
|
|
9
|
+
export const handoffStateCookieName = "raybase_handoff_state";
|
|
10
|
+
const defaultClockToleranceSeconds = 30;
|
|
11
|
+
const stateMaxAgeSeconds = 600;
|
|
12
|
+
const localHttpHosts = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
|
|
13
|
+
const hubIssuerKinds = ["sso", "pass"];
|
|
14
|
+
const secondaryIssuerKinds = ["link", "machine"];
|
|
15
|
+
// A lookup object would answer for "constructor" and every other inherited
|
|
16
|
+
// key, so the mapping is a switch and nothing else.
|
|
17
|
+
function principalKindFor(kind) {
|
|
18
|
+
switch (kind) {
|
|
19
|
+
case "sso":
|
|
20
|
+
case "pass":
|
|
21
|
+
return "identity";
|
|
22
|
+
case "link":
|
|
23
|
+
return "link";
|
|
24
|
+
case "machine":
|
|
25
|
+
return "machine";
|
|
26
|
+
default:
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const remoteKeySets = new Map();
|
|
31
|
+
const pinnedKeys = new Map();
|
|
32
|
+
function trimIssuer(issuer) {
|
|
33
|
+
return issuer.replace(/\/$/, "");
|
|
34
|
+
}
|
|
35
|
+
/** Freshness for a key set whose issuer states none of its own. The hub
|
|
36
|
+
* sends `max-age=300`; this only covers an issuer that says nothing. */
|
|
37
|
+
const defaultJwksMaxAgeSeconds = 300;
|
|
38
|
+
/**
|
|
39
|
+
* Fetches a key set through the edge cache when there is one.
|
|
40
|
+
*
|
|
41
|
+
* `jose` caches a fetched key set on the `createRemoteJWKSet` closure, which
|
|
42
|
+
* lives exactly as long as the isolate holding it. On a busy resource that
|
|
43
|
+
* is free; on a quiet one nearly every request arrives at a fresh isolate
|
|
44
|
+
* and re-fetches the issuer's JWKS before it can verify a single token —
|
|
45
|
+
* synchronously, on the critical path, at whatever the issuer's own latency
|
|
46
|
+
* happens to be. Measured against `itself-hub`, that put 2.3–3.9 s in front
|
|
47
|
+
* of every artifact a signed-in reader opened, and the key had not changed
|
|
48
|
+
* in days.
|
|
49
|
+
*
|
|
50
|
+
* The colo cache is the missing lifetime: shared by every isolate in the
|
|
51
|
+
* location, invisible to a rotation for no longer than the issuer's own
|
|
52
|
+
* `Cache-Control` allows. A rotation therefore heals on its own within that
|
|
53
|
+
* window rather than needing a redeploy, which is why this is a cache and
|
|
54
|
+
* not a pin.
|
|
55
|
+
*
|
|
56
|
+
* Where there is no `caches` — Node, a test runner, a non-Workers host —
|
|
57
|
+
* this is exactly `fetch`, and a cache that refuses a response is not an
|
|
58
|
+
* error: the fetch already succeeded, and the only thing lost is the
|
|
59
|
+
* saving.
|
|
60
|
+
*/
|
|
61
|
+
const cachingJwksFetch = async (input, init) => {
|
|
62
|
+
const request = new Request(input, init);
|
|
63
|
+
const store = globalThis.caches?.default;
|
|
64
|
+
if (!store || request.method !== "GET")
|
|
65
|
+
return await fetch(request);
|
|
66
|
+
const hit = await store.match(request).catch(() => undefined);
|
|
67
|
+
if (hit)
|
|
68
|
+
return hit;
|
|
69
|
+
const response = await fetch(request);
|
|
70
|
+
if (!response.ok)
|
|
71
|
+
return response;
|
|
72
|
+
const cacheable = new Response(response.body, response);
|
|
73
|
+
if (!cacheable.headers.has("cache-control")) {
|
|
74
|
+
cacheable.headers.set("cache-control", `public, max-age=${defaultJwksMaxAgeSeconds}`);
|
|
75
|
+
}
|
|
76
|
+
await store.put(request, cacheable.clone()).catch(() => undefined);
|
|
77
|
+
return cacheable;
|
|
78
|
+
};
|
|
79
|
+
function remoteKeySet(url) {
|
|
80
|
+
let keySet = remoteKeySets.get(url);
|
|
81
|
+
if (!keySet) {
|
|
82
|
+
keySet = createRemoteJWKSet(new URL(url), { [customFetch]: cachingJwksFetch });
|
|
83
|
+
remoteKeySets.set(url, keySet);
|
|
84
|
+
}
|
|
85
|
+
return keySet;
|
|
86
|
+
}
|
|
87
|
+
function pinnedKey(jwk) {
|
|
88
|
+
const cacheKey = JSON.stringify(jwk);
|
|
89
|
+
let key = pinnedKeys.get(cacheKey);
|
|
90
|
+
if (!key) {
|
|
91
|
+
key = importJWK(jwk, "ES256");
|
|
92
|
+
pinnedKeys.set(cacheKey, key);
|
|
93
|
+
}
|
|
94
|
+
return key;
|
|
95
|
+
}
|
|
96
|
+
// Everything exported below is deliberate public API for resource owners:
|
|
97
|
+
// most resources mount consumeHandoff/requireHandoff, but a Worker that gates
|
|
98
|
+
// its own way composes extractHandoffToken, verifyHandoffToken,
|
|
99
|
+
// isHandoffNavigation, handoffAuthorizeUrl and serializeHandoffCookie itself.
|
|
100
|
+
function readCookie(request, name) {
|
|
101
|
+
const cookie = request.headers.get("cookie") ?? "";
|
|
102
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
103
|
+
const match = cookie.match(new RegExp(`(?:^|;\\s*)${escaped}=([^;]+)`));
|
|
104
|
+
return match?.[1] ? decodeURIComponent(match[1]) : null;
|
|
105
|
+
}
|
|
106
|
+
/** A bearer beats a cookie: a caller that names its token means it. */
|
|
107
|
+
export function extractHandoffToken(request, cookieName = defaultCookieName) {
|
|
108
|
+
const bearer = request.headers.get("authorization")?.match(/^Bearer\s+(.+)$/i)?.[1]?.trim();
|
|
109
|
+
return bearer || readCookie(request, cookieName);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Verify a handoff token against the configured issuers. The unverified `iss`
|
|
113
|
+
* claim only selects which configured key to verify against; an issuer that is
|
|
114
|
+
* not listed is rejected before any signature check.
|
|
115
|
+
*/
|
|
116
|
+
export async function verifyHandoffToken(token, cfg) {
|
|
117
|
+
if (!cfg.resource)
|
|
118
|
+
throw new Error("Handoff consumer config requires a resource id");
|
|
119
|
+
if (!cfg.issuers?.length)
|
|
120
|
+
throw new Error("Handoff consumer config requires at least one issuer");
|
|
121
|
+
let claimedIssuer;
|
|
122
|
+
try {
|
|
123
|
+
claimedIssuer = trimIssuer(String(decodeJwt(token).iss ?? ""));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
throw new Error("Handoff token is malformed");
|
|
127
|
+
}
|
|
128
|
+
const index = cfg.issuers.findIndex((candidate) => trimIssuer(candidate.issuer) === claimedIssuer);
|
|
129
|
+
if (index < 0)
|
|
130
|
+
throw new Error(`Handoff token issuer "${claimedIssuer}" is not a configured issuer`);
|
|
131
|
+
const issuer = cfg.issuers[index];
|
|
132
|
+
const options = {
|
|
133
|
+
issuer: trimIssuer(issuer.issuer),
|
|
134
|
+
audience: `raybase-handoff:${cfg.resource}`,
|
|
135
|
+
clockTolerance: cfg.clockToleranceSeconds ?? defaultClockToleranceSeconds
|
|
136
|
+
};
|
|
137
|
+
const { payload } = issuer.publicJwk
|
|
138
|
+
? await jwtVerify(token, await pinnedKey(issuer.publicJwk), options)
|
|
139
|
+
: await jwtVerify(token, remoteKeySet(issuer.jwks ?? `${trimIssuer(issuer.issuer)}/.well-known/jwks.json`), options);
|
|
140
|
+
if (payload.resource !== cfg.resource)
|
|
141
|
+
throw new Error("Handoff token names a different resource");
|
|
142
|
+
if (!payload.sub)
|
|
143
|
+
throw new Error("Handoff token is missing a subject");
|
|
144
|
+
if (!payload.jti)
|
|
145
|
+
throw new Error("Handoff token is missing a token id");
|
|
146
|
+
if (typeof payload.exp !== "number")
|
|
147
|
+
throw new Error("Handoff token is missing an expiry");
|
|
148
|
+
// What this issuer is allowed to say, before anything is made of what it said.
|
|
149
|
+
const allowedKinds = issuer.kinds ?? (index === 0 ? hubIssuerKinds : secondaryIssuerKinds);
|
|
150
|
+
if (typeof payload.kind !== "string" || !allowedKinds.includes(payload.kind)) {
|
|
151
|
+
throw new Error(`Handoff token issuer "${claimedIssuer}" may not mint kind "${String(payload.kind)}"`);
|
|
152
|
+
}
|
|
153
|
+
const kind = principalKindFor(payload.kind);
|
|
154
|
+
if (!kind)
|
|
155
|
+
throw new Error(`Handoff token has an unknown kind "${payload.kind}"`);
|
|
156
|
+
// The hard rule: a pass never carries roles and never enrolls anyone. Roles
|
|
157
|
+
// ride only on the SSO front channel, where a membership backs them.
|
|
158
|
+
if (payload.roles !== undefined && payload.kind !== "sso")
|
|
159
|
+
throw new Error("Handoff token carries roles but is not an SSO handoff");
|
|
160
|
+
return {
|
|
161
|
+
kind,
|
|
162
|
+
sub: payload.sub,
|
|
163
|
+
...(payload.email ? { email: payload.email } : {}),
|
|
164
|
+
...(payload.email_verified === undefined ? {} : { emailVerified: payload.email_verified === true }),
|
|
165
|
+
...(payload.name ? { name: payload.name } : {}),
|
|
166
|
+
...(payload.kind === "sso" ? { roles: Array.isArray(payload.roles) ? payload.roles.map(String) : [] } : {}),
|
|
167
|
+
...(payload.appId ? { appId: payload.appId } : {}),
|
|
168
|
+
resource: cfg.resource,
|
|
169
|
+
issuer: trimIssuer(issuer.issuer),
|
|
170
|
+
exp: payload.exp,
|
|
171
|
+
jti: payload.jti
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** The request's principal, or null when it carries no usable handoff token. */
|
|
175
|
+
export async function verifyHandoff(request, cfg) {
|
|
176
|
+
const token = extractHandoffToken(request, cfg.cookieName ?? defaultCookieName);
|
|
177
|
+
if (!token)
|
|
178
|
+
return null;
|
|
179
|
+
return await verifyHandoffToken(token, cfg).catch(() => null);
|
|
180
|
+
}
|
|
181
|
+
export function serializeHandoffCookie(value, options) {
|
|
182
|
+
const requestUrl = typeof options.requestUrl === "string" ? new URL(options.requestUrl) : options.requestUrl;
|
|
183
|
+
const attributes = [
|
|
184
|
+
`${options.cookieName ?? defaultCookieName}=${encodeURIComponent(value)}`,
|
|
185
|
+
"Path=/",
|
|
186
|
+
`Max-Age=${Math.max(0, Math.trunc(options.maxAgeSeconds))}`,
|
|
187
|
+
"HttpOnly"
|
|
188
|
+
];
|
|
189
|
+
if (!(requestUrl.protocol === "http:" && localHttpHosts.has(requestUrl.hostname)))
|
|
190
|
+
attributes.push("Secure");
|
|
191
|
+
// Lax, not Strict: the hub's 302 back into the resource is a cross-site
|
|
192
|
+
// top-level navigation and must arrive carrying the cookie just set.
|
|
193
|
+
attributes.push("SameSite=Lax");
|
|
194
|
+
return attributes.join("; ");
|
|
195
|
+
}
|
|
196
|
+
export function handoffAuthorizeUrl(request, cfg, state) {
|
|
197
|
+
const url = new URL("/api/handoff/authorize", cfg.hub);
|
|
198
|
+
url.searchParams.set("resource", cfg.resource);
|
|
199
|
+
url.searchParams.set("return", request.url);
|
|
200
|
+
if (state)
|
|
201
|
+
url.searchParams.set("state", state);
|
|
202
|
+
return url.toString();
|
|
203
|
+
}
|
|
204
|
+
/** 32 random bytes, base64url: the nonce the hub echoes back through consume. */
|
|
205
|
+
function newHandoffState() {
|
|
206
|
+
const bytes = crypto.getRandomValues(new Uint8Array(32));
|
|
207
|
+
let binary = "";
|
|
208
|
+
for (const byte of bytes)
|
|
209
|
+
binary += String.fromCharCode(byte);
|
|
210
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
211
|
+
}
|
|
212
|
+
/** A top-level navigation, which can be bounced; anything else gets JSON. */
|
|
213
|
+
export function isHandoffNavigation(request) {
|
|
214
|
+
if (request.method !== "GET" && request.method !== "HEAD")
|
|
215
|
+
return false;
|
|
216
|
+
const mode = request.headers.get("sec-fetch-mode")?.toLowerCase();
|
|
217
|
+
if (mode)
|
|
218
|
+
return mode === "navigate";
|
|
219
|
+
return (request.headers.get("accept")?.toLowerCase() ?? "").includes("text/html");
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* The consume route handler: verify the token the hub redirected with, set the
|
|
223
|
+
* resource's own cookie, and send the visitor on to where they were going.
|
|
224
|
+
*/
|
|
225
|
+
export async function consumeHandoff(request, cfg, hooks) {
|
|
226
|
+
const url = new URL(request.url);
|
|
227
|
+
const token = url.searchParams.get("token");
|
|
228
|
+
if (!token)
|
|
229
|
+
return handoffJson({ error: "handoff_token_missing" }, 400);
|
|
230
|
+
// A consume URL is only good in the browser that started the bounce: the
|
|
231
|
+
// nonce this resource minted must come back in both the query and its own
|
|
232
|
+
// cookie. Without it, a token captured or planted anywhere would sign the
|
|
233
|
+
// visitor in as somebody else the moment they followed a link.
|
|
234
|
+
const state = url.searchParams.get("state");
|
|
235
|
+
const expectedState = readCookie(request, handoffStateCookieName);
|
|
236
|
+
if (!state || !expectedState || state.length !== expectedState.length || state !== expectedState) {
|
|
237
|
+
return handoffJson({ error: "handoff_state_mismatch" }, 401);
|
|
238
|
+
}
|
|
239
|
+
let principal;
|
|
240
|
+
try {
|
|
241
|
+
principal = await verifyHandoffToken(token, cfg);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// Never echo token internals back to the browser: a failed consume is a
|
|
245
|
+
// stale or forged token and the visitor's next step is the bounce.
|
|
246
|
+
return handoffJson({ error: "handoff_token_invalid" }, 401);
|
|
247
|
+
}
|
|
248
|
+
const fallback = safeHandoffPath(cfg.returnTo, "/");
|
|
249
|
+
const override = await hooks?.onPrincipal?.(principal);
|
|
250
|
+
const location = safeHandoffPath(override ?? url.searchParams.get("return"), fallback);
|
|
251
|
+
// Real time, not the app clock: the cookie must die with the token, and the
|
|
252
|
+
// token's expiry was signed against the wall clock.
|
|
253
|
+
const maxAgeSeconds = principal.exp - Math.floor(Date.now() / 1000);
|
|
254
|
+
const headers = new Headers({ location, "cache-control": "no-store", "referrer-policy": "no-referrer" });
|
|
255
|
+
headers.append("set-cookie", serializeHandoffCookie(token, { cookieName: cfg.cookieName, requestUrl: url, maxAgeSeconds }));
|
|
256
|
+
headers.append("set-cookie", serializeHandoffCookie("", { cookieName: handoffStateCookieName, requestUrl: url, maxAgeSeconds: 0 }));
|
|
257
|
+
return new Response(null, { status: 302, headers });
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* The gate: null admits the request, a Response refuses it. Navigations bounce
|
|
261
|
+
* to the hub's authorize endpoint; everything else gets a 401 naming it.
|
|
262
|
+
*/
|
|
263
|
+
export async function requireHandoff(request, cfg) {
|
|
264
|
+
if (await verifyHandoff(request, cfg))
|
|
265
|
+
return null;
|
|
266
|
+
// The nonce goes out with the bounce and comes home through consume, which
|
|
267
|
+
// is what ties the round trip to this browser.
|
|
268
|
+
const state = newHandoffState();
|
|
269
|
+
const authorize = handoffAuthorizeUrl(request, cfg, state);
|
|
270
|
+
const stateCookie = serializeHandoffCookie(state, {
|
|
271
|
+
cookieName: handoffStateCookieName,
|
|
272
|
+
requestUrl: new URL(request.url),
|
|
273
|
+
maxAgeSeconds: stateMaxAgeSeconds
|
|
274
|
+
});
|
|
275
|
+
if (isHandoffNavigation(request)) {
|
|
276
|
+
return new Response(null, {
|
|
277
|
+
status: 302,
|
|
278
|
+
headers: { location: authorize, "set-cookie": stateCookie, "cache-control": "no-store", "referrer-policy": "no-referrer" }
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
return handoffJson({ error: "handoff_required", authorize }, 401, stateCookie);
|
|
282
|
+
}
|
|
283
|
+
function handoffJson(body, status, setCookie) {
|
|
284
|
+
const headers = new Headers({ "content-type": "application/json", "cache-control": "no-store" });
|
|
285
|
+
if (setCookie)
|
|
286
|
+
headers.append("set-cookie", setCookie);
|
|
287
|
+
return new Response(JSON.stringify(body), { status, headers });
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* The canonical Raybase path rule, and the only place it is spelled out: a
|
|
291
|
+
* single leading slash, no backslash, and no control character at all. The
|
|
292
|
+
* WHATWG URL parser strips TAB/CR/LF before parsing, so "/\t//evil.example"
|
|
293
|
+
* would otherwise reach a browser as a protocol-relative URL and leave the
|
|
294
|
+
* resource entirely.
|
|
295
|
+
*/
|
|
296
|
+
const handoffPathPattern = /^\/(?!\/)[^\\\x00-\x1f\x7f]*$/;
|
|
297
|
+
function safeHandoffPath(value, fallback) {
|
|
298
|
+
return typeof value === "string" && handoffPathPattern.test(value) ? value : fallback;
|
|
299
|
+
}
|
|
300
|
+
//# sourceMappingURL=handoff-consumer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff-consumer.js","sourceRoot":"","sources":["../src/handoff-consumer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { RaybaseConfig } from "./schema.js";
|
|
2
|
+
import type { RaybaseHandoffTokenKind } from "./handoff-consumer.js";
|
|
3
|
+
import type { RaybaseUser } from "./policies.js";
|
|
4
|
+
export type RaybaseHandoffResourceConfig = NonNullable<RaybaseConfig["handoff"]>["resources"][number];
|
|
5
|
+
/** What a registered resource is: a thing you belong to, or a thing you are shown. */
|
|
6
|
+
export type RaybaseHandoffKind = Extract<RaybaseHandoffTokenKind, "sso" | "pass">;
|
|
7
|
+
export type { RaybaseHandoffTokenKind };
|
|
8
|
+
export type RaybaseHandoffJwtPayload = {
|
|
9
|
+
iss: string;
|
|
10
|
+
aud: string;
|
|
11
|
+
sub: string;
|
|
12
|
+
email: string;
|
|
13
|
+
email_verified: boolean;
|
|
14
|
+
name: string;
|
|
15
|
+
appId?: string;
|
|
16
|
+
resource: string;
|
|
17
|
+
kind: RaybaseHandoffTokenKind;
|
|
18
|
+
/** Present only for `kind: "sso"`. A pass never carries roles. */
|
|
19
|
+
roles?: string[];
|
|
20
|
+
iat: number;
|
|
21
|
+
exp: number;
|
|
22
|
+
jti: string;
|
|
23
|
+
};
|
|
24
|
+
type JsonWebKeyRecord = JsonWebKey & Record<string, unknown>;
|
|
25
|
+
export declare function handoffEnabled(config: RaybaseConfig): boolean;
|
|
26
|
+
export declare function handoffTokenTtlSeconds(config: RaybaseConfig): number;
|
|
27
|
+
export declare function handoffResourceById(config: RaybaseConfig, id: string): RaybaseHandoffResourceConfig | null;
|
|
28
|
+
/**
|
|
29
|
+
* The `iss` the hub signs with. Configure `handoff.issuer` when the hub is
|
|
30
|
+
* reachable under more than one hostname: consumers pin one issuer string, so
|
|
31
|
+
* whichever hostname a visitor arrived on, the token must say the same thing.
|
|
32
|
+
*/
|
|
33
|
+
export declare function handoffIssuer(config: RaybaseConfig, requestOrigin: string): string;
|
|
34
|
+
export declare function handoffResourceConsumePath(resource: RaybaseHandoffResourceConfig): string;
|
|
35
|
+
export declare function handoffResourceOriginForEnv(config: RaybaseConfig, resource: RaybaseHandoffResourceConfig, env: {
|
|
36
|
+
RAYBASE_SITE_ORIGIN?: string;
|
|
37
|
+
}): string;
|
|
38
|
+
/**
|
|
39
|
+
* Every issue that would make the registry unusable at runtime. Called by the
|
|
40
|
+
* worker factory (so a bad registry fails loudly at startup) and by
|
|
41
|
+
* `raybase doctor`.
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateHandoffConfig(config: RaybaseConfig): string[];
|
|
44
|
+
export declare function parseHandoffPrivateJwk(raw: string | undefined): JsonWebKeyRecord;
|
|
45
|
+
export declare function publicJwkFromPrivate(raw: string | undefined): Promise<JsonWebKeyRecord>;
|
|
46
|
+
export declare function handoffJwks(raw: string | undefined): Promise<{
|
|
47
|
+
keys: JsonWebKeyRecord[];
|
|
48
|
+
}>;
|
|
49
|
+
export declare function signHandoffToken(input: {
|
|
50
|
+
privateJwk: string | undefined;
|
|
51
|
+
issuer: string;
|
|
52
|
+
resource: RaybaseHandoffResourceConfig;
|
|
53
|
+
user: RaybaseUser;
|
|
54
|
+
appId?: string;
|
|
55
|
+
ttlSeconds: number;
|
|
56
|
+
}): Promise<{
|
|
57
|
+
token: string;
|
|
58
|
+
payload: RaybaseHandoffJwtPayload;
|
|
59
|
+
expiresAt: string;
|
|
60
|
+
}>;
|
|
61
|
+
export declare function handoffConsumeUrl(resource: RaybaseHandoffResourceConfig, origin: string, token: string, returnTo: string, state?: string): string;
|
|
62
|
+
/** Path-only, so a return value can never send a browser off the resource. */
|
|
63
|
+
export declare function sanitizeHandoffReturnTo(value: unknown, fallback: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* Reduce a caller-supplied return target to a path on the resource. An absolute
|
|
66
|
+
* URL is accepted only when it is on the resource's own origin, so the bounce
|
|
67
|
+
* can hand back the URL the visitor actually asked for.
|
|
68
|
+
*/
|
|
69
|
+
export declare function handoffReturnPath(resource: RaybaseHandoffResourceConfig, origin: string, value: unknown): string;
|
|
70
|
+
//# sourceMappingURL=handoff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handoff.d.ts","sourceRoot":"","sources":["../src/handoff.ts"],"names":[],"mappings":"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"}
|