@oxy.so/core 1.18.0 → 3.0.0
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/README.md +13 -7
- package/dist/cjs/HttpService.js +189 -112
- package/dist/cjs/OxyServices.errors.js +48 -1
- package/dist/cjs/OxyServices.js +263 -60
- package/dist/cjs/api/accounts.js +231 -0
- package/dist/cjs/api/agency.js +102 -0
- package/dist/cjs/api/appData.js +45 -0
- package/dist/cjs/api/apps.js +197 -0
- package/dist/cjs/api/assets.js +329 -0
- package/dist/cjs/api/auth.js +900 -0
- package/dist/cjs/api/billing.js +44 -0
- package/dist/cjs/api/civic.js +289 -0
- package/dist/cjs/api/contacts.js +16 -0
- package/dist/cjs/api/devices.js +351 -0
- package/dist/cjs/api/follows.js +240 -0
- package/dist/cjs/api/identity.js +569 -0
- package/dist/cjs/api/linkedAccounts.js +48 -0
- package/dist/cjs/api/nodes.js +75 -0
- package/dist/cjs/api/notifications.js +75 -0
- package/dist/cjs/api/privacy.js +105 -0
- package/dist/cjs/api/reputation.js +74 -0
- package/dist/cjs/api/session.js +177 -0
- package/dist/cjs/api/store.js +199 -0
- package/dist/cjs/api/topics.js +66 -0
- package/dist/cjs/api/users.js +309 -0
- package/dist/cjs/boot/sessionColdBoot.js +4 -4
- package/dist/cjs/civic/index.js +16 -0
- package/dist/cjs/civic/payloads.js +156 -0
- package/dist/cjs/client/context.js +2 -0
- package/dist/cjs/crypto/identityLink.js +5 -5
- package/dist/cjs/crypto/index.js +44 -0
- package/dist/cjs/crypto/internal.js +37 -0
- package/dist/cjs/crypto/keyManager.js +2 -2
- package/dist/cjs/crypto/polyfill.js +9 -80
- package/dist/cjs/crypto/recoveryPhrase.js +1 -0
- package/dist/cjs/crypto/registrationPow.js +1 -1
- package/dist/cjs/crypto/signatureService.js +1 -0
- package/dist/cjs/i18n/accountCategoryLabels.js +3 -3
- package/dist/cjs/i18n/accountRoleLabels.js +7 -7
- package/dist/cjs/i18n/index.js +130 -52
- package/dist/cjs/i18n/locales/{ar-SA.json → ar-SA.js} +134 -52
- package/dist/cjs/i18n/locales/{ca-ES.json → ca-ES.js} +134 -52
- package/dist/{esm/i18n/locales/de-DE.json → cjs/i18n/locales/de-DE.js} +136 -54
- package/dist/{esm/i18n/locales/en-US.json → cjs/i18n/locales/en-US.js} +163 -245
- package/dist/{esm/i18n/locales/es-ES.json → cjs/i18n/locales/es-ES.js} +163 -245
- package/dist/cjs/i18n/locales/{fr-FR.json → fr-FR.js} +134 -52
- package/dist/cjs/i18n/locales/{it-IT.json → it-IT.js} +134 -52
- package/dist/{esm/i18n/locales/ja-JP.json → cjs/i18n/locales/ja-JP.js} +134 -52
- package/dist/cjs/i18n/locales/{ko-KR.json → ko-KR.js} +134 -52
- package/dist/{esm/i18n/locales/pt-PT.json → cjs/i18n/locales/pt-PT.js} +136 -54
- package/dist/{esm/i18n/locales/zh-CN.json → cjs/i18n/locales/zh-CN.js} +135 -53
- package/dist/cjs/i18n/reputationCategoryLabels.js +2 -2
- package/dist/cjs/i18n/trustTierLabels.js +2 -2
- package/dist/cjs/index.js +55 -263
- package/dist/cjs/inference/index.js +21 -0
- package/dist/cjs/server/OxyServer.js +521 -0
- package/dist/cjs/server/auth.js +2 -2
- package/dist/cjs/server/index.js +23 -6
- package/dist/cjs/server/middleware.js +1154 -0
- package/dist/cjs/server/namespaces.js +214 -0
- package/dist/cjs/server/rateLimit.js +2 -2
- package/dist/cjs/server/requesterAssertion.js +5 -5
- package/dist/cjs/server/securityHeaders.js +3 -3
- package/dist/cjs/server/traffic.js +7 -6
- package/dist/cjs/server/trafficNodeHttp.js +9 -3
- package/dist/cjs/server/userInvalidation.js +5 -5
- package/dist/cjs/session/accountDialogController.js +23 -23
- package/dist/cjs/session/authStateStore.js +2 -2
- package/dist/cjs/session/identitySession.js +3 -3
- package/dist/cjs/session/index.js +131 -0
- package/dist/cjs/session/refresh.js +37 -30
- package/dist/cjs/session/sessionClientHost.js +5 -5
- package/dist/cjs/session/sharedDeviceCredential.js +3 -2
- package/dist/cjs/shared/utils/networkUtils.js +2 -2
- package/dist/cjs/utils/accountCacheSweep.js +11 -15
- package/dist/cjs/utils/asyncUtils.js +22 -163
- package/dist/cjs/utils/authHelpers.js +2 -2
- package/dist/cjs/utils/authWebUrl.js +3 -4
- package/dist/cjs/utils/avatarUtils.js +2 -2
- package/dist/cjs/utils/cache.js +32 -2
- package/dist/cjs/utils/cacheKey.js +5 -10
- package/dist/cjs/utils/deviceManager.js +17 -16
- package/dist/cjs/utils/edgeRegion.js +2 -3
- package/dist/cjs/utils/identityCacheSweep.js +6 -10
- package/dist/cjs/utils/oxyServiceEnvironment.js +3 -7
- package/dist/cjs/utils/requestUtils.js +40 -33
- package/dist/cjs/utils/sessionUtils.js +0 -2
- package/dist/cjs/utils/tokenClaims.js +34 -0
- package/dist/esm/HttpService.js +190 -113
- package/dist/esm/OxyServices.errors.js +45 -0
- package/dist/esm/OxyServices.js +262 -57
- package/dist/esm/api/accounts.js +218 -0
- package/dist/esm/api/agency.js +95 -0
- package/dist/esm/api/appData.js +40 -0
- package/dist/esm/api/apps.js +191 -0
- package/dist/esm/api/assets.js +324 -0
- package/dist/esm/api/auth.js +858 -0
- package/dist/esm/api/billing.js +40 -0
- package/dist/esm/api/civic.js +250 -0
- package/dist/esm/api/contacts.js +12 -0
- package/dist/esm/api/devices.js +346 -0
- package/dist/esm/api/follows.js +236 -0
- package/dist/esm/api/identity.js +527 -0
- package/dist/esm/api/linkedAccounts.js +44 -0
- package/dist/esm/api/nodes.js +71 -0
- package/dist/esm/api/notifications.js +71 -0
- package/dist/esm/api/privacy.js +101 -0
- package/dist/esm/api/reputation.js +70 -0
- package/dist/esm/api/session.js +173 -0
- package/dist/esm/api/store.js +192 -0
- package/dist/esm/api/topics.js +62 -0
- package/dist/esm/api/users.js +272 -0
- package/dist/esm/boot/sessionColdBoot.js +4 -4
- package/dist/esm/civic/index.js +10 -0
- package/dist/esm/civic/payloads.js +118 -0
- package/dist/esm/client/context.js +1 -0
- package/dist/esm/crypto/identityLink.js +5 -5
- package/dist/esm/crypto/index.js +24 -0
- package/dist/esm/crypto/internal.js +19 -0
- package/dist/esm/crypto/keyManager.js +2 -2
- package/dist/esm/crypto/polyfill.js +10 -81
- package/dist/esm/crypto/recoveryPhrase.js +1 -0
- package/dist/esm/crypto/registrationPow.js +1 -1
- package/dist/esm/crypto/signatureService.js +1 -0
- package/dist/esm/i18n/accountCategoryLabels.js +2 -2
- package/dist/esm/i18n/accountRoleLabels.js +1 -1
- package/dist/esm/i18n/index.js +93 -52
- package/dist/esm/i18n/locales/{ar-SA.json → ar-SA.js} +132 -52
- package/dist/esm/i18n/locales/{ca-ES.json → ca-ES.js} +132 -52
- package/dist/{cjs/i18n/locales/de-DE.json → esm/i18n/locales/de-DE.js} +134 -54
- package/dist/{cjs/i18n/locales/en-US.json → esm/i18n/locales/en-US.js} +161 -245
- package/dist/{cjs/i18n/locales/es-ES.json → esm/i18n/locales/es-ES.js} +161 -245
- package/dist/esm/i18n/locales/{fr-FR.json → fr-FR.js} +132 -52
- package/dist/esm/i18n/locales/{it-IT.json → it-IT.js} +132 -52
- package/dist/{cjs/i18n/locales/ja-JP.json → esm/i18n/locales/ja-JP.js} +132 -52
- package/dist/esm/i18n/locales/{ko-KR.json → ko-KR.js} +132 -52
- package/dist/{cjs/i18n/locales/pt-PT.json → esm/i18n/locales/pt-PT.js} +134 -54
- package/dist/{cjs/i18n/locales/zh-CN.json → esm/i18n/locales/zh-CN.js} +133 -53
- package/dist/esm/i18n/reputationCategoryLabels.js +1 -1
- package/dist/esm/i18n/trustTierLabels.js +1 -1
- package/dist/esm/index.js +30 -166
- package/dist/esm/inference/index.js +13 -0
- package/dist/esm/server/OxyServer.js +516 -0
- package/dist/esm/server/auth.js +2 -2
- package/dist/esm/server/index.js +10 -5
- package/dist/esm/server/middleware.js +1147 -0
- package/dist/esm/server/namespaces.js +206 -0
- package/dist/esm/server/rateLimit.js +2 -2
- package/dist/esm/server/requesterAssertion.js +5 -5
- package/dist/esm/server/securityHeaders.js +3 -3
- package/dist/esm/server/traffic.js +7 -6
- package/dist/esm/server/trafficNodeHttp.js +9 -3
- package/dist/esm/server/userInvalidation.js +5 -5
- package/dist/esm/session/accountDialogController.js +23 -23
- package/dist/esm/session/authStateStore.js +2 -2
- package/dist/esm/session/identitySession.js +3 -3
- package/dist/esm/session/index.js +82 -0
- package/dist/esm/session/refresh.js +37 -30
- package/dist/esm/session/sessionClientHost.js +5 -5
- package/dist/esm/session/sharedDeviceCredential.js +3 -2
- package/dist/esm/shared/utils/networkUtils.js +2 -2
- package/dist/esm/utils/accountCacheSweep.js +11 -15
- package/dist/esm/utils/asyncUtils.js +22 -151
- package/dist/esm/utils/authHelpers.js +2 -2
- package/dist/esm/utils/authWebUrl.js +3 -4
- package/dist/esm/utils/avatarUtils.js +2 -2
- package/dist/esm/utils/cache.js +32 -2
- package/dist/esm/utils/cacheKey.js +5 -10
- package/dist/esm/utils/deviceManager.js +17 -16
- package/dist/esm/utils/edgeRegion.js +1 -2
- package/dist/esm/utils/identityCacheSweep.js +6 -10
- package/dist/esm/utils/oxyServiceEnvironment.js +3 -7
- package/dist/esm/utils/requestUtils.js +40 -33
- package/dist/esm/utils/sessionUtils.js +0 -2
- package/dist/esm/utils/tokenClaims.js +31 -0
- package/dist/types/HttpService.d.ts +47 -9
- package/dist/types/OxyServices.d.ts +160 -131
- package/dist/types/OxyServices.errors.d.ts +42 -0
- package/dist/types/api/accounts.d.ts +415 -0
- package/dist/types/api/agency.d.ts +135 -0
- package/dist/types/api/appData.d.ts +27 -0
- package/dist/types/api/apps.d.ts +433 -0
- package/dist/types/api/assets.d.ts +174 -0
- package/dist/types/api/auth.d.ts +766 -0
- package/dist/types/api/billing.d.ts +113 -0
- package/dist/types/api/civic.d.ts +203 -0
- package/dist/types/api/contacts.d.ts +31 -0
- package/{src/mixins/OxyServices.deviceBoot.ts → dist/types/api/devices.d.ts} +130 -110
- package/dist/types/api/follows.d.ts +236 -0
- package/dist/types/api/identity.d.ts +275 -0
- package/dist/types/api/linkedAccounts.d.ts +48 -0
- package/dist/types/api/nodes.d.ts +102 -0
- package/dist/types/api/notifications.d.ts +77 -0
- package/dist/types/api/privacy.d.ts +43 -0
- package/dist/types/api/reputation.d.ts +50 -0
- package/dist/types/api/session.d.ts +85 -0
- package/dist/types/api/store.d.ts +278 -0
- package/dist/types/api/topics.d.ts +34 -0
- package/dist/types/api/users.d.ts +134 -0
- package/dist/types/boot/sessionColdBoot.d.ts +1 -1
- package/dist/types/civic/index.d.ts +10 -0
- package/dist/types/civic/payloads.d.ts +83 -0
- package/dist/types/client/context.d.ts +33 -0
- package/dist/types/crypto/identityLink.d.ts +5 -5
- package/dist/types/crypto/index.d.ts +24 -0
- package/dist/types/crypto/internal.d.ts +19 -0
- package/dist/types/crypto/polyfill.d.ts +6 -9
- package/dist/types/crypto/registrationPow.d.ts +1 -1
- package/dist/types/i18n/accountCategoryLabels.d.ts +1 -1
- package/dist/types/i18n/accountRoleLabels.d.ts +1 -1
- package/dist/types/i18n/index.d.ts +20 -1
- package/dist/types/i18n/locales/ar-SA.d.ts +386 -0
- package/dist/types/i18n/locales/ca-ES.d.ts +386 -0
- package/dist/types/i18n/locales/de-DE.d.ts +386 -0
- package/dist/types/i18n/locales/en-US.d.ts +2034 -0
- package/dist/types/i18n/locales/es-ES.d.ts +2034 -0
- package/dist/types/i18n/locales/fr-FR.d.ts +386 -0
- package/dist/types/i18n/locales/it-IT.d.ts +386 -0
- package/dist/types/i18n/locales/ja-JP.d.ts +386 -0
- package/dist/types/i18n/locales/ko-KR.d.ts +386 -0
- package/dist/types/i18n/locales/pt-PT.d.ts +386 -0
- package/dist/types/i18n/locales/zh-CN.d.ts +386 -0
- package/dist/types/index.d.ts +46 -95
- package/dist/types/inference/index.d.ts +22 -0
- package/dist/types/models/interfaces.d.ts +1 -1
- package/dist/types/server/OxyServer.d.ts +183 -0
- package/dist/types/server/auth.d.ts +10 -7
- package/dist/types/server/index.d.ts +10 -4
- package/dist/types/server/middleware.d.ts +291 -0
- package/dist/types/server/namespaces.d.ts +98 -0
- package/dist/types/server/rateLimit.d.ts +7 -5
- package/dist/types/server/requesterAssertion.d.ts +14 -11
- package/dist/types/server/securityHeaders.d.ts +4 -5
- package/dist/types/server/userInvalidation.d.ts +10 -8
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/accountDialogController.d.ts +8 -8
- package/dist/types/session/accountSwitchTargets.d.ts +1 -1
- package/dist/types/session/authStateStore.d.ts +7 -6
- package/dist/types/session/index.d.ts +40 -0
- package/dist/types/utils/accountCacheSweep.d.ts +7 -10
- package/dist/types/utils/apiUtils.d.ts +3 -3
- package/dist/types/utils/asyncUtils.d.ts +11 -58
- package/dist/types/utils/authWebUrl.d.ts +3 -4
- package/dist/types/utils/avatarUtils.d.ts +5 -6
- package/dist/types/utils/cache.d.ts +11 -3
- package/dist/types/utils/commonsApproval.d.ts +1 -1
- package/dist/types/utils/edgeRegion.d.ts +1 -2
- package/dist/types/utils/identityCacheSweep.d.ts +6 -4
- package/dist/types/utils/oauthPkce.d.ts +2 -2
- package/dist/types/utils/oxyServiceEnvironment.d.ts +3 -7
- package/dist/types/utils/requestUtils.d.ts +18 -14
- package/dist/types/utils/tokenClaims.d.ts +9 -0
- package/package.json +68 -7
- package/src/HttpService.ts +201 -132
- package/src/OxyServices.errors.ts +73 -0
- package/src/OxyServices.ts +289 -164
- package/src/api/accounts.ts +579 -0
- package/src/api/agency.ts +277 -0
- package/src/api/appData.ts +63 -0
- package/src/api/apps.ts +596 -0
- package/src/api/assets.ts +416 -0
- package/src/api/auth.ts +1457 -0
- package/src/api/billing.ts +144 -0
- package/src/api/civic.ts +428 -0
- package/src/api/contacts.ts +41 -0
- package/src/api/devices.ts +438 -0
- package/src/api/follows.ts +414 -0
- package/src/api/identity.ts +727 -0
- package/src/api/linkedAccounts.ts +78 -0
- package/src/api/nodes.ts +169 -0
- package/src/api/notifications.ts +135 -0
- package/src/api/privacy.ts +120 -0
- package/src/api/reputation.ts +134 -0
- package/src/api/session.ts +210 -0
- package/src/api/store.ts +435 -0
- package/src/api/topics.ts +83 -0
- package/src/api/users.ts +357 -0
- package/src/boot/sessionColdBoot.ts +4 -4
- package/src/civic/index.ts +12 -0
- package/src/civic/payloads.ts +175 -0
- package/src/client/context.ts +34 -0
- package/src/crypto/identityLink.ts +5 -5
- package/src/crypto/index.ts +39 -0
- package/src/crypto/internal.ts +20 -0
- package/src/crypto/keyManager.ts +2 -2
- package/src/crypto/polyfill.ts +9 -89
- package/src/crypto/recoveryPhrase.ts +1 -0
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +1 -0
- package/src/i18n/accountCategoryLabels.ts +2 -2
- package/src/i18n/accountRoleLabels.ts +2 -2
- package/src/i18n/index.ts +105 -54
- package/src/i18n/locales/{ar-SA.json → ar-SA.ts} +132 -52
- package/src/i18n/locales/{ca-ES.json → ca-ES.ts} +132 -52
- package/{dist/cjs/i18n/locales/locales/de-DE.json → src/i18n/locales/de-DE.ts} +134 -54
- package/src/i18n/locales/{en-US.json → en-US.ts} +161 -245
- package/{dist/cjs/i18n/locales/locales/es-ES.json → src/i18n/locales/es-ES.ts} +161 -245
- package/src/i18n/locales/{fr-FR.json → fr-FR.ts} +132 -52
- package/src/i18n/locales/{it-IT.json → it-IT.ts} +132 -52
- package/{dist/cjs/i18n/locales/locales/ja-JP.json → src/i18n/locales/ja-JP.ts} +132 -52
- package/src/i18n/locales/{ko-KR.json → ko-KR.ts} +132 -52
- package/src/i18n/locales/{pt-PT.json → pt-PT.ts} +134 -54
- package/src/i18n/locales/{zh-CN.json → zh-CN.ts} +133 -53
- package/src/i18n/reputationCategoryLabels.ts +1 -1
- package/src/i18n/trustTierLabels.ts +1 -1
- package/src/index.ts +170 -501
- package/src/inference/index.ts +48 -0
- package/src/models/interfaces.ts +1 -1
- package/src/server/OxyServer.ts +637 -0
- package/src/server/auth.ts +12 -8
- package/src/server/index.ts +28 -5
- package/src/server/middleware.ts +1520 -0
- package/src/server/namespaces.ts +257 -0
- package/src/server/rateLimit.ts +10 -9
- package/src/server/requesterAssertion.ts +13 -10
- package/src/server/securityHeaders.ts +7 -8
- package/src/server/traffic.ts +6 -6
- package/src/server/trafficNodeHttp.ts +7 -3
- package/src/server/userInvalidation.ts +9 -9
- package/src/session/accountDelegationAccess.ts +1 -1
- package/src/session/accountDialogController.ts +24 -24
- package/src/session/accountSwitchTargets.ts +1 -1
- package/src/session/authStateStore.ts +9 -8
- package/src/session/identitySession.ts +3 -3
- package/src/session/index.ts +210 -0
- package/src/session/refresh.ts +36 -30
- package/src/session/sessionClientHost.ts +5 -5
- package/src/session/sharedDeviceCredential.ts +3 -2
- package/src/shared/utils/networkUtils.ts +2 -2
- package/src/utils/accountCacheSweep.ts +11 -15
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +38 -235
- package/src/utils/authHelpers.ts +2 -2
- package/src/utils/authWebUrl.ts +3 -4
- package/src/utils/avatarUtils.ts +4 -7
- package/src/utils/cache.ts +36 -5
- package/src/utils/cacheKey.ts +5 -9
- package/src/utils/commonsApproval.ts +1 -1
- package/src/utils/deviceManager.ts +17 -16
- package/src/utils/edgeRegion.ts +1 -2
- package/src/utils/identityCacheSweep.ts +7 -12
- package/src/utils/oauthPkce.ts +2 -2
- package/src/utils/oxyServiceEnvironment.ts +3 -7
- package/src/utils/requestUtils.ts +48 -44
- package/src/utils/sessionUtils.ts +0 -2
- package/src/utils/tokenClaims.ts +38 -0
- package/dist/cjs/.tsbuildinfo +0 -1
- package/dist/cjs/OxyServices.base.js +0 -392
- package/dist/cjs/i18n/locales/locales/ar-SA.json +0 -306
- package/dist/cjs/i18n/locales/locales/ca-ES.json +0 -306
- package/dist/cjs/i18n/locales/locales/en-US.json +0 -2127
- package/dist/cjs/i18n/locales/locales/fr-FR.json +0 -306
- package/dist/cjs/i18n/locales/locales/it-IT.json +0 -306
- package/dist/cjs/i18n/locales/locales/ko-KR.json +0 -306
- package/dist/cjs/i18n/locales/locales/pt-PT.json +0 -306
- package/dist/cjs/i18n/locales/locales/zh-CN.json +0 -306
- package/dist/cjs/mixins/OxyServices.accounts.js +0 -555
- package/dist/cjs/mixins/OxyServices.agency.js +0 -154
- package/dist/cjs/mixins/OxyServices.analytics.js +0 -49
- package/dist/cjs/mixins/OxyServices.appData.js +0 -108
- package/dist/cjs/mixins/OxyServices.assets.js +0 -854
- package/dist/cjs/mixins/OxyServices.auth.js +0 -1440
- package/dist/cjs/mixins/OxyServices.chains.js +0 -73
- package/dist/cjs/mixins/OxyServices.civic.js +0 -611
- package/dist/cjs/mixins/OxyServices.connectedApps.js +0 -95
- package/dist/cjs/mixins/OxyServices.contacts.js +0 -50
- package/dist/cjs/mixins/OxyServices.deviceBoot.js +0 -191
- package/dist/cjs/mixins/OxyServices.devices.js +0 -116
- package/dist/cjs/mixins/OxyServices.features.js +0 -335
- package/dist/cjs/mixins/OxyServices.followGraph.js +0 -221
- package/dist/cjs/mixins/OxyServices.identity.js +0 -562
- package/dist/cjs/mixins/OxyServices.identityBackup.js +0 -172
- package/dist/cjs/mixins/OxyServices.inference.js +0 -59
- package/dist/cjs/mixins/OxyServices.language.js +0 -125
- package/dist/cjs/mixins/OxyServices.linkedAccounts.js +0 -79
- package/dist/cjs/mixins/OxyServices.location.js +0 -43
- package/dist/cjs/mixins/OxyServices.nodes.js +0 -175
- package/dist/cjs/mixins/OxyServices.notifications.js +0 -63
- package/dist/cjs/mixins/OxyServices.payment.js +0 -158
- package/dist/cjs/mixins/OxyServices.privacy.js +0 -199
- package/dist/cjs/mixins/OxyServices.reputation.js +0 -289
- package/dist/cjs/mixins/OxyServices.security.js +0 -89
- package/dist/cjs/mixins/OxyServices.store.js +0 -266
- package/dist/cjs/mixins/OxyServices.topics.js +0 -137
- package/dist/cjs/mixins/OxyServices.user.js +0 -954
- package/dist/cjs/mixins/OxyServices.utility.js +0 -1402
- package/dist/cjs/mixins/index.js +0 -136
- package/dist/cjs/mixins/mixinHelpers.js +0 -53
- package/dist/cjs/utils/webauthnOrigin.js +0 -51
- package/dist/esm/.tsbuildinfo +0 -1
- package/dist/esm/OxyServices.base.js +0 -388
- package/dist/esm/i18n/locales/locales/ar-SA.json +0 -306
- package/dist/esm/i18n/locales/locales/ca-ES.json +0 -306
- package/dist/esm/i18n/locales/locales/de-DE.json +0 -306
- package/dist/esm/i18n/locales/locales/en-US.json +0 -2127
- package/dist/esm/i18n/locales/locales/es-ES.json +0 -2127
- package/dist/esm/i18n/locales/locales/fr-FR.json +0 -306
- package/dist/esm/i18n/locales/locales/it-IT.json +0 -306
- package/dist/esm/i18n/locales/locales/ja-JP.json +0 -306
- package/dist/esm/i18n/locales/locales/ko-KR.json +0 -306
- package/dist/esm/i18n/locales/locales/pt-PT.json +0 -306
- package/dist/esm/i18n/locales/locales/zh-CN.json +0 -306
- package/dist/esm/mixins/OxyServices.accounts.js +0 -543
- package/dist/esm/mixins/OxyServices.agency.js +0 -151
- package/dist/esm/mixins/OxyServices.analytics.js +0 -46
- package/dist/esm/mixins/OxyServices.appData.js +0 -103
- package/dist/esm/mixins/OxyServices.assets.js +0 -851
- package/dist/esm/mixins/OxyServices.auth.js +0 -1400
- package/dist/esm/mixins/OxyServices.chains.js +0 -70
- package/dist/esm/mixins/OxyServices.civic.js +0 -605
- package/dist/esm/mixins/OxyServices.connectedApps.js +0 -92
- package/dist/esm/mixins/OxyServices.contacts.js +0 -47
- package/dist/esm/mixins/OxyServices.deviceBoot.js +0 -186
- package/dist/esm/mixins/OxyServices.devices.js +0 -113
- package/dist/esm/mixins/OxyServices.features.js +0 -332
- package/dist/esm/mixins/OxyServices.followGraph.js +0 -218
- package/dist/esm/mixins/OxyServices.identity.js +0 -558
- package/dist/esm/mixins/OxyServices.identityBackup.js +0 -169
- package/dist/esm/mixins/OxyServices.inference.js +0 -56
- package/dist/esm/mixins/OxyServices.language.js +0 -122
- package/dist/esm/mixins/OxyServices.linkedAccounts.js +0 -76
- package/dist/esm/mixins/OxyServices.location.js +0 -40
- package/dist/esm/mixins/OxyServices.nodes.js +0 -172
- package/dist/esm/mixins/OxyServices.notifications.js +0 -60
- package/dist/esm/mixins/OxyServices.payment.js +0 -155
- package/dist/esm/mixins/OxyServices.privacy.js +0 -196
- package/dist/esm/mixins/OxyServices.reputation.js +0 -286
- package/dist/esm/mixins/OxyServices.security.js +0 -86
- package/dist/esm/mixins/OxyServices.store.js +0 -263
- package/dist/esm/mixins/OxyServices.topics.js +0 -134
- package/dist/esm/mixins/OxyServices.user.js +0 -951
- package/dist/esm/mixins/OxyServices.utility.js +0 -1397
- package/dist/esm/mixins/index.js +0 -133
- package/dist/esm/mixins/mixinHelpers.js +0 -48
- package/dist/esm/utils/webauthnOrigin.js +0 -48
- package/dist/types/.tsbuildinfo +0 -1
- package/dist/types/OxyServices.base.d.ts +0 -189
- package/dist/types/mixins/OxyServices.accounts.d.ts +0 -868
- package/dist/types/mixins/OxyServices.agency.d.ts +0 -176
- package/dist/types/mixins/OxyServices.analytics.d.ts +0 -72
- package/dist/types/mixins/OxyServices.appData.d.ts +0 -108
- package/dist/types/mixins/OxyServices.assets.d.ts +0 -371
- package/dist/types/mixins/OxyServices.auth.d.ts +0 -965
- package/dist/types/mixins/OxyServices.chains.d.ts +0 -156
- package/dist/types/mixins/OxyServices.civic.d.ts +0 -520
- package/dist/types/mixins/OxyServices.connectedApps.d.ts +0 -184
- package/dist/types/mixins/OxyServices.contacts.d.ts +0 -100
- package/dist/types/mixins/OxyServices.deviceBoot.d.ts +0 -185
- package/dist/types/mixins/OxyServices.devices.d.ts +0 -103
- package/dist/types/mixins/OxyServices.features.d.ts +0 -250
- package/dist/types/mixins/OxyServices.followGraph.d.ts +0 -223
- package/dist/types/mixins/OxyServices.identity.d.ts +0 -337
- package/dist/types/mixins/OxyServices.identityBackup.d.ts +0 -129
- package/dist/types/mixins/OxyServices.inference.d.ts +0 -95
- package/dist/types/mixins/OxyServices.language.d.ts +0 -87
- package/dist/types/mixins/OxyServices.linkedAccounts.d.ts +0 -107
- package/dist/types/mixins/OxyServices.location.d.ts +0 -70
- package/dist/types/mixins/OxyServices.nodes.d.ts +0 -198
- package/dist/types/mixins/OxyServices.notifications.d.ts +0 -143
- package/dist/types/mixins/OxyServices.payment.d.ts +0 -117
- package/dist/types/mixins/OxyServices.privacy.d.ts +0 -146
- package/dist/types/mixins/OxyServices.reputation.d.ts +0 -202
- package/dist/types/mixins/OxyServices.security.d.ts +0 -84
- package/dist/types/mixins/OxyServices.store.d.ts +0 -334
- package/dist/types/mixins/OxyServices.topics.d.ts +0 -110
- package/dist/types/mixins/OxyServices.user.d.ts +0 -600
- package/dist/types/mixins/OxyServices.utility.d.ts +0 -526
- package/dist/types/mixins/index.d.ts +0 -87
- package/dist/types/mixins/mixinHelpers.d.ts +0 -31
- package/dist/types/utils/webauthnOrigin.d.ts +0 -32
- package/src/OxyServices.base.ts +0 -480
- package/src/__tests__/authSocket.test.ts +0 -96
- package/src/__tests__/fixEsmImports.test.ts +0 -132
- package/src/__tests__/httpServiceAbort.test.ts +0 -308
- package/src/__tests__/httpServiceActivityId.test.ts +0 -49
- package/src/__tests__/httpServiceAuthSelfAwait.test.ts +0 -108
- package/src/__tests__/httpServiceCache.test.ts +0 -318
- package/src/__tests__/httpServiceFormEncoded.test.ts +0 -139
- package/src/__tests__/httpServiceQueueDeadlock.test.ts +0 -128
- package/src/__tests__/httpServiceRateLimitedRefresh.test.ts +0 -160
- package/src/__tests__/httpServiceUnwrapEnvelope.test.ts +0 -115
- package/src/__tests__/httpServiceWrites.test.ts +0 -175
- package/src/__tests__/inSessionRefresh.test.ts +0 -313
- package/src/__tests__/linkedClient.test.ts +0 -363
- package/src/__tests__/nearExpiryMintStorm.test.ts +0 -165
- package/src/__tests__/parseHttpErrorBody.test.ts +0 -116
- package/src/__tests__/publicInterfaceParity.test.ts +0 -75
- package/src/__tests__/serverValueImportsDeclared.test.ts +0 -120
- package/src/__tests__/serviceTokenWorkloadFallback.test.ts +0 -85
- package/src/__tests__/userIdentity.test.ts +0 -143
- package/src/boot/__tests__/sessionColdBoot.identity.test.ts +0 -393
- package/src/boot/__tests__/sessionColdBoot.sharedDevice.test.ts +0 -325
- package/src/boot/__tests__/sessionColdBoot.test.ts +0 -570
- package/src/crypto/__tests__/backupMaterial.test.ts +0 -86
- package/src/crypto/__tests__/cryptoPrimitives.test.ts +0 -226
- package/src/crypto/__tests__/identityLink.test.ts +0 -18
- package/src/crypto/__tests__/identityMocks.ts +0 -125
- package/src/crypto/__tests__/identityProof.test.ts +0 -81
- package/src/crypto/__tests__/keyManager.atomicity.test.ts +0 -272
- package/src/crypto/__tests__/keyManager.cacheSafety.test.ts +0 -175
- package/src/crypto/__tests__/keyManager.deviceBackup.test.ts +0 -310
- package/src/crypto/__tests__/keyManager.identityStatus.test.ts +0 -217
- package/src/crypto/__tests__/keyManager.recoveryLadder.test.ts +0 -179
- package/src/crypto/__tests__/keyManager.recoveryMnemonic.test.ts +0 -138
- package/src/crypto/__tests__/keyManager.sharedSlotSync.test.ts +0 -150
- package/src/crypto/__tests__/keyManager.storageMigration.test.ts +0 -227
- package/src/crypto/__tests__/keyManager.test.ts +0 -329
- package/src/crypto/__tests__/polyfill.test.ts +0 -109
- package/src/crypto/__tests__/polyfillOrder.test.ts +0 -114
- package/src/crypto/__tests__/recoveryPhrase.test.ts +0 -61
- package/src/crypto/__tests__/registrationPow.test.ts +0 -61
- package/src/crypto/__tests__/scopedSeed.test.ts +0 -126
- package/src/crypto/__tests__/signChallengeShared.test.ts +0 -63
- package/src/crypto/__tests__/signedRecord.test.ts +0 -230
- package/src/i18n/__tests__/accountCategoryLabels.test.ts +0 -62
- package/src/i18n/__tests__/accountRoleLabels.test.ts +0 -54
- package/src/i18n/__tests__/reputationCategoryLabels.test.ts +0 -56
- package/src/i18n/__tests__/trustTierLabels.test.ts +0 -47
- package/src/i18n/locales/de-DE.json +0 -306
- package/src/i18n/locales/es-ES.json +0 -2127
- package/src/i18n/locales/ja-JP.json +0 -306
- package/src/inference/__tests__/OxyInferenceClient.test.ts +0 -899
- package/src/logger/__tests__/logger.test.ts +0 -207
- package/src/mixins/OxyServices.accounts.ts +0 -1330
- package/src/mixins/OxyServices.agency.ts +0 -353
- package/src/mixins/OxyServices.analytics.ts +0 -53
- package/src/mixins/OxyServices.appData.ts +0 -158
- package/src/mixins/OxyServices.assets.ts +0 -964
- package/src/mixins/OxyServices.auth.ts +0 -2028
- package/src/mixins/OxyServices.chains.ts +0 -134
- package/src/mixins/OxyServices.civic.ts +0 -945
- package/src/mixins/OxyServices.connectedApps.ts +0 -212
- package/src/mixins/OxyServices.contacts.ts +0 -73
- package/src/mixins/OxyServices.devices.ts +0 -120
- package/src/mixins/OxyServices.features.ts +0 -454
- package/src/mixins/OxyServices.followGraph.ts +0 -293
- package/src/mixins/OxyServices.identity.ts +0 -787
- package/src/mixins/OxyServices.identityBackup.ts +0 -250
- package/src/mixins/OxyServices.inference.ts +0 -57
- package/src/mixins/OxyServices.language.ts +0 -144
- package/src/mixins/OxyServices.linkedAccounts.ts +0 -129
- package/src/mixins/OxyServices.location.ts +0 -46
- package/src/mixins/OxyServices.nodes.ts +0 -337
- package/src/mixins/OxyServices.notifications.ts +0 -142
- package/src/mixins/OxyServices.payment.ts +0 -163
- package/src/mixins/OxyServices.privacy.ts +0 -219
- package/src/mixins/OxyServices.reputation.ts +0 -436
- package/src/mixins/OxyServices.security.ts +0 -110
- package/src/mixins/OxyServices.store.ts +0 -585
- package/src/mixins/OxyServices.topics.ts +0 -169
- package/src/mixins/OxyServices.user.ts +0 -1208
- package/src/mixins/OxyServices.utility.ts +0 -1803
- package/src/mixins/__tests__/OxyServices.civic.test.ts +0 -1095
- package/src/mixins/__tests__/OxyServices.deviceBoot.test.ts +0 -124
- package/src/mixins/__tests__/OxyServices.identity.test.ts +0 -301
- package/src/mixins/__tests__/OxyServices.nodes.test.ts +0 -341
- package/src/mixins/__tests__/OxyServices.rotateKey.test.ts +0 -323
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadata.test.ts +0 -192
- package/src/mixins/__tests__/OxyServices.serviceAssetMetadataBySha.test.ts +0 -135
- package/src/mixins/__tests__/OxyServices.serviceLinkedDownloadUrl.test.ts +0 -139
- package/src/mixins/__tests__/accountEvents.test.ts +0 -158
- package/src/mixins/__tests__/accounts.test.ts +0 -727
- package/src/mixins/__tests__/agency.test.ts +0 -120
- package/src/mixins/__tests__/appData.test.ts +0 -203
- package/src/mixins/__tests__/assetCredentials.test.ts +0 -47
- package/src/mixins/__tests__/assetUpload.test.ts +0 -191
- package/src/mixins/__tests__/authRefusalObservability.test.ts +0 -396
- package/src/mixins/__tests__/backgroundCredential.httpIntegration.test.ts +0 -130
- package/src/mixins/__tests__/chains.test.ts +0 -113
- package/src/mixins/__tests__/commonsSignIn.test.ts +0 -1147
- package/src/mixins/__tests__/connectedApps.test.ts +0 -146
- package/src/mixins/__tests__/deviceTokenMintPinned.test.ts +0 -113
- package/src/mixins/__tests__/discoveryErrorHandling.test.ts +0 -265
- package/src/mixins/__tests__/followCacheInvalidation.test.ts +0 -173
- package/src/mixins/__tests__/followGraph.test.ts +0 -147
- package/src/mixins/__tests__/followGraphPagination.test.ts +0 -271
- package/src/mixins/__tests__/getFileDownloadUrl.test.ts +0 -346
- package/src/mixins/__tests__/getFollowStatuses.test.ts +0 -95
- package/src/mixins/__tests__/getUsersByIds.test.ts +0 -176
- package/src/mixins/__tests__/identityBackup.test.ts +0 -315
- package/src/mixins/__tests__/identityLink.test.ts +0 -89
- package/src/mixins/__tests__/identityWriteCacheInvalidation.test.ts +0 -407
- package/src/mixins/__tests__/inferenceFactory.test.ts +0 -58
- package/src/mixins/__tests__/linkedAccounts.test.ts +0 -109
- package/src/mixins/__tests__/notifications.read.test.ts +0 -82
- package/src/mixins/__tests__/onTokensChanged.test.ts +0 -129
- package/src/mixins/__tests__/preSessionSkipAuth.test.ts +0 -284
- package/src/mixins/__tests__/privacyCacheInvalidation.test.ts +0 -155
- package/src/mixins/__tests__/reputation.test.ts +0 -522
- package/src/mixins/__tests__/serviceAuth.test.ts +0 -889
- package/src/mixins/__tests__/serviceTokenJwks.test.ts +0 -208
- package/src/mixins/__tests__/store.test.ts +0 -304
- package/src/mixins/__tests__/topics.test.ts +0 -155
- package/src/mixins/__tests__/userReadCacheBypass.test.ts +0 -129
- package/src/mixins/__tests__/userTokenAuth.test.ts +0 -746
- package/src/mixins/__tests__/verifyChallenge.test.ts +0 -161
- package/src/mixins/__tests__/verifyServiceActingAs.test.ts +0 -167
- package/src/mixins/__tests__/webauthnAuth.test.ts +0 -279
- package/src/mixins/index.ts +0 -203
- package/src/mixins/mixinHelpers.ts +0 -69
- package/src/server/__tests__/auth.test.ts +0 -78
- package/src/server/__tests__/capabilityTicket.test.ts +0 -111
- package/src/server/__tests__/cors.socket.test.ts +0 -225
- package/src/server/__tests__/cors.test.ts +0 -158
- package/src/server/__tests__/rateLimit.test.ts +0 -257
- package/src/server/__tests__/requesterAssertion.test.ts +0 -359
- package/src/server/__tests__/safeFetch.test.ts +0 -232
- package/src/server/__tests__/securityHeaders.test.ts +0 -387
- package/src/server/__tests__/serviceTokenAttribution.test.ts +0 -396
- package/src/server/__tests__/traffic.test.ts +0 -180
- package/src/server/__tests__/trafficNodeHttp.test.ts +0 -38
- package/src/server/__tests__/userInvalidation.test.ts +0 -203
- package/src/server/__tests__/verifySecret.test.ts +0 -40
- package/src/server/__tests__/workloadIdentity.client.test.ts +0 -16
- package/src/server/__tests__/workloadIdentity.test.ts +0 -128
- package/src/session/__tests__/SessionClient.additive.test.ts +0 -153
- package/src/session/__tests__/SessionClient.broadcastChannel.test.ts +0 -114
- package/src/session/__tests__/SessionClient.diagnostics.test.ts +0 -91
- package/src/session/__tests__/SessionClient.directory.test.ts +0 -688
- package/src/session/__tests__/SessionClient.httpIntegration.test.ts +0 -65
- package/src/session/__tests__/SessionClient.identityPin.test.ts +0 -175
- package/src/session/__tests__/SessionClient.rest.test.ts +0 -119
- package/src/session/__tests__/SessionClient.serverEvents.test.ts +0 -72
- package/src/session/__tests__/SessionClient.socket.test.ts +0 -202
- package/src/session/__tests__/SessionClient.socketFactory.test.ts +0 -81
- package/src/session/__tests__/SessionClient.state.test.ts +0 -78
- package/src/session/__tests__/SessionClient.switchTokenOrder.test.ts +0 -170
- package/src/session/__tests__/accountDelegationAccess.test.ts +0 -104
- package/src/session/__tests__/accountDialogController.test.ts +0 -2502
- package/src/session/__tests__/accountDialogShape.test.ts +0 -120
- package/src/session/__tests__/accountSwitchTargets.test.ts +0 -137
- package/src/session/__tests__/authStateStore.test.ts +0 -451
- package/src/session/__tests__/deviceDirectory.test.ts +0 -422
- package/src/session/__tests__/deviceSwitcherRows.test.ts +0 -223
- package/src/session/__tests__/identityPin.test.ts +0 -131
- package/src/session/__tests__/identitySession.test.ts +0 -194
- package/src/session/__tests__/projectSessionState.test.ts +0 -105
- package/src/session/__tests__/refresh.identityPin.test.ts +0 -307
- package/src/session/__tests__/refresh.test.ts +0 -606
- package/src/session/__tests__/sessionIntegration.test.ts +0 -209
- package/src/session/__tests__/sharedDeviceCredential.test.ts +0 -300
- package/src/utils/__tests__/accountUtils.test.ts +0 -151
- package/src/utils/__tests__/activityId.test.ts +0 -45
- package/src/utils/__tests__/asyncUtils.test.ts +0 -279
- package/src/utils/__tests__/authWebUrl.test.ts +0 -15
- package/src/utils/__tests__/cacheKey.test.ts +0 -0
- package/src/utils/__tests__/cacheLifecycle.test.ts +0 -65
- package/src/utils/__tests__/coldBoot.test.ts +0 -496
- package/src/utils/__tests__/commonsApproval.test.ts +0 -60
- package/src/utils/__tests__/identityCacheSweep.test.ts +0 -151
- package/src/utils/__tests__/languageUtils.test.ts +0 -244
- package/src/utils/__tests__/oauthPkce.test.ts +0 -303
- package/src/utils/__tests__/officialOrigins.test.ts +0 -31
- package/src/utils/__tests__/oxyServiceEnvironment.test.ts +0 -7
- package/src/utils/__tests__/profileLinks.test.ts +0 -180
- package/src/utils/__tests__/redactUrl.test.ts +0 -33
- package/src/utils/__tests__/registrableApex.test.ts +0 -62
- package/src/utils/__tests__/requestUtilsAbort.test.ts +0 -155
- package/src/utils/__tests__/textNormalization.test.ts +0 -205
- package/src/utils/__tests__/validationUtils.test.ts +0 -703
- package/src/utils/__tests__/webauthnOrigin.test.ts +0 -83
- package/src/utils/webauthnOrigin.ts +0 -52
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `OxyServer` — the Oxy client for a backend.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { OxyServer } from '@oxy.so/core/server';
|
|
6
|
+
*
|
|
7
|
+
* const oxy = new OxyServer({
|
|
8
|
+
* baseURL: 'https://api.oxy.so',
|
|
9
|
+
* serviceAuth: { apiKey: process.env.OXY_SERVICE_API_KEY!, apiSecret: process.env.OXY_SERVICE_API_SECRET! },
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* app.use('/api', oxy.middleware.auth());
|
|
13
|
+
* io.use(oxy.middleware.socket());
|
|
14
|
+
* app.use('/internal', oxy.middleware.service(), oxy.middleware.requireScope('files:read'));
|
|
15
|
+
*
|
|
16
|
+
* const people = await oxy.users.getMany(ids); // service lane when available
|
|
17
|
+
* const meta = await oxy.assets.metadataByIds(fileIds); // service-only
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Everything `OxyServices` has, plus the service-token lane (a key pair from
|
|
21
|
+
* `serviceAuth` / `configureServiceAuth`, or — with neither — the process's
|
|
22
|
+
* attested workload identity, ADR 0026), the Express / Socket.IO middleware,
|
|
23
|
+
* account events, and the service-only methods of `assets`, `notifications`,
|
|
24
|
+
* `linkedAccounts`, `agency` and `reputation`.
|
|
25
|
+
*
|
|
26
|
+
* Node only.
|
|
27
|
+
*/
|
|
28
|
+
import { jwtDecode } from 'jwt-decode';
|
|
29
|
+
import { loadNodeCrypto } from '@oxy.so/protocol';
|
|
30
|
+
import { OxyServices } from '../OxyServices.js';
|
|
31
|
+
import { logger } from '../logger/index.js';
|
|
32
|
+
import { canAttestWorkloadIdentity, requestWorkloadServiceToken } from './workloadIdentity.js';
|
|
33
|
+
import { createOxyMiddleware, OXY_ACCOUNT_DELETED_EVENT_URI, OXY_JWT_ISSUER, OxyAccountEventError, parseJsonSegment, resolveServiceTokenPublicKey, } from './middleware.js';
|
|
34
|
+
import { ServerAgencyApi, ServerAssetsApi, ServerLinkedAccountsApi, ServerNotificationsApi, ServerReputationApi, } from './namespaces.js';
|
|
35
|
+
/**
|
|
36
|
+
* How long a failed service-token mint sends session-less requests anonymous
|
|
37
|
+
* before the next attempt, under `serviceIdentity: 'when-anonymous'`.
|
|
38
|
+
*/
|
|
39
|
+
export const ANONYMOUS_SERVICE_TOKEN_RETRY_MS = 30000;
|
|
40
|
+
/**
|
|
41
|
+
* Sentinel error raised when a service token is asked for with a known apiKey
|
|
42
|
+
* but a non-matching secret: credential drift in the caller, or a cross-tenant
|
|
43
|
+
* cache lookup attempt. Surface as a 401-equivalent.
|
|
44
|
+
*/
|
|
45
|
+
export class ServiceCredentialMismatchError extends Error {
|
|
46
|
+
constructor() {
|
|
47
|
+
super('Service credential mismatch: provided secret does not match the secret stored for this apiKey');
|
|
48
|
+
this.name = 'ServiceCredentialMismatchError';
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
const WORKLOAD_CACHE_KEY = 'workload-identity';
|
|
52
|
+
/** A token is reused until 60s before expiry (clock drift). */
|
|
53
|
+
const TOKEN_REUSE_MARGIN_MS = 60000;
|
|
54
|
+
/** Bound on remembered `appId:userId` delegation answers. */
|
|
55
|
+
const ACTING_AS_CACHE_MAX = 1000;
|
|
56
|
+
/** A positive grant is reused for 5 minutes — the revocation latency window. */
|
|
57
|
+
const ACTING_AS_GRANT_TTL_MS = 5 * 60 * 1000;
|
|
58
|
+
/** A negative answer (or a failed lookup) is reused for 1 minute. */
|
|
59
|
+
const ACTING_AS_DENIAL_TTL_MS = 60 * 1000;
|
|
60
|
+
export class OxyServer extends OxyServices {
|
|
61
|
+
constructor(config) {
|
|
62
|
+
super(config);
|
|
63
|
+
this.serviceTokens = new Map();
|
|
64
|
+
this.serviceApiKey = null;
|
|
65
|
+
this.serviceApiSecret = null;
|
|
66
|
+
this.actingAs = new Map();
|
|
67
|
+
this.actingAsPending = new Map();
|
|
68
|
+
/** Public keys only; never private material. */
|
|
69
|
+
this.jwksCache = { keys: new Map(), expiresAt: 0, lastAttemptAt: 0 };
|
|
70
|
+
/**
|
|
71
|
+
* Before this instant a request without a user session does not try to mint
|
|
72
|
+
* a service token and goes out anonymous. Set after a failed mint.
|
|
73
|
+
*/
|
|
74
|
+
this.anonymousServiceTokenRetryAt = 0;
|
|
75
|
+
/**
|
|
76
|
+
* Account events addressed to this application (Oxy account deletions every
|
|
77
|
+
* relying application must honour, OxyHQ/Mention#1169).
|
|
78
|
+
*/
|
|
79
|
+
this.accountEvents = {
|
|
80
|
+
/**
|
|
81
|
+
* Verify an account event token — a webhook body, or a feed entry's `token`
|
|
82
|
+
* — and return the event. Throws {@link OxyAccountEventError} unless it is
|
|
83
|
+
* an EdDSA `secevent+jwt` from Oxy's key set, issued by `oxy-auth`,
|
|
84
|
+
* addressed to this application, carrying exactly one known event. Be
|
|
85
|
+
* idempotent on `eventId`: Oxy delivers at least once.
|
|
86
|
+
*/
|
|
87
|
+
verify: (token, options = {}) => this.verifyAccountEvent(token, options),
|
|
88
|
+
/**
|
|
89
|
+
* One page of account events for this application, oldest first — the pull
|
|
90
|
+
* feed behind the webhook. Verify each entry's `token` before acting on it.
|
|
91
|
+
*/
|
|
92
|
+
list: async (options = {}) => {
|
|
93
|
+
const query = {};
|
|
94
|
+
if (options.after)
|
|
95
|
+
query.after = options.after;
|
|
96
|
+
if (options.limit !== undefined)
|
|
97
|
+
query.limit = String(options.limit);
|
|
98
|
+
return this.serviceRequest('GET', '/account-events', query);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
if (config.serviceAuth) {
|
|
102
|
+
this.configureServiceAuth(config.serviceAuth.apiKey, config.serviceAuth.apiSecret);
|
|
103
|
+
}
|
|
104
|
+
const server = this;
|
|
105
|
+
const serviceLane = {
|
|
106
|
+
get available() {
|
|
107
|
+
return server.canMintServiceToken();
|
|
108
|
+
},
|
|
109
|
+
request: (...args) => this.serviceRequest(...args),
|
|
110
|
+
};
|
|
111
|
+
this.context.service = serviceLane;
|
|
112
|
+
if (config.serviceIdentity === 'when-anonymous') {
|
|
113
|
+
this.http.setAnonymousAuthProvider(() => this.serviceTokenForAnonymousRequest());
|
|
114
|
+
}
|
|
115
|
+
this.middleware = createOxyMiddleware({
|
|
116
|
+
get baseURL() {
|
|
117
|
+
return server.baseURL;
|
|
118
|
+
},
|
|
119
|
+
jwksCache: this.jwksCache,
|
|
120
|
+
validateSession: (sessionId, options) => this.session.validate(sessionId, options),
|
|
121
|
+
verifyActingAs: (appId, userId) => this.verifyActingAs(appId, userId),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
/** Files, plus the service-only metadata and linked-URL lookups. */
|
|
125
|
+
get assets() {
|
|
126
|
+
if (!this._serverAssets)
|
|
127
|
+
this._serverAssets = new ServerAssetsApi(this.context);
|
|
128
|
+
return this._serverAssets;
|
|
129
|
+
}
|
|
130
|
+
/** The inbox and push tokens, plus `create`. */
|
|
131
|
+
get notifications() {
|
|
132
|
+
if (!this._serverNotifications)
|
|
133
|
+
this._serverNotifications = new ServerNotificationsApi(this.context);
|
|
134
|
+
return this._serverNotifications;
|
|
135
|
+
}
|
|
136
|
+
/** Linked external accounts, plus `forUser`. */
|
|
137
|
+
get linkedAccounts() {
|
|
138
|
+
if (!this._serverLinkedAccounts)
|
|
139
|
+
this._serverLinkedAccounts = new ServerLinkedAccountsApi(this.context);
|
|
140
|
+
return this._serverLinkedAccounts;
|
|
141
|
+
}
|
|
142
|
+
/** Delegated capabilities, plus `introspectRequesterAssertion`. */
|
|
143
|
+
get agency() {
|
|
144
|
+
if (!this._serverAgency)
|
|
145
|
+
this._serverAgency = new ServerAgencyApi(this.context);
|
|
146
|
+
return this._serverAgency;
|
|
147
|
+
}
|
|
148
|
+
/** Reputation reads, plus `award`. */
|
|
149
|
+
get reputation() {
|
|
150
|
+
if (!this._serverReputation)
|
|
151
|
+
this._serverReputation = new ServerReputationApi(this.context);
|
|
152
|
+
return this._serverReputation;
|
|
153
|
+
}
|
|
154
|
+
// ── Service token ────────────────────────────────────────────────────────
|
|
155
|
+
/**
|
|
156
|
+
* Set this service's application credential. Each `(apiKey, apiSecret)` pair
|
|
157
|
+
* is cached independently, so a multi-tenant host switching credentials
|
|
158
|
+
* cannot leak one tenant's token to another.
|
|
159
|
+
*/
|
|
160
|
+
configureServiceAuth(apiKey, apiSecret) {
|
|
161
|
+
this.serviceApiKey = apiKey;
|
|
162
|
+
this.serviceApiSecret = apiSecret;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A service token (short-lived, cached and refreshed per credential pair;
|
|
166
|
+
* concurrent callers share one mint).
|
|
167
|
+
*
|
|
168
|
+
* With no credential configured or passed, the token comes from the process's
|
|
169
|
+
* attested workload identity (ADR 0026); with neither, this throws.
|
|
170
|
+
*
|
|
171
|
+
* If the cache already holds a token for `apiKey` but `apiSecret` does not
|
|
172
|
+
* constant-time match the secret that produced it, this throws
|
|
173
|
+
* {@link ServiceCredentialMismatchError} rather than return the cached token.
|
|
174
|
+
*/
|
|
175
|
+
async serviceToken(apiKey, apiSecret) {
|
|
176
|
+
const key = apiKey || this.serviceApiKey;
|
|
177
|
+
const secret = apiSecret || this.serviceApiSecret;
|
|
178
|
+
if (!key || !secret) {
|
|
179
|
+
// No credential — prove what this process IS instead. The fallback, not the
|
|
180
|
+
// preference: a deployment that still has a credential keeps using it.
|
|
181
|
+
if (canAttestWorkloadIdentity()) {
|
|
182
|
+
return this.workloadServiceToken();
|
|
183
|
+
}
|
|
184
|
+
throw new Error('Service credentials not provided. Pass serviceAuth, call configureServiceAuth(), or pass apiKey and apiSecret.');
|
|
185
|
+
}
|
|
186
|
+
// The apiKey is the credential's PUBLIC id (`oxy_dk_…`, the OAuth
|
|
187
|
+
// client_id), so it keys the in-memory cache as is; the secret never does.
|
|
188
|
+
const cacheKey = key;
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
const providedSecretBuf = Buffer.from(secret, 'utf8');
|
|
191
|
+
let entry = this.serviceTokens.get(cacheKey);
|
|
192
|
+
if (entry) {
|
|
193
|
+
// Verify the secret on every hit, fresh token or not. Constant-time, and
|
|
194
|
+
// run on equal-length inputs even when the lengths differ.
|
|
195
|
+
const nodeCrypto = await loadNodeCrypto();
|
|
196
|
+
const stored = entry.secretBuf;
|
|
197
|
+
const lengthMatch = stored.length === providedSecretBuf.length;
|
|
198
|
+
const compareBuf = lengthMatch ? providedSecretBuf : Buffer.alloc(stored.length);
|
|
199
|
+
const equal = nodeCrypto.timingSafeEqual(stored, compareBuf);
|
|
200
|
+
if (!lengthMatch || !equal) {
|
|
201
|
+
logger.warn('[oxy.auth] Service token cache hit with mismatched secret', {
|
|
202
|
+
component: 'auth',
|
|
203
|
+
method: 'serviceToken',
|
|
204
|
+
});
|
|
205
|
+
throw new ServiceCredentialMismatchError();
|
|
206
|
+
}
|
|
207
|
+
if (entry.token && entry.expiresAt > now + TOKEN_REUSE_MARGIN_MS) {
|
|
208
|
+
return entry.token;
|
|
209
|
+
}
|
|
210
|
+
if (entry.pending) {
|
|
211
|
+
return entry.pending;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
// Seed an empty entry so concurrent callers serialize on one promise.
|
|
216
|
+
entry = { token: '', expiresAt: 0, secretBuf: providedSecretBuf, pending: null, apiKey: key };
|
|
217
|
+
this.serviceTokens.set(cacheKey, entry);
|
|
218
|
+
}
|
|
219
|
+
const pending = this.mintServiceToken(key, secret, cacheKey, providedSecretBuf);
|
|
220
|
+
entry.pending = pending;
|
|
221
|
+
try {
|
|
222
|
+
return await pending;
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
// Never keep an entry that never held a token: a wrong first secret must
|
|
226
|
+
// not make the right one fail locally as a mismatch later.
|
|
227
|
+
const failed = this.serviceTokens.get(cacheKey);
|
|
228
|
+
if (failed?.pending === pending && !failed.token) {
|
|
229
|
+
this.serviceTokens.delete(cacheKey);
|
|
230
|
+
}
|
|
231
|
+
throw error;
|
|
232
|
+
}
|
|
233
|
+
finally {
|
|
234
|
+
const settled = this.serviceTokens.get(cacheKey);
|
|
235
|
+
if (settled?.pending === pending)
|
|
236
|
+
settled.pending = null;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Forget cached service token(s) so the next `serviceToken()` mints anew —
|
|
241
|
+
* the way back from a 401 after a credential was revoked or rotated.
|
|
242
|
+
*
|
|
243
|
+
* `apiKey` clears that credential's entry; with none, the configured
|
|
244
|
+
* credential's; with neither, every entry. Synchronous.
|
|
245
|
+
*/
|
|
246
|
+
invalidateServiceToken(apiKey) {
|
|
247
|
+
const targetKey = apiKey ?? this.serviceApiKey;
|
|
248
|
+
if (!targetKey) {
|
|
249
|
+
this.serviceTokens.clear();
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
this.serviceTokens.delete(targetKey);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* One request with this service's token. `actAs` sends `X-Oxy-User-Id`: the
|
|
256
|
+
* request is on behalf of that user (the API checks the delegation grant).
|
|
257
|
+
* Never cached unless `cache` says so. Rejects with `OxyApiError`.
|
|
258
|
+
*/
|
|
259
|
+
async serviceRequest(method, url, data, options = {}) {
|
|
260
|
+
const { actAs, headers, ...rest } = options;
|
|
261
|
+
const token = await this.serviceToken();
|
|
262
|
+
const merged = { ...headers, Authorization: `Bearer ${token}` };
|
|
263
|
+
if (actAs)
|
|
264
|
+
merged['X-Oxy-User-Id'] = actAs;
|
|
265
|
+
return this.request(method, url, data, { cache: false, ...rest, headers: merged });
|
|
266
|
+
}
|
|
267
|
+
// ── Delegation and account events ────────────────────────────────────────
|
|
268
|
+
/**
|
|
269
|
+
* Whether service app `appId` holds an active delegation grant to act for
|
|
270
|
+
* `userId`; the grant's scopes, or `null`. Used by `middleware.auth()` for
|
|
271
|
+
* `X-Oxy-User-Id`.
|
|
272
|
+
*
|
|
273
|
+
* Answers are cached per `appId:userId` (a grant for 5 minutes — the
|
|
274
|
+
* revocation window; a denial or failed lookup for 1 minute), bounded to the
|
|
275
|
+
* 1000 most recent pairs, and concurrent lookups of one pair share a single
|
|
276
|
+
* request.
|
|
277
|
+
*/
|
|
278
|
+
async verifyActingAs(appId, userId) {
|
|
279
|
+
const cacheKey = `${appId}:${userId}`;
|
|
280
|
+
const cached = this.actingAs.get(cacheKey);
|
|
281
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
282
|
+
// Refresh recency for the LRU bound.
|
|
283
|
+
this.actingAs.delete(cacheKey);
|
|
284
|
+
this.actingAs.set(cacheKey, cached);
|
|
285
|
+
return cached.result;
|
|
286
|
+
}
|
|
287
|
+
const inflight = this.actingAsPending.get(cacheKey);
|
|
288
|
+
if (inflight)
|
|
289
|
+
return inflight;
|
|
290
|
+
const lookup = this.lookupActingAs(appId, userId).finally(() => {
|
|
291
|
+
this.actingAsPending.delete(cacheKey);
|
|
292
|
+
});
|
|
293
|
+
this.actingAsPending.set(cacheKey, lookup);
|
|
294
|
+
return lookup;
|
|
295
|
+
}
|
|
296
|
+
// ── Internals ────────────────────────────────────────────────────────────
|
|
297
|
+
/**
|
|
298
|
+
* The bearer for a request with no user session, under `serviceIdentity:
|
|
299
|
+
* 'when-anonymous'`: this process's service token, or `null` to send the
|
|
300
|
+
* request anonymous.
|
|
301
|
+
*
|
|
302
|
+
* `null`, never a throw, whenever there is no token to offer:
|
|
303
|
+
* - no key pair and no attestable workload (a local checkout);
|
|
304
|
+
* - the mint failed. The request still goes out, anonymous, and so does every
|
|
305
|
+
* request for the next {@link ANONYMOUS_SERVICE_TOKEN_RETRY_MS}, so an Oxy
|
|
306
|
+
* refusing attestation is asked once per window rather than once per read.
|
|
307
|
+
*
|
|
308
|
+
* The token comes from {@link serviceToken}: cached and single-flight, so
|
|
309
|
+
* concurrent reads share one mint.
|
|
310
|
+
*/
|
|
311
|
+
async serviceTokenForAnonymousRequest() {
|
|
312
|
+
if (Date.now() < this.anonymousServiceTokenRetryAt)
|
|
313
|
+
return null;
|
|
314
|
+
if (!this.canMintServiceToken())
|
|
315
|
+
return null;
|
|
316
|
+
try {
|
|
317
|
+
return await this.serviceToken();
|
|
318
|
+
}
|
|
319
|
+
catch (error) {
|
|
320
|
+
this.anonymousServiceTokenRetryAt = Date.now() + ANONYMOUS_SERVICE_TOKEN_RETRY_MS;
|
|
321
|
+
logger.warn('[oxy.auth] No service token for a request without a session; sending it anonymous', {
|
|
322
|
+
component: 'auth',
|
|
323
|
+
method: 'serviceTokenForAnonymousRequest',
|
|
324
|
+
retryInMs: ANONYMOUS_SERVICE_TOKEN_RETRY_MS,
|
|
325
|
+
error: error instanceof Error ? error.message : String(error),
|
|
326
|
+
});
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
canMintServiceToken() {
|
|
331
|
+
return Boolean(this.serviceApiKey && this.serviceApiSecret) || canAttestWorkloadIdentity();
|
|
332
|
+
}
|
|
333
|
+
async mintServiceToken(key, secret, cacheKey, secretBuf) {
|
|
334
|
+
const response = await this.request('POST', '/auth/service-token', { apiKey: key, apiSecret: secret }, { cache: false, retry: false, skipAuth: true });
|
|
335
|
+
const expiresAt = Date.now() + response.expiresIn * 1000;
|
|
336
|
+
const entry = this.serviceTokens.get(cacheKey);
|
|
337
|
+
if (entry) {
|
|
338
|
+
entry.token = response.token;
|
|
339
|
+
entry.expiresAt = expiresAt;
|
|
340
|
+
entry.secretBuf = secretBuf;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
this.serviceTokens.set(cacheKey, { token: response.token, expiresAt, secretBuf, pending: null, apiKey: key });
|
|
344
|
+
}
|
|
345
|
+
return response.token;
|
|
346
|
+
}
|
|
347
|
+
/** A token obtained by attestation, cached like a credential's (one identity per process). */
|
|
348
|
+
async workloadServiceToken() {
|
|
349
|
+
const entry = this.serviceTokens.get(WORKLOAD_CACHE_KEY);
|
|
350
|
+
if (entry?.token && entry.expiresAt > Date.now() + TOKEN_REUSE_MARGIN_MS)
|
|
351
|
+
return entry.token;
|
|
352
|
+
if (entry?.pending)
|
|
353
|
+
return entry.pending;
|
|
354
|
+
const seeded = entry ?? { token: '', expiresAt: 0, secretBuf: Buffer.alloc(0), pending: null, apiKey: WORKLOAD_CACHE_KEY };
|
|
355
|
+
this.serviceTokens.set(WORKLOAD_CACHE_KEY, seeded);
|
|
356
|
+
const pending = (async () => {
|
|
357
|
+
const granted = await requestWorkloadServiceToken({ baseUrl: this.baseURL });
|
|
358
|
+
const current = this.serviceTokens.get(WORKLOAD_CACHE_KEY);
|
|
359
|
+
if (current) {
|
|
360
|
+
current.token = granted.token;
|
|
361
|
+
current.expiresAt = Date.now() + granted.expiresIn * 1000;
|
|
362
|
+
}
|
|
363
|
+
return granted.token;
|
|
364
|
+
})();
|
|
365
|
+
seeded.pending = pending;
|
|
366
|
+
try {
|
|
367
|
+
return await pending;
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
const failed = this.serviceTokens.get(WORKLOAD_CACHE_KEY);
|
|
371
|
+
if (failed?.pending === pending && !failed.token)
|
|
372
|
+
this.serviceTokens.delete(WORKLOAD_CACHE_KEY);
|
|
373
|
+
throw error;
|
|
374
|
+
}
|
|
375
|
+
finally {
|
|
376
|
+
const settled = this.serviceTokens.get(WORKLOAD_CACHE_KEY);
|
|
377
|
+
if (settled?.pending === pending)
|
|
378
|
+
settled.pending = null;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
async lookupActingAs(appId, userId) {
|
|
382
|
+
try {
|
|
383
|
+
// The verify endpoint admits only a platform-trusted caller, so this
|
|
384
|
+
// carries the VERIFIER's own service token. No retry and a short timeout:
|
|
385
|
+
// it runs inside request-handling middleware, and a retry loop would
|
|
386
|
+
// multiply the latency of every delegated request. A verifier with no
|
|
387
|
+
// credential throws here and is refused below — a host that cannot prove
|
|
388
|
+
// who it is has no business learning who delegated to whom.
|
|
389
|
+
const serviceToken = await this.serviceToken();
|
|
390
|
+
const result = await this.request('GET', '/internal/service-acting-as/verify', { appId, userId }, { cache: false, retry: false, timeout: 5000, headers: { Authorization: `Bearer ${serviceToken}` } });
|
|
391
|
+
const verified = result?.authorized
|
|
392
|
+
? { authorized: true, scopes: Array.isArray(result.scopes) ? result.scopes : [] }
|
|
393
|
+
: null;
|
|
394
|
+
this.rememberActingAs(`${appId}:${userId}`, verified, ACTING_AS_GRANT_TTL_MS);
|
|
395
|
+
return verified;
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
logger.warn('[oxy.auth] verifyActingAs lookup failed — caching negative result', {
|
|
399
|
+
component: 'auth',
|
|
400
|
+
method: 'verifyActingAs',
|
|
401
|
+
appId,
|
|
402
|
+
userId,
|
|
403
|
+
}, error);
|
|
404
|
+
this.rememberActingAs(`${appId}:${userId}`, null, ACTING_AS_DENIAL_TTL_MS);
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
rememberActingAs(cacheKey, result, ttlMs) {
|
|
409
|
+
this.actingAs.delete(cacheKey);
|
|
410
|
+
this.actingAs.set(cacheKey, { result, expiresAt: Date.now() + ttlMs });
|
|
411
|
+
if (this.actingAs.size > ACTING_AS_CACHE_MAX) {
|
|
412
|
+
const oldest = this.actingAs.keys().next().value;
|
|
413
|
+
if (oldest !== undefined)
|
|
414
|
+
this.actingAs.delete(oldest);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
async verifyAccountEvent(token, options) {
|
|
418
|
+
if (typeof token !== 'string' || token.length === 0 || token.length > 16 * 1024) {
|
|
419
|
+
throw new OxyAccountEventError('Account event token is missing or oversized');
|
|
420
|
+
}
|
|
421
|
+
const parts = token.split('.');
|
|
422
|
+
if (parts.length !== 3 || parts.some((part) => part.length === 0)) {
|
|
423
|
+
throw new OxyAccountEventError('Account event token is not a compact JWS');
|
|
424
|
+
}
|
|
425
|
+
const [headerB64, payloadB64, signatureB64] = parts;
|
|
426
|
+
let header;
|
|
427
|
+
let payload;
|
|
428
|
+
try {
|
|
429
|
+
header = parseJsonSegment(headerB64);
|
|
430
|
+
payload = parseJsonSegment(payloadB64);
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
throw new OxyAccountEventError('Account event token is malformed');
|
|
434
|
+
}
|
|
435
|
+
if (Object.keys(header).length !== 3
|
|
436
|
+
|| header.alg !== 'EdDSA'
|
|
437
|
+
|| header.typ !== 'secevent+jwt'
|
|
438
|
+
|| typeof header.kid !== 'string'
|
|
439
|
+
|| !/^[A-Za-z0-9._-]{1,128}$/.test(header.kid)) {
|
|
440
|
+
throw new OxyAccountEventError('Account event token header is not supported');
|
|
441
|
+
}
|
|
442
|
+
const nodeCrypto = await loadNodeCrypto();
|
|
443
|
+
let jwk;
|
|
444
|
+
try {
|
|
445
|
+
jwk = await resolveServiceTokenPublicKey(header.kid, options.jwksUrl ?? new URL('/.well-known/jwks.json', this.baseURL).toString(), this.jwksCache);
|
|
446
|
+
}
|
|
447
|
+
catch (error) {
|
|
448
|
+
throw new OxyAccountEventError(error instanceof Error ? error.message.replace('Service token', 'Account event') : 'Signing key is unavailable');
|
|
449
|
+
}
|
|
450
|
+
const signature = Buffer.from(signatureB64, 'base64url');
|
|
451
|
+
if (signature.toString('base64url') !== signatureB64 || signature.length !== 64) {
|
|
452
|
+
throw new OxyAccountEventError('Account event token signature is malformed');
|
|
453
|
+
}
|
|
454
|
+
let verified = false;
|
|
455
|
+
try {
|
|
456
|
+
const publicKey = nodeCrypto.createPublicKey({ key: jwk, format: 'jwk' });
|
|
457
|
+
verified = nodeCrypto.verify(null, Buffer.from(`${headerB64}.${payloadB64}`), publicKey, signature);
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
verified = false;
|
|
461
|
+
}
|
|
462
|
+
if (!verified)
|
|
463
|
+
throw new OxyAccountEventError('Account event token signature is invalid');
|
|
464
|
+
if (payload.iss !== OXY_JWT_ISSUER) {
|
|
465
|
+
throw new OxyAccountEventError('Account event token issuer is not Oxy');
|
|
466
|
+
}
|
|
467
|
+
const audience = options.audience ?? await this.configuredServiceAppId();
|
|
468
|
+
if (typeof payload.aud !== 'string' || payload.aud !== audience) {
|
|
469
|
+
throw new OxyAccountEventError('Account event token is addressed to another application');
|
|
470
|
+
}
|
|
471
|
+
if (typeof payload.jti !== 'string' || payload.jti.length === 0 || payload.jti.length > 128) {
|
|
472
|
+
throw new OxyAccountEventError('Account event token has no event id');
|
|
473
|
+
}
|
|
474
|
+
if (typeof payload.iat !== 'number' || !Number.isFinite(payload.iat)) {
|
|
475
|
+
throw new OxyAccountEventError('Account event token has no issue time');
|
|
476
|
+
}
|
|
477
|
+
const events = payload.events;
|
|
478
|
+
if (typeof events !== 'object' || events === null || Array.isArray(events)) {
|
|
479
|
+
throw new OxyAccountEventError('Account event token carries no events');
|
|
480
|
+
}
|
|
481
|
+
const entries = Object.entries(events);
|
|
482
|
+
const deleted = events[OXY_ACCOUNT_DELETED_EVENT_URI];
|
|
483
|
+
if (entries.length !== 1 || typeof deleted !== 'object' || deleted === null || Array.isArray(deleted)) {
|
|
484
|
+
throw new OxyAccountEventError('Account event token carries an unknown event');
|
|
485
|
+
}
|
|
486
|
+
const body = deleted;
|
|
487
|
+
if (typeof body.userId !== 'string' || body.userId.length === 0 || body.userId.length > 128) {
|
|
488
|
+
throw new OxyAccountEventError('Account event names no account');
|
|
489
|
+
}
|
|
490
|
+
if (typeof body.occurredAt !== 'string' || Number.isNaN(Date.parse(body.occurredAt))) {
|
|
491
|
+
throw new OxyAccountEventError('Account event has no occurrence time');
|
|
492
|
+
}
|
|
493
|
+
if (body.username !== undefined && body.username !== null && typeof body.username !== 'string') {
|
|
494
|
+
throw new OxyAccountEventError('Account event username is malformed');
|
|
495
|
+
}
|
|
496
|
+
return {
|
|
497
|
+
eventId: payload.jti,
|
|
498
|
+
type: 'account.deleted',
|
|
499
|
+
userId: body.userId,
|
|
500
|
+
username: typeof body.username === 'string' ? body.username : null,
|
|
501
|
+
occurredAt: body.occurredAt,
|
|
502
|
+
retained: body.retained === true,
|
|
503
|
+
applicationId: payload.aud,
|
|
504
|
+
issuedAt: payload.iat,
|
|
505
|
+
};
|
|
506
|
+
}
|
|
507
|
+
/** The `appId` claim of this service's own token. */
|
|
508
|
+
async configuredServiceAppId() {
|
|
509
|
+
const serviceToken = await this.serviceToken();
|
|
510
|
+
const appId = jwtDecode(serviceToken).appId;
|
|
511
|
+
if (typeof appId !== 'string' || appId.length === 0) {
|
|
512
|
+
throw new OxyAccountEventError('No audience given and the service credential names no application');
|
|
513
|
+
}
|
|
514
|
+
return appId;
|
|
515
|
+
}
|
|
516
|
+
}
|
package/dist/esm/server/auth.js
CHANGED
|
@@ -111,7 +111,7 @@ export function getRequiredOxyUserId(req) {
|
|
|
111
111
|
* Why the credential on this request was refused, or `null` when none was
|
|
112
112
|
* presented (or it was accepted).
|
|
113
113
|
*
|
|
114
|
-
* Set by `
|
|
114
|
+
* Set by `server.middleware.auth()` — including the `optional: true` mount the composed
|
|
115
115
|
* helpers use, where a refusal otherwise leaves no trace: the request simply
|
|
116
116
|
* arrives unauthenticated and the host answers its own generic 401. Hosts log
|
|
117
117
|
* this beside their own 401; it is diagnostic and **must not be put into a
|
|
@@ -149,7 +149,7 @@ export function requireOxyAuth(req, res, next) {
|
|
|
149
149
|
next();
|
|
150
150
|
}
|
|
151
151
|
export function createOptionalOxyAuth(oxy, options = {}) {
|
|
152
|
-
const resolveSession = oxy.auth({ ...options.auth, optional: true });
|
|
152
|
+
const resolveSession = oxy.middleware.auth({ ...options.auth, optional: true });
|
|
153
153
|
return (req, res, next) => {
|
|
154
154
|
if (getOxyUserId(req)) {
|
|
155
155
|
next();
|
package/dist/esm/server/index.js
CHANGED
|
@@ -6,14 +6,19 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```ts
|
|
9
|
-
* import { createOxyRateLimit } from '@oxy.so/core/server';
|
|
10
|
-
* import { oxyClient } from '@oxy.so/core';
|
|
9
|
+
* import { OxyServer, createOxyAuthMiddleware, createOxyRateLimit } from '@oxy.so/core/server';
|
|
11
10
|
*
|
|
12
|
-
* const oxy =
|
|
11
|
+
* const oxy = new OxyServer({ baseURL: 'https://api.oxy.so', serviceAuth: { apiKey, apiSecret } });
|
|
13
12
|
*
|
|
14
13
|
* app.use(createOxyRateLimit(oxy, { store: redisStore }));
|
|
14
|
+
* app.use('/api', createOxyAuthMiddleware(oxy));
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
17
|
+
// The backend client: OxyServices plus the service-token lane, middleware,
|
|
18
|
+
// account events and the service-only namespace methods.
|
|
19
|
+
export { OxyServer, ServiceCredentialMismatchError, ANONYMOUS_SERVICE_TOKEN_RETRY_MS } from './OxyServer.js';
|
|
20
|
+
export { ServerAgencyApi, ServerAssetsApi, ServerLinkedAccountsApi, ServerNotificationsApi, ServerReputationApi, } from './namespaces.js';
|
|
21
|
+
export { OxyAccountEventError, OXY_ACCOUNT_DELETED_EVENT_URI } from './middleware.js';
|
|
17
22
|
export { createOptionalOxyAuth, createOxyAuthMiddleware, getOxyAuthRefusal, getOxyBillingPrincipal, getOxyDelegatedUserId, getOxyRequestAttribution, getOxyUserId, getRequiredOxyBillingPrincipal, getRequiredOxyUserId, isOxyAuthenticated, requireOxyAuth, OXY_SERVICE_ENVIRONMENTS, } from './auth.js';
|
|
18
23
|
export { createOxyRateLimit } from './rateLimit.js';
|
|
19
24
|
// SSRF-safe upstream fetch + URL validation (Node-only).
|
|
@@ -39,7 +44,7 @@ export { verifySecret } from './verifySecret.js';
|
|
|
39
44
|
// changes, every consuming backend sweeps its caches instead of waiting out a TTL.
|
|
40
45
|
export { createOxyUserInvalidationHandler, publishOxyUserInvalidation, } from './userInvalidation.js';
|
|
41
46
|
// The identity-key enumeration itself is platform-neutral (`src/utils/`) so the
|
|
42
|
-
// client
|
|
47
|
+
// client namespaces and this Node-only subscriber sweep the SAME list — a second
|
|
43
48
|
// copy is what let `updateAccount` and `updateProfile` drift apart.
|
|
44
49
|
export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES } from '../utils/identityCacheSweep.js';
|
|
45
50
|
// Registrable-apex (eTLD+1) derivation via the Public Suffix List — the SINGLE
|
|
@@ -47,7 +52,7 @@ export { evictOxyIdentityCache, oxyUserByIdCacheKey, OXY_IDENTITY_CACHE_PREFIXES
|
|
|
47
52
|
// Pure host handling (no browser deps), so it is safe on the server subpath and
|
|
48
53
|
// lets `@oxy.so/api` derive `auth.<apex>` without duplicating PSL logic.
|
|
49
54
|
export { registrableApex } from '../utils/registrableApex.js';
|
|
50
|
-
export { isOfficialWebOrigin } from '../utils/officialOrigins.js';
|
|
55
|
+
export { isLoopbackOrigin, isOfficialWebOrigin, isAllowedDeviceJoinOrigin } from '../utils/officialOrigins.js';
|
|
51
56
|
export { createEcosystemTraffic } from './traffic.js';
|
|
52
57
|
export { observeNodeHttp, withoutNodeHttpObservation } from './trafficNodeHttp.js';
|
|
53
58
|
/**
|