@oxy.so/core 1.18.1 → 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 +159 -111
- 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 +160 -112
- 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 +26 -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 -22
- 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 +166 -131
- 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 -22
- 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 -1495
- 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 -1455
- 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 -998
- 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__/serviceIdentityWhenAnonymous.test.ts +0 -159
- 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 -2083
- 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
|
@@ -1,179 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* attemptIdentityRecovery — the ladder that restores a `lost` identity from an
|
|
3
|
-
* independent, key_v1-surviving source (backup slot, then cross-app shared slot)
|
|
4
|
-
* WITHOUT the recovery phrase. Every rung validates well-formed + derive-match +
|
|
5
|
-
* `publicKey === marker.publicKey`, so a source holding a DIFFERENT account is
|
|
6
|
-
* skipped (never a silent switch).
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { setPlatformOS } from '../../utils/platform';
|
|
10
|
-
|
|
11
|
-
jest.mock(
|
|
12
|
-
'expo-secure-store',
|
|
13
|
-
() => {
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
15
|
-
const { createSecureStoreMock } = require('./identityMocks');
|
|
16
|
-
return createSecureStoreMock();
|
|
17
|
-
},
|
|
18
|
-
{ virtual: true },
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
jest.mock(
|
|
22
|
-
'expo-crypto',
|
|
23
|
-
() => ({
|
|
24
|
-
__esModule: true,
|
|
25
|
-
getRandomBytes: (length: number) => {
|
|
26
|
-
const out = new Uint8Array(length);
|
|
27
|
-
for (let i = 0; i < length; i++) out[i] = (Math.random() * 256) & 0xff;
|
|
28
|
-
return out;
|
|
29
|
-
},
|
|
30
|
-
digestStringAsync: async () => '0'.repeat(64),
|
|
31
|
-
CryptoDigestAlgorithm: { SHA256: 'SHA-256' },
|
|
32
|
-
}),
|
|
33
|
-
{ virtual: true },
|
|
34
|
-
);
|
|
35
|
-
|
|
36
|
-
jest.mock('@oxy.so/protocol', () => {
|
|
37
|
-
const actual = jest.requireActual('@oxy.so/protocol');
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
39
|
-
const { createAsyncStorageMock } = require('./identityMocks');
|
|
40
|
-
const asyncStorage = createAsyncStorageMock();
|
|
41
|
-
return {
|
|
42
|
-
__esModule: true,
|
|
43
|
-
...actual,
|
|
44
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
45
|
-
loadExpoCrypto: async () => require('expo-crypto'),
|
|
46
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
47
|
-
loadSecureStore: async () => require('expo-secure-store'),
|
|
48
|
-
loadAsyncStorage: async () => ({ default: asyncStorage }),
|
|
49
|
-
loadSharedIdentityBridge: async () => null,
|
|
50
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
51
|
-
loadNodeCrypto: async () => require('crypto'),
|
|
52
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
53
|
-
getRandomBytesRN: (n: number) => require('expo-crypto').getRandomBytes(n),
|
|
54
|
-
};
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
const PRIMARY_SVC = 'oxy_identity';
|
|
58
|
-
const BACKUP_SVC = 'oxy_identity_backup';
|
|
59
|
-
const V2_PRIV = 'oxy_identity_private_key_v2';
|
|
60
|
-
const V2_PUB = 'oxy_identity_public_key_v2';
|
|
61
|
-
const V2_BPRIV = 'oxy_identity_backup_private_key_v2';
|
|
62
|
-
const V2_BPUB = 'oxy_identity_backup_public_key_v2';
|
|
63
|
-
|
|
64
|
-
interface SecureStoreTestHandle {
|
|
65
|
-
__resetStore__: () => void;
|
|
66
|
-
__getRaw__: (key: string, service?: string) => string | null;
|
|
67
|
-
__setRaw__: (key: string, value: string, service?: string) => void;
|
|
68
|
-
__simulateKeystoreDeath__: (service: string) => void;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
describe('KeyManager.attemptIdentityRecovery (recovery ladder)', () => {
|
|
72
|
-
let KeyManager: typeof import('../keyManager').KeyManager;
|
|
73
|
-
let ss: SecureStoreTestHandle;
|
|
74
|
-
|
|
75
|
-
const resetCaches = () => {
|
|
76
|
-
const km = KeyManager as unknown as {
|
|
77
|
-
cachedPublicKey: unknown;
|
|
78
|
-
cachedHasIdentity: unknown;
|
|
79
|
-
cachedPublicKeyResolved: unknown;
|
|
80
|
-
cachedSharedPublicKey: unknown;
|
|
81
|
-
cachedHasSharedIdentity: unknown;
|
|
82
|
-
};
|
|
83
|
-
km.cachedPublicKey = null;
|
|
84
|
-
km.cachedHasIdentity = null;
|
|
85
|
-
km.cachedPublicKeyResolved = false;
|
|
86
|
-
km.cachedSharedPublicKey = null;
|
|
87
|
-
km.cachedHasSharedIdentity = null;
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
beforeAll(() => {
|
|
91
|
-
setPlatformOS('ios');
|
|
92
|
-
(globalThis as unknown as { navigator: unknown }).navigator = { product: 'ReactNative' };
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
beforeEach(async () => {
|
|
96
|
-
jest.resetModules();
|
|
97
|
-
setPlatformOS('ios');
|
|
98
|
-
ss = (await import('expo-secure-store' as string)) as unknown as SecureStoreTestHandle;
|
|
99
|
-
ss.__resetStore__();
|
|
100
|
-
const mod = await import('../keyManager');
|
|
101
|
-
KeyManager = mod.KeyManager;
|
|
102
|
-
resetCaches();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
it('recovers from the BACKUP slot when the primary keychain key dies', async () => {
|
|
106
|
-
const pub = await KeyManager.createIdentity();
|
|
107
|
-
// Kill ONLY the primary service — the backup slot (independent key) survives.
|
|
108
|
-
ss.__simulateKeystoreDeath__(PRIMARY_SVC);
|
|
109
|
-
resetCaches();
|
|
110
|
-
|
|
111
|
-
expect((await KeyManager.getIdentityStatus()).state).toBe('lost');
|
|
112
|
-
resetCaches();
|
|
113
|
-
|
|
114
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
115
|
-
expect(result).toEqual({ recovered: true, source: 'backup', publicKey: pub.toLowerCase() });
|
|
116
|
-
expect((await KeyManager.getIdentityStatus()).state).toBe('present');
|
|
117
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBe((await KeyManager.getPrivateKey()));
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
it('recovers from the SHARED slot when both primary and backup keys die', async () => {
|
|
121
|
-
await KeyManager.createIdentity();
|
|
122
|
-
const priv = await KeyManager.getPrivateKey();
|
|
123
|
-
if (!priv) throw new Error('expected private key');
|
|
124
|
-
const pub = KeyManager.derivePublicKey(priv);
|
|
125
|
-
// Mirror the identity into the cross-app shared slot (survives key_v1 death).
|
|
126
|
-
await KeyManager.importSharedIdentity(priv);
|
|
127
|
-
|
|
128
|
-
ss.__simulateKeystoreDeath__(PRIMARY_SVC);
|
|
129
|
-
ss.__simulateKeystoreDeath__(BACKUP_SVC);
|
|
130
|
-
resetCaches();
|
|
131
|
-
|
|
132
|
-
expect((await KeyManager.getIdentityStatus()).state).toBe('lost');
|
|
133
|
-
resetCaches();
|
|
134
|
-
|
|
135
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
136
|
-
expect(result).toEqual({ recovered: true, source: 'shared', publicKey: pub.toLowerCase() });
|
|
137
|
-
expect((await KeyManager.getIdentityStatus()).state).toBe('present');
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
it('SKIPS a source that holds a DIFFERENT account (never silently switches)', async () => {
|
|
141
|
-
await KeyManager.createIdentity();
|
|
142
|
-
// Plant a DIFFERENT identity B in both the backup and shared slots.
|
|
143
|
-
const b = await KeyManager.generateKeyPair();
|
|
144
|
-
ss.__setRaw__(V2_BPRIV, b.privateKey, BACKUP_SVC);
|
|
145
|
-
ss.__setRaw__(V2_BPUB, b.publicKey, BACKUP_SVC);
|
|
146
|
-
await KeyManager.importSharedIdentity(b.privateKey);
|
|
147
|
-
|
|
148
|
-
ss.__simulateKeystoreDeath__(PRIMARY_SVC);
|
|
149
|
-
resetCaches();
|
|
150
|
-
|
|
151
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
152
|
-
expect(result).toEqual({ recovered: false, reason: 'mismatch' });
|
|
153
|
-
// The primary was NOT switched to B.
|
|
154
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).not.toBe(b.privateKey);
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
it('is a no-op when the identity is NOT lost (present)', async () => {
|
|
158
|
-
await KeyManager.createIdentity();
|
|
159
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
160
|
-
expect(result).toEqual({ recovered: false, reason: 'not-lost' });
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('is a no-op on a genuinely absent (fresh) device', async () => {
|
|
164
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
165
|
-
expect(result).toEqual({ recovered: false, reason: 'not-lost' });
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
it('reports no-sources when every recovery slot is empty or malformed', async () => {
|
|
169
|
-
await KeyManager.createIdentity();
|
|
170
|
-
// Corrupt the backup so it is not a valid candidate.
|
|
171
|
-
ss.__setRaw__(V2_BPRIV, 'zz-not-hex', BACKUP_SVC);
|
|
172
|
-
ss.__setRaw__(V2_BPUB, 'garbage', BACKUP_SVC);
|
|
173
|
-
ss.__simulateKeystoreDeath__(PRIMARY_SVC);
|
|
174
|
-
resetCaches();
|
|
175
|
-
|
|
176
|
-
const result = await KeyManager.attemptIdentityRecovery();
|
|
177
|
-
expect(result).toEqual({ recovered: false, reason: 'no-sources' });
|
|
178
|
-
});
|
|
179
|
-
});
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Recovery-mnemonic storage: a dedicated, device-only keychain slot that lets a
|
|
3
|
-
* user re-reveal their 12-word phrase from Settings. Isolated from the identity
|
|
4
|
-
* primary/backup slots (its own keychain service), null-on-absent, typed-throw
|
|
5
|
-
* on a locked keychain, and wiped when the identity is deleted.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { setPlatformOS } from '../../utils/platform';
|
|
9
|
-
|
|
10
|
-
jest.mock(
|
|
11
|
-
'expo-secure-store',
|
|
12
|
-
() => {
|
|
13
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
14
|
-
const { createSecureStoreMock } = require('./identityMocks');
|
|
15
|
-
return createSecureStoreMock();
|
|
16
|
-
},
|
|
17
|
-
{ virtual: true },
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
jest.mock(
|
|
21
|
-
'expo-crypto',
|
|
22
|
-
() => ({
|
|
23
|
-
__esModule: true,
|
|
24
|
-
getRandomBytes: (length: number) => {
|
|
25
|
-
const out = new Uint8Array(length);
|
|
26
|
-
for (let i = 0; i < length; i++) out[i] = (Math.random() * 256) & 0xff;
|
|
27
|
-
return out;
|
|
28
|
-
},
|
|
29
|
-
digestStringAsync: async () => '0'.repeat(64),
|
|
30
|
-
CryptoDigestAlgorithm: { SHA256: 'SHA-256' },
|
|
31
|
-
}),
|
|
32
|
-
{ virtual: true },
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
jest.mock('@oxy.so/protocol', () => {
|
|
36
|
-
const actual = jest.requireActual('@oxy.so/protocol');
|
|
37
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
38
|
-
const { createAsyncStorageMock } = require('./identityMocks');
|
|
39
|
-
const asyncStorage = createAsyncStorageMock();
|
|
40
|
-
return {
|
|
41
|
-
__esModule: true,
|
|
42
|
-
...actual,
|
|
43
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
44
|
-
loadExpoCrypto: async () => require('expo-crypto'),
|
|
45
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
46
|
-
loadSecureStore: async () => require('expo-secure-store'),
|
|
47
|
-
loadAsyncStorage: async () => ({ default: asyncStorage }),
|
|
48
|
-
loadSharedIdentityBridge: async () => null,
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
50
|
-
loadNodeCrypto: async () => require('crypto'),
|
|
51
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
52
|
-
getRandomBytesRN: (n: number) => require('expo-crypto').getRandomBytes(n),
|
|
53
|
-
};
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
const MNEMONIC_SVC = 'oxy_identity_mnemonic';
|
|
57
|
-
const MNEMONIC_KEY = 'oxy_identity_mnemonic_v1';
|
|
58
|
-
const PRIMARY_SVC = 'oxy_identity';
|
|
59
|
-
const PHRASE = 'legal winner thank year wave sausage worth useful legal winner thank yellow';
|
|
60
|
-
|
|
61
|
-
interface SecureStoreTestHandle {
|
|
62
|
-
__resetStore__: () => void;
|
|
63
|
-
__getRaw__: (key: string, service?: string) => string | null;
|
|
64
|
-
__simulateKeystoreDeath__: (service: string) => void;
|
|
65
|
-
__failPlan__: { failKey?: string; failOp?: 'set' | 'get'; failTimes?: number; failService?: string };
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
describe('KeyManager recovery mnemonic storage', () => {
|
|
69
|
-
let KeyManager: typeof import('../keyManager').KeyManager;
|
|
70
|
-
let IdentityUnavailableError: typeof import('../keyManager').IdentityUnavailableError;
|
|
71
|
-
let ss: SecureStoreTestHandle;
|
|
72
|
-
|
|
73
|
-
beforeAll(() => {
|
|
74
|
-
setPlatformOS('ios');
|
|
75
|
-
(globalThis as unknown as { navigator: unknown }).navigator = { product: 'ReactNative' };
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
beforeEach(async () => {
|
|
79
|
-
jest.resetModules();
|
|
80
|
-
setPlatformOS('ios');
|
|
81
|
-
ss = (await import('expo-secure-store' as string)) as unknown as SecureStoreTestHandle;
|
|
82
|
-
ss.__resetStore__();
|
|
83
|
-
const km = await import('../keyManager');
|
|
84
|
-
KeyManager = km.KeyManager;
|
|
85
|
-
IdentityUnavailableError = km.IdentityUnavailableError;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
it('round-trips a stored mnemonic', async () => {
|
|
89
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
90
|
-
expect(await KeyManager.getRecoveryMnemonic()).toBe(PHRASE);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('persists under its OWN keychain service, isolated from the identity slots', async () => {
|
|
94
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
95
|
-
// Present under the mnemonic service, invisible under the primary service.
|
|
96
|
-
expect(ss.__getRaw__(MNEMONIC_KEY, MNEMONIC_SVC)).toBe(PHRASE);
|
|
97
|
-
expect(ss.__getRaw__(MNEMONIC_KEY, PRIMARY_SVC)).toBeNull();
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('returns null when no mnemonic was ever stored (pre-feature identity)', async () => {
|
|
101
|
-
expect(await KeyManager.getRecoveryMnemonic()).toBeNull();
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
it('survives a keystore death of the identity primary service', async () => {
|
|
105
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
106
|
-
// The identity primary slot dies; the mnemonic lives in a distinct service.
|
|
107
|
-
ss.__simulateKeystoreDeath__(PRIMARY_SVC);
|
|
108
|
-
expect(await KeyManager.getRecoveryMnemonic()).toBe(PHRASE);
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
it('throws IdentityUnavailableError (never null) when the read throws', async () => {
|
|
112
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
113
|
-
ss.__failPlan__.failOp = 'get';
|
|
114
|
-
ss.__failPlan__.failKey = MNEMONIC_KEY;
|
|
115
|
-
ss.__failPlan__.failService = MNEMONIC_SVC;
|
|
116
|
-
await expect(KeyManager.getRecoveryMnemonic()).rejects.toBeInstanceOf(IdentityUnavailableError);
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
it('throws IdentityUnavailableError when the write throws', async () => {
|
|
120
|
-
ss.__failPlan__.failOp = 'set';
|
|
121
|
-
ss.__failPlan__.failKey = MNEMONIC_KEY;
|
|
122
|
-
ss.__failPlan__.failService = MNEMONIC_SVC;
|
|
123
|
-
await expect(KeyManager.storeRecoveryMnemonic(PHRASE)).rejects.toBeInstanceOf(IdentityUnavailableError);
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('deleteRecoveryMnemonic removes the stored phrase', async () => {
|
|
127
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
128
|
-
await KeyManager.deleteRecoveryMnemonic();
|
|
129
|
-
expect(await KeyManager.getRecoveryMnemonic()).toBeNull();
|
|
130
|
-
});
|
|
131
|
-
|
|
132
|
-
it('deleteIdentity(force) wipes the stored mnemonic', async () => {
|
|
133
|
-
await KeyManager.createIdentity();
|
|
134
|
-
await KeyManager.storeRecoveryMnemonic(PHRASE);
|
|
135
|
-
await KeyManager.deleteIdentity(true, true, true);
|
|
136
|
-
expect(await KeyManager.getRecoveryMnemonic()).toBeNull();
|
|
137
|
-
});
|
|
138
|
-
});
|
|
@@ -1,150 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The two identity slots must never disagree, because the disagreement is
|
|
3
|
-
* silent and it is money.
|
|
4
|
-
*
|
|
5
|
-
* Cross-app readers take the SHARED slot first — `deriveScopedSeed`, which is
|
|
6
|
-
* where Peable's FairCoin wallet comes from — while signing and the server take
|
|
7
|
-
* the PRIMARY. A key rotation used to write only the primary, so the shared slot
|
|
8
|
-
* kept the replaced key: the recipient's wallet watched addresses derived from a
|
|
9
|
-
* key the DID no longer published, and payers sent to addresses it never
|
|
10
|
-
* watched. Nothing errored on either side.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { setPlatformOS } from '../../utils/platform';
|
|
14
|
-
|
|
15
|
-
jest.mock(
|
|
16
|
-
'expo-secure-store',
|
|
17
|
-
() => {
|
|
18
|
-
const store = new Map<string, string>();
|
|
19
|
-
return {
|
|
20
|
-
__esModule: true,
|
|
21
|
-
WHEN_UNLOCKED_THIS_DEVICE_ONLY: 'WHEN_UNLOCKED_THIS_DEVICE_ONLY',
|
|
22
|
-
WHEN_UNLOCKED: 'WHEN_UNLOCKED',
|
|
23
|
-
setItemAsync: jest.fn(async (k: string, v: string) => { store.set(k, v); }),
|
|
24
|
-
getItemAsync: jest.fn(async (k: string) => store.get(k) ?? null),
|
|
25
|
-
deleteItemAsync: jest.fn(async (k: string) => { store.delete(k); }),
|
|
26
|
-
__resetStore__: () => store.clear(),
|
|
27
|
-
};
|
|
28
|
-
},
|
|
29
|
-
{ virtual: true },
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
jest.mock(
|
|
33
|
-
'expo-crypto',
|
|
34
|
-
() => ({
|
|
35
|
-
__esModule: true,
|
|
36
|
-
getRandomBytes: (length: number) => {
|
|
37
|
-
const out = new Uint8Array(length);
|
|
38
|
-
for (let i = 0; i < length; i++) out[i] = (Math.random() * 256) & 0xff;
|
|
39
|
-
return out;
|
|
40
|
-
},
|
|
41
|
-
digestStringAsync: async () => '0'.repeat(64),
|
|
42
|
-
CryptoDigestAlgorithm: { SHA256: 'SHA-256' },
|
|
43
|
-
}),
|
|
44
|
-
{ virtual: true },
|
|
45
|
-
);
|
|
46
|
-
|
|
47
|
-
jest.mock('@oxy.so/protocol', () => ({
|
|
48
|
-
__esModule: true,
|
|
49
|
-
...jest.requireActual('@oxy.so/protocol'),
|
|
50
|
-
loadExpoCrypto: async () => require('expo-crypto'),
|
|
51
|
-
loadSecureStore: async () => require('expo-secure-store'),
|
|
52
|
-
loadNodeCrypto: async () => require('node:crypto'),
|
|
53
|
-
loadSharedIdentityBridge: async () => null,
|
|
54
|
-
}));
|
|
55
|
-
|
|
56
|
-
const KEY_A = 'aa'.repeat(32);
|
|
57
|
-
const KEY_B = 'bb'.repeat(32);
|
|
58
|
-
const toHex = (b: Uint8Array): string => Buffer.from(b).toString('hex');
|
|
59
|
-
|
|
60
|
-
describe('identity slots stay in sync', () => {
|
|
61
|
-
let KeyManager: typeof import('../keyManager').KeyManager;
|
|
62
|
-
|
|
63
|
-
beforeEach(async () => {
|
|
64
|
-
jest.resetModules();
|
|
65
|
-
setPlatformOS('ios');
|
|
66
|
-
const secureStore = (await import('expo-secure-store' as string)) as unknown as {
|
|
67
|
-
__resetStore__: () => void;
|
|
68
|
-
};
|
|
69
|
-
secureStore.__resetStore__();
|
|
70
|
-
({ KeyManager } = await import('../keyManager'));
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
/** The shape a rotation used to leave behind: each slot on a different key. */
|
|
74
|
-
async function makeSlotsDisagree(): Promise<{ publicA: string; publicB: string }> {
|
|
75
|
-
const publicA = await KeyManager.importSharedIdentity(KEY_A);
|
|
76
|
-
await KeyManager.importKeyPair(KEY_B, { overwrite: true });
|
|
77
|
-
const publicB = KeyManager.derivePublicKey(KEY_B);
|
|
78
|
-
return { publicA, publicB };
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
it('reports both slots, and which one money derives from', async () => {
|
|
82
|
-
const { publicA, publicB } = await makeSlotsDisagree();
|
|
83
|
-
|
|
84
|
-
const state = await KeyManager.getIdentityKeyState();
|
|
85
|
-
|
|
86
|
-
expect(state.sharedPublicKey).toBe(KeyManager.canonicalPublicKey(publicA));
|
|
87
|
-
expect(state.primaryPublicKey).toBe(KeyManager.canonicalPublicKey(publicB));
|
|
88
|
-
// The shared slot wins, which is exactly why a disagreement is dangerous.
|
|
89
|
-
expect(state.activePublicKey).toBe(state.sharedPublicKey);
|
|
90
|
-
expect(state.inSync).toBe(false);
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
it('is in sync when both slots hold the same key', async () => {
|
|
94
|
-
await KeyManager.importSharedIdentity(KEY_A);
|
|
95
|
-
await KeyManager.importKeyPair(KEY_A, { overwrite: true });
|
|
96
|
-
|
|
97
|
-
const state = await KeyManager.getIdentityKeyState();
|
|
98
|
-
|
|
99
|
-
expect(state.inSync).toBe(true);
|
|
100
|
-
expect(state.activePublicKey).toBe(state.primaryPublicKey);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// A device with one slot populated has nothing to contradict, so it must not
|
|
104
|
-
// read as a disagreement — otherwise every fresh install would report one.
|
|
105
|
-
it('is in sync when only one slot is populated', async () => {
|
|
106
|
-
await KeyManager.importKeyPair(KEY_A, { overwrite: true });
|
|
107
|
-
|
|
108
|
-
const state = await KeyManager.getIdentityKeyState();
|
|
109
|
-
|
|
110
|
-
expect(state.sharedPublicKey).toBeNull();
|
|
111
|
-
expect(state.activePublicKey).toBe(state.primaryPublicKey);
|
|
112
|
-
expect(state.inSync).toBe(true);
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
it('repairs a disagreeing shared slot from the primary instead of skipping', async () => {
|
|
116
|
-
const { publicB } = await makeSlotsDisagree();
|
|
117
|
-
|
|
118
|
-
const migrated = await KeyManager.syncSharedIdentity();
|
|
119
|
-
|
|
120
|
-
expect(migrated).toBe(true);
|
|
121
|
-
const state = await KeyManager.getIdentityKeyState();
|
|
122
|
-
expect(state.inSync).toBe(true);
|
|
123
|
-
expect(state.sharedPublicKey).toBe(KeyManager.canonicalPublicKey(publicB));
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
// The wallet is the reason any of this matters: the seed must follow the
|
|
127
|
-
// repaired key, not the one the stale slot was still handing out.
|
|
128
|
-
it('moves the derived wallet seed onto the repaired key', async () => {
|
|
129
|
-
await makeSlotsDisagree();
|
|
130
|
-
const strandedSeed = await KeyManager.deriveScopedSeed('peable/faircoin/v1');
|
|
131
|
-
|
|
132
|
-
await KeyManager.syncSharedIdentity();
|
|
133
|
-
const repairedSeed = await KeyManager.deriveScopedSeed('peable/faircoin/v1');
|
|
134
|
-
|
|
135
|
-
if (!strandedSeed || !repairedSeed) throw new Error('expected seeds');
|
|
136
|
-
expect(toHex(repairedSeed)).not.toBe(toHex(strandedSeed));
|
|
137
|
-
|
|
138
|
-
// And it is the seed a device holding only that one key would derive.
|
|
139
|
-
jest.resetModules();
|
|
140
|
-
const secureStore = (await import('expo-secure-store' as string)) as unknown as {
|
|
141
|
-
__resetStore__: () => void;
|
|
142
|
-
};
|
|
143
|
-
secureStore.__resetStore__();
|
|
144
|
-
const { KeyManager: Fresh } = await import('../keyManager');
|
|
145
|
-
await Fresh.importSharedIdentity(KEY_B);
|
|
146
|
-
const expected = await Fresh.deriveScopedSeed('peable/faircoin/v1');
|
|
147
|
-
if (!expected) throw new Error('expected a seed');
|
|
148
|
-
expect(toHex(repairedSeed)).toBe(toHex(expected));
|
|
149
|
-
});
|
|
150
|
-
});
|
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Lazy migration of the identity from the legacy shared-`key_v1` slots onto the
|
|
3
|
-
* isolated v2 slots (primary service `oxy_identity`, backup service
|
|
4
|
-
* `oxy_identity_backup`).
|
|
5
|
-
*
|
|
6
|
-
* INVARIANT under test: at every instant ≥1 readable copy of a previously
|
|
7
|
-
* existing identity remains — legacy is deleted ONLY after the v2 copy is
|
|
8
|
-
* verified re-readable; a failed v2 write serves legacy for the session; any
|
|
9
|
-
* read-throw defers everything (zero writes/deletes).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { setPlatformOS } from '../../utils/platform';
|
|
13
|
-
|
|
14
|
-
jest.mock(
|
|
15
|
-
'expo-secure-store',
|
|
16
|
-
() => {
|
|
17
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
18
|
-
const { createSecureStoreMock } = require('./identityMocks');
|
|
19
|
-
return createSecureStoreMock();
|
|
20
|
-
},
|
|
21
|
-
{ virtual: true },
|
|
22
|
-
);
|
|
23
|
-
|
|
24
|
-
jest.mock(
|
|
25
|
-
'expo-crypto',
|
|
26
|
-
() => ({
|
|
27
|
-
__esModule: true,
|
|
28
|
-
getRandomBytes: (length: number) => {
|
|
29
|
-
const out = new Uint8Array(length);
|
|
30
|
-
for (let i = 0; i < length; i++) out[i] = (Math.random() * 256) & 0xff;
|
|
31
|
-
return out;
|
|
32
|
-
},
|
|
33
|
-
digestStringAsync: async () => '0'.repeat(64),
|
|
34
|
-
CryptoDigestAlgorithm: { SHA256: 'SHA-256' },
|
|
35
|
-
}),
|
|
36
|
-
{ virtual: true },
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
jest.mock('@oxy.so/protocol', () => {
|
|
40
|
-
const actual = jest.requireActual('@oxy.so/protocol');
|
|
41
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
42
|
-
const { createAsyncStorageMock } = require('./identityMocks');
|
|
43
|
-
const asyncStorage = createAsyncStorageMock();
|
|
44
|
-
return {
|
|
45
|
-
__esModule: true,
|
|
46
|
-
...actual,
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
48
|
-
loadExpoCrypto: async () => require('expo-crypto'),
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
50
|
-
loadSecureStore: async () => require('expo-secure-store'),
|
|
51
|
-
loadAsyncStorage: async () => ({ default: asyncStorage }),
|
|
52
|
-
loadSharedIdentityBridge: async () => null,
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
54
|
-
loadNodeCrypto: async () => require('crypto'),
|
|
55
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
56
|
-
getRandomBytesRN: (n: number) => require('expo-crypto').getRandomBytes(n),
|
|
57
|
-
};
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const PRIMARY_SVC = 'oxy_identity';
|
|
61
|
-
const BACKUP_SVC = 'oxy_identity_backup';
|
|
62
|
-
const V2_PRIV = 'oxy_identity_private_key_v2';
|
|
63
|
-
const V2_PUB = 'oxy_identity_public_key_v2';
|
|
64
|
-
const V2_BPRIV = 'oxy_identity_backup_private_key_v2';
|
|
65
|
-
const V2_BPUB = 'oxy_identity_backup_public_key_v2';
|
|
66
|
-
// Legacy slots (default keychain service).
|
|
67
|
-
const L_PRIV = 'oxy_identity_private_key';
|
|
68
|
-
const L_PUB = 'oxy_identity_public_key';
|
|
69
|
-
const L_BPRIV = 'oxy_identity_backup_private_key';
|
|
70
|
-
const L_BPUB = 'oxy_identity_backup_public_key';
|
|
71
|
-
|
|
72
|
-
interface SecureStoreTestHandle {
|
|
73
|
-
__resetStore__: () => void;
|
|
74
|
-
__getRaw__: (key: string, service?: string) => string | null;
|
|
75
|
-
__setRaw__: (key: string, value: string, service?: string) => void;
|
|
76
|
-
__simulateKeystoreDeath__: (service: string) => void;
|
|
77
|
-
__failPlan__: { failKey?: string; failOp?: 'set' | 'get'; failTimes?: number; failService?: string };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface MigrationCapable {
|
|
81
|
-
_ensureIdentitySlotsMigrated: () => Promise<{ mode: 'v2' | 'legacy' | 'deferred' }>;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
describe('KeyManager identity slot migration (legacy → v2)', () => {
|
|
85
|
-
let KeyManager: typeof import('../keyManager').KeyManager;
|
|
86
|
-
let ss: SecureStoreTestHandle;
|
|
87
|
-
|
|
88
|
-
const resetCaches = () => {
|
|
89
|
-
const km = KeyManager as unknown as {
|
|
90
|
-
cachedPublicKey: unknown;
|
|
91
|
-
cachedHasIdentity: unknown;
|
|
92
|
-
cachedPublicKeyResolved: unknown;
|
|
93
|
-
};
|
|
94
|
-
km.cachedPublicKey = null;
|
|
95
|
-
km.cachedHasIdentity = null;
|
|
96
|
-
km.cachedPublicKeyResolved = false;
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
beforeAll(() => {
|
|
100
|
-
setPlatformOS('ios');
|
|
101
|
-
(globalThis as unknown as { navigator: unknown }).navigator = { product: 'ReactNative' };
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
beforeEach(async () => {
|
|
105
|
-
jest.resetModules();
|
|
106
|
-
setPlatformOS('ios');
|
|
107
|
-
ss = (await import('expo-secure-store' as string)) as unknown as SecureStoreTestHandle;
|
|
108
|
-
ss.__resetStore__();
|
|
109
|
-
const km = await import('../keyManager');
|
|
110
|
-
KeyManager = km.KeyManager;
|
|
111
|
-
resetCaches();
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
/** Seed a valid legacy identity (default keychain service) without migrating. */
|
|
115
|
-
const seedLegacyIdentity = async (): Promise<{ privateKey: string; publicKey: string }> => {
|
|
116
|
-
const kp = await KeyManager.generateKeyPair();
|
|
117
|
-
ss.__setRaw__(L_PRIV, kp.privateKey);
|
|
118
|
-
ss.__setRaw__(L_PUB, kp.publicKey);
|
|
119
|
-
ss.__setRaw__(L_BPRIV, kp.privateKey);
|
|
120
|
-
ss.__setRaw__(L_BPUB, kp.publicKey);
|
|
121
|
-
return kp;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
it('migrates a healthy legacy identity into the v2 slots and deletes the legacy copy', async () => {
|
|
125
|
-
const kp = await seedLegacyIdentity();
|
|
126
|
-
|
|
127
|
-
// Trigger migration via any accessor.
|
|
128
|
-
expect(await KeyManager.getPublicKey()).toBe(kp.publicKey.toLowerCase());
|
|
129
|
-
|
|
130
|
-
// v2 now owns the identity...
|
|
131
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBe(kp.privateKey.toLowerCase());
|
|
132
|
-
expect(ss.__getRaw__(V2_PUB, PRIMARY_SVC)).toBe(kp.publicKey.toLowerCase());
|
|
133
|
-
// ...and the legacy copy is gone (only after the v2 copy verified).
|
|
134
|
-
expect(ss.__getRaw__(L_PRIV)).toBeNull();
|
|
135
|
-
expect(ss.__getRaw__(L_PUB)).toBeNull();
|
|
136
|
-
expect(await KeyManager.hasIdentity()).toBe(true);
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('is idempotent — a second run leaves v2 intact and does not resurrect legacy', async () => {
|
|
140
|
-
const kp = await seedLegacyIdentity();
|
|
141
|
-
await KeyManager.getPublicKey();
|
|
142
|
-
resetCaches();
|
|
143
|
-
// Re-run (fresh caches, same process → migration memoized as v2).
|
|
144
|
-
expect(await KeyManager.getPublicKey()).toBe(kp.publicKey.toLowerCase());
|
|
145
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBe(kp.privateKey.toLowerCase());
|
|
146
|
-
expect(ss.__getRaw__(L_PRIV)).toBeNull();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it('interrupted-after-copy (v2 healthy AND legacy still present) → cleans up legacy', async () => {
|
|
150
|
-
// Model a prior run that copied to v2 but crashed before deleting legacy.
|
|
151
|
-
const kp = await KeyManager.generateKeyPair();
|
|
152
|
-
ss.__setRaw__(V2_PRIV, kp.privateKey.toLowerCase(), PRIMARY_SVC);
|
|
153
|
-
ss.__setRaw__(V2_PUB, kp.publicKey.toLowerCase(), PRIMARY_SVC);
|
|
154
|
-
ss.__setRaw__(L_PRIV, kp.privateKey);
|
|
155
|
-
ss.__setRaw__(L_PUB, kp.publicKey);
|
|
156
|
-
|
|
157
|
-
expect(await KeyManager.getPublicKey()).toBe(kp.publicKey.toLowerCase());
|
|
158
|
-
// v2 kept, legacy cleaned up.
|
|
159
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBe(kp.privateKey.toLowerCase());
|
|
160
|
-
expect(ss.__getRaw__(L_PRIV)).toBeNull();
|
|
161
|
-
expect(ss.__getRaw__(L_PUB)).toBeNull();
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
it('a failed v2 write serves the identity from legacy this session and never deletes legacy', async () => {
|
|
165
|
-
const kp = await seedLegacyIdentity();
|
|
166
|
-
// Make every v2 primary public write fail → migration cannot verify v2.
|
|
167
|
-
ss.__failPlan__.failOp = 'set';
|
|
168
|
-
ss.__failPlan__.failKey = V2_PUB;
|
|
169
|
-
ss.__failPlan__.failService = PRIMARY_SVC;
|
|
170
|
-
|
|
171
|
-
// Reads still succeed — served from the UNTOUCHED legacy slots.
|
|
172
|
-
expect(await KeyManager.getPublicKey()).toBe(kp.publicKey);
|
|
173
|
-
expect(await KeyManager.hasIdentity()).toBe(true);
|
|
174
|
-
// Legacy is intact; v2 primary was not left half-written.
|
|
175
|
-
expect(ss.__getRaw__(L_PRIV)).toBe(kp.privateKey);
|
|
176
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBeNull();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
it('a legacy read throwing defers everything (unavailable, zero writes)', async () => {
|
|
180
|
-
await seedLegacyIdentity();
|
|
181
|
-
// v2 read succeeds (empty); the legacy private read throws → defer.
|
|
182
|
-
ss.__failPlan__.failOp = 'get';
|
|
183
|
-
ss.__failPlan__.failKey = L_PRIV;
|
|
184
|
-
ss.__failPlan__.failService = 'default';
|
|
185
|
-
|
|
186
|
-
const status = await KeyManager.getIdentityStatus();
|
|
187
|
-
expect(status.state).toBe('unavailable');
|
|
188
|
-
await expect(KeyManager.hasIdentity()).rejects.toMatchObject({ name: 'IdentityUnavailableError' });
|
|
189
|
-
// Nothing was written to v2.
|
|
190
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBeNull();
|
|
191
|
-
});
|
|
192
|
-
|
|
193
|
-
it('a keystore death BEFORE migration (loss predates markers) → absent, not a phantom identity', async () => {
|
|
194
|
-
await seedLegacyIdentity();
|
|
195
|
-
// key_v1 death: the legacy (default-service) entries are deleted on read.
|
|
196
|
-
ss.__simulateKeystoreDeath__('default');
|
|
197
|
-
|
|
198
|
-
const status = await KeyManager.getIdentityStatus();
|
|
199
|
-
// No marker existed (loss predates markers) → a genuine fresh device.
|
|
200
|
-
expect(status.state).toBe('absent');
|
|
201
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBeNull();
|
|
202
|
-
});
|
|
203
|
-
|
|
204
|
-
it('a fresh device (no legacy, no v2) resolves to the empty v2 layout', async () => {
|
|
205
|
-
const status = await KeyManager.getIdentityStatus();
|
|
206
|
-
expect(status.state).toBe('absent');
|
|
207
|
-
expect(await KeyManager.hasIdentity()).toBe(false);
|
|
208
|
-
});
|
|
209
|
-
|
|
210
|
-
it('concurrent callers share ONE migration run', async () => {
|
|
211
|
-
const kp = await seedLegacyIdentity();
|
|
212
|
-
const km = KeyManager as unknown as MigrationCapable;
|
|
213
|
-
const [a, b] = await Promise.all([km._ensureIdentitySlotsMigrated(), km._ensureIdentitySlotsMigrated()]);
|
|
214
|
-
// Same memoized result object → a single shared run.
|
|
215
|
-
expect(a).toBe(b);
|
|
216
|
-
expect(a.mode).toBe('v2');
|
|
217
|
-
expect(ss.__getRaw__(V2_PRIV, PRIMARY_SVC)).toBe(kp.privateKey.toLowerCase());
|
|
218
|
-
});
|
|
219
|
-
|
|
220
|
-
it('migrates a healthy legacy backup into the v2 backup slot', async () => {
|
|
221
|
-
const kp = await seedLegacyIdentity();
|
|
222
|
-
await KeyManager.getPublicKey();
|
|
223
|
-
expect(ss.__getRaw__(V2_BPRIV, BACKUP_SVC)).toBe(kp.privateKey.toLowerCase());
|
|
224
|
-
expect(ss.__getRaw__(V2_BPUB, BACKUP_SVC)).toBe(kp.publicKey.toLowerCase());
|
|
225
|
-
expect(ss.__getRaw__(L_BPRIV)).toBeNull();
|
|
226
|
-
});
|
|
227
|
-
});
|