decane-connect-kit 2.8.1 → 2.9.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/dist/index.cjs CHANGED
@@ -3694,20 +3694,17 @@ async function createDecaneConnect(config) {
3694
3694
  const pin = await config.promptPin();
3695
3695
  return deriveKeyFromPin(pin, stored.pinSalt);
3696
3696
  }
3697
- async function registerPasskeyAndBackup(userId, jwt, deviceShare) {
3698
- if (!isPasskeySupported()) return;
3697
+ async function registerPasskeyForDevice(userId, jwt, deviceShare) {
3698
+ if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
3699
3699
  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;
3700
+ const { credentialId, prfOutput } = await registerWebAuthnCredential({
3701
+ api,
3702
+ jwt,
3703
+ rpId,
3704
+ rpName,
3705
+ prfSalt
3706
+ });
3707
+ if (!prfOutput) throw new WebAuthnNotSupportedError();
3711
3708
  const wrappingKey = await importAesKey(prfOutput);
3712
3709
  const iv = generateRandomBytes(12);
3713
3710
  const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
@@ -3732,6 +3729,17 @@ async function createDecaneConnect(config) {
3732
3729
  console.warn("decane-connect-kit: wrapped share backup upload failed; user can retry from settings.", e);
3733
3730
  }
3734
3731
  }
3732
+ async function registerPasskeyAndBackup(userId, jwt, deviceShare) {
3733
+ if (!isPasskeySupported()) return;
3734
+ try {
3735
+ await registerPasskeyForDevice(userId, jwt, deviceShare);
3736
+ } catch (e) {
3737
+ console.warn(
3738
+ "decane-connect-kit: passkey provisioning failed; the user can set one up later with addPasskey().",
3739
+ e
3740
+ );
3741
+ }
3742
+ }
3735
3743
  async function firstTimeSetup(userId, jwt) {
3736
3744
  prewarmAttestation(teeUrl);
3737
3745
  let unlockMethod;
@@ -4181,6 +4189,34 @@ async function createDecaneConnect(config) {
4181
4189
  if (!candidate) throw new NewDeviceError();
4182
4190
  return passkeyLogin(candidate);
4183
4191
  },
4192
+ async hasPasskey() {
4193
+ if (!auth) return false;
4194
+ const stored = await storage.getShare(auth.userId);
4195
+ return stored?.unlockMethod === "passkey";
4196
+ },
4197
+ async addPasskey() {
4198
+ if (!auth) throw new ReconnectRequiredError();
4199
+ if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
4200
+ const stored = await storage.getShare(auth.userId);
4201
+ if (!stored) throw new NewDeviceError();
4202
+ if (stored.unlockMethod === "passkey") return;
4203
+ let deviceShare;
4204
+ try {
4205
+ deviceShare = await aesGcmDecrypt(
4206
+ await getWrappingKey(stored),
4207
+ stored.wrappedDeviceShare,
4208
+ stored.iv
4209
+ );
4210
+ } catch (e) {
4211
+ if (e instanceof DecaneConnectError) throw e;
4212
+ throw new ShareCorruptedError();
4213
+ }
4214
+ try {
4215
+ await registerPasskeyForDevice(auth.userId, auth.jwt, deviceShare);
4216
+ } finally {
4217
+ zeroize(deviceShare);
4218
+ }
4219
+ },
4184
4220
  async unlock() {
4185
4221
  if (!auth) {
4186
4222
  const candidate = await passkeyLoginCandidate();
@@ -6940,6 +6976,16 @@ function DecaneKit({ config, children }) {
6940
6976
  if (!sdk) throw new Error("Social wallet not connected");
6941
6977
  return sdk.exportPortableBackup(opts);
6942
6978
  }, []);
6979
+ const socialHasPasskey = (0, import_react5.useCallback)(async () => {
6980
+ const sdk = socialRef.current;
6981
+ if (!sdk) throw new Error("Social wallet not connected");
6982
+ return sdk.hasPasskey();
6983
+ }, []);
6984
+ const socialAddPasskey = (0, import_react5.useCallback)(async () => {
6985
+ const sdk = socialRef.current;
6986
+ if (!sdk) throw new Error("Social wallet not connected");
6987
+ return sdk.addPasskey();
6988
+ }, []);
6943
6989
  const socialHasRecoveryShare = (0, import_react5.useCallback)(async () => {
6944
6990
  const sdk = socialRef.current;
6945
6991
  if (!sdk) throw new Error("Social wallet not connected");
@@ -7001,6 +7047,8 @@ function DecaneKit({ config, children }) {
7001
7047
  socialRotateShares,
7002
7048
  socialExportPortableBackup,
7003
7049
  socialHasRecoveryShare,
7050
+ socialHasPasskey,
7051
+ socialAddPasskey,
7004
7052
  socialShouldPromptRecovery,
7005
7053
  socialDismissRecoveryPrompt,
7006
7054
  socialModalOpen,
@@ -7280,6 +7328,8 @@ function useSocialWallet() {
7280
7328
  socialRotateShares,
7281
7329
  socialExportPortableBackup,
7282
7330
  socialHasRecoveryShare,
7331
+ socialHasPasskey,
7332
+ socialAddPasskey,
7283
7333
  socialShouldPromptRecovery,
7284
7334
  socialDismissRecoveryPrompt,
7285
7335
  openSocialModal,
@@ -7367,6 +7417,16 @@ function useSocialWallet() {
7367
7417
  (opts) => run(() => socialExportPortableBackup(opts)),
7368
7418
  [socialExportPortableBackup]
7369
7419
  );
7420
+ const hasPasskey = (0, import_react6.useCallback)(() => run(() => socialHasPasskey()), [socialHasPasskey]);
7421
+ const addPasskey = (0, import_react6.useCallback)(async () => {
7422
+ setError(null);
7423
+ try {
7424
+ await socialAddPasskey();
7425
+ } catch (e) {
7426
+ setError(e.message);
7427
+ throw e;
7428
+ }
7429
+ }, [socialAddPasskey]);
7370
7430
  const hasRecoveryShare = (0, import_react6.useCallback)(
7371
7431
  () => run(() => socialHasRecoveryShare()),
7372
7432
  [socialHasRecoveryShare]
@@ -7420,6 +7480,9 @@ function useSocialWallet() {
7420
7480
  // The Decane JWT — authenticate the user to your own backend (bundler proxy,
7421
7481
  // etc.); verify server-side against backend.decane.app/.well-known/jwks.json.
7422
7482
  getAccessToken: socialGetAccessToken,
7483
+ // Passkey management for THIS device
7484
+ hasPasskey,
7485
+ addPasskey,
7423
7486
  // Recovery (2-of-3 Shamir share set)
7424
7487
  rotateShares,
7425
7488
  exportPortableBackup,