decane-connect-kit 2.15.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.cjs +60 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +60 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -3858,14 +3858,35 @@ async function createDecaneConnect(config) {
|
|
|
3858
3858
|
async function registerPasskeyForDevice(userId, jwt, deviceShare) {
|
|
3859
3859
|
if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
|
|
3860
3860
|
const prfSalt = generateRandomBytes(32);
|
|
3861
|
-
|
|
3862
|
-
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3861
|
+
let credentialId;
|
|
3862
|
+
let prfOutput;
|
|
3863
|
+
try {
|
|
3864
|
+
({ credentialId, prfOutput } = await registerWebAuthnCredential({
|
|
3865
|
+
api,
|
|
3866
|
+
jwt,
|
|
3867
|
+
rpId,
|
|
3868
|
+
rpName,
|
|
3869
|
+
prfSalt
|
|
3870
|
+
}));
|
|
3871
|
+
} catch (e) {
|
|
3872
|
+
if (e?.name !== "InvalidStateError") throw e;
|
|
3873
|
+
return adoptExistingPasskey(userId, jwt, deviceShare);
|
|
3874
|
+
}
|
|
3875
|
+
let key = prfOutput;
|
|
3876
|
+
if (!key) {
|
|
3877
|
+
try {
|
|
3878
|
+
key = await getPrfOutput({ rpId, credentialId, prfSalt });
|
|
3879
|
+
} catch (e) {
|
|
3880
|
+
console.warn(
|
|
3881
|
+
"decane-connect-kit: the new credential did not return a PRF output; it cannot wrap the share.",
|
|
3882
|
+
e
|
|
3883
|
+
);
|
|
3884
|
+
}
|
|
3885
|
+
}
|
|
3886
|
+
if (!key) throw new WebAuthnNotSupportedError();
|
|
3887
|
+
await storeShareUnderPasskey(userId, jwt, deviceShare, credentialId, key, prfSalt);
|
|
3888
|
+
}
|
|
3889
|
+
async function storeShareUnderPasskey(userId, jwt, deviceShare, credentialId, prfOutput, prfSalt) {
|
|
3869
3890
|
const wrappingKey = await importAesKey(prfOutput);
|
|
3870
3891
|
const iv = generateRandomBytes(12);
|
|
3871
3892
|
const wrappedDeviceShare = await aesGcmEncrypt(wrappingKey, deviceShare, iv);
|
|
@@ -3898,6 +3919,24 @@ async function createDecaneConnect(config) {
|
|
|
3898
3919
|
console.warn("decane-connect-kit: wrapped share backup upload failed; user can retry from settings.", e);
|
|
3899
3920
|
}
|
|
3900
3921
|
}
|
|
3922
|
+
async function adoptExistingPasskey(userId, jwt, deviceShare) {
|
|
3923
|
+
const options = await api.getWebAuthnLoginOptions(userId, rpId);
|
|
3924
|
+
if (!options) throw new WebAuthnNotSupportedError();
|
|
3925
|
+
const prfSalt = generateRandomBytes(32);
|
|
3926
|
+
const { response, prfOutput } = await authenticateWithPasskey({
|
|
3927
|
+
optionsJSON: options,
|
|
3928
|
+
prfSalt
|
|
3929
|
+
});
|
|
3930
|
+
if (!prfOutput) throw new WebAuthnNotSupportedError();
|
|
3931
|
+
await storeShareUnderPasskey(
|
|
3932
|
+
userId,
|
|
3933
|
+
jwt,
|
|
3934
|
+
deviceShare,
|
|
3935
|
+
b64uToBuffer(response.id),
|
|
3936
|
+
prfOutput,
|
|
3937
|
+
prfSalt
|
|
3938
|
+
);
|
|
3939
|
+
}
|
|
3901
3940
|
async function registerPasskeyAndBackup(userId, jwt, deviceShare) {
|
|
3902
3941
|
if (!isPasskeySupported()) return;
|
|
3903
3942
|
try {
|
|
@@ -4577,8 +4616,19 @@ async function createDecaneConnect(config) {
|
|
|
4577
4616
|
if (!auth) throw new ReconnectRequiredError();
|
|
4578
4617
|
if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
|
|
4579
4618
|
const stored = await storage.getShare(auth.userId);
|
|
4580
|
-
if (
|
|
4581
|
-
if (stored
|
|
4619
|
+
if (stored?.unlockMethod === "passkey") return;
|
|
4620
|
+
if (!stored) {
|
|
4621
|
+
if (!serverAssistedRecovery) throw new NewDeviceError();
|
|
4622
|
+
const tee = new TeeClient(teeUrl);
|
|
4623
|
+
const provisioned = await tee.provisionDeviceShare(auth.jwt);
|
|
4624
|
+
if (!provisioned) throw new NewDeviceError();
|
|
4625
|
+
try {
|
|
4626
|
+
await registerPasskeyForDevice(auth.userId, auth.jwt, provisioned);
|
|
4627
|
+
} finally {
|
|
4628
|
+
zeroize(provisioned);
|
|
4629
|
+
}
|
|
4630
|
+
return;
|
|
4631
|
+
}
|
|
4582
4632
|
let deviceShare;
|
|
4583
4633
|
try {
|
|
4584
4634
|
deviceShare = await aesGcmDecrypt(
|