@undefineds.co/xpod 0.4.3 → 0.4.5
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/config/cloud.json +1 -1
- package/config/main.json +36 -2
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.d.ts +3 -0
- package/dist/api/ai-gateway/auth/GatewayApiKeyAuthenticator.js +1 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.d.ts +2 -1
- package/dist/api/ai-gateway/auth/PodGatewayAccessKeyRepository.js +101 -32
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.d.ts +80 -0
- package/dist/api/ai-gateway/connect/DeviceCodeProtocol.js +3 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.d.ts +38 -0
- package/dist/api/ai-gateway/connect/FileSessionImportAdapter.js +63 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.d.ts +24 -0
- package/dist/api/ai-gateway/connect/LoopbackAuthorizationCallbackReceiver.js +136 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/connect/OAuthConnectAdapter.js +2 -1
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.d.ts +17 -13
- package/dist/api/ai-gateway/connect/OAuthIntegrationRegistry.js +52 -19
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.d.ts +4 -28
- package/dist/api/ai-gateway/connect/OpenAiSubscriptionSessionImportAdapter.js +7 -58
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.d.ts +4 -0
- package/dist/api/ai-gateway/connect/ProviderAuthorizationProfiles.js +116 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.d.ts +10 -0
- package/dist/api/ai-gateway/connect/SessionImportProfiles.js +112 -0
- package/dist/api/ai-gateway/connect/index.d.ts +125 -23
- package/dist/api/ai-gateway/connect/index.js +1277 -260
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.d.ts +4 -1
- package/dist/api/ai-gateway/models/PodModelSelectionRepository.js +154 -19
- package/dist/api/ai-gateway/providers/DeepSeekRuntimeAdapter.js +10 -6
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.d.ts +7 -0
- package/dist/api/ai-gateway/providers/ModelsDevCatalog.js +25 -1
- package/dist/api/ai-gateway/providers/OfferingAuthorization.d.ts +24 -0
- package/dist/api/ai-gateway/providers/OfferingAuthorization.js +37 -0
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.d.ts +1 -1
- package/dist/api/ai-gateway/providers/OpenAiRuntimeAdapter.js +5 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.d.ts +6 -3
- package/dist/api/ai-gateway/providers/ProviderRegistry.js +55 -16
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.d.ts +2 -0
- package/dist/api/ai-gateway/providers/ProviderRuntimeAdapter.js +37 -4
- package/dist/api/ai-gateway/providers/ProviderRuntimeRegistry.js +7 -0
- package/dist/api/ai-gateway/quota/SubscriptionQuotaAdapters.js +2 -1
- package/dist/api/ai-gateway/routing/ModelRouter.js +3 -1
- package/dist/api/container/common.js +30 -40
- package/dist/api/container/index.js +6 -2
- package/dist/api/container/routes.js +5 -22
- package/dist/api/handlers/AiClientConfigurationHandler.js +39 -1
- package/dist/api/handlers/AiGatewayManagementHandler.d.ts +3 -0
- package/dist/api/handlers/AiGatewayManagementHandler.js +173 -58
- package/dist/api/service/AiClientConfigurationService.d.ts +4 -15
- package/dist/api/service/AiClientConfigurationService.js +17 -64
- package/dist/cli/commands/start.js +2 -0
- package/dist/components/components.jsonld +1 -0
- package/dist/components/context.jsonld +80 -0
- package/dist/http/InternalPodDataHttpHandler.d.ts +3 -0
- package/dist/http/InternalPodDataHttpHandler.js +13 -2
- package/dist/http/InternalPodDataHttpHandler.jsonld +12 -0
- package/dist/identity/oidc/RememberedClientPromptFactory.d.ts +1 -1
- package/dist/identity/oidc/RememberedClientPromptFactory.js +5 -2
- package/dist/identity/oidc/RememberedConsentHandler.js +1 -1
- package/dist/identity/oidc/ScopedPickWebIdHandler.d.ts +1 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.js +26 -0
- package/dist/identity/oidc/ScopedPickWebIdHandler.jsonld +4 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.d.ts +10 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.js +21 -0
- package/dist/identity/oidc/SessionBoundIdentityProviderFactory.jsonld +172 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +4 -2
- package/dist/runtime/component-parameter-keys.js +18 -2
- package/dist/storage/accessors/MixDataAccessor.js +6 -2
- package/dist/storage/rdf/PostgresRdfEngine.js +10 -2
- package/dist/storage/rdf/RdfContentTypes.js +4 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.d.ts +3 -0
- package/node_modules/@undefineds.co/ai-connections/dist/AiClientConfigurationSection.js +13 -16
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsList.js +1 -3
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.d.ts +2 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsMain.js +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiConnectionsPanel.js +127 -57
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiCredentialPoolSection.js +436 -83
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.d.ts +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/AiGatewayKeysSection.js +212 -76
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.d.ts +6 -4
- package/node_modules/@undefineds.co/ai-connections/dist/AiProviderCard.js +58 -41
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.d.ts +4 -1
- package/node_modules/@undefineds.co/ai-connections/dist/AiQuotaCard.js +63 -4
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.d.ts +46 -6
- package/node_modules/@undefineds.co/ai-connections/dist/ai-connections-client.js +143 -14
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.d.ts +19 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/base-adapter.js +45 -7
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.d.ts +7 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/codex.js +305 -40
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/index.cjs +383 -50
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/json-env-adapter.js +3 -2
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/pi.js +12 -3
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/transaction.js +39 -4
- package/node_modules/@undefineds.co/ai-connections/dist/client-config/types.d.ts +8 -1
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.d.ts +2 -0
- package/node_modules/@undefineds.co/ai-connections/dist/client-visuals.js +14 -0
- package/node_modules/@undefineds.co/ai-connections/dist/controller.d.ts +2 -2
- package/node_modules/@undefineds.co/ai-connections/dist/controller.js +216 -57
- package/node_modules/@undefineds.co/ai-connections/dist/index.d.ts +3 -1
- package/node_modules/@undefineds.co/ai-connections/dist/index.js +16 -2
- package/node_modules/@undefineds.co/ai-connections/dist/provider-visuals.js +6 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/execution/ldp-executor.js +27 -6
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/query-builders/select-query-builder.js +2 -2
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/sparql/builder/update-builder.js +12 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/builder.js +1 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/array.js +8 -0
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/default.js +9 -1
- package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/triple/handlers/inline.js +3 -3
- package/node_modules/@undefineds.co/extension-sdk/dist/web.d.ts +31 -0
- package/package.json +2 -2
- package/static/app/assets/{index-BikOyGPu.js → index-BCZVzMpj.js} +44 -44
- package/static/app/assets/inrupt-smoke.js +2 -2
- package/static/app/assets/main.css +1 -1
- package/static/app/assets/main.js +10 -10
- package/static/auth-callback/assets/{AiConfigContext-DrCH6ckh.js → AiConfigContext-DVkh8Kg2.js} +1 -1
- package/static/auth-callback/assets/{AiConfigPage-DVrlSSdA.js → AiConfigPage-HWVWpe-P.js} +1 -1
- package/static/auth-callback/assets/{DocumentProcessingPanel-_Md-v2R2.js → DocumentProcessingPanel-DDq-mH17.js} +1 -1
- package/static/auth-callback/assets/{IndexLifecyclePanel-BbWwe23H.js → IndexLifecyclePanel-Cx4cjrdP.js} +1 -1
- package/static/auth-callback/assets/{IndexSubjectPanel-upH9MjU-.js → IndexSubjectPanel-DzSw8M9j.js} +1 -1
- package/static/auth-callback/assets/{ModelAssignmentsPanel-CVGH4t4g.js → ModelAssignmentsPanel-BsRxGc2p.js} +1 -1
- package/static/auth-callback/assets/ModelsPage-DEe1lo6Q.js +10 -0
- package/static/auth-callback/assets/{NetworkPage-Dcbrb1fd.js → NetworkPage-DBiEh1Oz.js} +1 -1
- package/static/auth-callback/assets/{PaneListHeader-DrY-1wBq.js → PaneListHeader-lEEgjyN9.js} +1 -1
- package/static/auth-callback/assets/{SearchIndexingPanel-Dw25y53v.js → SearchIndexingPanel-CZCUUGt6.js} +1 -1
- package/static/auth-callback/assets/{StatusSubjectPanel-BHlz9rNF.js → StatusSubjectPanel-21qdueMr.js} +1 -1
- package/static/auth-callback/assets/{StatusWorkspace-BH7exQP5.js → StatusWorkspace-R8RKsqVz.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsPage-BYLKnM9f.js → SystemSettingsPage-BQ4e-4Wy.js} +1 -1
- package/static/auth-callback/assets/{SystemSettingsSubjectPanel-DT34LKku.js → SystemSettingsSubjectPanel-BopXD7SE.js} +1 -1
- package/static/auth-callback/assets/{activity-DdULRcSI.js → activity-DSfmTGfY.js} +1 -1
- package/static/auth-callback/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/auth-callback/assets/{auth-callback-D7l2P25I.js → auth-callback-DleaitAS.js} +91 -91
- package/static/auth-callback/assets/auth-callback-vPSC2d2F.css +1 -0
- package/static/auth-callback/assets/{badge-j4zjFnmg.js → badge-B0aLu1sl.js} +1 -1
- package/static/auth-callback/assets/{download-DGXoks01.js → download-D_bFwdYJ.js} +1 -1
- package/static/auth-callback/assets/{external-link-CvbgXXaI.js → external-link-DRfjTaQu.js} +1 -1
- package/static/auth-callback/assets/{index-LRWvKJ2i.js → index-CG23cLYQ.js} +1 -1
- package/static/auth-callback/assets/{index-BOK3j1dz.js → index-CyV9ejwx.js} +1 -1
- package/static/auth-callback/assets/{index-browser-C1Qpe0g4.js → index-browser-D70paxIg.js} +1 -1
- package/static/auth-callback/assets/{key-round-CmgS5UdQ.js → key-round-BjV_mVYH.js} +1 -1
- package/static/auth-callback/assets/{rotate-ccw-c4CSG6Rq.js → rotate-ccw-CKoOAfse.js} +1 -1
- package/static/auth-callback/assets/{skeleton-ZPMTiRSM.js → skeleton-BZNjZaHx.js} +1 -1
- package/static/auth-callback/assets/{waypoints-xjyBflU5.js → waypoints-DoaJVzZv.js} +1 -1
- package/static/auth-callback/assets/{workspace-layout-B9nj6F5J.js → workspace-layout-CaP46_ZR.js} +1 -1
- package/static/auth-callback/auth-callback.html +2 -2
- package/static/dashboard/assets/{AiConfigContext-BWOOSYNr.js → AiConfigContext-BSrR27yD.js} +1 -1
- package/static/dashboard/assets/{AiConfigPage-CG2kQ9Wy.js → AiConfigPage-D65Z2LET.js} +1 -1
- package/static/dashboard/assets/{DocumentProcessingPanel-B4VXajfj.js → DocumentProcessingPanel-DyTe7Nei.js} +1 -1
- package/static/dashboard/assets/{IndexLifecyclePanel-CWCy0CC8.js → IndexLifecyclePanel-fK8ZGlrL.js} +1 -1
- package/static/dashboard/assets/{IndexSubjectPanel-CSgyQnG_.js → IndexSubjectPanel-CZPGor7v.js} +1 -1
- package/static/dashboard/assets/{ModelAssignmentsPanel-CdGIGidT.js → ModelAssignmentsPanel-CfYn5LMQ.js} +1 -1
- package/static/dashboard/assets/ModelsPage-djlJsghe.js +25 -0
- package/static/dashboard/assets/{NetworkPage-COia9NCH.js → NetworkPage-Coj6GnPl.js} +1 -1
- package/static/dashboard/assets/{PaneListHeader-SZWyr602.js → PaneListHeader-CUuFNSsZ.js} +1 -1
- package/static/dashboard/assets/{SearchIndexingPanel-D6PZtG6k.js → SearchIndexingPanel-CyJLioXS.js} +1 -1
- package/static/dashboard/assets/{StatusSubjectPanel-CxRD4kv0.js → StatusSubjectPanel-Cv26GSVC.js} +1 -1
- package/static/dashboard/assets/{StatusWorkspace-D3PfmY9-.js → StatusWorkspace-CDjFrsmB.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsPage-COg1MmMj.js → SystemSettingsPage-BuNOyNoa.js} +1 -1
- package/static/dashboard/assets/{SystemSettingsSubjectPanel-BSVVB9Ol.js → SystemSettingsSubjectPanel-B2dasdez.js} +1 -1
- package/static/dashboard/assets/{activity-BJJx5cN-.js → activity-D1d2j_4Z.js} +1 -1
- package/static/dashboard/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/dashboard/assets/{badge-elmrFSCj.js → badge-BeAAv6sp.js} +1 -1
- package/static/dashboard/assets/{dashboard-IvQrNmru.js → dashboard-BnGrUGv8.js} +68 -68
- package/static/dashboard/assets/dashboard-vPSC2d2F.css +1 -0
- package/static/dashboard/assets/{download-C3FH2KzG.js → download-DfFGiZRn.js} +1 -1
- package/static/dashboard/assets/{external-link-Bx7F0uKb.js → external-link-IsjU_LC9.js} +1 -1
- package/static/dashboard/assets/{index-liRoRIP1.js → index-BWQTucPe.js} +1 -1
- package/static/dashboard/assets/{index-M4-kWiGz.js → index-Dj75OjnW.js} +1 -1
- package/static/dashboard/assets/{key-round-CXg0bKAj.js → key-round-BJ_9wmQ_.js} +1 -1
- package/static/dashboard/assets/{rotate-ccw-yxJKOBrX.js → rotate-ccw-D3JGiFbR.js} +1 -1
- package/static/dashboard/assets/{skeleton-x9jNGrQT.js → skeleton-CC4nc-z-.js} +1 -1
- package/static/dashboard/assets/{waypoints-CTKeRsGp.js → waypoints-h7sqFqiG.js} +1 -1
- package/static/dashboard/assets/{workspace-layout--YkgkS38.js → workspace-layout-ZAPTOHhs.js} +1 -1
- package/static/dashboard/dashboard.html +2 -2
- package/static/settings/assets/{AiConfigContext-CelxXFcQ.js → AiConfigContext-lGkWpvKP.js} +1 -1
- package/static/settings/assets/{AiConfigPage-BaP-EovM.js → AiConfigPage-BbZWIBZq.js} +1 -1
- package/static/settings/assets/{DocumentProcessingPanel-DzLZluFv.js → DocumentProcessingPanel-DvYdjT-V.js} +1 -1
- package/static/settings/assets/{IndexLifecyclePanel-Bzj1-_oI.js → IndexLifecyclePanel-W5OGQZj7.js} +1 -1
- package/static/settings/assets/{IndexSubjectPanel-B263QLUh.js → IndexSubjectPanel-g_Aa5soq.js} +1 -1
- package/static/settings/assets/{ModelAssignmentsPanel-BAdT4UR0.js → ModelAssignmentsPanel-COlMBKXj.js} +1 -1
- package/static/settings/assets/ModelsPage-mApKi-aw.js +10 -0
- package/static/settings/assets/{NetworkPage-BK6a7l4g.js → NetworkPage-BDT05JUq.js} +1 -1
- package/static/settings/assets/{PaneListHeader-BAS2ICPq.js → PaneListHeader-CByhNpMG.js} +1 -1
- package/static/settings/assets/{SearchIndexingPanel-Cb_p-NgW.js → SearchIndexingPanel-BFAyzXls.js} +1 -1
- package/static/settings/assets/{StatusSubjectPanel-CcjqUua6.js → StatusSubjectPanel-Bz_XZ3VU.js} +1 -1
- package/static/settings/assets/{StatusWorkspace-7Ibty3_k.js → StatusWorkspace-CeVypHcW.js} +1 -1
- package/static/settings/assets/{SystemSettingsPage-DPSz4dg4.js → SystemSettingsPage-Dh7cQIfx.js} +1 -1
- package/static/settings/assets/{SystemSettingsSubjectPanel-Cb4HkKT5.js → SystemSettingsSubjectPanel-CSnpciO0.js} +1 -1
- package/static/settings/assets/{activity-Qhsr5Pxu.js → activity-DXz3EfFN.js} +1 -1
- package/static/settings/assets/ai-connections-C03UWyPh.js +1 -0
- package/static/settings/assets/{badge-B1vf2qCl.js → badge-1ZA144i4.js} +1 -1
- package/static/settings/assets/{download-CYNt0aZ-.js → download-CUHimlYa.js} +1 -1
- package/static/settings/assets/{external-link-ClKb39NT.js → external-link-BYHSVj2Z.js} +1 -1
- package/static/settings/assets/{index-y8ew3MLM.js → index-DKPDMdW5.js} +1 -1
- package/static/settings/assets/{index-browser-DJhvgpNI.js → index-browser-BaEFz0e0.js} +1 -1
- package/static/settings/assets/{index-BgiIDSch.js → index-viSgSvbO.js} +1 -1
- package/static/settings/assets/{key-round-5d-DrJz-.js → key-round-COByPOg8.js} +1 -1
- package/static/settings/assets/{rotate-ccw-CHZY7kS5.js → rotate-ccw-BC2EN6cE.js} +1 -1
- package/static/settings/assets/{settings-D5VRWyx6.js → settings-DLH9XUoT.js} +86 -86
- package/static/settings/assets/settings-vPSC2d2F.css +1 -0
- package/static/settings/assets/{skeleton-FNabNxNE.js → skeleton-B0-FOhKL.js} +1 -1
- package/static/settings/assets/{waypoints-BnL_8ljo.js → waypoints-DGMsvqWo.js} +1 -1
- package/static/settings/assets/{workspace-layout-D5q3F59S.js → workspace-layout-B0SVrJIu.js} +1 -1
- package/static/settings/settings.html +2 -2
- package/static/auth-callback/assets/ModelsPage-BpkVFKbf.js +0 -10
- package/static/auth-callback/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/auth-callback/assets/auth-callback-01yz-UDU.css +0 -1
- package/static/dashboard/assets/ModelsPage-Chd5UK0D.js +0 -25
- package/static/dashboard/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/dashboard/assets/dashboard-01yz-UDU.css +0 -1
- package/static/settings/assets/ModelsPage-C0NFa1zq.js +0 -10
- package/static/settings/assets/ai-connections-Bm52UO7Y.js +0 -1
- package/static/settings/assets/settings-01yz-UDU.css +0 -1
package/config/cloud.json
CHANGED
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
"unstructuredDataAccessor": {
|
|
140
140
|
"@id": "urn:undefineds:xpod:RemoteDataAccessor"
|
|
141
141
|
},
|
|
142
|
-
"presignedRedirectEnabled":
|
|
142
|
+
"presignedRedirectEnabled": false,
|
|
143
143
|
"textSearchIndexingEnabled": true,
|
|
144
144
|
"rdfSearchIntentSink": {
|
|
145
145
|
"@id": "urn:undefineds:xpod:RdfSearchIntentSink"
|
package/config/main.json
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
{
|
|
2
|
-
"@context":
|
|
2
|
+
"@context": [
|
|
3
|
+
"https://linkedsoftwaredependencies.org/bundles/npm/@solid/community-server/^8.0.0/components/context.jsonld",
|
|
4
|
+
"https://linkedsoftwaredependencies.org/bundles/npm/@undefineds.co/xpod/^0.0.0/components/context.jsonld"
|
|
5
|
+
],
|
|
3
6
|
"import": [
|
|
4
7
|
"css:config/app/init/static-root.json",
|
|
5
8
|
"css:config/app/main/default.json",
|
|
@@ -67,7 +70,38 @@
|
|
|
67
70
|
"@id": "urn:solid-server:default:IdentityProviderFactory"
|
|
68
71
|
},
|
|
69
72
|
"overrideParameters": {
|
|
70
|
-
"@type": "
|
|
73
|
+
"@type": "SessionBoundIdentityProviderFactory",
|
|
74
|
+
"args_promptFactory": {
|
|
75
|
+
"@id": "urn:solid-server:default:PromptFactory"
|
|
76
|
+
},
|
|
77
|
+
"args_adapterFactory": {
|
|
78
|
+
"@id": "urn:solid-server:default:IdpAdapterFactory"
|
|
79
|
+
},
|
|
80
|
+
"args_baseUrl": {
|
|
81
|
+
"@id": "urn:solid-server:default:variable:baseUrl"
|
|
82
|
+
},
|
|
83
|
+
"args_oidcPath": "/.oidc",
|
|
84
|
+
"args_clientCredentialsStore": {
|
|
85
|
+
"@id": "urn:solid-server:default:ClientCredentialsStore"
|
|
86
|
+
},
|
|
87
|
+
"args_storage": {
|
|
88
|
+
"@id": "urn:solid-server:default:KeyStorage"
|
|
89
|
+
},
|
|
90
|
+
"args_jwkGenerator": {
|
|
91
|
+
"@id": "urn:solid-server:default:JwkGenerator"
|
|
92
|
+
},
|
|
93
|
+
"args_showStackTrace": {
|
|
94
|
+
"@id": "urn:solid-server:default:variable:showStackTrace"
|
|
95
|
+
},
|
|
96
|
+
"args_errorHandler": {
|
|
97
|
+
"@id": "urn:solid-server:default:ErrorHandler"
|
|
98
|
+
},
|
|
99
|
+
"args_responseWriter": {
|
|
100
|
+
"@id": "urn:solid-server:default:ResponseWriter"
|
|
101
|
+
},
|
|
102
|
+
"args_interactionRoute": {
|
|
103
|
+
"@id": "urn:solid-server:default:IndexRoute"
|
|
104
|
+
},
|
|
71
105
|
"config": {
|
|
72
106
|
"extraParams": [
|
|
73
107
|
"provisionCode"
|
|
@@ -5,6 +5,9 @@ import { type GatewayDeployment } from './GatewayApiKey';
|
|
|
5
5
|
import type { InvocationTokenCodec } from './InvocationTokenCodec';
|
|
6
6
|
export interface GatewayAccessKeyRecord {
|
|
7
7
|
id: string;
|
|
8
|
+
/** CSS credentials are saved configuration, never legacy Gateway authentication records. */
|
|
9
|
+
kind?: 'client-credentials';
|
|
10
|
+
credentialResource?: string;
|
|
8
11
|
owner: string;
|
|
9
12
|
secretHash: string;
|
|
10
13
|
deployment: GatewayDeployment;
|
|
@@ -53,7 +53,7 @@ class GatewayApiKeyAuthenticator {
|
|
|
53
53
|
catch (cause) {
|
|
54
54
|
return infrastructureError(cause);
|
|
55
55
|
}
|
|
56
|
-
if (!record) {
|
|
56
|
+
if (!record || record.kind === 'client-credentials') {
|
|
57
57
|
await (0, GatewayApiKey_1.verifyGatewayApiKeySecret)(parsed.secret, await this.dummyHash);
|
|
58
58
|
return invalidGatewayApiKey();
|
|
59
59
|
}
|
|
@@ -64,8 +64,9 @@ export declare class PodGatewayAccessKeyRepository implements GatewayAccessKeyRe
|
|
|
64
64
|
private resolveTrustedFetch;
|
|
65
65
|
private wrapPodFetch;
|
|
66
66
|
private readSecrets;
|
|
67
|
+
private readSecretSnapshot;
|
|
67
68
|
private writeSecret;
|
|
68
69
|
private deleteSecret;
|
|
69
|
-
private
|
|
70
|
+
private mutateSecrets;
|
|
70
71
|
}
|
|
71
72
|
export {};
|
|
@@ -20,6 +20,23 @@ class PodGatewayAccessKeyRepository {
|
|
|
20
20
|
}
|
|
21
21
|
async create(record, context) {
|
|
22
22
|
const { db, resource, fetch, podUrl } = await this.dbForOwner(record.owner, context);
|
|
23
|
+
if (record.kind === 'client-credentials') {
|
|
24
|
+
if (!record.plaintext || !record.credentialResource) {
|
|
25
|
+
throw new Error('client_credentials_registration_incomplete');
|
|
26
|
+
}
|
|
27
|
+
const locator = this.locatorCodec.decode(record.id);
|
|
28
|
+
if (locator?.owner !== record.owner || locator.deployment !== record.deployment) {
|
|
29
|
+
throw new Error('client_credentials_registration_owner_mismatch');
|
|
30
|
+
}
|
|
31
|
+
await this.mutateSecrets(record.owner, podUrl, fetch, (secrets) => {
|
|
32
|
+
secrets.keys[record.id] = {
|
|
33
|
+
kind: 'client-credentials', plaintext: record.plaintext, createdAt: record.createdAt.toISOString(),
|
|
34
|
+
name: record.name, owner: record.owner, deployment: record.deployment,
|
|
35
|
+
credentialResource: record.credentialResource,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
return { ...record, scopes: [], secretHash: '' };
|
|
39
|
+
}
|
|
23
40
|
const valid = models_1.aiGatewayRepository.validateAccessKey(toGatewayAccessKeyInsert(record));
|
|
24
41
|
await db.insert(resource).values(valid).execute();
|
|
25
42
|
if (record.plaintext) {
|
|
@@ -33,19 +50,30 @@ class PodGatewayAccessKeyRepository {
|
|
|
33
50
|
if (!locator) {
|
|
34
51
|
return undefined;
|
|
35
52
|
}
|
|
36
|
-
const { db, resource } = await this.dbForOwner(locator.owner, context);
|
|
53
|
+
const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
|
|
54
|
+
// Legacy authentication reads only its RDF verifier rows. Recoverable CSS
|
|
55
|
+
// credentials belong exclusively to owner-authorized management requests.
|
|
56
|
+
if (!context?.internalPodAccess) {
|
|
57
|
+
const saved = (await this.readSecrets(locator.owner, podUrl, fetch)).keys[id];
|
|
58
|
+
if (saved?.kind === 'client-credentials')
|
|
59
|
+
return clientCredentialRecord(id, locator.owner, saved);
|
|
60
|
+
}
|
|
37
61
|
const row = await db.findById(resource, gatewayAccessKeyStorageId(id));
|
|
38
62
|
return row ? recordFromRow(row) : undefined;
|
|
39
63
|
}
|
|
40
64
|
async listByOwner(owner, context) {
|
|
41
|
-
const { db, listResource } = await this.dbForOwner(owner, context);
|
|
65
|
+
const { db, listResource, fetch, podUrl } = await this.dbForOwner(owner, context);
|
|
66
|
+
const secrets = await this.readSecrets(owner, podUrl, fetch);
|
|
42
67
|
const rows = await db
|
|
43
68
|
.select()
|
|
44
69
|
.from(listResource)
|
|
45
70
|
.where((0, drizzle_solid_1.eq)(listResource.owner, owner))
|
|
46
71
|
.execute();
|
|
47
|
-
|
|
48
|
-
.
|
|
72
|
+
const credentials = Object.entries(secrets.keys)
|
|
73
|
+
.filter(([id]) => this.locatorCodec.decode(id)?.owner === owner)
|
|
74
|
+
.map(([id, saved]) => clientCredentialRecord(id, owner, saved))
|
|
75
|
+
.filter((record) => Boolean(record));
|
|
76
|
+
return [...rows.map(recordFromRow).filter((record) => secrets.keys[record.id]?.kind !== 'client-credentials'), ...credentials]
|
|
49
77
|
.filter((record) => !record.revokedAt)
|
|
50
78
|
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
|
|
51
79
|
}
|
|
@@ -54,7 +82,10 @@ class PodGatewayAccessKeyRepository {
|
|
|
54
82
|
if (!locator) {
|
|
55
83
|
return undefined;
|
|
56
84
|
}
|
|
57
|
-
const { db, resource } = await this.dbForOwner(locator.owner, context);
|
|
85
|
+
const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
|
|
86
|
+
if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
|
|
87
|
+
throw new Error('client_credentials_suspension_unsupported');
|
|
88
|
+
}
|
|
58
89
|
const row = await db.updateById(resource, gatewayAccessKeyStorageId(id), { disabledAt: enabled ? null : changedAt });
|
|
59
90
|
return row ? recordFromRow(row) : undefined;
|
|
60
91
|
}
|
|
@@ -63,7 +94,10 @@ class PodGatewayAccessKeyRepository {
|
|
|
63
94
|
if (!locator) {
|
|
64
95
|
return undefined;
|
|
65
96
|
}
|
|
66
|
-
const { db, resource } = await this.dbForOwner(locator.owner, context);
|
|
97
|
+
const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
|
|
98
|
+
if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
|
|
99
|
+
throw new Error('client_credentials_revocation_requires_account');
|
|
100
|
+
}
|
|
67
101
|
const row = await db.updateById(resource, gatewayAccessKeyStorageId(id), { revokedAt });
|
|
68
102
|
return row ? recordFromRow(row) : undefined;
|
|
69
103
|
}
|
|
@@ -73,6 +107,12 @@ class PodGatewayAccessKeyRepository {
|
|
|
73
107
|
return false;
|
|
74
108
|
}
|
|
75
109
|
const { db, resource, fetch, podUrl } = await this.dbForOwner(locator.owner, context);
|
|
110
|
+
if ((await this.readSecrets(locator.owner, podUrl, fetch)).keys[id]?.kind === 'client-credentials') {
|
|
111
|
+
// The Account host revokes the actual CSS credential. This operation
|
|
112
|
+
// removes only its saved client configuration, not an authentication row.
|
|
113
|
+
await this.deleteSecret(locator.owner, podUrl, id, fetch);
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
76
116
|
const storageId = gatewayAccessKeyStorageId(id);
|
|
77
117
|
await db.updateById(resource, storageId, { revokedAt: new Date() });
|
|
78
118
|
await this.deleteSecret(locator.owner, podUrl, id, fetch);
|
|
@@ -162,56 +202,85 @@ class PodGatewayAccessKeyRepository {
|
|
|
162
202
|
};
|
|
163
203
|
}
|
|
164
204
|
async readSecrets(owner, podUrl, trustedFetch) {
|
|
205
|
+
return (await this.readSecretSnapshot(owner, podUrl, trustedFetch)).secrets;
|
|
206
|
+
}
|
|
207
|
+
async readSecretSnapshot(owner, podUrl, trustedFetch) {
|
|
165
208
|
const response = await trustedFetch((0, AiConnectionsServiceAccess_1.resolveGatewayAccessKeySecretResourceUrl)(owner, podUrl), {
|
|
166
209
|
method: 'GET',
|
|
167
210
|
headers: { Accept: 'application/json' },
|
|
168
211
|
});
|
|
169
|
-
if (
|
|
170
|
-
return emptySecrets();
|
|
171
|
-
|
|
212
|
+
if (response.status === 404)
|
|
213
|
+
return { secrets: emptySecrets(), exists: false };
|
|
214
|
+
if (!response.ok)
|
|
215
|
+
throw new Error('gateway_key_secret_read_failed');
|
|
172
216
|
const text = (await response.text()).trim();
|
|
173
217
|
if (!text || !response.headers.get('content-type')?.toLowerCase().includes('application/json')) {
|
|
174
|
-
|
|
218
|
+
throw new Error('gateway_key_secret_invalid_document');
|
|
175
219
|
}
|
|
176
220
|
try {
|
|
177
221
|
const parsed = JSON.parse(text);
|
|
178
|
-
if (parsed.version !== 1 || !parsed.keys || typeof parsed.keys !== 'object') {
|
|
179
|
-
|
|
222
|
+
if (parsed.version !== 1 || !parsed.keys || typeof parsed.keys !== 'object' || Array.isArray(parsed.keys)) {
|
|
223
|
+
throw new Error('gateway_key_secret_invalid_document');
|
|
224
|
+
}
|
|
225
|
+
if (Object.values(parsed.keys).some((value) => !value || typeof value !== 'object' || typeof value.plaintext !== 'string')) {
|
|
226
|
+
throw new Error('gateway_key_secret_invalid_document');
|
|
180
227
|
}
|
|
181
228
|
return {
|
|
182
|
-
|
|
183
|
-
|
|
229
|
+
exists: true,
|
|
230
|
+
etag: response.headers.get('etag') ?? undefined,
|
|
231
|
+
secrets: {
|
|
232
|
+
version: 1,
|
|
233
|
+
keys: parsed.keys,
|
|
234
|
+
},
|
|
184
235
|
};
|
|
185
236
|
}
|
|
186
237
|
catch {
|
|
187
|
-
|
|
238
|
+
throw new Error('gateway_key_secret_invalid_document');
|
|
188
239
|
}
|
|
189
240
|
}
|
|
190
241
|
async writeSecret(owner, podUrl, keyId, plaintext, trustedFetch) {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
createdAt: new Date().toISOString(),
|
|
195
|
-
};
|
|
196
|
-
await this.writeSecrets(owner, podUrl, secrets, trustedFetch);
|
|
242
|
+
await this.mutateSecrets(owner, podUrl, trustedFetch, (secrets) => {
|
|
243
|
+
secrets.keys[keyId] = { plaintext, createdAt: new Date().toISOString() };
|
|
244
|
+
});
|
|
197
245
|
}
|
|
198
246
|
async deleteSecret(owner, podUrl, keyId, trustedFetch) {
|
|
199
|
-
|
|
200
|
-
delete secrets.keys[keyId];
|
|
201
|
-
await this.writeSecrets(owner, podUrl, secrets, trustedFetch);
|
|
247
|
+
await this.mutateSecrets(owner, podUrl, trustedFetch, (secrets) => { delete secrets.keys[keyId]; });
|
|
202
248
|
}
|
|
203
|
-
async
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
249
|
+
async mutateSecrets(owner, podUrl, trustedFetch, mutate) {
|
|
250
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
251
|
+
const snapshot = await this.readSecretSnapshot(owner, podUrl, trustedFetch);
|
|
252
|
+
if (snapshot.exists && (!snapshot.etag || !/^"[^"]*"$/u.test(snapshot.etag))) {
|
|
253
|
+
throw new Error('gateway_key_secret_etag_required');
|
|
254
|
+
}
|
|
255
|
+
mutate(snapshot.secrets);
|
|
256
|
+
const response = await trustedFetch((0, AiConnectionsServiceAccess_1.resolveGatewayAccessKeySecretResourceUrl)(owner, podUrl), {
|
|
257
|
+
method: 'PUT',
|
|
258
|
+
headers: {
|
|
259
|
+
'Content-Type': 'application/json',
|
|
260
|
+
...(snapshot.exists ? { 'If-Match': snapshot.etag } : { 'If-None-Match': '*' }),
|
|
261
|
+
},
|
|
262
|
+
body: JSON.stringify(snapshot.secrets, null, 2),
|
|
263
|
+
});
|
|
264
|
+
if (response.status === 412)
|
|
265
|
+
continue;
|
|
266
|
+
if (!response.ok)
|
|
267
|
+
throw new Error('gateway_key_secret_write_failed');
|
|
268
|
+
return;
|
|
211
269
|
}
|
|
270
|
+
throw new Error('gateway_key_secret_write_conflict');
|
|
212
271
|
}
|
|
213
272
|
}
|
|
214
273
|
exports.PodGatewayAccessKeyRepository = PodGatewayAccessKeyRepository;
|
|
274
|
+
function clientCredentialRecord(id, owner, saved) {
|
|
275
|
+
const createdAt = toDate(saved.createdAt);
|
|
276
|
+
if (saved.kind !== 'client-credentials' || saved.owner !== owner || !saved.credentialResource || !createdAt
|
|
277
|
+
|| (saved.deployment !== 'cloud' && saved.deployment !== 'local'))
|
|
278
|
+
return undefined;
|
|
279
|
+
return {
|
|
280
|
+
id, owner, kind: 'client-credentials', credentialResource: saved.credentialResource,
|
|
281
|
+
name: saved.name, createdAt, deployment: saved.deployment, scopes: [], secretHash: '',
|
|
282
|
+
};
|
|
283
|
+
}
|
|
215
284
|
function createDefaultGatewayAccessKeyDb(input) {
|
|
216
285
|
const resource = input.resource ?? models_1.gatewayAccessKeyResource;
|
|
217
286
|
const listResource = input.listResource ?? resource;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export type DeviceCodeHttpBodyEncoding = 'form' | 'json';
|
|
2
|
+
export type DeviceCodeBeginCodec = 'oauthDeviceCode' | 'oauthDeviceCodePkce' | 'deviceCodeJson';
|
|
3
|
+
export type DeviceCodePollCodec = 'oauthDeviceCode' | 'oauthDeviceCodePkce' | 'deviceCodeJson';
|
|
4
|
+
export type DeviceCodeTokenExchangeCodec = 'none' | 'authorizationCodeForm';
|
|
5
|
+
export type OAuthConnectMode = 'deviceCodeOAuth' | 'authorizationCodeOAuth';
|
|
6
|
+
export interface DeviceCodeEndpointDescriptor {
|
|
7
|
+
endpoint: string;
|
|
8
|
+
headers?: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
export interface DeviceCodeProtocolDescriptor {
|
|
11
|
+
id: string;
|
|
12
|
+
verificationUriOrigins?: string[];
|
|
13
|
+
begin: DeviceCodeEndpointDescriptor & {
|
|
14
|
+
codec: DeviceCodeBeginCodec;
|
|
15
|
+
deviceCodeField?: string;
|
|
16
|
+
userCodeField?: string;
|
|
17
|
+
verificationUriField?: string;
|
|
18
|
+
verificationUriCompleteField?: string;
|
|
19
|
+
expiresInField?: string;
|
|
20
|
+
expiresAtField?: string;
|
|
21
|
+
intervalField?: string;
|
|
22
|
+
defaultExpiresInSeconds?: number;
|
|
23
|
+
defaultIntervalSeconds?: number;
|
|
24
|
+
};
|
|
25
|
+
poll: DeviceCodeEndpointDescriptor & {
|
|
26
|
+
codec: DeviceCodePollCodec;
|
|
27
|
+
deviceCodeField?: string;
|
|
28
|
+
pendingHttpStatuses?: number[];
|
|
29
|
+
};
|
|
30
|
+
tokenExchange?: DeviceCodeEndpointDescriptor & {
|
|
31
|
+
codec: DeviceCodeTokenExchangeCodec;
|
|
32
|
+
redirectUri?: string;
|
|
33
|
+
codeField?: string;
|
|
34
|
+
codeVerifierField?: string;
|
|
35
|
+
};
|
|
36
|
+
refresh?: DeviceCodeEndpointDescriptor & {
|
|
37
|
+
codec: 'refreshTokenForm';
|
|
38
|
+
};
|
|
39
|
+
defaultVerificationUri?: string;
|
|
40
|
+
accountIdClaim?: string | string[];
|
|
41
|
+
}
|
|
42
|
+
export interface AuthorizationCodeProtocolDescriptor {
|
|
43
|
+
id: string;
|
|
44
|
+
authorization: DeviceCodeEndpointDescriptor & {
|
|
45
|
+
redirectUris: string[];
|
|
46
|
+
scopes?: string[];
|
|
47
|
+
responseType?: 'code';
|
|
48
|
+
codeChallengeMethod?: 'S256';
|
|
49
|
+
extraParams?: Record<string, string>;
|
|
50
|
+
};
|
|
51
|
+
token: DeviceCodeEndpointDescriptor & {
|
|
52
|
+
codec: 'authorizationCodeForm';
|
|
53
|
+
codeField?: string;
|
|
54
|
+
codeVerifierField?: string;
|
|
55
|
+
};
|
|
56
|
+
refresh?: DeviceCodeEndpointDescriptor & {
|
|
57
|
+
codec: 'refreshTokenForm';
|
|
58
|
+
};
|
|
59
|
+
accountIdClaim?: string | string[];
|
|
60
|
+
}
|
|
61
|
+
interface BaseOAuthIntegration {
|
|
62
|
+
provider: string;
|
|
63
|
+
offeringId: string;
|
|
64
|
+
mode: OAuthConnectMode;
|
|
65
|
+
integrationId: string;
|
|
66
|
+
issuedBy: string;
|
|
67
|
+
clientId: string;
|
|
68
|
+
accountLabel?: string;
|
|
69
|
+
accountId?: string;
|
|
70
|
+
}
|
|
71
|
+
export interface DeviceCodeOAuthIntegration extends BaseOAuthIntegration {
|
|
72
|
+
mode: 'deviceCodeOAuth';
|
|
73
|
+
protocol: DeviceCodeProtocolDescriptor;
|
|
74
|
+
}
|
|
75
|
+
export interface AuthorizationCodeOAuthIntegration extends BaseOAuthIntegration {
|
|
76
|
+
mode: 'authorizationCodeOAuth';
|
|
77
|
+
protocol: AuthorizationCodeProtocolDescriptor;
|
|
78
|
+
}
|
|
79
|
+
export type OAuthIntegration = DeviceCodeOAuthIntegration | AuthorizationCodeOAuthIntegration;
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ProviderSecret } from '../credentials/CredentialVault';
|
|
2
|
+
import type { GatewayDeployment } from '../auth/InvocationTokenCodec';
|
|
3
|
+
import type { SessionImportProfile } from './SessionImportProfiles';
|
|
4
|
+
export interface LocalSessionImportResult {
|
|
5
|
+
secret: ProviderSecret;
|
|
6
|
+
/**
|
|
7
|
+
* How the imported credential authenticates upstream. The import itself is
|
|
8
|
+
* local, but an imported subscription session is still an OAuth credential.
|
|
9
|
+
*/
|
|
10
|
+
credentialAuthMode?: 'deviceCodeOAuth' | 'local';
|
|
11
|
+
accountLabel?: string;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
export interface LocalSessionImportInput {
|
|
15
|
+
deployment: GatewayDeployment;
|
|
16
|
+
}
|
|
17
|
+
export interface LocalSessionImportAdapter {
|
|
18
|
+
provider: string;
|
|
19
|
+
offeringId: string;
|
|
20
|
+
importSession(input: LocalSessionImportInput): Promise<LocalSessionImportResult>;
|
|
21
|
+
}
|
|
22
|
+
export interface FileSessionImportAdapterOptions {
|
|
23
|
+
profile: SessionImportProfile;
|
|
24
|
+
homeDir?: string;
|
|
25
|
+
readFile?: (filePath: string, encoding: BufferEncoding) => Promise<string>;
|
|
26
|
+
maxBytes?: number;
|
|
27
|
+
}
|
|
28
|
+
export declare class FileSessionImportAdapter implements LocalSessionImportAdapter {
|
|
29
|
+
readonly provider: string;
|
|
30
|
+
readonly offeringId: string;
|
|
31
|
+
private readonly profile;
|
|
32
|
+
private readonly homeDir;
|
|
33
|
+
private readonly readFile;
|
|
34
|
+
private readonly maxBytes;
|
|
35
|
+
constructor(options: FileSessionImportAdapterOptions);
|
|
36
|
+
importSession(input: LocalSessionImportInput): Promise<LocalSessionImportResult>;
|
|
37
|
+
private readSessionFile;
|
|
38
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FileSessionImportAdapter = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const node_os_1 = __importDefault(require("node:os"));
|
|
9
|
+
const DEFAULT_MAX_SESSION_FILE_BYTES = 256 * 1024;
|
|
10
|
+
class FileSessionImportAdapter {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.profile = options.profile;
|
|
13
|
+
this.provider = options.profile.provider;
|
|
14
|
+
this.offeringId = options.profile.offeringId;
|
|
15
|
+
this.homeDir = options.homeDir ?? node_os_1.default.homedir();
|
|
16
|
+
this.readFile = options.readFile ?? node_fs_1.promises.readFile;
|
|
17
|
+
this.maxBytes = options.maxBytes ?? DEFAULT_MAX_SESSION_FILE_BYTES;
|
|
18
|
+
}
|
|
19
|
+
async importSession(input) {
|
|
20
|
+
if (input.deployment !== 'local') {
|
|
21
|
+
throw new Error('local_session_import_unavailable_in_cloud');
|
|
22
|
+
}
|
|
23
|
+
const raw = await this.readSessionFile(this.profile.resolvePath(this.homeDir));
|
|
24
|
+
const payload = parseJsonObject(raw);
|
|
25
|
+
return this.profile.importSession(payload);
|
|
26
|
+
}
|
|
27
|
+
async readSessionFile(filePath) {
|
|
28
|
+
let raw;
|
|
29
|
+
try {
|
|
30
|
+
raw = await this.readFile(filePath, 'utf8');
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (isErrno(error, 'ENOENT')) {
|
|
34
|
+
throw new Error('local_session_file_missing');
|
|
35
|
+
}
|
|
36
|
+
throw new Error('local_session_file_read_failed');
|
|
37
|
+
}
|
|
38
|
+
if (Buffer.byteLength(raw, 'utf8') > this.maxBytes) {
|
|
39
|
+
throw new Error('local_session_file_too_large');
|
|
40
|
+
}
|
|
41
|
+
return raw;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
exports.FileSessionImportAdapter = FileSessionImportAdapter;
|
|
45
|
+
function parseJsonObject(raw) {
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(raw);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new Error('local_session_file_invalid_json');
|
|
52
|
+
}
|
|
53
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
54
|
+
throw new Error('local_session_file_invalid_json');
|
|
55
|
+
}
|
|
56
|
+
return parsed;
|
|
57
|
+
}
|
|
58
|
+
function isErrno(error, code) {
|
|
59
|
+
return error instanceof Error
|
|
60
|
+
&& 'code' in error
|
|
61
|
+
&& error.code === code;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=FileSessionImportAdapter.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface AuthorizationCodeCallbackReceiver {
|
|
2
|
+
register(input: {
|
|
3
|
+
redirectUris: string[];
|
|
4
|
+
state: string;
|
|
5
|
+
expiresAt: Date;
|
|
6
|
+
onCallback(result: {
|
|
7
|
+
code?: string;
|
|
8
|
+
error?: string;
|
|
9
|
+
}): Promise<void> | void;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
redirectUri: string;
|
|
12
|
+
close(): void;
|
|
13
|
+
}>;
|
|
14
|
+
}
|
|
15
|
+
type RegistrationInput = Parameters<AuthorizationCodeCallbackReceiver['register']>[0];
|
|
16
|
+
/** Receives authorization codes locally; credential exchange belongs to the authenticated caller. */
|
|
17
|
+
export declare class LoopbackAuthorizationCallbackReceiver implements AuthorizationCodeCallbackReceiver {
|
|
18
|
+
private readonly listeners;
|
|
19
|
+
private pending;
|
|
20
|
+
register(input: RegistrationInput): ReturnType<AuthorizationCodeCallbackReceiver['register']>;
|
|
21
|
+
private registerSerial;
|
|
22
|
+
private handle;
|
|
23
|
+
}
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.LoopbackAuthorizationCallbackReceiver = void 0;
|
|
4
|
+
const node_http_1 = require("node:http");
|
|
5
|
+
/** Receives authorization codes locally; credential exchange belongs to the authenticated caller. */
|
|
6
|
+
class LoopbackAuthorizationCallbackReceiver {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.listeners = new Map();
|
|
9
|
+
this.pending = Promise.resolve();
|
|
10
|
+
}
|
|
11
|
+
register(input) {
|
|
12
|
+
const result = this.pending.then(() => this.registerSerial(input));
|
|
13
|
+
this.pending = result.catch(() => undefined);
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
async registerSerial(input) {
|
|
17
|
+
if (!input.state || !Number.isFinite(input.expiresAt.getTime()) || input.expiresAt.getTime() <= Date.now()) {
|
|
18
|
+
throw new Error('Authorization callback registration is invalid or expired.');
|
|
19
|
+
}
|
|
20
|
+
if ([...this.listeners.values()].some(listener => listener.registrations.has(input.state))) {
|
|
21
|
+
throw new Error('Authorization callback state is already registered.');
|
|
22
|
+
}
|
|
23
|
+
const uris = input.redirectUris.map(value => {
|
|
24
|
+
let uri;
|
|
25
|
+
try {
|
|
26
|
+
uri = new URL(value);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
throw new Error('Invalid loopback authorization redirect URI.');
|
|
30
|
+
}
|
|
31
|
+
if (uri.protocol !== 'http:' || !['localhost', '127.0.0.1'].includes(uri.hostname) ||
|
|
32
|
+
uri.username || uri.password || uri.search || uri.hash || uri.port === '0') {
|
|
33
|
+
throw new Error('Invalid loopback authorization redirect URI.');
|
|
34
|
+
}
|
|
35
|
+
return uri;
|
|
36
|
+
});
|
|
37
|
+
for (const uri of uris) {
|
|
38
|
+
const port = Number(uri.port || 80);
|
|
39
|
+
let listener = this.listeners.get(port);
|
|
40
|
+
if (!listener) {
|
|
41
|
+
const registrations = new Map();
|
|
42
|
+
const server = (0, node_http_1.createServer)((request, response) => {
|
|
43
|
+
void this.handle(request, response, port, registrations);
|
|
44
|
+
});
|
|
45
|
+
try {
|
|
46
|
+
await new Promise((resolve, reject) => {
|
|
47
|
+
server.once('error', reject);
|
|
48
|
+
server.listen(port, '127.0.0.1', () => {
|
|
49
|
+
server.removeListener('error', reject);
|
|
50
|
+
resolve();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
if (error.code === 'EADDRINUSE') {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
throw new Error('Unable to start the local authorization callback listener.');
|
|
59
|
+
}
|
|
60
|
+
server.unref();
|
|
61
|
+
listener = { server, registrations };
|
|
62
|
+
this.listeners.set(port, listener);
|
|
63
|
+
}
|
|
64
|
+
const selected = listener;
|
|
65
|
+
let timer;
|
|
66
|
+
let active = true;
|
|
67
|
+
const close = () => {
|
|
68
|
+
if (!active) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
active = false;
|
|
72
|
+
clearTimeout(timer);
|
|
73
|
+
selected.registrations.delete(input.state);
|
|
74
|
+
if (selected.registrations.size === 0 && this.listeners.get(port) === selected) {
|
|
75
|
+
this.listeners.delete(port);
|
|
76
|
+
selected.server.close();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
selected.registrations.set(input.state, { ...input, path: uri.pathname, close });
|
|
80
|
+
timer = setTimeout(close, Math.max(0, Math.min(input.expiresAt.getTime() - Date.now(), 2_147_483_647)));
|
|
81
|
+
timer.unref();
|
|
82
|
+
return { redirectUri: uri.toString(), close };
|
|
83
|
+
}
|
|
84
|
+
throw new Error('The registered local authorization callback ports are unavailable. Close the application using them and retry.');
|
|
85
|
+
}
|
|
86
|
+
async handle(request, response, port, registrations) {
|
|
87
|
+
const reply = (status, success = false) => {
|
|
88
|
+
response.writeHead(status, {
|
|
89
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
90
|
+
'Cache-Control': 'no-store',
|
|
91
|
+
'Connection': 'close',
|
|
92
|
+
'Content-Security-Policy': "default-src 'none'; frame-ancestors 'none'",
|
|
93
|
+
'Referrer-Policy': 'no-referrer',
|
|
94
|
+
});
|
|
95
|
+
response.end(success ? '授权已返回 Xpod,请切回应用完成连接。' : '授权回调无效或已过期,请返回应用重试。');
|
|
96
|
+
};
|
|
97
|
+
const allowedHosts = ['localhost', '127.0.0.1'].map(host => port === 80 ? host : `${host}:${port}`);
|
|
98
|
+
if (request.method !== 'GET' || !allowedHosts.includes(request.headers.host ?? '') ||
|
|
99
|
+
!request.url?.startsWith('/') || request.url.startsWith('//') ||
|
|
100
|
+
request.rawHeaders.filter((value, index) => index % 2 === 0 && value.toLowerCase() === 'host').length !== 1) {
|
|
101
|
+
reply(400);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let uri;
|
|
105
|
+
try {
|
|
106
|
+
uri = new URL(request.url, `http://127.0.0.1:${port}`);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
reply(400);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const query = uri.searchParams;
|
|
113
|
+
if (['state', 'code', 'error'].some(key => query.getAll(key).length > 1) ||
|
|
114
|
+
!query.get('state') || (!!query.get('code') === !!query.get('error')) ||
|
|
115
|
+
(query.has('code') && query.has('error'))) {
|
|
116
|
+
reply(400);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const registration = registrations.get(query.get('state'));
|
|
120
|
+
if (!registration || registration.path !== request.url.split('?')[0] || uri.hash ||
|
|
121
|
+
registration.expiresAt.getTime() <= Date.now()) {
|
|
122
|
+
reply(400);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
registration.close();
|
|
126
|
+
try {
|
|
127
|
+
await registration.onCallback(query.has('code') ? { code: query.get('code') } : { error: query.get('error') });
|
|
128
|
+
reply(200, !query.has('error'));
|
|
129
|
+
}
|
|
130
|
+
catch {
|
|
131
|
+
reply(500);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.LoopbackAuthorizationCallbackReceiver = LoopbackAuthorizationCallbackReceiver;
|
|
136
|
+
//# sourceMappingURL=LoopbackAuthorizationCallbackReceiver.js.map
|
|
@@ -4,12 +4,14 @@ import type { AuthContext } from '../../auth/AuthContext';
|
|
|
4
4
|
import type { ConnectCredentialRecord, PodCredentialRepository } from './index';
|
|
5
5
|
export interface OAuthConnectCredentialStoreOptions {
|
|
6
6
|
provider: string;
|
|
7
|
+
offeringId: string;
|
|
7
8
|
deployment: GatewayDeployment;
|
|
8
9
|
credentialRepository: PodCredentialRepository;
|
|
9
10
|
vault: CredentialVault;
|
|
10
11
|
}
|
|
11
12
|
export declare class OAuthConnectCredentialStore {
|
|
12
13
|
private readonly provider;
|
|
14
|
+
private readonly offeringId;
|
|
13
15
|
private readonly credentialRepository;
|
|
14
16
|
private readonly vault;
|
|
15
17
|
constructor(options: OAuthConnectCredentialStoreOptions);
|