decane-connect-kit 2.7.3 → 2.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +85 -42
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +33 -1
- package/dist/index.d.ts +33 -1
- package/dist/index.js +85 -42
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2352,6 +2352,26 @@ async function teeFetch(url, init) {
|
|
|
2352
2352
|
clearTimeout(timer);
|
|
2353
2353
|
}
|
|
2354
2354
|
}
|
|
2355
|
+
var ATTESTATION_TTL_MS = 10 * 6e4;
|
|
2356
|
+
var attestationCache = /* @__PURE__ */ new Map();
|
|
2357
|
+
function attestOnce(teeUrl, verify) {
|
|
2358
|
+
const hit = attestationCache.get(teeUrl);
|
|
2359
|
+
if (hit && Date.now() - hit.at < ATTESTATION_TTL_MS) return hit.promise;
|
|
2360
|
+
const promise = verify().catch((e) => {
|
|
2361
|
+
attestationCache.delete(teeUrl);
|
|
2362
|
+
throw e;
|
|
2363
|
+
});
|
|
2364
|
+
attestationCache.set(teeUrl, { at: Date.now(), promise });
|
|
2365
|
+
return promise;
|
|
2366
|
+
}
|
|
2367
|
+
function prewarmAttestation(teeUrl) {
|
|
2368
|
+
void attestOnce(teeUrl, async () => {
|
|
2369
|
+
const nonce = crypto.getRandomValues(new Uint8Array(16));
|
|
2370
|
+
const nonceHex = Array.from(nonce).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2371
|
+
await verifyTeeAttestation(teeUrl, nonceHex);
|
|
2372
|
+
}).catch(() => {
|
|
2373
|
+
});
|
|
2374
|
+
}
|
|
2355
2375
|
var TeeClient = class {
|
|
2356
2376
|
constructor(teeUrl) {
|
|
2357
2377
|
this.teeUrl = teeUrl;
|
|
@@ -2393,9 +2413,11 @@ var TeeClient = class {
|
|
|
2393
2413
|
}
|
|
2394
2414
|
async ensureAttested() {
|
|
2395
2415
|
if (this.attested) return;
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2416
|
+
await attestOnce(this.teeUrl, async () => {
|
|
2417
|
+
const nonce = crypto.getRandomValues(new Uint8Array(16));
|
|
2418
|
+
const nonceHex = Array.from(nonce).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
2419
|
+
await verifyTeeAttestation(this.teeUrl, nonceHex);
|
|
2420
|
+
});
|
|
2399
2421
|
this.attested = true;
|
|
2400
2422
|
}
|
|
2401
2423
|
/**
|
|
@@ -3541,6 +3563,26 @@ async function createDecaneConnect(config) {
|
|
|
3541
3563
|
zeroize(share);
|
|
3542
3564
|
}
|
|
3543
3565
|
}
|
|
3566
|
+
async function enrolInBackground(jwt, share) {
|
|
3567
|
+
try {
|
|
3568
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
3569
|
+
try {
|
|
3570
|
+
await new TeeClient(teeUrl).enrolAuthShare(jwt, share);
|
|
3571
|
+
return;
|
|
3572
|
+
} catch (e) {
|
|
3573
|
+
if (attempt === 2) {
|
|
3574
|
+
events.emit("enrolment-failed");
|
|
3575
|
+
console.warn(
|
|
3576
|
+
"decane-connect-kit: could not enrol this wallet for server-assisted recovery. The wallet is fine and fully usable; it will be re-enrolled automatically on the next unlock. Until then a brand-new device would need a passkey backup or a recovery file.",
|
|
3577
|
+
e
|
|
3578
|
+
);
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
}
|
|
3582
|
+
} finally {
|
|
3583
|
+
zeroize(share);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3544
3586
|
const PROVISIONING_BUDGET_MS = 9e4;
|
|
3545
3587
|
function withDeadline(promise, ms, step) {
|
|
3546
3588
|
let timer;
|
|
@@ -3671,6 +3713,7 @@ async function createDecaneConnect(config) {
|
|
|
3671
3713
|
}
|
|
3672
3714
|
}
|
|
3673
3715
|
async function firstTimeSetup(userId, jwt) {
|
|
3716
|
+
prewarmAttestation(teeUrl);
|
|
3674
3717
|
let unlockMethod;
|
|
3675
3718
|
let wrappingKey;
|
|
3676
3719
|
let meta = {};
|
|
@@ -3774,49 +3817,49 @@ async function createDecaneConnect(config) {
|
|
|
3774
3817
|
addresses.solana = solanaAddress = confirmed.solana;
|
|
3775
3818
|
addresses.tron = tronAddress = confirmed.tron ?? evmToTronAddress2(confirmed.evm);
|
|
3776
3819
|
if (serverAssistedRecovery) {
|
|
3777
|
-
|
|
3778
|
-
try {
|
|
3779
|
-
const tee = new TeeClient(teeUrl);
|
|
3780
|
-
await tee.enrolAuthShare(jwt, shareSet.recovery);
|
|
3781
|
-
break;
|
|
3782
|
-
} catch (e) {
|
|
3783
|
-
if (attempt === 2) {
|
|
3784
|
-
console.warn(
|
|
3785
|
-
"decane-connect-kit: could not enrol this wallet for server-assisted recovery; a recovery file will be required on a new device. This wallet will get a 409 not_enrolled from /signer/provision until it is re-enrolled.",
|
|
3786
|
-
e
|
|
3787
|
-
);
|
|
3788
|
-
}
|
|
3789
|
-
}
|
|
3790
|
-
}
|
|
3820
|
+
void enrolInBackground(jwt, new Uint8Array(shareSet.recovery));
|
|
3791
3821
|
}
|
|
3792
|
-
if (config.offerRecoveryAtSignup
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
);
|
|
3802
|
-
} else if (choice.wants) {
|
|
3803
|
-
const file = await buildRecoveryShareFile(
|
|
3804
|
-
shareSet.recovery,
|
|
3805
|
-
choice.password,
|
|
3806
|
-
addresses,
|
|
3807
|
-
shareSet.version,
|
|
3808
|
-
choice.passwordHint
|
|
3809
|
-
);
|
|
3810
|
-
await config.onRecoveryFileReady?.(file, recoveryShareFileName(evmAddress));
|
|
3811
|
-
await api.markRecoveryShareSaved(jwt);
|
|
3812
|
-
}
|
|
3813
|
-
} catch (e) {
|
|
3814
|
-
console.warn("decane-connect-kit: recovery share offer failed or was skipped.", e);
|
|
3815
|
-
}
|
|
3822
|
+
if (config.offerRecoveryAtSignup === true && config.onRecoveryShareOffer) {
|
|
3823
|
+
void offerRecoveryShare(
|
|
3824
|
+
jwt,
|
|
3825
|
+
new Uint8Array(shareSet.recovery),
|
|
3826
|
+
{ ...addresses },
|
|
3827
|
+
shareSet.version,
|
|
3828
|
+
evmAddress,
|
|
3829
|
+
solanaAddress
|
|
3830
|
+
);
|
|
3816
3831
|
}
|
|
3817
3832
|
zeroize(shareSet.recovery);
|
|
3818
3833
|
return addresses;
|
|
3819
3834
|
}
|
|
3835
|
+
async function offerRecoveryShare(jwt, recoveryShare, addresses, shareSetVersion, evmAddress, solanaAddress) {
|
|
3836
|
+
try {
|
|
3837
|
+
const choice = await withTimeout(
|
|
3838
|
+
config.onRecoveryShareOffer({ evmAddress, solanaAddress }),
|
|
3839
|
+
RECOVERY_OFFER_TIMEOUT_MS
|
|
3840
|
+
);
|
|
3841
|
+
if (!choice) {
|
|
3842
|
+
console.warn(
|
|
3843
|
+
`decane-connect-kit: onRecoveryShareOffer did not settle within ${RECOVERY_OFFER_TIMEOUT_MS / 6e4} minutes, so no recovery file was offered. The wallet is unaffected \u2014 it was already created and enrolled \u2014 and the user can generate a recovery share later via rotateShares(). Check that your handler always resolves or rejects.`
|
|
3844
|
+
);
|
|
3845
|
+
return;
|
|
3846
|
+
}
|
|
3847
|
+
if (!choice.wants) return;
|
|
3848
|
+
const file = await buildRecoveryShareFile(
|
|
3849
|
+
recoveryShare,
|
|
3850
|
+
choice.password,
|
|
3851
|
+
addresses,
|
|
3852
|
+
shareSetVersion,
|
|
3853
|
+
choice.passwordHint
|
|
3854
|
+
);
|
|
3855
|
+
await config.onRecoveryFileReady?.(file, recoveryShareFileName(evmAddress));
|
|
3856
|
+
await api.markRecoveryShareSaved(jwt);
|
|
3857
|
+
} catch (e) {
|
|
3858
|
+
console.warn("decane-connect-kit: recovery share offer failed or was skipped.", e);
|
|
3859
|
+
} finally {
|
|
3860
|
+
zeroize(recoveryShare);
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3820
3863
|
async function returningUserUnlock(userId, jwt) {
|
|
3821
3864
|
const rawAddresses = await api.getAddresses(jwt);
|
|
3822
3865
|
const recordedAddresses = rawAddresses.evm && rawAddresses.solana ? { evm: rawAddresses.evm, solana: rawAddresses.solana, tron: rawAddresses.tron ?? evmToTronAddress2(rawAddresses.evm) } : null;
|
|
@@ -6722,7 +6765,7 @@ function DecaneKit({ config, children }) {
|
|
|
6722
6765
|
chains: config?.social?.chains
|
|
6723
6766
|
}
|
|
6724
6767
|
),
|
|
6725
|
-
/* @__PURE__ */ import_react5.default.createElement(WalletStatusOverlay, { phase: socialAuth.phase, theme })
|
|
6768
|
+
config?.social?.showStatusOverlay !== false && /* @__PURE__ */ import_react5.default.createElement(WalletStatusOverlay, { phase: socialAuth.phase, theme })
|
|
6726
6769
|
);
|
|
6727
6770
|
}
|
|
6728
6771
|
function useDecaneContext() {
|