decane-connect-kit 2.16.0 → 2.17.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.js CHANGED
@@ -3776,13 +3776,20 @@ async function createDecaneConnect(config) {
3776
3776
  async function registerPasskeyForDevice(userId, jwt, deviceShare) {
3777
3777
  if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
3778
3778
  const prfSalt = generateRandomBytes(32);
3779
- const { credentialId, prfOutput } = await registerWebAuthnCredential({
3780
- api,
3781
- jwt,
3782
- rpId,
3783
- rpName,
3784
- prfSalt
3785
- });
3779
+ let credentialId;
3780
+ let prfOutput;
3781
+ try {
3782
+ ({ credentialId, prfOutput } = await registerWebAuthnCredential({
3783
+ api,
3784
+ jwt,
3785
+ rpId,
3786
+ rpName,
3787
+ prfSalt
3788
+ }));
3789
+ } catch (e) {
3790
+ if (e?.name !== "InvalidStateError") throw e;
3791
+ return adoptExistingPasskey(userId, jwt, deviceShare);
3792
+ }
3786
3793
  let key = prfOutput;
3787
3794
  if (!key) {
3788
3795
  try {
@@ -3795,7 +3802,10 @@ async function createDecaneConnect(config) {
3795
3802
  }
3796
3803
  }
3797
3804
  if (!key) throw new WebAuthnNotSupportedError();
3798
- const wrappingKey = await importAesKey(key);
3805
+ await storeShareUnderPasskey(userId, jwt, deviceShare, credentialId, key, prfSalt);
3806
+ }
3807
+ async function storeShareUnderPasskey(userId, jwt, deviceShare, credentialId, prfOutput, prfSalt) {
3808
+ const wrappingKey = await importAesKey(prfOutput);
3799
3809
  const iv = generateRandomBytes(12);
3800
3810
  const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
3801
3811
  const existing = await storage.getShare(userId);
@@ -3827,6 +3837,24 @@ async function createDecaneConnect(config) {
3827
3837
  console.warn("decane-connect-kit: wrapped share backup upload failed; user can retry from settings.", e);
3828
3838
  }
3829
3839
  }
3840
+ async function adoptExistingPasskey(userId, jwt, deviceShare) {
3841
+ const options = await api.getWebAuthnLoginOptions(userId, rpId);
3842
+ if (!options) throw new WebAuthnNotSupportedError();
3843
+ const prfSalt = generateRandomBytes(32);
3844
+ const { response, prfOutput } = await authenticateWithPasskey({
3845
+ optionsJSON: options,
3846
+ prfSalt
3847
+ });
3848
+ if (!prfOutput) throw new WebAuthnNotSupportedError();
3849
+ await storeShareUnderPasskey(
3850
+ userId,
3851
+ jwt,
3852
+ deviceShare,
3853
+ b64uToBuffer(response.id),
3854
+ prfOutput,
3855
+ prfSalt
3856
+ );
3857
+ }
3830
3858
  async function registerPasskeyAndBackup(userId, jwt, deviceShare) {
3831
3859
  if (!isPasskeySupported()) return;
3832
3860
  try {