@dynamic-labs/waas 4.89.0 → 4.90.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/CHANGELOG.md +19 -0
- package/package.cjs +1 -1
- package/package.js +1 -1
- package/package.json +13 -13
- package/src/DynamicWaasMixin.cjs +46 -14
- package/src/DynamicWaasMixin.d.ts +3 -3
- package/src/DynamicWaasMixin.js +47 -15
- package/utils/tokenHasPendingAuthScope.cjs +55 -0
- package/utils/tokenHasPendingAuthScope.d.ts +17 -0
- package/utils/tokenHasPendingAuthScope.js +51 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,23 @@
|
|
|
1
1
|
|
|
2
|
+
## [4.90.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.89.0...v4.90.0) (2026-06-19)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* add microsoft to social providers list ([#11631](https://github.com/dynamic-labs/dynamic-auth/issues/11631)) ([761b82d](https://github.com/dynamic-labs/dynamic-auth/commit/761b82dea2e2e86ec1c8b3fc8bab32ed72492132))
|
|
8
|
+
* **sdk-react-core:** preconnect to waas iframe origin at auth-flow start ([#11549](https://github.com/dynamic-labs/dynamic-auth/issues/11549)) ([1bb810c](https://github.com/dynamic-labs/dynamic-auth/commit/1bb810c4eb3d592b43f62c1eaf5450a0e42981c9)), closes [dynamic-labs/dynamic-wallet-sdk#1314](https://github.com/dynamic-labs/dynamic-wallet-sdk/issues/1314)
|
|
9
|
+
* **waas:** opt into SDK eager key-share recovery, drop host RECOVER loop (DYNT-1125) ([#11620](https://github.com/dynamic-labs/dynamic-auth/issues/11620)) ([4bef955](https://github.com/dynamic-labs/dynamic-auth/commit/4bef955b902a7e484ba8bd6323582843bb692a17))
|
|
10
|
+
* **wallet-connector-core:** add isMidnightConnector util + Midnight interface hooks ([#11005](https://github.com/dynamic-labs/dynamic-auth/issues/11005)) ([55117a8](https://github.com/dynamic-labs/dynamic-auth/commit/55117a8cf59640d00b358f68be8df6b29231fab5))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **sdk-react-core:** gate smart-wallet init on user:basic scope ([#11624](https://github.com/dynamic-labs/dynamic-auth/issues/11624)) ([9f891a4](https://github.com/dynamic-labs/dynamic-auth/commit/9f891a46a191532acdd4a91b74c4586089ef0e1a)), closes [#11623](https://github.com/dynamic-labs/dynamic-auth/issues/11623) [#11623](https://github.com/dynamic-labs/dynamic-auth/issues/11623) [#11626](https://github.com/dynamic-labs/dynamic-auth/issues/11626)
|
|
16
|
+
* **sdk-react-core:** search wallet list by metadata name in addition to connector name ([#11638](https://github.com/dynamic-labs/dynamic-auth/issues/11638)) ([a647614](https://github.com/dynamic-labs/dynamic-auth/commit/a647614bcba769e09ef59bf1ddb925ce9835842e))
|
|
17
|
+
* **waas:** rebuild WaaS client on session change after step-up reauth ([#11581](https://github.com/dynamic-labs/dynamic-auth/issues/11581)) ([2b7093e](https://github.com/dynamic-labs/dynamic-auth/commit/2b7093e27f57f1dfcdd303361d436d9bf33e28a9))
|
|
18
|
+
* **waas:** refuse to build WaaS client while auth scope is pending (createRooms 401 chokepoint) ([#11623](https://github.com/dynamic-labs/dynamic-auth/issues/11623)) ([08755f0](https://github.com/dynamic-labs/dynamic-auth/commit/08755f0bda2b74c7bcdff3d0ac9c228a5205ad6e)), closes [#11624](https://github.com/dynamic-labs/dynamic-auth/issues/11624)
|
|
19
|
+
* **wallet-connect:** skip address comparison on reconnect when expectedAddress is empty ([#11639](https://github.com/dynamic-labs/dynamic-auth/issues/11639)) ([8d665cf](https://github.com/dynamic-labs/dynamic-auth/commit/8d665cf3bf1fb0e498d71f14cc8a53d91593c23d))
|
|
20
|
+
|
|
2
21
|
## [4.89.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.88.6...v4.89.0) (2026-06-16)
|
|
3
22
|
|
|
4
23
|
|
package/package.cjs
CHANGED
package/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dynamic-labs/waas",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.90.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"author": "Dynamic Labs, Inc.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -16,18 +16,18 @@
|
|
|
16
16
|
"./package.json": "./package.json"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@dynamic-labs-sdk/client": "1.
|
|
20
|
-
"@dynamic-labs/assert-package-version": "4.
|
|
21
|
-
"@dynamic-labs/sdk-api-core": "0.0.
|
|
22
|
-
"@dynamic-labs-wallet/browser-wallet-client": "1.0.
|
|
23
|
-
"@dynamic-labs-wallet/forward-mpc-client": "0.
|
|
24
|
-
"@dynamic-labs/ethereum-core": "4.
|
|
25
|
-
"@dynamic-labs/logger": "4.
|
|
26
|
-
"@dynamic-labs/solana-core": "4.
|
|
27
|
-
"@dynamic-labs/sui-core": "4.
|
|
28
|
-
"@dynamic-labs/utils": "4.
|
|
29
|
-
"@dynamic-labs/wallet-book": "4.
|
|
30
|
-
"@dynamic-labs/wallet-connector-core": "4.
|
|
19
|
+
"@dynamic-labs-sdk/client": "1.12.1",
|
|
20
|
+
"@dynamic-labs/assert-package-version": "4.90.0",
|
|
21
|
+
"@dynamic-labs/sdk-api-core": "0.0.1046",
|
|
22
|
+
"@dynamic-labs-wallet/browser-wallet-client": "1.0.42",
|
|
23
|
+
"@dynamic-labs-wallet/forward-mpc-client": "0.12.0",
|
|
24
|
+
"@dynamic-labs/ethereum-core": "4.90.0",
|
|
25
|
+
"@dynamic-labs/logger": "4.90.0",
|
|
26
|
+
"@dynamic-labs/solana-core": "4.90.0",
|
|
27
|
+
"@dynamic-labs/sui-core": "4.90.0",
|
|
28
|
+
"@dynamic-labs/utils": "4.90.0",
|
|
29
|
+
"@dynamic-labs/wallet-book": "4.90.0",
|
|
30
|
+
"@dynamic-labs/wallet-connector-core": "4.90.0"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {}
|
|
33
33
|
}
|
package/src/DynamicWaasMixin.cjs
CHANGED
|
@@ -11,6 +11,7 @@ var _package = require('../package.cjs');
|
|
|
11
11
|
var constants = require('../utils/constants.cjs');
|
|
12
12
|
var createWaasClientSecureStorage = require('../utils/createWaasClientSecureStorage.cjs');
|
|
13
13
|
var instrumentation = require('../utils/instrumentation.cjs');
|
|
14
|
+
var tokenHasPendingAuthScope = require('../utils/tokenHasPendingAuthScope.cjs');
|
|
14
15
|
|
|
15
16
|
// Fallback error code used when a thrown value carries no code, or when
|
|
16
17
|
// formatting the error itself fails.
|
|
@@ -35,9 +36,6 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
35
36
|
setGetAuthTokenFunction(getAuthToken) {
|
|
36
37
|
this.getAuthToken = getAuthToken;
|
|
37
38
|
}
|
|
38
|
-
setOnUnauthorizedFunction(onUnauthorized) {
|
|
39
|
-
this.onUnauthorized = onUnauthorized;
|
|
40
|
-
}
|
|
41
39
|
setWaasAuthMode(authMode) {
|
|
42
40
|
this.authMode = authMode;
|
|
43
41
|
}
|
|
@@ -194,14 +192,15 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
194
192
|
baseClientKeysharesRelayApiUrl: this.baseClientKeysharesRelayApiUrl,
|
|
195
193
|
baseMPCRelayApiUrl: this.relayUrl || constants.DEFAULT_BASE_MPC_RELAY_API_URL,
|
|
196
194
|
chainName: this.chainName,
|
|
195
|
+
// Opt into the SDK self-driving eager key-share recovery on auth-token
|
|
196
|
+
// arrival, so the host no longer runs its own per-wallet RECOVER loop.
|
|
197
|
+
eagerlyRecoverKeyShares: true,
|
|
197
198
|
environmentId: this.environmentId,
|
|
198
199
|
sdkVersion: _package.version,
|
|
199
|
-
}, Object.assign(Object.assign(
|
|
200
|
+
}, Object.assign(Object.assign({}, (utils.PlatformService.isWaasSecureStorageSupported
|
|
200
201
|
? { secureStorage: createWaasClientSecureStorage.createWaasClientSecureStorage() }
|
|
201
202
|
: {})), (this.getSignedSessionId
|
|
202
203
|
? { getSignedSessionId: this.getSignedSessionId }
|
|
203
|
-
: {})), (this.onUnauthorized
|
|
204
|
-
? { onUnauthorized: this.onUnauthorized }
|
|
205
204
|
: {})));
|
|
206
205
|
this.instrumentAsync({
|
|
207
206
|
context: traceContext,
|
|
@@ -212,9 +211,29 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
212
211
|
return client;
|
|
213
212
|
});
|
|
214
213
|
}
|
|
215
|
-
getWaasWalletClient(
|
|
216
|
-
return _tslib.__awaiter(this,
|
|
214
|
+
getWaasWalletClient(traceContext_1) {
|
|
215
|
+
return _tslib.__awaiter(this, arguments, void 0, function* (traceContext, { forceRebuild = false } = {}) {
|
|
216
|
+
var _a;
|
|
217
|
+
// forceRebuild drops the cached client so the iframe re-auths with the
|
|
218
|
+
// fresh session (e.g. after a step-up reauth) instead of 401-ing on the
|
|
219
|
+
// stale cached token. Callers must only force a rebuild when a token is
|
|
220
|
+
// available (see getWaasWalletConnector's live-token guard); otherwise
|
|
221
|
+
// createDynamicWaasClient would throw "Auth token is required".
|
|
222
|
+
if (forceRebuild) {
|
|
223
|
+
this.dynamicWaasClient = undefined;
|
|
224
|
+
}
|
|
217
225
|
if (!this.dynamicWaasClient) {
|
|
226
|
+
// Chokepoint: never build + initialize the iframe client while the auth
|
|
227
|
+
// token is still pending MFA/KYC/device registration. The iframe's
|
|
228
|
+
// init-time room-cache pre-warm fires `createRooms` using the token
|
|
229
|
+
// captured at construction — before any per-operation token resync
|
|
230
|
+
// exists to correct it. Built during the pending window, that pre-warm
|
|
231
|
+
// 401s and trips the iframe's unauthorized → forced-logout path. Every
|
|
232
|
+
// WaaS caller funnels through here, so this single guard covers auto
|
|
233
|
+
// wallet creation, ZeroDev smart-wallet init, getWallet, etc.
|
|
234
|
+
if (tokenHasPendingAuthScope.tokenHasPendingAuthScope((_a = this.getAuthToken) === null || _a === void 0 ? void 0 : _a.call(this))) {
|
|
235
|
+
throw new utils.WaasAuthScopePendingError();
|
|
236
|
+
}
|
|
218
237
|
this.dynamicWaasClient = yield this.createDynamicWaasClient(traceContext);
|
|
219
238
|
}
|
|
220
239
|
return this.dynamicWaasClient;
|
|
@@ -612,9 +631,18 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
612
631
|
}
|
|
613
632
|
endSession(reason) {
|
|
614
633
|
return _tslib.__awaiter(this, void 0, void 0, function* () {
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
634
|
+
// Building the wallet client requires an auth token (createDynamicWaasClient
|
|
635
|
+
// throws in header auth mode when none is present); the new scope guard in
|
|
636
|
+
// getWaasWalletClient also throws during pending-auth (MFA/KYC/device). On
|
|
637
|
+
// logout we must not let either throw abort logout — the security-critical
|
|
638
|
+
// key share removal below does not need the client. Only the iframe cleanup
|
|
639
|
+
// does, so we proceed without it if the client can't be obtained.
|
|
640
|
+
let waasClient;
|
|
641
|
+
try {
|
|
642
|
+
waasClient = yield this.getWaasWalletClient();
|
|
643
|
+
}
|
|
644
|
+
catch (error) {
|
|
645
|
+
this.instrument('[endSession] getWaasWalletClient failed; proceeding', Object.assign({ key: 'endSession-getClient-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
|
|
618
646
|
}
|
|
619
647
|
// When a session token expires, we preserve key shares in storage instead
|
|
620
648
|
// of clearing them. Customers with short-lived sessions (minutes) were
|
|
@@ -646,9 +674,13 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
646
674
|
// iframe cleanup's request-channel timeout. The iframe handler already
|
|
647
675
|
// swallows its own errors, and the DOM teardown obsoletes anything it
|
|
648
676
|
// misses. Promise.resolve guards against a non-promise return in tests.
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
677
|
+
// Skipped when the client could not be built/obtained (no token, or
|
|
678
|
+
// pending-auth scope guard) — there is no iframe to tear down then.
|
|
679
|
+
if (waasClient) {
|
|
680
|
+
void Promise.resolve(waasClient.cleanup()).catch((error) => {
|
|
681
|
+
this.instrument('[endSession] background iframe cleanup failed', Object.assign({ key: 'endSession-cleanup-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
|
|
682
|
+
});
|
|
683
|
+
}
|
|
652
684
|
}
|
|
653
685
|
this.dynamicWaasClient = undefined;
|
|
654
686
|
});
|
|
@@ -23,7 +23,6 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
|
|
|
23
23
|
getElevatedAccessToken?: ((props: {
|
|
24
24
|
scope: TokenScope;
|
|
25
25
|
}) => Promise<string | undefined>) | undefined;
|
|
26
|
-
onUnauthorized?: (() => void | Promise<void>) | undefined;
|
|
27
26
|
environmentId?: string | undefined;
|
|
28
27
|
baseApiUrl?: string | undefined;
|
|
29
28
|
relayUrl?: string | undefined;
|
|
@@ -35,7 +34,6 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
|
|
|
35
34
|
__exportHandler: WaasExportHandler;
|
|
36
35
|
validateActiveWallet(expectedAddress: string): Promise<void>;
|
|
37
36
|
setGetAuthTokenFunction(getAuthToken: () => string): void;
|
|
38
|
-
setOnUnauthorizedFunction(onUnauthorized: () => void | Promise<void>): void;
|
|
39
37
|
setWaasAuthMode(authMode: 'cookie' | 'header'): void;
|
|
40
38
|
setGetMfaTokenFunction(getMfaToken: (props?: {
|
|
41
39
|
mfaAction?: MFAAction;
|
|
@@ -76,7 +74,9 @@ export declare const withDynamicWaas: <T extends abstract new (...args: any[]) =
|
|
|
76
74
|
password?: string;
|
|
77
75
|
}): Promise<void>;
|
|
78
76
|
createDynamicWaasClient(traceContext?: TraceContext): Promise<DynamicWalletClient>;
|
|
79
|
-
getWaasWalletClient(traceContext?: TraceContext
|
|
77
|
+
getWaasWalletClient(traceContext?: TraceContext, { forceRebuild }?: {
|
|
78
|
+
forceRebuild?: boolean;
|
|
79
|
+
}): Promise<DynamicWalletClient>;
|
|
80
80
|
createWalletAccount({ thresholdSignatureScheme, password, bitcoinConfig, }?: {
|
|
81
81
|
thresholdSignatureScheme?: string;
|
|
82
82
|
password?: string;
|
package/src/DynamicWaasMixin.js
CHANGED
|
@@ -2,11 +2,12 @@
|
|
|
2
2
|
import { __awaiter } from '../_virtual/_tslib.js';
|
|
3
3
|
import { DynamicWalletClient } from '@dynamic-labs-wallet/browser-wallet-client';
|
|
4
4
|
import { MFAAction, TokenScope } from '@dynamic-labs/sdk-api-core';
|
|
5
|
-
import { DynamicError, UserRejectedRequestError, PlatformService } from '@dynamic-labs/utils';
|
|
5
|
+
import { DynamicError, UserRejectedRequestError, PlatformService, WaasAuthScopePendingError } from '@dynamic-labs/utils';
|
|
6
6
|
import { version } from '../package.js';
|
|
7
7
|
import { DEFAULT_BASE_API_URL, DEFAULT_BASE_MPC_RELAY_API_URL } from '../utils/constants.js';
|
|
8
8
|
import { createWaasClientSecureStorage } from '../utils/createWaasClientSecureStorage.js';
|
|
9
9
|
import { InstrumentationTimer } from '../utils/instrumentation.js';
|
|
10
|
+
import { tokenHasPendingAuthScope } from '../utils/tokenHasPendingAuthScope.js';
|
|
10
11
|
|
|
11
12
|
// Fallback error code used when a thrown value carries no code, or when
|
|
12
13
|
// formatting the error itself fails.
|
|
@@ -31,9 +32,6 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
31
32
|
setGetAuthTokenFunction(getAuthToken) {
|
|
32
33
|
this.getAuthToken = getAuthToken;
|
|
33
34
|
}
|
|
34
|
-
setOnUnauthorizedFunction(onUnauthorized) {
|
|
35
|
-
this.onUnauthorized = onUnauthorized;
|
|
36
|
-
}
|
|
37
35
|
setWaasAuthMode(authMode) {
|
|
38
36
|
this.authMode = authMode;
|
|
39
37
|
}
|
|
@@ -190,14 +188,15 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
190
188
|
baseClientKeysharesRelayApiUrl: this.baseClientKeysharesRelayApiUrl,
|
|
191
189
|
baseMPCRelayApiUrl: this.relayUrl || DEFAULT_BASE_MPC_RELAY_API_URL,
|
|
192
190
|
chainName: this.chainName,
|
|
191
|
+
// Opt into the SDK self-driving eager key-share recovery on auth-token
|
|
192
|
+
// arrival, so the host no longer runs its own per-wallet RECOVER loop.
|
|
193
|
+
eagerlyRecoverKeyShares: true,
|
|
193
194
|
environmentId: this.environmentId,
|
|
194
195
|
sdkVersion: version,
|
|
195
|
-
}, Object.assign(Object.assign(
|
|
196
|
+
}, Object.assign(Object.assign({}, (PlatformService.isWaasSecureStorageSupported
|
|
196
197
|
? { secureStorage: createWaasClientSecureStorage() }
|
|
197
198
|
: {})), (this.getSignedSessionId
|
|
198
199
|
? { getSignedSessionId: this.getSignedSessionId }
|
|
199
|
-
: {})), (this.onUnauthorized
|
|
200
|
-
? { onUnauthorized: this.onUnauthorized }
|
|
201
200
|
: {})));
|
|
202
201
|
this.instrumentAsync({
|
|
203
202
|
context: traceContext,
|
|
@@ -208,9 +207,29 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
208
207
|
return client;
|
|
209
208
|
});
|
|
210
209
|
}
|
|
211
|
-
getWaasWalletClient(
|
|
212
|
-
return __awaiter(this,
|
|
210
|
+
getWaasWalletClient(traceContext_1) {
|
|
211
|
+
return __awaiter(this, arguments, void 0, function* (traceContext, { forceRebuild = false } = {}) {
|
|
212
|
+
var _a;
|
|
213
|
+
// forceRebuild drops the cached client so the iframe re-auths with the
|
|
214
|
+
// fresh session (e.g. after a step-up reauth) instead of 401-ing on the
|
|
215
|
+
// stale cached token. Callers must only force a rebuild when a token is
|
|
216
|
+
// available (see getWaasWalletConnector's live-token guard); otherwise
|
|
217
|
+
// createDynamicWaasClient would throw "Auth token is required".
|
|
218
|
+
if (forceRebuild) {
|
|
219
|
+
this.dynamicWaasClient = undefined;
|
|
220
|
+
}
|
|
213
221
|
if (!this.dynamicWaasClient) {
|
|
222
|
+
// Chokepoint: never build + initialize the iframe client while the auth
|
|
223
|
+
// token is still pending MFA/KYC/device registration. The iframe's
|
|
224
|
+
// init-time room-cache pre-warm fires `createRooms` using the token
|
|
225
|
+
// captured at construction — before any per-operation token resync
|
|
226
|
+
// exists to correct it. Built during the pending window, that pre-warm
|
|
227
|
+
// 401s and trips the iframe's unauthorized → forced-logout path. Every
|
|
228
|
+
// WaaS caller funnels through here, so this single guard covers auto
|
|
229
|
+
// wallet creation, ZeroDev smart-wallet init, getWallet, etc.
|
|
230
|
+
if (tokenHasPendingAuthScope((_a = this.getAuthToken) === null || _a === void 0 ? void 0 : _a.call(this))) {
|
|
231
|
+
throw new WaasAuthScopePendingError();
|
|
232
|
+
}
|
|
214
233
|
this.dynamicWaasClient = yield this.createDynamicWaasClient(traceContext);
|
|
215
234
|
}
|
|
216
235
|
return this.dynamicWaasClient;
|
|
@@ -608,9 +627,18 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
608
627
|
}
|
|
609
628
|
endSession(reason) {
|
|
610
629
|
return __awaiter(this, void 0, void 0, function* () {
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
630
|
+
// Building the wallet client requires an auth token (createDynamicWaasClient
|
|
631
|
+
// throws in header auth mode when none is present); the new scope guard in
|
|
632
|
+
// getWaasWalletClient also throws during pending-auth (MFA/KYC/device). On
|
|
633
|
+
// logout we must not let either throw abort logout — the security-critical
|
|
634
|
+
// key share removal below does not need the client. Only the iframe cleanup
|
|
635
|
+
// does, so we proceed without it if the client can't be obtained.
|
|
636
|
+
let waasClient;
|
|
637
|
+
try {
|
|
638
|
+
waasClient = yield this.getWaasWalletClient();
|
|
639
|
+
}
|
|
640
|
+
catch (error) {
|
|
641
|
+
this.instrument('[endSession] getWaasWalletClient failed; proceeding', Object.assign({ key: 'endSession-getClient-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
|
|
614
642
|
}
|
|
615
643
|
// When a session token expires, we preserve key shares in storage instead
|
|
616
644
|
// of clearing them. Customers with short-lived sessions (minutes) were
|
|
@@ -642,9 +670,13 @@ const withDynamicWaas = (BaseClass) => {
|
|
|
642
670
|
// iframe cleanup's request-channel timeout. The iframe handler already
|
|
643
671
|
// swallows its own errors, and the DOM teardown obsoletes anything it
|
|
644
672
|
// misses. Promise.resolve guards against a non-promise return in tests.
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
673
|
+
// Skipped when the client could not be built/obtained (no token, or
|
|
674
|
+
// pending-auth scope guard) — there is no iframe to tear down then.
|
|
675
|
+
if (waasClient) {
|
|
676
|
+
void Promise.resolve(waasClient.cleanup()).catch((error) => {
|
|
677
|
+
this.instrument('[endSession] background iframe cleanup failed', Object.assign({ key: 'endSession-cleanup-failed', time: 0 }, this.buildErrorInstrumentContext(error)));
|
|
678
|
+
});
|
|
679
|
+
}
|
|
648
680
|
}
|
|
649
681
|
this.dynamicWaasClient = undefined;
|
|
650
682
|
});
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
5
|
+
|
|
6
|
+
var sdkApiCore = require('@dynamic-labs/sdk-api-core');
|
|
7
|
+
|
|
8
|
+
// Scopes that mean the user has not finished authenticating (MFA / KYC /
|
|
9
|
+
// device registration still pending). A JWT carrying any of these has not
|
|
10
|
+
// upgraded to `user:basic`, and the WaaS backend rejects calls made with it
|
|
11
|
+
// (e.g. createRooms) with a 401.
|
|
12
|
+
//
|
|
13
|
+
// Note `user:basic` and `waasBackupToken` are intentionally NOT in this list:
|
|
14
|
+
// backup / recovery flows legitimately run with a `waasBackupToken` scope, so
|
|
15
|
+
// only the pending-auth scopes below should block WaaS client creation.
|
|
16
|
+
const PENDING_AUTH_SCOPES = [
|
|
17
|
+
sdkApiCore.JwtScope.RequiresAdditionalAuth,
|
|
18
|
+
sdkApiCore.JwtScope.UserDataForm,
|
|
19
|
+
sdkApiCore.JwtScope.Deviceregister,
|
|
20
|
+
];
|
|
21
|
+
const decodeScope = (authToken) => {
|
|
22
|
+
const payload = authToken === null || authToken === void 0 ? void 0 : authToken.split('.')[1];
|
|
23
|
+
if (!payload) {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(atob(payload)).scope;
|
|
28
|
+
}
|
|
29
|
+
catch (_a) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Returns true when the auth token still carries a pending-authentication
|
|
35
|
+
* scope (`requiresAdditionalAuth` / `userDataForm` / `device:register`).
|
|
36
|
+
*
|
|
37
|
+
* The WaaS iframe's API client is a shared, mutable axios instance. The token
|
|
38
|
+
* captured at client construction is what the init-time room-cache pre-warm
|
|
39
|
+
* `createRooms` uses — it runs before any per-operation token resync. So if the
|
|
40
|
+
* client is built during this pending window, that pre-warm fires with the
|
|
41
|
+
* stale pre-`user:basic` token and 401s; the iframe reports the 401 back to the
|
|
42
|
+
* host, which force-logs-out the user. Callers must therefore refuse to build
|
|
43
|
+
* the client until the token clears (the vulnerable window is construction +
|
|
44
|
+
* init, not the whole client lifetime).
|
|
45
|
+
*
|
|
46
|
+
* A token with no decodable scope is treated as not-pending (returns false):
|
|
47
|
+
* the backend remains the source of truth and will reject anything invalid.
|
|
48
|
+
*/
|
|
49
|
+
const tokenHasPendingAuthScope = (authToken) => {
|
|
50
|
+
var _a, _b;
|
|
51
|
+
const scopes = (_b = (_a = decodeScope(authToken)) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
|
|
52
|
+
return scopes.some((scope) => PENDING_AUTH_SCOPES.includes(scope));
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
exports.tokenHasPendingAuthScope = tokenHasPendingAuthScope;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns true when the auth token still carries a pending-authentication
|
|
3
|
+
* scope (`requiresAdditionalAuth` / `userDataForm` / `device:register`).
|
|
4
|
+
*
|
|
5
|
+
* The WaaS iframe's API client is a shared, mutable axios instance. The token
|
|
6
|
+
* captured at client construction is what the init-time room-cache pre-warm
|
|
7
|
+
* `createRooms` uses — it runs before any per-operation token resync. So if the
|
|
8
|
+
* client is built during this pending window, that pre-warm fires with the
|
|
9
|
+
* stale pre-`user:basic` token and 401s; the iframe reports the 401 back to the
|
|
10
|
+
* host, which force-logs-out the user. Callers must therefore refuse to build
|
|
11
|
+
* the client until the token clears (the vulnerable window is construction +
|
|
12
|
+
* init, not the whole client lifetime).
|
|
13
|
+
*
|
|
14
|
+
* A token with no decodable scope is treated as not-pending (returns false):
|
|
15
|
+
* the backend remains the source of truth and will reject anything invalid.
|
|
16
|
+
*/
|
|
17
|
+
export declare const tokenHasPendingAuthScope: (authToken?: string) => boolean;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
import { JwtScope } from '@dynamic-labs/sdk-api-core';
|
|
3
|
+
|
|
4
|
+
// Scopes that mean the user has not finished authenticating (MFA / KYC /
|
|
5
|
+
// device registration still pending). A JWT carrying any of these has not
|
|
6
|
+
// upgraded to `user:basic`, and the WaaS backend rejects calls made with it
|
|
7
|
+
// (e.g. createRooms) with a 401.
|
|
8
|
+
//
|
|
9
|
+
// Note `user:basic` and `waasBackupToken` are intentionally NOT in this list:
|
|
10
|
+
// backup / recovery flows legitimately run with a `waasBackupToken` scope, so
|
|
11
|
+
// only the pending-auth scopes below should block WaaS client creation.
|
|
12
|
+
const PENDING_AUTH_SCOPES = [
|
|
13
|
+
JwtScope.RequiresAdditionalAuth,
|
|
14
|
+
JwtScope.UserDataForm,
|
|
15
|
+
JwtScope.Deviceregister,
|
|
16
|
+
];
|
|
17
|
+
const decodeScope = (authToken) => {
|
|
18
|
+
const payload = authToken === null || authToken === void 0 ? void 0 : authToken.split('.')[1];
|
|
19
|
+
if (!payload) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(atob(payload)).scope;
|
|
24
|
+
}
|
|
25
|
+
catch (_a) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Returns true when the auth token still carries a pending-authentication
|
|
31
|
+
* scope (`requiresAdditionalAuth` / `userDataForm` / `device:register`).
|
|
32
|
+
*
|
|
33
|
+
* The WaaS iframe's API client is a shared, mutable axios instance. The token
|
|
34
|
+
* captured at client construction is what the init-time room-cache pre-warm
|
|
35
|
+
* `createRooms` uses — it runs before any per-operation token resync. So if the
|
|
36
|
+
* client is built during this pending window, that pre-warm fires with the
|
|
37
|
+
* stale pre-`user:basic` token and 401s; the iframe reports the 401 back to the
|
|
38
|
+
* host, which force-logs-out the user. Callers must therefore refuse to build
|
|
39
|
+
* the client until the token clears (the vulnerable window is construction +
|
|
40
|
+
* init, not the whole client lifetime).
|
|
41
|
+
*
|
|
42
|
+
* A token with no decodable scope is treated as not-pending (returns false):
|
|
43
|
+
* the backend remains the source of truth and will reject anything invalid.
|
|
44
|
+
*/
|
|
45
|
+
const tokenHasPendingAuthScope = (authToken) => {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
const scopes = (_b = (_a = decodeScope(authToken)) === null || _a === void 0 ? void 0 : _a.split(' ')) !== null && _b !== void 0 ? _b : [];
|
|
48
|
+
return scopes.some((scope) => PENDING_AUTH_SCOPES.includes(scope));
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { tokenHasPendingAuthScope };
|