decane-connect-kit 2.8.0 → 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 +92 -13
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +26 -1
- package/dist/index.d.ts +26 -1
- package/dist/index.js +92 -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,
|
|
@@ -7079,6 +7127,7 @@ function useSocialAuth() {
|
|
|
7079
7127
|
const {
|
|
7080
7128
|
socialAuth,
|
|
7081
7129
|
connectWithGoogle,
|
|
7130
|
+
connectWithKingsChat,
|
|
7082
7131
|
connectWithEmail,
|
|
7083
7132
|
verifyEmailCode: verifyEmailCode2,
|
|
7084
7133
|
connectWithPhone,
|
|
@@ -7091,6 +7140,7 @@ function useSocialAuth() {
|
|
|
7091
7140
|
socialDisconnect
|
|
7092
7141
|
} = useDecaneContext();
|
|
7093
7142
|
const [googleLoading, setGoogleLoading] = (0, import_react6.useState)(false);
|
|
7143
|
+
const [kingschatLoading, setKingschatLoading] = (0, import_react6.useState)(false);
|
|
7094
7144
|
const [emailLoading, setEmailLoading] = (0, import_react6.useState)(false);
|
|
7095
7145
|
const [phoneLoading, setPhoneLoading] = (0, import_react6.useState)(false);
|
|
7096
7146
|
const [tokenLoading, setTokenLoading] = (0, import_react6.useState)(false);
|
|
@@ -7106,6 +7156,18 @@ function useSocialAuth() {
|
|
|
7106
7156
|
setGoogleLoading(false);
|
|
7107
7157
|
}
|
|
7108
7158
|
}, [connectWithGoogle]);
|
|
7159
|
+
const signInWithKingsChat = (0, import_react6.useCallback)(async () => {
|
|
7160
|
+
setKingschatLoading(true);
|
|
7161
|
+
setError(null);
|
|
7162
|
+
try {
|
|
7163
|
+
await connectWithKingsChat();
|
|
7164
|
+
} catch (e) {
|
|
7165
|
+
setError(e.message);
|
|
7166
|
+
throw e;
|
|
7167
|
+
} finally {
|
|
7168
|
+
setKingschatLoading(false);
|
|
7169
|
+
}
|
|
7170
|
+
}, [connectWithKingsChat]);
|
|
7109
7171
|
const sendEmailCode = (0, import_react6.useCallback)(async (email) => {
|
|
7110
7172
|
setEmailLoading(true);
|
|
7111
7173
|
setError(null);
|
|
@@ -7225,6 +7287,7 @@ function useSocialAuth() {
|
|
|
7225
7287
|
// this into a real reconnect (signInWithGoogle / sendEmailCode), not unlock().
|
|
7226
7288
|
needsReconnect: socialAuth.needsReconnect,
|
|
7227
7289
|
googleLoading,
|
|
7290
|
+
kingschatLoading,
|
|
7228
7291
|
emailLoading,
|
|
7229
7292
|
phoneLoading,
|
|
7230
7293
|
tokenLoading,
|
|
@@ -7233,6 +7296,7 @@ function useSocialAuth() {
|
|
|
7233
7296
|
error,
|
|
7234
7297
|
clearError: () => setError(null),
|
|
7235
7298
|
signInWithGoogle,
|
|
7299
|
+
signInWithKingsChat,
|
|
7236
7300
|
sendEmailCode,
|
|
7237
7301
|
confirmEmailCode,
|
|
7238
7302
|
sendPhoneCode,
|
|
@@ -7264,6 +7328,8 @@ function useSocialWallet() {
|
|
|
7264
7328
|
socialRotateShares,
|
|
7265
7329
|
socialExportPortableBackup,
|
|
7266
7330
|
socialHasRecoveryShare,
|
|
7331
|
+
socialHasPasskey,
|
|
7332
|
+
socialAddPasskey,
|
|
7267
7333
|
socialShouldPromptRecovery,
|
|
7268
7334
|
socialDismissRecoveryPrompt,
|
|
7269
7335
|
openSocialModal,
|
|
@@ -7351,6 +7417,16 @@ function useSocialWallet() {
|
|
|
7351
7417
|
(opts) => run(() => socialExportPortableBackup(opts)),
|
|
7352
7418
|
[socialExportPortableBackup]
|
|
7353
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]);
|
|
7354
7430
|
const hasRecoveryShare = (0, import_react6.useCallback)(
|
|
7355
7431
|
() => run(() => socialHasRecoveryShare()),
|
|
7356
7432
|
[socialHasRecoveryShare]
|
|
@@ -7404,6 +7480,9 @@ function useSocialWallet() {
|
|
|
7404
7480
|
// The Decane JWT — authenticate the user to your own backend (bundler proxy,
|
|
7405
7481
|
// etc.); verify server-side against backend.decane.app/.well-known/jwks.json.
|
|
7406
7482
|
getAccessToken: socialGetAccessToken,
|
|
7483
|
+
// Passkey management for THIS device
|
|
7484
|
+
hasPasskey,
|
|
7485
|
+
addPasskey,
|
|
7407
7486
|
// Recovery (2-of-3 Shamir share set)
|
|
7408
7487
|
rotateShares,
|
|
7409
7488
|
exportPortableBackup,
|