decane-connect-kit 2.12.0 → 2.13.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
@@ -2968,9 +2968,6 @@ async function deriveKeyFromPin(pin, salt) {
2968
2968
  ["encrypt", "decrypt"]
2969
2969
  );
2970
2970
  }
2971
- function validatePin(pin) {
2972
- if (!/^\d{4,8}$/.test(pin)) throw new Error("PIN must be 4\u20138 digits");
2973
- }
2974
2971
 
2975
2972
  // src/social/crypto/passkey.ts
2976
2973
  var import_browser2 = require("@simplewebauthn/browser");
@@ -3784,21 +3781,38 @@ async function createDecaneConnect(config) {
3784
3781
  }
3785
3782
  }
3786
3783
  events.on("session-expired", () => dropLiveSession());
3787
- async function pinSetup() {
3788
- if (!config.promptPin) throw new PromptPinNotConfiguredError();
3789
- const pin = await config.promptPin();
3790
- validatePin(pin);
3791
- const pinSalt = generateRandomBytes(32);
3792
- const wrappingKey = await deriveKeyFromPin(pin, pinSalt);
3784
+ async function passwordSetup() {
3785
+ if (!config.promptUnlockPassword) throw new PromptPasswordNotConfiguredError();
3786
+ const password = await config.promptUnlockPassword({ kind: "set" });
3787
+ validateUnlockPassword(password);
3788
+ const passwordSalt = generateRandomBytes(32);
3789
+ const { shareKey, tokenKey } = await derivePasswordKeys(password, passwordSalt);
3793
3790
  return {
3794
- wrappingKey,
3791
+ wrappingKey: shareKey,
3792
+ tokenKey,
3795
3793
  meta: {
3796
- unlockMethod: "pin",
3797
- pinSalt: bufferToB64u(pinSalt),
3798
- pinIterations: 6e5
3794
+ unlockMethod: "password",
3795
+ passwordSalt: bufferToB64u(passwordSalt),
3796
+ passwordIterations: PBKDF2_ITERATIONS
3799
3797
  }
3800
3798
  };
3801
3799
  }
3800
+ async function attachUnlockToken(userId, jwt, tokenKey) {
3801
+ try {
3802
+ const stored = await storage.getShare(userId);
3803
+ if (!stored) return;
3804
+ const { token } = await api.issueUnlockToken(jwt);
3805
+ const unlockTokenIv = generateRandomBytes(12);
3806
+ const wrappedUnlockToken = await aesGcmEncrypt(
3807
+ tokenKey,
3808
+ new TextEncoder().encode(token),
3809
+ unlockTokenIv
3810
+ );
3811
+ await storage.putShare({ ...stored, wrappedUnlockToken, unlockTokenIv });
3812
+ } catch (e) {
3813
+ console.warn("decane-connect-kit: could not store an unlock token for this device.", e);
3814
+ }
3815
+ }
3802
3816
  async function persistRotatedDeviceShare(userId, deviceShare) {
3803
3817
  const stored = await storage.getShare(userId);
3804
3818
  if (!stored) {
@@ -3892,6 +3906,7 @@ async function createDecaneConnect(config) {
3892
3906
  let unlockMethod;
3893
3907
  let wrappingKey;
3894
3908
  let meta = {};
3909
+ let unlockTokenKey = null;
3895
3910
  if (isPasskeySupported()) {
3896
3911
  const prfSalt = generateRandomBytes(32);
3897
3912
  try {
@@ -3905,18 +3920,18 @@ async function createDecaneConnect(config) {
3905
3920
  prfSalt: bufferToB64u(prfSalt)
3906
3921
  };
3907
3922
  } else {
3908
- ({ wrappingKey, meta } = await pinSetup());
3909
- unlockMethod = "pin";
3923
+ ({ wrappingKey, meta, tokenKey: unlockTokenKey } = await passwordSetup());
3924
+ unlockMethod = "password";
3910
3925
  }
3911
3926
  } catch (e) {
3912
3927
  if (e.name === "UserCancelledError")
3913
3928
  throw new UserCancelledError();
3914
- ({ wrappingKey, meta } = await pinSetup());
3915
- unlockMethod = "pin";
3929
+ ({ wrappingKey, meta, tokenKey: unlockTokenKey } = await passwordSetup());
3930
+ unlockMethod = "password";
3916
3931
  }
3917
3932
  } else {
3918
- ({ wrappingKey, meta } = await pinSetup());
3919
- unlockMethod = "pin";
3933
+ ({ wrappingKey, meta, tokenKey: unlockTokenKey } = await passwordSetup());
3934
+ unlockMethod = "password";
3920
3935
  }
3921
3936
  const provisioningStartedAt = Date.now();
3922
3937
  const remainingBudget = () => PROVISIONING_BUDGET_MS - (Date.now() - provisioningStartedAt);
@@ -3948,8 +3963,11 @@ async function createDecaneConnect(config) {
3948
3963
  prfSalt: meta.prfSalt ? b64uToBuffer(meta.prfSalt) : void 0,
3949
3964
  pinSalt: meta.pinSalt ? b64uToBuffer(meta.pinSalt) : void 0,
3950
3965
  pinIterations: meta.pinIterations,
3966
+ passwordSalt: meta.passwordSalt ? b64uToBuffer(meta.passwordSalt) : void 0,
3967
+ passwordIterations: meta.passwordIterations,
3951
3968
  version: 1
3952
3969
  });
3970
+ if (unlockTokenKey) await attachUnlockToken(userId, jwt, unlockTokenKey);
3953
3971
  const serverIv = generateRandomBytes(12);
3954
3972
  await withDeadline(api.putShare(jwt, {
3955
3973
  ciphertext: shareSet.server,
@@ -7018,6 +7036,7 @@ function DecaneKit({ config, children }) {
7018
7036
  apiKey,
7019
7037
  authMethods,
7020
7038
  promptPin,
7039
+ promptUnlockPassword,
7021
7040
  apiBaseUrl,
7022
7041
  chains,
7023
7042
  rpcUrls,
@@ -7040,6 +7059,7 @@ function DecaneKit({ config, children }) {
7040
7059
  chains: chains ?? ["evm:1", "solana:mainnet"],
7041
7060
  rpcUrls,
7042
7061
  promptPin,
7062
+ promptUnlockPassword,
7043
7063
  requireAssertionPerSignature,
7044
7064
  offerRecoveryAtSignup,
7045
7065
  onRecoveryShareOffer,