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 +76 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +24 -1
- package/dist/index.d.ts +24 -1
- package/dist/index.js +76 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
3698
|
-
if (!isPasskeySupported())
|
|
3697
|
+
async function registerPasskeyForDevice(userId, jwt, deviceShare) {
|
|
3698
|
+
if (!isPasskeySupported()) throw new WebAuthnNotSupportedError();
|
|
3699
3699
|
const prfSalt = generateRandomBytes(32);
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
}
|
|
3707
|
-
|
|
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,
|