decane-connect-kit 2.8.1 → 2.9.1
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 +81 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +81 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2291,14 +2291,15 @@ init_errors();
|
|
|
2291
2291
|
|
|
2292
2292
|
// ../../infra/tee-measurement.json
|
|
2293
2293
|
var tee_measurement_default = {
|
|
2294
|
-
signerVersion: "0.
|
|
2294
|
+
signerVersion: "0.2.10",
|
|
2295
2295
|
acceptedMrtd: [
|
|
2296
|
+
'["fb14dc139f33d6fcf474bc8332cac001259fb31cfbcb6b34d4ceeb552a2c4466884a0cbde45ad98a05c5c060c23ad65a","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]',
|
|
2296
2297
|
'["68102e7b524af310f7b7d426ce75481e36c40f5d513a9009c046e9d37e31551f0134d954b496a3357fd61d03f07ffe96","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]'
|
|
2297
2298
|
],
|
|
2298
|
-
primaryMrtd: '["
|
|
2299
|
-
capturedAt: "2026-
|
|
2299
|
+
primaryMrtd: '["fb14dc139f33d6fcf474bc8332cac001259fb31cfbcb6b34d4ceeb552a2c4466884a0cbde45ad98a05c5c060c23ad65a","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]',
|
|
2300
|
+
capturedAt: "2026-09-07T07:19:30.544601Z",
|
|
2300
2301
|
tcbStatus: "UpToDate",
|
|
2301
|
-
_note: "Captured from
|
|
2302
|
+
_note: "Captured from the live CVM 786e714d-5042-4bf1-8060-0bc358f6a72f (app_4405742df08d\u2026) after the 2026-09-07 credential recovery. RTMR0 changed; RTMR1-3 did not \u2014 RTMR3 is the app-compose measurement, so the app's identity is unchanged and this is a platform/firmware move underneath the CVM (Phala node v0.6.0), not a change to what we deploy. Sealing was verified intact across it (/signer/sealing-status: sealingAvailable, roundTripOk, ready), so no auth_shares were lost. The previous measurement is retained above so a rollback still verifies. measurement is the JSON.stringify(replayRtmrs()) output, compared as an opaque string (not parsed per-RTMR), matching social/attestation.ts."
|
|
2302
2303
|
};
|
|
2303
2304
|
|
|
2304
2305
|
// src/social/attestation.ts
|
|
@@ -3694,20 +3695,17 @@ async function createDecaneConnect(config) {
|
|
|
3694
3695
|
const pin = await config.promptPin();
|
|
3695
3696
|
return deriveKeyFromPin(pin, stored.pinSalt);
|
|
3696
3697
|
}
|
|
3697
|
-
async function
|
|
3698
|
-
if (!isPasskeySupported())
|
|
3698
|
+
async function registerPasskeyForDevice(userId, jwt, deviceShare) {
|
|
3699
|
+
if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
|
|
3699
3700
|
const prfSalt = generateRandomBytes(32);
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
}
|
|
3707
|
-
|
|
3708
|
-
return;
|
|
3709
|
-
}
|
|
3710
|
-
if (!prfOutput) return;
|
|
3701
|
+
const { credentialId, prfOutput } = await registerWebAuthnCredential({
|
|
3702
|
+
api,
|
|
3703
|
+
jwt,
|
|
3704
|
+
rpId,
|
|
3705
|
+
rpName,
|
|
3706
|
+
prfSalt
|
|
3707
|
+
});
|
|
3708
|
+
if (!prfOutput) throw new WebAuthnNotSupportedError();
|
|
3711
3709
|
const wrappingKey = await importAesKey(prfOutput);
|
|
3712
3710
|
const iv = generateRandomBytes(12);
|
|
3713
3711
|
const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
|
|
@@ -3732,6 +3730,17 @@ async function createDecaneConnect(config) {
|
|
|
3732
3730
|
console.warn("decane-connect-kit: wrapped share backup upload failed; user can retry from settings.", e);
|
|
3733
3731
|
}
|
|
3734
3732
|
}
|
|
3733
|
+
async function registerPasskeyAndBackup(userId, jwt, deviceShare) {
|
|
3734
|
+
if (!isPasskeySupported()) return;
|
|
3735
|
+
try {
|
|
3736
|
+
await registerPasskeyForDevice(userId, jwt, deviceShare);
|
|
3737
|
+
} catch (e) {
|
|
3738
|
+
console.warn(
|
|
3739
|
+
"decane-connect-kit: passkey provisioning failed; the user can set one up later with addPasskey().",
|
|
3740
|
+
e
|
|
3741
|
+
);
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3735
3744
|
async function firstTimeSetup(userId, jwt) {
|
|
3736
3745
|
prewarmAttestation(teeUrl);
|
|
3737
3746
|
let unlockMethod;
|
|
@@ -4181,6 +4190,34 @@ async function createDecaneConnect(config) {
|
|
|
4181
4190
|
if (!candidate) throw new NewDeviceError();
|
|
4182
4191
|
return passkeyLogin(candidate);
|
|
4183
4192
|
},
|
|
4193
|
+
async hasPasskey() {
|
|
4194
|
+
if (!auth) return false;
|
|
4195
|
+
const stored = await storage.getShare(auth.userId);
|
|
4196
|
+
return stored?.unlockMethod === "passkey";
|
|
4197
|
+
},
|
|
4198
|
+
async addPasskey() {
|
|
4199
|
+
if (!auth) throw new ReconnectRequiredError();
|
|
4200
|
+
if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
|
|
4201
|
+
const stored = await storage.getShare(auth.userId);
|
|
4202
|
+
if (!stored) throw new NewDeviceError();
|
|
4203
|
+
if (stored.unlockMethod === "passkey") return;
|
|
4204
|
+
let deviceShare;
|
|
4205
|
+
try {
|
|
4206
|
+
deviceShare = await aesGcmDecrypt(
|
|
4207
|
+
await getWrappingKey(stored),
|
|
4208
|
+
stored.wrappedDeviceShare,
|
|
4209
|
+
stored.iv
|
|
4210
|
+
);
|
|
4211
|
+
} catch (e) {
|
|
4212
|
+
if (e instanceof DecaneConnectError) throw e;
|
|
4213
|
+
throw new ShareCorruptedError();
|
|
4214
|
+
}
|
|
4215
|
+
try {
|
|
4216
|
+
await registerPasskeyForDevice(auth.userId, auth.jwt, deviceShare);
|
|
4217
|
+
} finally {
|
|
4218
|
+
zeroize(deviceShare);
|
|
4219
|
+
}
|
|
4220
|
+
},
|
|
4184
4221
|
async unlock() {
|
|
4185
4222
|
if (!auth) {
|
|
4186
4223
|
const candidate = await passkeyLoginCandidate();
|
|
@@ -6940,6 +6977,16 @@ function DecaneKit({ config, children }) {
|
|
|
6940
6977
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
6941
6978
|
return sdk.exportPortableBackup(opts);
|
|
6942
6979
|
}, []);
|
|
6980
|
+
const socialHasPasskey = (0, import_react5.useCallback)(async () => {
|
|
6981
|
+
const sdk = socialRef.current;
|
|
6982
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
6983
|
+
return sdk.hasPasskey();
|
|
6984
|
+
}, []);
|
|
6985
|
+
const socialAddPasskey = (0, import_react5.useCallback)(async () => {
|
|
6986
|
+
const sdk = socialRef.current;
|
|
6987
|
+
if (!sdk) throw new Error("Social wallet not connected");
|
|
6988
|
+
return sdk.addPasskey();
|
|
6989
|
+
}, []);
|
|
6943
6990
|
const socialHasRecoveryShare = (0, import_react5.useCallback)(async () => {
|
|
6944
6991
|
const sdk = socialRef.current;
|
|
6945
6992
|
if (!sdk) throw new Error("Social wallet not connected");
|
|
@@ -7001,6 +7048,8 @@ function DecaneKit({ config, children }) {
|
|
|
7001
7048
|
socialRotateShares,
|
|
7002
7049
|
socialExportPortableBackup,
|
|
7003
7050
|
socialHasRecoveryShare,
|
|
7051
|
+
socialHasPasskey,
|
|
7052
|
+
socialAddPasskey,
|
|
7004
7053
|
socialShouldPromptRecovery,
|
|
7005
7054
|
socialDismissRecoveryPrompt,
|
|
7006
7055
|
socialModalOpen,
|
|
@@ -7280,6 +7329,8 @@ function useSocialWallet() {
|
|
|
7280
7329
|
socialRotateShares,
|
|
7281
7330
|
socialExportPortableBackup,
|
|
7282
7331
|
socialHasRecoveryShare,
|
|
7332
|
+
socialHasPasskey,
|
|
7333
|
+
socialAddPasskey,
|
|
7283
7334
|
socialShouldPromptRecovery,
|
|
7284
7335
|
socialDismissRecoveryPrompt,
|
|
7285
7336
|
openSocialModal,
|
|
@@ -7367,6 +7418,16 @@ function useSocialWallet() {
|
|
|
7367
7418
|
(opts) => run(() => socialExportPortableBackup(opts)),
|
|
7368
7419
|
[socialExportPortableBackup]
|
|
7369
7420
|
);
|
|
7421
|
+
const hasPasskey = (0, import_react6.useCallback)(() => run(() => socialHasPasskey()), [socialHasPasskey]);
|
|
7422
|
+
const addPasskey = (0, import_react6.useCallback)(async () => {
|
|
7423
|
+
setError(null);
|
|
7424
|
+
try {
|
|
7425
|
+
await socialAddPasskey();
|
|
7426
|
+
} catch (e) {
|
|
7427
|
+
setError(e.message);
|
|
7428
|
+
throw e;
|
|
7429
|
+
}
|
|
7430
|
+
}, [socialAddPasskey]);
|
|
7370
7431
|
const hasRecoveryShare = (0, import_react6.useCallback)(
|
|
7371
7432
|
() => run(() => socialHasRecoveryShare()),
|
|
7372
7433
|
[socialHasRecoveryShare]
|
|
@@ -7420,6 +7481,9 @@ function useSocialWallet() {
|
|
|
7420
7481
|
// The Decane JWT — authenticate the user to your own backend (bundler proxy,
|
|
7421
7482
|
// etc.); verify server-side against backend.decane.app/.well-known/jwks.json.
|
|
7422
7483
|
getAccessToken: socialGetAccessToken,
|
|
7484
|
+
// Passkey management for THIS device
|
|
7485
|
+
hasPasskey,
|
|
7486
|
+
addPasskey,
|
|
7423
7487
|
// Recovery (2-of-3 Shamir share set)
|
|
7424
7488
|
rotateShares,
|
|
7425
7489
|
exportPortableBackup,
|