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 CHANGED
@@ -2291,14 +2291,15 @@ init_errors();
2291
2291
 
2292
2292
  // ../../infra/tee-measurement.json
2293
2293
  var tee_measurement_default = {
2294
- signerVersion: "0.1.3",
2294
+ signerVersion: "0.2.10",
2295
2295
  acceptedMrtd: [
2296
+ '["fb14dc139f33d6fcf474bc8332cac001259fb31cfbcb6b34d4ceeb552a2c4466884a0cbde45ad98a05c5c060c23ad65a","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]',
2296
2297
  '["68102e7b524af310f7b7d426ce75481e36c40f5d513a9009c046e9d37e31551f0134d954b496a3357fd61d03f07ffe96","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]'
2297
2298
  ],
2298
- primaryMrtd: '["68102e7b524af310f7b7d426ce75481e36c40f5d513a9009c046e9d37e31551f0134d954b496a3357fd61d03f07ffe96","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]',
2299
- capturedAt: "2026-07-20T10:08:58.717Z",
2299
+ primaryMrtd: '["fb14dc139f33d6fcf474bc8332cac001259fb31cfbcb6b34d4ceeb552a2c4466884a0cbde45ad98a05c5c060c23ad65a","07e6f51aa763abfe75c3ddfbf4f425fe3f0ceff66d807a75e049303dce9addf68e7218729bd419638af63a370f65878c","a2a58c9a959a4fa44bd6da0c97a2270c051faf12084cfe91ae900e4fdff6cdd4f69a82005e04ee920f231497894d677f","a76a81147b7f733cb400914c8791ec149bb3a31f3727b1c1e12ec22e9c1a183b6e617e78636dca37075f5a695afd46c2"]',
2300
+ capturedAt: "2026-09-07T07:19:30.544601Z",
2300
2301
  tcbStatus: "UpToDate",
2301
- _note: "Captured from a live, signature-verified TDX quote (getCollateralAndVerify -> UpToDate) against decane-tee-signer v0.1.3 running on Phala Cloud CVM 786e714d-5042-4bf1-8060-0bc358f6a72f. measurement is the JSON.stringify(replayRtmrs()) output, compared as an opaque string (not parsed per-RTMR), matching the actual comparison logic in social/attestation.ts."
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 registerPasskeyAndBackup(userId, jwt, deviceShare) {
3698
- if (!isPasskeySupported()) return;
3698
+ async function registerPasskeyForDevice(userId, jwt, deviceShare) {
3699
+ if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
3699
3700
  const prfSalt = generateRandomBytes(32);
3700
- let credentialId;
3701
- let prfOutput;
3702
- try {
3703
- const result = await registerWebAuthnCredential({ api, jwt, rpId, rpName, prfSalt });
3704
- credentialId = result.credentialId;
3705
- prfOutput = result.prfOutput;
3706
- } catch (e) {
3707
- console.warn("decane-connect-kit: passkey provisioning after recovery failed; user can set this up later.", e);
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,