@oxy.so/core 4.5.0-oxy-one.0 → 4.5.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 +1 -1
- package/dist/cjs/HttpService.js +63 -19
- package/dist/cjs/api/accounts.js +10 -3
- package/dist/cjs/api/agency.js +3 -1
- package/dist/cjs/api/apps.js +15 -4
- package/dist/cjs/api/assets.js +49 -12
- package/dist/cjs/api/auth.js +37 -11
- package/dist/cjs/api/billing.js +24 -7
- package/dist/cjs/api/civic.js +14 -4
- package/dist/cjs/api/follows.js +9 -2
- package/dist/cjs/api/identity.js +31 -9
- package/dist/cjs/api/nodes.js +3 -1
- package/dist/cjs/api/privacy.js +8 -2
- package/dist/cjs/api/session.js +15 -4
- package/dist/cjs/api/store.js +15 -5
- package/dist/cjs/api/topics.js +10 -3
- package/dist/cjs/api/users.js +16 -4
- package/dist/cjs/boot/sessionColdBoot.js +40 -13
- package/dist/cjs/constants/version.js +6 -6
- package/dist/cjs/crypto/identityMarker.js +3 -1
- package/dist/cjs/crypto/identityProof.js +6 -1
- package/dist/cjs/crypto/keyManager.js +87 -32
- package/dist/cjs/crypto/recoveryPhrase.js +2 -2
- package/dist/cjs/crypto/signatureService.js +3 -4
- package/dist/cjs/i18n/index.js +16 -3
- package/dist/cjs/i18n/locales/ar-SA.js +366 -366
- package/dist/cjs/i18n/locales/ca-ES.js +366 -366
- package/dist/cjs/i18n/locales/de-DE.js +366 -366
- package/dist/cjs/i18n/locales/en-US.js +1994 -1994
- package/dist/cjs/i18n/locales/es-ES.js +1994 -1994
- package/dist/cjs/i18n/locales/fr-FR.js +366 -366
- package/dist/cjs/i18n/locales/it-IT.js +366 -366
- package/dist/cjs/i18n/locales/ja-JP.js +366 -366
- package/dist/cjs/i18n/locales/ko-KR.js +366 -366
- package/dist/cjs/i18n/locales/pt-PT.js +366 -366
- package/dist/cjs/i18n/locales/zh-CN.js +366 -366
- package/dist/cjs/inference/OxyInferenceClient.js +12 -18
- package/dist/cjs/models/interfaces.js +11 -11
- package/dist/cjs/server/OxyServer.js +86 -28
- package/dist/cjs/server/agentAccount.js +6 -2
- package/dist/cjs/server/aliaMachineCredential.js +39 -14
- package/dist/cjs/server/auth.js +5 -4
- package/dist/cjs/server/capabilityTicket.js +5 -5
- package/dist/cjs/server/index.js +2 -1
- package/dist/cjs/server/liveCapabilityTicket.js +4 -1
- package/dist/cjs/server/middleware.js +61 -42
- package/dist/cjs/server/namespaces.js +28 -7
- package/dist/cjs/server/requesterAssertion.js +36 -30
- package/dist/cjs/server/serviceTokenLifetime.js +7 -4
- package/dist/cjs/server/traffic.js +53 -14
- package/dist/cjs/server/trafficNodeHttp.js +33 -8
- package/dist/cjs/server/workloadIdentity.client.js +4 -0
- package/dist/cjs/server/workloadIdentity.js +28 -1
- package/dist/cjs/session/SessionClient.js +54 -17
- package/dist/cjs/session/accountDelegationAccess.js +4 -6
- package/dist/cjs/session/accountDialogController.js +1 -1
- package/dist/cjs/session/authStateStore.js +18 -9
- package/dist/cjs/session/identityPin.js +6 -2
- package/dist/cjs/session/refresh.js +81 -23
- package/dist/cjs/session/sharedDeviceCredential.js +28 -15
- package/dist/cjs/shared/utils/errorUtils.js +1 -1
- package/dist/cjs/shared/utils/networkUtils.js +1 -1
- package/dist/cjs/shared/utils/themeUtils.js +1 -1
- package/dist/cjs/utils/accountCacheSweep.js +3 -1
- package/dist/cjs/utils/accountUtils.js +1 -3
- package/dist/cjs/utils/asyncUtils.js +1 -1
- package/dist/cjs/utils/authHelpers.js +2 -1
- package/dist/cjs/utils/avatarUtils.js +4 -2
- package/dist/cjs/utils/cache.js +1 -1
- package/dist/cjs/utils/cacheKey.js +3 -1
- package/dist/cjs/utils/deviceManager.js +4 -4
- package/dist/cjs/utils/errorUtils.js +6 -4
- package/dist/cjs/utils/languageUtils.js +404 -57
- package/dist/cjs/utils/profileLinks.js +1 -3
- package/dist/cjs/utils/requestUtils.js +7 -1
- package/dist/cjs/utils/userIdentity.js +1 -1
- package/dist/cjs/utils/validationUtils.js +5 -6
- package/dist/esm/HttpService.js +64 -20
- package/dist/esm/api/accounts.js +11 -4
- package/dist/esm/api/agency.js +3 -1
- package/dist/esm/api/apps.js +15 -4
- package/dist/esm/api/assets.js +49 -12
- package/dist/esm/api/auth.js +37 -11
- package/dist/esm/api/billing.js +25 -8
- package/dist/esm/api/civic.js +14 -4
- package/dist/esm/api/follows.js +9 -2
- package/dist/esm/api/identity.js +31 -9
- package/dist/esm/api/nodes.js +3 -1
- package/dist/esm/api/privacy.js +8 -2
- package/dist/esm/api/session.js +15 -4
- package/dist/esm/api/store.js +15 -5
- package/dist/esm/api/topics.js +10 -3
- package/dist/esm/api/users.js +16 -4
- package/dist/esm/boot/sessionColdBoot.js +41 -14
- package/dist/esm/constants/version.js +6 -6
- package/dist/esm/crypto/identityMarker.js +3 -1
- package/dist/esm/crypto/identityProof.js +6 -1
- package/dist/esm/crypto/internal.js +1 -1
- package/dist/esm/crypto/keyManager.js +87 -32
- package/dist/esm/crypto/recoveryPhrase.js +2 -2
- package/dist/esm/crypto/signatureService.js +3 -4
- package/dist/esm/i18n/index.js +16 -3
- package/dist/esm/i18n/locales/ar-SA.js +366 -366
- package/dist/esm/i18n/locales/ca-ES.js +366 -366
- package/dist/esm/i18n/locales/de-DE.js +366 -366
- package/dist/esm/i18n/locales/en-US.js +1994 -1994
- package/dist/esm/i18n/locales/es-ES.js +1994 -1994
- package/dist/esm/i18n/locales/fr-FR.js +366 -366
- package/dist/esm/i18n/locales/it-IT.js +366 -366
- package/dist/esm/i18n/locales/ja-JP.js +366 -366
- package/dist/esm/i18n/locales/ko-KR.js +366 -366
- package/dist/esm/i18n/locales/pt-PT.js +366 -366
- package/dist/esm/i18n/locales/zh-CN.js +366 -366
- package/dist/esm/index.js +1 -1
- package/dist/esm/inference/OxyInferenceClient.js +13 -19
- package/dist/esm/models/interfaces.js +11 -11
- package/dist/esm/server/OxyServer.js +87 -29
- package/dist/esm/server/agentAccount.js +6 -2
- package/dist/esm/server/aliaMachineCredential.js +39 -14
- package/dist/esm/server/auth.js +6 -5
- package/dist/esm/server/capabilityTicket.js +6 -6
- package/dist/esm/server/index.js +5 -5
- package/dist/esm/server/liveCapabilityTicket.js +6 -3
- package/dist/esm/server/middleware.js +62 -43
- package/dist/esm/server/namespaces.js +31 -10
- package/dist/esm/server/requesterAssertion.js +36 -30
- package/dist/esm/server/serviceTokenLifetime.js +7 -4
- package/dist/esm/server/traffic.js +55 -16
- package/dist/esm/server/trafficNodeHttp.js +34 -9
- package/dist/esm/server/userInvalidation.js +1 -1
- package/dist/esm/server/workloadIdentity.client.js +3 -0
- package/dist/esm/server/workloadIdentity.js +27 -1
- package/dist/esm/session/SessionClient.js +54 -17
- package/dist/esm/session/accountDelegationAccess.js +5 -7
- package/dist/esm/session/accountDialogController.js +1 -1
- package/dist/esm/session/authStateStore.js +18 -9
- package/dist/esm/session/identityPin.js +6 -2
- package/dist/esm/session/refresh.js +82 -24
- package/dist/esm/session/sharedDeviceCredential.js +28 -15
- package/dist/esm/shared/utils/errorUtils.js +1 -1
- package/dist/esm/shared/utils/networkUtils.js +1 -1
- package/dist/esm/shared/utils/themeUtils.js +1 -1
- package/dist/esm/utils/accountCacheSweep.js +3 -1
- package/dist/esm/utils/accountUtils.js +1 -3
- package/dist/esm/utils/asyncUtils.js +1 -1
- package/dist/esm/utils/authHelpers.js +2 -1
- package/dist/esm/utils/avatarUtils.js +4 -2
- package/dist/esm/utils/cache.js +1 -1
- package/dist/esm/utils/cacheKey.js +3 -1
- package/dist/esm/utils/deviceManager.js +4 -4
- package/dist/esm/utils/errorUtils.js +6 -4
- package/dist/esm/utils/languageUtils.js +404 -57
- package/dist/esm/utils/profileLinks.js +1 -3
- package/dist/esm/utils/requestUtils.js +7 -1
- package/dist/esm/utils/userIdentity.js +1 -1
- package/dist/esm/utils/validationUtils.js +5 -6
- package/dist/types/HttpService.d.ts +1 -1
- package/dist/types/api/accounts.d.ts +1 -1
- package/dist/types/api/apps.d.ts +4 -4
- package/dist/types/api/assets.d.ts +2 -0
- package/dist/types/api/auth.d.ts +8 -3
- package/dist/types/crypto/internal.d.ts +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/server/index.d.ts +6 -6
- package/dist/types/server/requesterAssertion.d.ts +2 -2
- package/dist/types/server/workloadIdentity.client.d.ts +5 -1
- package/dist/types/server/workloadIdentity.d.ts +26 -0
- package/dist/types/session/accountDelegationAccess.d.ts +1 -1
- package/dist/types/session/index.d.ts +1 -1
- package/dist/types/utils/userIdentity.d.ts +1 -1
- package/dist/types/utils/validationUtils.d.ts +4 -5
- package/package.json +2 -3
- package/src/HttpService.ts +183 -53
- package/src/OxyServices.errors.ts +7 -3
- package/src/OxyServices.ts +6 -2
- package/src/api/accounts.ts +76 -26
- package/src/api/agency.ts +24 -9
- package/src/api/appData.ts +12 -2
- package/src/api/apps.ts +81 -31
- package/src/api/assets.ts +122 -40
- package/src/api/auth.ts +154 -79
- package/src/api/billing.ts +112 -65
- package/src/api/civic.ts +61 -19
- package/src/api/contacts.ts +4 -1
- package/src/api/devices.ts +54 -21
- package/src/api/follows.ts +88 -31
- package/src/api/identity.ts +101 -33
- package/src/api/linkedAccounts.ts +26 -8
- package/src/api/nodes.ts +18 -6
- package/src/api/notifications.ts +26 -6
- package/src/api/privacy.ts +42 -8
- package/src/api/reputation.ts +18 -7
- package/src/api/session.ts +23 -5
- package/src/api/store.ts +81 -31
- package/src/api/topics.ts +18 -6
- package/src/api/users.ts +98 -35
- package/src/boot/sessionColdBoot.ts +60 -19
- package/src/civic/payloads.ts +1 -4
- package/src/client/context.ts +6 -1
- package/src/constants/version.ts +7 -6
- package/src/crypto/aead.ts +1 -5
- package/src/crypto/ecdh.ts +1 -4
- package/src/crypto/identityDerivations.ts +5 -1
- package/src/crypto/identityMarker.ts +3 -1
- package/src/crypto/identityProof.ts +6 -1
- package/src/crypto/index.ts +11 -11
- package/src/crypto/internal.ts +6 -1
- package/src/crypto/keyManager.ts +348 -98
- package/src/crypto/recoveryPhrase.ts +14 -9
- package/src/crypto/registrationPow.ts +1 -1
- package/src/crypto/signatureService.ts +14 -6
- package/src/i18n/accountCategoryLabels.ts +1 -4
- package/src/i18n/accountRoleLabels.ts +1 -4
- package/src/i18n/index.ts +25 -7
- package/src/i18n/locales/ar-SA.ts +375 -366
- package/src/i18n/locales/ca-ES.ts +382 -366
- package/src/i18n/locales/de-DE.ts +387 -366
- package/src/i18n/locales/en-US.ts +2034 -1994
- package/src/i18n/locales/es-ES.ts +2043 -1994
- package/src/i18n/locales/fr-FR.ts +387 -366
- package/src/i18n/locales/it-IT.ts +380 -366
- package/src/i18n/locales/ja-JP.ts +380 -366
- package/src/i18n/locales/ko-KR.ts +377 -366
- package/src/i18n/locales/pt-PT.ts +383 -366
- package/src/i18n/locales/zh-CN.ts +373 -366
- package/src/i18n/trustTierLabels.ts +1 -4
- package/src/index.ts +371 -349
- package/src/inference/OxyInferenceClient.ts +784 -780
- package/src/models/interfaces.ts +30 -27
- package/src/server/OxyServer.ts +227 -68
- package/src/server/agentAccount.ts +8 -2
- package/src/server/aliaMachineCredential.ts +57 -16
- package/src/server/auth.ts +9 -5
- package/src/server/capabilityTicket.ts +30 -21
- package/src/server/index.ts +29 -6
- package/src/server/liveCapabilityTicket.ts +31 -9
- package/src/server/middleware.ts +212 -121
- package/src/server/namespaces.ts +247 -94
- package/src/server/rateLimit.ts +2 -4
- package/src/server/requesterAssertion.ts +93 -54
- package/src/server/serviceTokenLifetime.ts +9 -4
- package/src/server/traffic.ts +117 -23
- package/src/server/trafficNodeHttp.ts +61 -14
- package/src/server/userInvalidation.ts +1 -4
- package/src/server/workloadIdentity.client.ts +12 -1
- package/src/server/workloadIdentity.ts +52 -5
- package/src/session/SessionClient.ts +170 -49
- package/src/session/accountDelegationAccess.ts +24 -31
- package/src/session/accountDialogController.ts +59 -14
- package/src/session/accountSwitchTargets.ts +10 -15
- package/src/session/authStateStore.ts +121 -81
- package/src/session/deviceDirectory.ts +1 -3
- package/src/session/identityPin.ts +10 -11
- package/src/session/identitySession.ts +3 -1
- package/src/session/index.ts +87 -82
- package/src/session/refresh.ts +138 -44
- package/src/session/sessionClientHost.ts +1 -3
- package/src/session/sharedDeviceCredential.ts +35 -14
- package/src/session/socketLoader.ts +9 -2
- package/src/shared/utils/errorUtils.ts +5 -2
- package/src/shared/utils/networkUtils.ts +5 -8
- package/src/shared/utils/themeUtils.ts +2 -6
- package/src/types/buffer.d.ts +66 -21
- package/src/types/expo-secure-store.d.ts +5 -1
- package/src/utils/accountCacheSweep.ts +4 -5
- package/src/utils/accountUtils.ts +107 -108
- package/src/utils/apiUtils.ts +3 -3
- package/src/utils/asyncUtils.ts +2 -2
- package/src/utils/authHelpers.ts +10 -5
- package/src/utils/avatarUtils.ts +11 -6
- package/src/utils/cache.ts +9 -10
- package/src/utils/cacheKey.ts +5 -1
- package/src/utils/coldBoot.ts +1 -3
- package/src/utils/commonsDelivery.ts +1 -4
- package/src/utils/deviceManager.ts +15 -14
- package/src/utils/errorUtils.ts +68 -86
- package/src/utils/languageUtils.ts +407 -58
- package/src/utils/oauthPkce.ts +1 -4
- package/src/utils/platform.ts +0 -1
- package/src/utils/profileLinks.ts +2 -5
- package/src/utils/requestUtils.ts +18 -14
- package/src/utils/sessionUtils.ts +34 -33
- package/src/utils/userHandle.ts +3 -1
- package/src/utils/userIdentity.ts +1 -1
- package/src/utils/validationUtils.ts +11 -9
|
@@ -11,7 +11,9 @@ const node_async_hooks_1 = require("node:async_hooks");
|
|
|
11
11
|
const node_module_1 = require("node:module");
|
|
12
12
|
const collector_1 = require("@oxy.so/telemetry/collector");
|
|
13
13
|
const suppressed = new node_async_hooks_1.AsyncLocalStorage();
|
|
14
|
-
function withoutNodeHttpObservation(callback) {
|
|
14
|
+
function withoutNodeHttpObservation(callback) {
|
|
15
|
+
return suppressed.run(true, callback);
|
|
16
|
+
}
|
|
15
17
|
/** Node and Bun share the HTTP facade; Bun does not emit Node's HTTP diagnostic channels. */
|
|
16
18
|
function observeNodeHttp(collector, service, region, resolveEndpoint) {
|
|
17
19
|
const seen = new WeakSet();
|
|
@@ -29,11 +31,23 @@ function observeNodeHttp(collector, service, region, resolveEndpoint) {
|
|
|
29
31
|
const peer = resolveEndpoint(url);
|
|
30
32
|
if (peer && !request.headersSent)
|
|
31
33
|
request.setHeader('X-Oxy-Source-Region', region);
|
|
32
|
-
const flow = {
|
|
34
|
+
const flow = {
|
|
35
|
+
service,
|
|
36
|
+
region,
|
|
37
|
+
activityType: (0, collector_1.trafficType)(url.pathname),
|
|
38
|
+
scope: peer ? 'internal' : 'external',
|
|
39
|
+
direction: 'outbound',
|
|
40
|
+
sourceRegion: region,
|
|
41
|
+
sourceService: service,
|
|
42
|
+
targetService: peer?.service,
|
|
43
|
+
};
|
|
33
44
|
const emit = request.emit;
|
|
34
45
|
let recorded = false;
|
|
35
|
-
const restore = () => {
|
|
36
|
-
request.emit
|
|
46
|
+
const restore = () => {
|
|
47
|
+
if (request.emit === observedEmit)
|
|
48
|
+
request.emit = emit;
|
|
49
|
+
restoreRequests.delete(restore);
|
|
50
|
+
};
|
|
37
51
|
// Intercept notifications without adding an 'error' listener: observation
|
|
38
52
|
// must not turn an unhandled application error into a swallowed error.
|
|
39
53
|
const observedEmit = function (event, ...args) {
|
|
@@ -41,16 +55,27 @@ function observeNodeHttp(collector, service, region, resolveEndpoint) {
|
|
|
41
55
|
if (!recorded && event === 'response') {
|
|
42
56
|
recorded = true;
|
|
43
57
|
const response = args[0];
|
|
44
|
-
const targetRegion = peer
|
|
58
|
+
const targetRegion = peer
|
|
59
|
+
? (0, collector_1.normalizeInfrastructureRegion)(response.headers['x-oxy-region'])
|
|
60
|
+
: undefined;
|
|
45
61
|
collector.record({ ...flow, targetRegion });
|
|
46
|
-
collector.record({
|
|
62
|
+
collector.record({
|
|
63
|
+
...flow,
|
|
64
|
+
direction: 'inbound',
|
|
65
|
+
sourceRegion: targetRegion,
|
|
66
|
+
targetRegion: region,
|
|
67
|
+
sourceService: peer?.service,
|
|
68
|
+
targetService: service,
|
|
69
|
+
});
|
|
47
70
|
}
|
|
48
71
|
else if (!recorded && (event === 'error' || event === 'close')) {
|
|
49
72
|
recorded = true;
|
|
50
73
|
collector.record(flow);
|
|
51
74
|
}
|
|
52
75
|
}
|
|
53
|
-
catch {
|
|
76
|
+
catch {
|
|
77
|
+
/* A metrics failure cannot change a request's behavior. */
|
|
78
|
+
}
|
|
54
79
|
if (event === 'close')
|
|
55
80
|
restore();
|
|
56
81
|
return emit.call(this, event, ...args);
|
|
@@ -67,7 +92,7 @@ function observeNodeHttp(collector, service, region, resolveEndpoint) {
|
|
|
67
92
|
return request;
|
|
68
93
|
}
|
|
69
94
|
};
|
|
70
|
-
const patches = [node_http_1.default, node_https_1.default].map(module => {
|
|
95
|
+
const patches = [node_http_1.default, node_https_1.default].map((module) => {
|
|
71
96
|
const request = module.request;
|
|
72
97
|
const get = module.get;
|
|
73
98
|
const wrappedRequest = ((...args) => safelyObserve(request.apply(module, args)));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.canAttestWorkloadIdentity = canAttestWorkloadIdentity;
|
|
4
4
|
exports.requestWorkloadServiceToken = requestWorkloadServiceToken;
|
|
5
|
+
exports.attestWorkloadIdentity = attestWorkloadIdentity;
|
|
5
6
|
/** Workload attestation belongs to a Node host, never a browser or device. */
|
|
6
7
|
function canAttestWorkloadIdentity() {
|
|
7
8
|
return false;
|
|
@@ -9,3 +10,6 @@ function canAttestWorkloadIdentity() {
|
|
|
9
10
|
async function requestWorkloadServiceToken(_options) {
|
|
10
11
|
throw new Error('Workload identity is only available on a Node host');
|
|
11
12
|
}
|
|
13
|
+
async function attestWorkloadIdentity(_options) {
|
|
14
|
+
throw new Error('Workload identity is only available on a Node host');
|
|
15
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.canAttestWorkloadIdentity = canAttestWorkloadIdentity;
|
|
4
|
+
exports.attestWorkloadIdentity = attestWorkloadIdentity;
|
|
4
5
|
exports.requestWorkloadServiceToken = requestWorkloadServiceToken;
|
|
5
6
|
const node_crypto_1 = require("node:crypto");
|
|
6
7
|
const slashes_1 = require("../utils/slashes");
|
|
@@ -85,7 +86,10 @@ function sha256Hex(value) {
|
|
|
85
86
|
* does not cover can be swapped by whoever captured the attestation.
|
|
86
87
|
*/
|
|
87
88
|
function signGetCallerIdentity(credentials, nonce, now) {
|
|
88
|
-
const amzDate = now
|
|
89
|
+
const amzDate = now
|
|
90
|
+
.toISOString()
|
|
91
|
+
.replace(/[-:]/g, '')
|
|
92
|
+
.replace(/\.\d{3}/, '');
|
|
89
93
|
const dateStamp = amzDate.slice(0, 8);
|
|
90
94
|
const headers = {
|
|
91
95
|
host: STS_HOST,
|
|
@@ -120,6 +124,29 @@ async function awsContainerAttestation(fetchImpl, nonce) {
|
|
|
120
124
|
const credentials = await containerCredentials(fetchImpl);
|
|
121
125
|
return { headers: signGetCallerIdentity(credentials, nonce, new Date()) };
|
|
122
126
|
}
|
|
127
|
+
/**
|
|
128
|
+
* Signs this process's identity proof over a nonce the CALLER chose, and sends
|
|
129
|
+
* it nowhere.
|
|
130
|
+
*
|
|
131
|
+
* {@link requestWorkloadServiceToken} is the ordinary consumer: Oxy issues the
|
|
132
|
+
* nonce and replays the proof. This exists for the one host that is its own
|
|
133
|
+
* verifier — Oxy's API acting as an application it hosts (Inbox) needs to learn
|
|
134
|
+
* which role it runs as, and the honest way to learn that is the way it learns
|
|
135
|
+
* anyone else's: sign `GetCallerIdentity` and let STS say whose signature it is.
|
|
136
|
+
* Reading a role name out of configuration would be the process's own word for
|
|
137
|
+
* what it is, which is what ADR 0026 refuses from every other caller.
|
|
138
|
+
*
|
|
139
|
+
* The same signer, so the two can never disagree about the shape the verifier
|
|
140
|
+
* accepts. Throws exactly as the token path does when there is no identity here.
|
|
141
|
+
*/
|
|
142
|
+
async function attestWorkloadIdentity(options) {
|
|
143
|
+
if (!options.nonce)
|
|
144
|
+
throw new Error('A workload attestation needs a nonce to sign.');
|
|
145
|
+
return {
|
|
146
|
+
provider: 'aws-iam',
|
|
147
|
+
attestation: await awsContainerAttestation(options.fetch ?? fetch, options.nonce),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
123
150
|
/**
|
|
124
151
|
* Exchanges this process's identity for an Oxy service token.
|
|
125
152
|
*
|
|
@@ -252,7 +252,8 @@ class SessionClient {
|
|
|
252
252
|
// otherwise, so a mismatch always resolves to "mint".
|
|
253
253
|
const needsMintBeforeNotify = transport != null &&
|
|
254
254
|
next.accounts.length > 0 &&
|
|
255
|
-
(activeAccountId === null ||
|
|
255
|
+
(activeAccountId === null ||
|
|
256
|
+
(0, cacheKey_1.computeIdentityTag)(this.host.getAccessToken()) !== activeAccountId);
|
|
256
257
|
const publish = () => {
|
|
257
258
|
if (generation !== this.lifecycleGeneration || this.state !== next)
|
|
258
259
|
return;
|
|
@@ -294,13 +295,20 @@ class SessionClient {
|
|
|
294
295
|
// Warm cold boot may fetch authoritative empty state before it ever had a
|
|
295
296
|
// local projection. Its authenticated holder is history too. Decoding only
|
|
296
297
|
// identifies local history; authority remains the validated REST response.
|
|
297
|
-
const warmHolderEnded = previousState === null &&
|
|
298
|
-
|
|
298
|
+
const warmHolderEnded = previousState === null &&
|
|
299
|
+
origin === 'request' &&
|
|
300
|
+
typeof bearerAccount === 'string' &&
|
|
301
|
+
bearerAccount.length > 0 &&
|
|
299
302
|
this.host.getDeviceCredential()?.deviceId === next.deviceId;
|
|
300
|
-
if (((previousState?.deviceId === next.deviceId && previousState.accounts.length > 0) ||
|
|
301
|
-
|
|
303
|
+
if (((previousState?.deviceId === next.deviceId && previousState.accounts.length > 0) ||
|
|
304
|
+
warmHolderEnded) &&
|
|
305
|
+
next.accounts.length === 0 &&
|
|
306
|
+
pinnedAccountId === null &&
|
|
307
|
+
this.options.onFullExplicitSignOut) {
|
|
302
308
|
try {
|
|
303
|
-
void this.persistFullSignOut()
|
|
309
|
+
void this.persistFullSignOut()
|
|
310
|
+
.then(finishApply)
|
|
311
|
+
.catch((error) => {
|
|
304
312
|
logger_1.logger.error('[SessionClient] failed to persist received full sign-out', error);
|
|
305
313
|
finishApply();
|
|
306
314
|
});
|
|
@@ -312,7 +320,10 @@ class SessionClient {
|
|
|
312
320
|
return true;
|
|
313
321
|
}
|
|
314
322
|
if (needsMintBeforeNotify) {
|
|
315
|
-
void transport
|
|
323
|
+
void transport
|
|
324
|
+
.ensureActiveToken(next)
|
|
325
|
+
.then(finishApply)
|
|
326
|
+
.catch((error) => {
|
|
316
327
|
if (generation !== this.lifecycleGeneration)
|
|
317
328
|
return;
|
|
318
329
|
logger_1.logger.warn('[SessionClient] ensureActiveToken failed — reverting session state', { component: 'SessionClient' }, error);
|
|
@@ -348,10 +359,19 @@ class SessionClient {
|
|
|
348
359
|
const issues = parsed.success
|
|
349
360
|
? []
|
|
350
361
|
: parsed.error.issues.map((issue) => issue.code === 'invalid_type'
|
|
351
|
-
? {
|
|
362
|
+
? {
|
|
363
|
+
path: issue.path.join('.'),
|
|
364
|
+
code: issue.code,
|
|
365
|
+
expected: issue.expected,
|
|
366
|
+
received: issue.received,
|
|
367
|
+
}
|
|
352
368
|
: { path: issue.path.join('.'), code: issue.code });
|
|
353
369
|
const keys = raw && typeof raw === 'object' ? Object.keys(raw) : [];
|
|
354
|
-
logger_1.logger.warn('[SessionClient] discarded invalid session sync', {
|
|
370
|
+
logger_1.logger.warn('[SessionClient] discarded invalid session sync', {
|
|
371
|
+
component: 'SessionClient',
|
|
372
|
+
issues,
|
|
373
|
+
keys,
|
|
374
|
+
});
|
|
355
375
|
return;
|
|
356
376
|
}
|
|
357
377
|
this.commitSync(sync);
|
|
@@ -434,7 +454,9 @@ class SessionClient {
|
|
|
434
454
|
}
|
|
435
455
|
/** `GET /session/device/directory` → {@link applyDirectory}. No notify. */
|
|
436
456
|
async fetchDirectory() {
|
|
437
|
-
const res = await this.requestDevice('GET', '/session/device/directory', undefined, {
|
|
457
|
+
const res = await this.requestDevice('GET', '/session/device/directory', undefined, {
|
|
458
|
+
cache: false,
|
|
459
|
+
});
|
|
438
460
|
return this.applyDirectory(res);
|
|
439
461
|
}
|
|
440
462
|
/**
|
|
@@ -543,7 +565,9 @@ class SessionClient {
|
|
|
543
565
|
}
|
|
544
566
|
}
|
|
545
567
|
async bootstrap() {
|
|
546
|
-
const res = await this.requestDevice('GET', '/session/device/state', undefined, {
|
|
568
|
+
const res = await this.requestDevice('GET', '/session/device/state', undefined, {
|
|
569
|
+
cache: false,
|
|
570
|
+
});
|
|
547
571
|
await this.applySync(res);
|
|
548
572
|
}
|
|
549
573
|
/**
|
|
@@ -629,7 +653,9 @@ class SessionClient {
|
|
|
629
653
|
* {@link signOutPrincipal} for the two that can tell those apart.
|
|
630
654
|
*/
|
|
631
655
|
async signOut(target) {
|
|
632
|
-
const res = await this.requestDevice('POST', '/session/device/signout', target, {
|
|
656
|
+
const res = await this.requestDevice('POST', '/session/device/signout', target, {
|
|
657
|
+
cache: false,
|
|
658
|
+
});
|
|
633
659
|
await this.applySync(res);
|
|
634
660
|
this.postCommitPing();
|
|
635
661
|
if (this.state?.accounts.length === 0)
|
|
@@ -672,14 +698,19 @@ class SessionClient {
|
|
|
672
698
|
* applied this revision.
|
|
673
699
|
*/
|
|
674
700
|
async removeFromDevice(target) {
|
|
675
|
-
const res = await this.requestDevice('POST', '/session/device/signout', target, {
|
|
701
|
+
const res = await this.requestDevice('POST', '/session/device/signout', target, {
|
|
702
|
+
cache: false,
|
|
703
|
+
});
|
|
676
704
|
const removal = (0, contracts_1.safeParseContract)(contracts_1.deviceDirectorySyncSchema, res);
|
|
677
705
|
if (!removal) {
|
|
678
706
|
logger_1.logger.warn('[SessionClient] discarded invalid device removal response');
|
|
679
707
|
return;
|
|
680
708
|
}
|
|
681
709
|
const directoryApplied = this.applyDirectory(removal.directory);
|
|
682
|
-
const stateApplied = this.commitSync({
|
|
710
|
+
const stateApplied = this.commitSync({
|
|
711
|
+
state: removal.state,
|
|
712
|
+
activeToken: removal.activeToken,
|
|
713
|
+
});
|
|
683
714
|
if (this.fullSignOutPersistence?.state === this.state)
|
|
684
715
|
await this.fullSignOutPersistence.pending;
|
|
685
716
|
// `commitSync` publishes whenever the flat state moved. When only the
|
|
@@ -693,7 +724,9 @@ class SessionClient {
|
|
|
693
724
|
await this.persistFullSignOut();
|
|
694
725
|
}
|
|
695
726
|
async addCurrentAccount() {
|
|
696
|
-
const res = await this.requestDevice('POST', '/session/device/add', undefined, {
|
|
727
|
+
const res = await this.requestDevice('POST', '/session/device/add', undefined, {
|
|
728
|
+
cache: false,
|
|
729
|
+
});
|
|
697
730
|
await this.applySync(res);
|
|
698
731
|
this.postCommitPing();
|
|
699
732
|
}
|
|
@@ -787,7 +820,9 @@ class SessionClient {
|
|
|
787
820
|
// if THAT yields nothing — only when no factory was injected.
|
|
788
821
|
const io = this.options.socketFactory ?? (await (0, socketLoader_1.getSocketIO)());
|
|
789
822
|
if (!io) {
|
|
790
|
-
logger_1.logger.warn('[SessionClient] no socket.io-client; running REST-only (no realtime sync)', {
|
|
823
|
+
logger_1.logger.warn('[SessionClient] no socket.io-client; running REST-only (no realtime sync)', {
|
|
824
|
+
component: 'SessionClient',
|
|
825
|
+
});
|
|
791
826
|
return;
|
|
792
827
|
}
|
|
793
828
|
if (!this.started)
|
|
@@ -872,7 +907,9 @@ class SessionClient {
|
|
|
872
907
|
onSessionAccountsChanged(payload) {
|
|
873
908
|
const event = (0, contracts_1.safeParseContract)(contracts_1.sessionAccountsChangedEventSchema, payload);
|
|
874
909
|
if (!event) {
|
|
875
|
-
logger_1.logger.warn('[SessionClient] discarded invalid session_accounts_changed', {
|
|
910
|
+
logger_1.logger.warn('[SessionClient] discarded invalid session_accounts_changed', {
|
|
911
|
+
component: 'SessionClient',
|
|
912
|
+
});
|
|
876
913
|
return;
|
|
877
914
|
}
|
|
878
915
|
// The socket is in `user:<activeUserId>` for the planted bearer, so this should
|
|
@@ -31,18 +31,16 @@ const contracts_1 = require("@oxy.so/contracts");
|
|
|
31
31
|
*/
|
|
32
32
|
function resolveAccountDelegationAccess(node) {
|
|
33
33
|
const membership = node.callerMembership;
|
|
34
|
-
const activeMembership = membership?.status ===
|
|
35
|
-
const hasStanding = node.relationship ===
|
|
36
|
-
node.relationship === "owner" ||
|
|
37
|
-
activeMembership;
|
|
34
|
+
const activeMembership = membership?.status === 'active';
|
|
35
|
+
const hasStanding = node.relationship === 'self' || node.relationship === 'owner' || activeMembership;
|
|
38
36
|
if (!hasStanding || !(0, contracts_1.isDelegatedActAsEligibleKind)(node.kind)) {
|
|
39
37
|
return { hasStanding, canActAs: false };
|
|
40
38
|
}
|
|
41
39
|
if (membership !== null && membership !== undefined) {
|
|
42
40
|
return {
|
|
43
41
|
hasStanding,
|
|
44
|
-
canActAs: activeMembership && membership.permissions.includes(
|
|
42
|
+
canActAs: activeMembership && membership.permissions.includes('account:act_as'),
|
|
45
43
|
};
|
|
46
44
|
}
|
|
47
|
-
return { hasStanding, canActAs: node.relationship ===
|
|
45
|
+
return { hasStanding, canActAs: node.relationship === 'owner' };
|
|
48
46
|
}
|
|
@@ -985,7 +985,7 @@ class AccountDialogController {
|
|
|
985
985
|
// OAuth-bound sessions mint no sessionId on approval — they finalize
|
|
986
986
|
// into an authorization code. The account dialog only starts device
|
|
987
987
|
// sign-in today; stop rather than poll until expiry.
|
|
988
|
-
this.failSignIn('unsupported-flow',
|
|
988
|
+
this.failSignIn('unsupported-flow', "This sign-in flow cannot be completed here. Use the app's OAuth sign-in instead.");
|
|
989
989
|
return;
|
|
990
990
|
}
|
|
991
991
|
if (status.authorized && status.sessionId) {
|
|
@@ -27,9 +27,12 @@ const logger_1 = require("../logger");
|
|
|
27
27
|
function matchesAuthState(actual, expected) {
|
|
28
28
|
if (!actual || !expected)
|
|
29
29
|
return actual === expected;
|
|
30
|
-
return actual.deviceId === expected.deviceId &&
|
|
31
|
-
actual.
|
|
32
|
-
actual.
|
|
30
|
+
return (actual.deviceId === expected.deviceId &&
|
|
31
|
+
actual.deviceSecret === expected.deviceSecret &&
|
|
32
|
+
actual.sessionId === expected.sessionId &&
|
|
33
|
+
actual.userId === expected.userId &&
|
|
34
|
+
actual.accessToken === expected.accessToken &&
|
|
35
|
+
actual.expiresAt === expected.expiresAt);
|
|
33
36
|
}
|
|
34
37
|
/**
|
|
35
38
|
* Versioned DURABLE storage key. Holds ONLY the small, re-mint-critical fields
|
|
@@ -357,7 +360,8 @@ function createNativeAuthStateStore(storage) {
|
|
|
357
360
|
if (sessionMirror !== undefined)
|
|
358
361
|
return sessionMirror;
|
|
359
362
|
const [durable, warm] = await Promise.all([
|
|
360
|
-
storage.getItem(exports.AUTH_STATE_STORAGE_KEY),
|
|
363
|
+
storage.getItem(exports.AUTH_STATE_STORAGE_KEY),
|
|
364
|
+
storage.getItem(exports.AUTH_STATE_TOKEN_STORAGE_KEY),
|
|
361
365
|
]);
|
|
362
366
|
return composeState(durable, warm);
|
|
363
367
|
};
|
|
@@ -416,7 +420,8 @@ function createNativeAuthStateStore(storage) {
|
|
|
416
420
|
if (current === undefined) {
|
|
417
421
|
try {
|
|
418
422
|
const [durable, warm] = await Promise.all([
|
|
419
|
-
storage.getItem(exports.AUTH_STATE_STORAGE_KEY),
|
|
423
|
+
storage.getItem(exports.AUTH_STATE_STORAGE_KEY),
|
|
424
|
+
storage.getItem(exports.AUTH_STATE_TOKEN_STORAGE_KEY),
|
|
420
425
|
]);
|
|
421
426
|
current = composeState(durable, warm);
|
|
422
427
|
}
|
|
@@ -426,10 +431,14 @@ function createNativeAuthStateStore(storage) {
|
|
|
426
431
|
}
|
|
427
432
|
}
|
|
428
433
|
const expected = guard.expectedState;
|
|
429
|
-
if (!guard.isCurrent() ||
|
|
430
|
-
current
|
|
431
|
-
current.
|
|
432
|
-
current.
|
|
434
|
+
if (!guard.isCurrent() ||
|
|
435
|
+
!current ||
|
|
436
|
+
current.deviceId !== expected.deviceId ||
|
|
437
|
+
current.deviceSecret !== expected.deviceSecret ||
|
|
438
|
+
current.sessionId !== expected.sessionId ||
|
|
439
|
+
current.userId !== expected.userId ||
|
|
440
|
+
current.accessToken !== expected.accessToken ||
|
|
441
|
+
current.expiresAt !== expected.expiresAt)
|
|
433
442
|
return false;
|
|
434
443
|
}
|
|
435
444
|
suppressedMirror = suppressed;
|
|
@@ -174,7 +174,9 @@ function createWebIdentityPinStore() {
|
|
|
174
174
|
save: async (pin) => {
|
|
175
175
|
const json = serialize(pin);
|
|
176
176
|
if (!json) {
|
|
177
|
-
logger_1.logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
|
|
177
|
+
logger_1.logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
|
|
178
|
+
component: 'identityPin',
|
|
179
|
+
});
|
|
178
180
|
return false;
|
|
179
181
|
}
|
|
180
182
|
sessionMirror = { publicKey: pin.publicKey.toLowerCase(), accountId: pin.accountId };
|
|
@@ -224,7 +226,9 @@ function createNativeIdentityPinStore(storage) {
|
|
|
224
226
|
save: async (pin) => {
|
|
225
227
|
const json = serialize(pin);
|
|
226
228
|
if (!json) {
|
|
227
|
-
logger_1.logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
|
|
229
|
+
logger_1.logger.error('[identityPin] refusing to persist a malformed identity pin', undefined, {
|
|
230
|
+
component: 'identityPin',
|
|
231
|
+
});
|
|
228
232
|
return false;
|
|
229
233
|
}
|
|
230
234
|
sessionMirror = { publicKey: pin.publicKey.toLowerCase(), accountId: pin.accountId };
|
|
@@ -136,9 +136,12 @@ async function refreshDeviceSecretArm(deps) {
|
|
|
136
136
|
// push. Its exact live holder's authoritative empty-device rejection
|
|
137
137
|
// must suppress automatic key recovery on this and future boots.
|
|
138
138
|
// A late rejection for a replaced session/local epoch is not current.
|
|
139
|
-
if (pin === null &&
|
|
139
|
+
if (pin === null &&
|
|
140
|
+
store.setAutomaticIdentitySignInSuppressed &&
|
|
141
|
+
(!invalidSecret || (persisted.sessionId && persisted.userId))) {
|
|
140
142
|
const current = await store.load();
|
|
141
|
-
if (!isCurrent() ||
|
|
143
|
+
if (!isCurrent() ||
|
|
144
|
+
oxy.http.getSessionEpoch() !== epoch ||
|
|
142
145
|
current?.deviceId !== persisted.deviceId ||
|
|
143
146
|
current.deviceSecret !== persisted.deviceSecret ||
|
|
144
147
|
current.sessionId !== persisted.sessionId ||
|
|
@@ -146,7 +149,8 @@ async function refreshDeviceSecretArm(deps) {
|
|
|
146
149
|
current.accessToken !== persisted.accessToken)
|
|
147
150
|
return { status: 'session-ended' };
|
|
148
151
|
if (!(await store.setAutomaticIdentitySignInSuppressed(true, {
|
|
149
|
-
expectedState: persisted,
|
|
152
|
+
expectedState: persisted,
|
|
153
|
+
isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
|
|
150
154
|
})))
|
|
151
155
|
return { status: 'session-ended' };
|
|
152
156
|
}
|
|
@@ -194,7 +198,10 @@ async function refreshDeviceSecretArm(deps) {
|
|
|
194
198
|
// Persist nextDeviceSecret (read-back-verified) BEFORE planting the token.
|
|
195
199
|
// A failed durable persist must NOT plant.
|
|
196
200
|
const persistedOk = store.saveIfCurrent
|
|
197
|
-
? await store.saveIfCurrent(next, {
|
|
201
|
+
? await store.saveIfCurrent(next, {
|
|
202
|
+
expectedState: persisted,
|
|
203
|
+
isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
|
|
204
|
+
})
|
|
198
205
|
: await store.save(next);
|
|
199
206
|
if (!persistedOk) {
|
|
200
207
|
return { status: 'persist-failed' };
|
|
@@ -253,22 +260,39 @@ async function refreshSharedDeviceArm(deps) {
|
|
|
253
260
|
}
|
|
254
261
|
return { status: 'transient' };
|
|
255
262
|
}
|
|
256
|
-
const bound = mint.state.accounts.find(account => account.accountId === mint.state.activeAccountId);
|
|
257
|
-
if (!bound ||
|
|
263
|
+
const bound = mint.state.accounts.find((account) => account.accountId === mint.state.activeAccountId);
|
|
264
|
+
if (!bound ||
|
|
265
|
+
mint.state.deviceId !== credential.deviceId ||
|
|
266
|
+
!mint.accessToken ||
|
|
267
|
+
!mint.nextDeviceSecret)
|
|
258
268
|
return { status: 'transient' };
|
|
259
|
-
if (!isCurrent() ||
|
|
269
|
+
if (!isCurrent() ||
|
|
270
|
+
oxy.http.getSessionEpoch() !== epoch ||
|
|
271
|
+
!(0, authStateStore_1.matchesAuthState)(await store.load(), before))
|
|
260
272
|
return { status: 'session-ended' };
|
|
261
273
|
const next = {
|
|
262
|
-
deviceId: mint.state.deviceId,
|
|
263
|
-
|
|
264
|
-
|
|
274
|
+
deviceId: mint.state.deviceId,
|
|
275
|
+
deviceSecret: mint.nextDeviceSecret,
|
|
276
|
+
sessionId: bound.sessionId,
|
|
277
|
+
userId: bound.accountId,
|
|
278
|
+
accessToken: mint.accessToken,
|
|
279
|
+
expiresAt: mint.expiresAt,
|
|
265
280
|
};
|
|
266
|
-
if (!(await store.saveIfCurrent(next, {
|
|
281
|
+
if (!(await store.saveIfCurrent(next, {
|
|
282
|
+
expectedState: before,
|
|
283
|
+
isCurrent: () => isCurrent() && oxy.http.getSessionEpoch() === epoch,
|
|
284
|
+
})))
|
|
267
285
|
return { status: 'persist-failed' };
|
|
268
286
|
if (!isCurrent() || oxy.http.getSessionEpoch() !== epoch)
|
|
269
287
|
return { status: 'session-ended' };
|
|
270
288
|
oxy.session.setAccessToken(mint.accessToken);
|
|
271
|
-
return {
|
|
289
|
+
return {
|
|
290
|
+
status: 'ok',
|
|
291
|
+
token: mint.accessToken,
|
|
292
|
+
sessionId: bound.sessionId,
|
|
293
|
+
userId: bound.accountId,
|
|
294
|
+
state: mint.state,
|
|
295
|
+
};
|
|
272
296
|
});
|
|
273
297
|
}
|
|
274
298
|
/**
|
|
@@ -302,7 +326,10 @@ async function refreshPersistedSession(deps) {
|
|
|
302
326
|
return null;
|
|
303
327
|
const identity = deps.identity ?? null;
|
|
304
328
|
// The shared identity is never an identity-bound client's recovery path.
|
|
305
|
-
const allowCommonsIdentityFallback = identity
|
|
329
|
+
const allowCommonsIdentityFallback = identity
|
|
330
|
+
? false
|
|
331
|
+
: (deps.allowCommonsIdentityFallback ?? (0, platform_1.isNative)()) &&
|
|
332
|
+
!(await store.isAutomaticIdentitySignInSuppressed?.());
|
|
306
333
|
const epoch = oxy.http.getSessionEpoch();
|
|
307
334
|
// Resolved per call: a re-established identity session can move the pin, and a
|
|
308
335
|
// replaced/removed local key clears it (in which case arm 1 must NOT mint —
|
|
@@ -318,7 +345,10 @@ async function refreshPersistedSession(deps) {
|
|
|
318
345
|
case 'session-ended':
|
|
319
346
|
return null;
|
|
320
347
|
case 'transient':
|
|
321
|
-
logger_1.logger.debug('Persisted deviceSecret mint failed (transient) — keeping store', {
|
|
348
|
+
logger_1.logger.debug('Persisted deviceSecret mint failed (transient) — keeping store', {
|
|
349
|
+
component: 'refresh',
|
|
350
|
+
method: 'refreshPersistedSession',
|
|
351
|
+
});
|
|
322
352
|
return null;
|
|
323
353
|
case 'persist-failed':
|
|
324
354
|
// The server rotated the secret but it did not durably persist. Do NOT fall
|
|
@@ -330,13 +360,21 @@ async function refreshPersistedSession(deps) {
|
|
|
330
360
|
case 'invalid-secret':
|
|
331
361
|
case 'no-session': {
|
|
332
362
|
if (!identity && deps.sharedDeviceCredential) {
|
|
333
|
-
const joined = await refreshSharedDeviceArm({
|
|
363
|
+
const joined = await refreshSharedDeviceArm({
|
|
364
|
+
oxy,
|
|
365
|
+
store,
|
|
366
|
+
shared: deps.sharedDeviceCredential,
|
|
367
|
+
rejectedLocalHolder: true,
|
|
368
|
+
isCurrent: deps.isCurrent,
|
|
369
|
+
});
|
|
334
370
|
if (joined.status === 'ok')
|
|
335
371
|
return joined.token;
|
|
336
372
|
if (joined.status === 'session-ended' || joined.status === 'persist-failed')
|
|
337
373
|
return null;
|
|
338
374
|
}
|
|
339
|
-
if (!identity &&
|
|
375
|
+
if (!identity &&
|
|
376
|
+
arm1.status === 'invalid-secret' &&
|
|
377
|
+
(await store.isAutomaticIdentitySignInSuppressed?.()))
|
|
340
378
|
return null;
|
|
341
379
|
if (arm1.status === 'no-session' && !identity) {
|
|
342
380
|
if (store.setAutomaticIdentitySignInSuppressed)
|
|
@@ -346,7 +384,12 @@ async function refreshPersistedSession(deps) {
|
|
|
346
384
|
// to turn this signed-out verdict into a new account session.
|
|
347
385
|
const persisted = await store.load();
|
|
348
386
|
if (persisted?.deviceId && persisted.deviceSecret) {
|
|
349
|
-
await store.save({
|
|
387
|
+
await store.save({
|
|
388
|
+
sessionId: '',
|
|
389
|
+
userId: '',
|
|
390
|
+
deviceId: persisted.deviceId,
|
|
391
|
+
deviceSecret: persisted.deviceSecret,
|
|
392
|
+
});
|
|
350
393
|
}
|
|
351
394
|
return null;
|
|
352
395
|
}
|
|
@@ -373,10 +416,17 @@ async function refreshPersistedSession(deps) {
|
|
|
373
416
|
break;
|
|
374
417
|
case 'no-secret':
|
|
375
418
|
if (!identity && deps.sharedDeviceCredential) {
|
|
376
|
-
const joined = await refreshSharedDeviceArm({
|
|
419
|
+
const joined = await refreshSharedDeviceArm({
|
|
420
|
+
oxy,
|
|
421
|
+
store,
|
|
422
|
+
shared: deps.sharedDeviceCredential,
|
|
423
|
+
isCurrent: deps.isCurrent,
|
|
424
|
+
});
|
|
377
425
|
if (joined.status === 'ok')
|
|
378
426
|
return joined.token;
|
|
379
|
-
if (joined.status === 'session-ended' ||
|
|
427
|
+
if (joined.status === 'session-ended' ||
|
|
428
|
+
joined.status === 'persist-failed' ||
|
|
429
|
+
joined.status === 'transient')
|
|
380
430
|
return null;
|
|
381
431
|
}
|
|
382
432
|
break;
|
|
@@ -386,14 +436,19 @@ async function refreshPersistedSession(deps) {
|
|
|
386
436
|
}
|
|
387
437
|
// Never after a sign-out: the shared identity is a KEY, not a session, and
|
|
388
438
|
// proving it here would sign the user straight back in.
|
|
389
|
-
if (allowCommonsIdentityFallback &&
|
|
439
|
+
if (allowCommonsIdentityFallback &&
|
|
440
|
+
(deps.isCurrent?.() ?? true) &&
|
|
441
|
+
!oxy.http.hasSessionEnded() &&
|
|
442
|
+
!(await store.isAutomaticIdentitySignInSuppressed?.())) {
|
|
390
443
|
try {
|
|
391
444
|
// Planted here, not by the sign-in: a sign-out that lands while the
|
|
392
445
|
// challenge round-trips must win, or the identity proof signs the user
|
|
393
446
|
// straight back in.
|
|
394
447
|
const session = await oxy.auth.signInWithCommonsIdentity({ plantTokens: false });
|
|
395
448
|
if (session?.accessToken) {
|
|
396
|
-
if (!(deps.isCurrent?.() ?? true) ||
|
|
449
|
+
if (!(deps.isCurrent?.() ?? true) ||
|
|
450
|
+
oxy.http.getSessionEpoch() !== epoch ||
|
|
451
|
+
(await store.isAutomaticIdentitySignInSuppressed?.())) {
|
|
397
452
|
return null;
|
|
398
453
|
}
|
|
399
454
|
// Repopulate the fast device-secret lane from the identity re-mint.
|
|
@@ -407,7 +462,9 @@ async function refreshPersistedSession(deps) {
|
|
|
407
462
|
expiresAt: session.expiresAt,
|
|
408
463
|
});
|
|
409
464
|
}
|
|
410
|
-
if (!(deps.isCurrent?.() ?? true) ||
|
|
465
|
+
if (!(deps.isCurrent?.() ?? true) ||
|
|
466
|
+
oxy.http.getSessionEpoch() !== epoch ||
|
|
467
|
+
(await store.isAutomaticIdentitySignInSuppressed?.())) {
|
|
411
468
|
return null;
|
|
412
469
|
}
|
|
413
470
|
oxy.session.setAccessToken(session.accessToken);
|
|
@@ -528,7 +585,8 @@ function startTokenRefreshScheduler(oxy) {
|
|
|
528
585
|
scheduleFromExpiry();
|
|
529
586
|
return;
|
|
530
587
|
}
|
|
531
|
-
void oxy.http
|
|
588
|
+
void oxy.http
|
|
589
|
+
.refreshAccessToken('preflight')
|
|
532
590
|
.then((token) => Boolean(token))
|
|
533
591
|
.catch(() => false)
|
|
534
592
|
.then((ok) => {
|