@arbidocs/client 0.4.84 → 0.4.86
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 +137 -230
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +531 -334
- package/dist/index.d.ts +531 -334
- package/dist/index.js +131 -228
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -372,70 +372,98 @@ async function generateUserKeypairs(username, password, deploymentDomain) {
|
|
|
372
372
|
encryptionKeyPair
|
|
373
373
|
};
|
|
374
374
|
}
|
|
375
|
+
var IDENTITY_WRAP_CONTEXT = "arbi-identity-wrap-v1";
|
|
376
|
+
function identityWrappingKey(passwordSecretKey) {
|
|
377
|
+
return sodium__default.default.crypto_generichash(
|
|
378
|
+
32,
|
|
379
|
+
sodium__default.default.from_string(IDENTITY_WRAP_CONTEXT),
|
|
380
|
+
passwordSecretKey.slice(0, 32)
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
function generateIdentityKeypair() {
|
|
384
|
+
return generateRandomSigningKeypair();
|
|
385
|
+
}
|
|
386
|
+
function wrapIdentityKey(identitySecretKey, passwordSecretKey) {
|
|
387
|
+
const nonce = sodium__default.default.randombytes_buf(sodium__default.default.crypto_secretbox_NONCEBYTES);
|
|
388
|
+
const key = identityWrappingKey(passwordSecretKey);
|
|
389
|
+
try {
|
|
390
|
+
const boxed = sodium__default.default.crypto_secretbox_easy(identitySecretKey, nonce, key);
|
|
391
|
+
const out = new Uint8Array(nonce.length + boxed.length);
|
|
392
|
+
out.set(nonce);
|
|
393
|
+
out.set(boxed, nonce.length);
|
|
394
|
+
return base64Encode(out);
|
|
395
|
+
} finally {
|
|
396
|
+
key.fill(0);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function unwrapIdentityKey(wrapped, passwordSecretKey) {
|
|
400
|
+
if (!wrapped) return passwordSecretKey;
|
|
401
|
+
const bytes = base64Decode(wrapped);
|
|
402
|
+
const nonce = bytes.slice(0, sodium__default.default.crypto_secretbox_NONCEBYTES);
|
|
403
|
+
const key = identityWrappingKey(passwordSecretKey);
|
|
404
|
+
try {
|
|
405
|
+
return sodium__default.default.crypto_secretbox_open_easy(
|
|
406
|
+
bytes.slice(sodium__default.default.crypto_secretbox_NONCEBYTES),
|
|
407
|
+
nonce,
|
|
408
|
+
key
|
|
409
|
+
);
|
|
410
|
+
} catch {
|
|
411
|
+
throw new Error("Incorrect password");
|
|
412
|
+
} finally {
|
|
413
|
+
key.fill(0);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
375
416
|
|
|
376
417
|
// src/crypto/credentials.ts
|
|
418
|
+
function signedNow(email, key) {
|
|
419
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
420
|
+
return { signature: signMessage(`${email}|${timestamp}`, key), timestamp };
|
|
421
|
+
}
|
|
377
422
|
async function generateRegistrationCredentials(registrationData, password, deploymentDomain) {
|
|
378
|
-
const { signingKeyPair } = await generateUserKeypairs(
|
|
423
|
+
const { signingKeyPair: passwordKey } = await generateUserKeypairs(
|
|
379
424
|
registrationData.email,
|
|
380
425
|
password,
|
|
381
426
|
deploymentDomain
|
|
382
427
|
);
|
|
428
|
+
const identity = generateIdentityKeypair();
|
|
383
429
|
const request = {
|
|
384
430
|
...registrationData,
|
|
385
|
-
signing_key: base64Encode(
|
|
431
|
+
signing_key: base64Encode(identity.publicKey),
|
|
432
|
+
login_key: base64Encode(passwordKey.publicKey),
|
|
433
|
+
wrapped_identity_key: wrapIdentityKey(identity.secretKey, passwordKey.secretKey)
|
|
386
434
|
};
|
|
387
|
-
return { request, signingPrivateKey:
|
|
435
|
+
return { request, signingPrivateKey: identity.secretKey };
|
|
388
436
|
}
|
|
389
437
|
async function generateLoginCredentials(loginData, password, deploymentDomain) {
|
|
390
438
|
const { signingKeyPair } = await generateUserKeypairs(loginData.email, password, deploymentDomain);
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const request = {
|
|
395
|
-
...loginData,
|
|
396
|
-
signature,
|
|
397
|
-
timestamp
|
|
439
|
+
return {
|
|
440
|
+
request: { ...loginData, ...signedNow(loginData.email, signingKeyPair.secretKey) },
|
|
441
|
+
passwordPrivateKey: signingKeyPair.secretKey
|
|
398
442
|
};
|
|
399
|
-
return { request, signingPrivateKey: signingKeyPair.secretKey };
|
|
400
443
|
}
|
|
401
444
|
function generateLoginCredentialsFromKey(loginData, signingPrivateKey) {
|
|
402
445
|
if (signingPrivateKey.length !== 64) {
|
|
403
446
|
throw new Error("Invalid signing key: must be exactly 64 bytes");
|
|
404
447
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
const request = {
|
|
409
|
-
...loginData,
|
|
410
|
-
signature,
|
|
411
|
-
timestamp
|
|
412
|
-
};
|
|
413
|
-
return { request, signingPrivateKey };
|
|
414
|
-
}
|
|
415
|
-
async function generatePasswordChangeCredentials(email, currentPassword, newPassword, deploymentDomain) {
|
|
416
|
-
const currentKeypairs = await generateUserKeypairs(email, currentPassword, deploymentDomain);
|
|
417
|
-
const newKeypairs = await generateUserKeypairs(email, newPassword, deploymentDomain);
|
|
418
|
-
const timestamp = Math.floor(Date.now() / 1e3);
|
|
419
|
-
const message = `${email}|${timestamp}`;
|
|
420
|
-
const signature = signMessage(message, currentKeypairs.signingKeyPair.secretKey);
|
|
421
|
-
const request = {
|
|
422
|
-
signature,
|
|
423
|
-
timestamp,
|
|
424
|
-
new_signing_key: base64Encode(newKeypairs.signingKeyPair.publicKey)
|
|
448
|
+
return {
|
|
449
|
+
request: { ...loginData, ...signedNow(loginData.email, signingPrivateKey) },
|
|
450
|
+
signingPrivateKey
|
|
425
451
|
};
|
|
426
|
-
return { request, newSigningPrivateKey: newKeypairs.signingKeyPair.secretKey };
|
|
427
452
|
}
|
|
428
|
-
async function
|
|
429
|
-
const
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
453
|
+
async function generatePasswordChangeCredentials(params, deploymentDomain) {
|
|
454
|
+
const signer = params.currentPassword ? (await generateUserKeypairs(params.email, params.currentPassword, deploymentDomain)).signingKeyPair.secretKey : params.identitySecretKey;
|
|
455
|
+
const { signingKeyPair: newPasswordKey } = await generateUserKeypairs(
|
|
456
|
+
params.email,
|
|
457
|
+
params.newPassword,
|
|
458
|
+
deploymentDomain
|
|
459
|
+
);
|
|
460
|
+
return {
|
|
461
|
+
request: {
|
|
462
|
+
...signedNow(params.email, signer),
|
|
463
|
+
new_login_key: base64Encode(newPasswordKey.publicKey),
|
|
464
|
+
wrapped_identity_key: wrapIdentityKey(params.identitySecretKey, newPasswordKey.secretKey)
|
|
465
|
+
}
|
|
437
466
|
};
|
|
438
|
-
return { request, newSigningPrivateKey: newKeypairs.signingKeyPair.secretKey };
|
|
439
467
|
}
|
|
440
468
|
|
|
441
469
|
// src/middleware/bearer-auth.ts
|
|
@@ -601,7 +629,8 @@ function createReloginHandler(deps) {
|
|
|
601
629
|
await deps.sessionStorage.saveSession({
|
|
602
630
|
signingPrivateKey: session.signingPrivateKey,
|
|
603
631
|
serverSessionKey: loginResult.sessionKey,
|
|
604
|
-
userExtId: loginResult.userExtId
|
|
632
|
+
userExtId: loginResult.userExtId,
|
|
633
|
+
wrappedIdentityKey: loginResult.wrappedIdentityKey ?? null
|
|
605
634
|
});
|
|
606
635
|
await deps.onReloginSuccess?.({
|
|
607
636
|
email: userEmail,
|
|
@@ -852,6 +881,7 @@ async function saveSession(sessionData) {
|
|
|
852
881
|
encryptedServerSessionKey: encryptedServerSessionKey?.ciphertext,
|
|
853
882
|
serverSessionKeyIV: encryptedServerSessionKey?.iv,
|
|
854
883
|
userExtId: sessionData.userExtId,
|
|
884
|
+
wrappedIdentityKey: sessionData.wrappedIdentityKey ?? null,
|
|
855
885
|
timestamp: Date.now()
|
|
856
886
|
};
|
|
857
887
|
const request = store.put(data);
|
|
@@ -902,7 +932,8 @@ async function getSession() {
|
|
|
902
932
|
resolve({
|
|
903
933
|
signingPrivateKey,
|
|
904
934
|
serverSessionKey,
|
|
905
|
-
userExtId: result.userExtId
|
|
935
|
+
userExtId: result.userExtId,
|
|
936
|
+
wrappedIdentityKey: result.wrappedIdentityKey ?? null
|
|
906
937
|
});
|
|
907
938
|
} catch (error) {
|
|
908
939
|
console.error("[STORAGE] Failed to decrypt session data:", error);
|
|
@@ -918,22 +949,12 @@ async function getSession() {
|
|
|
918
949
|
};
|
|
919
950
|
});
|
|
920
951
|
}
|
|
921
|
-
async function
|
|
922
|
-
await
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
if (!existingSession) {
|
|
926
|
-
throw new Error("No existing session to update");
|
|
927
|
-
}
|
|
928
|
-
await saveSession({
|
|
929
|
-
signingPrivateKey: newSigningPrivateKey,
|
|
930
|
-
serverSessionKey: existingSession.serverSessionKey,
|
|
931
|
-
userExtId: existingSession.userExtId
|
|
932
|
-
});
|
|
933
|
-
} catch (error) {
|
|
934
|
-
console.error("[STORAGE] Failed to update signing private key:", error);
|
|
935
|
-
throw error;
|
|
952
|
+
async function updateWrappedIdentityKey(wrappedIdentityKey) {
|
|
953
|
+
const existingSession = await getSession();
|
|
954
|
+
if (!existingSession) {
|
|
955
|
+
throw new Error("No existing session to update");
|
|
936
956
|
}
|
|
957
|
+
await saveSession({ ...existingSession, wrappedIdentityKey });
|
|
937
958
|
}
|
|
938
959
|
async function clearSession() {
|
|
939
960
|
memorySession = null;
|
|
@@ -1032,6 +1053,34 @@ async function register(params, deps) {
|
|
|
1032
1053
|
return { signingPrivateKey: credentials.signingPrivateKey };
|
|
1033
1054
|
}
|
|
1034
1055
|
|
|
1056
|
+
// src/auth/identity.ts
|
|
1057
|
+
function bytesEqual(a, b) {
|
|
1058
|
+
return a.length === b.length && a.every((byte, i) => byte === b[i]);
|
|
1059
|
+
}
|
|
1060
|
+
function encryptionPublicKeyOf(identitySecretKey) {
|
|
1061
|
+
return base64Encode(
|
|
1062
|
+
deriveEncryptionKeypairFromSigning({
|
|
1063
|
+
publicKey: identitySecretKey.slice(32, 64),
|
|
1064
|
+
secretKey: identitySecretKey
|
|
1065
|
+
}).publicKey
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
function identityFromLoginResponse(passwordPrivateKey, response) {
|
|
1069
|
+
const identity = unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey);
|
|
1070
|
+
if (encryptionPublicKeyOf(identity) !== response.user.encryption_public_key) {
|
|
1071
|
+
throw new Error("The account key does not match this account");
|
|
1072
|
+
}
|
|
1073
|
+
return identity;
|
|
1074
|
+
}
|
|
1075
|
+
async function unlockIdentityWithPassword(email, password, deploymentDomain) {
|
|
1076
|
+
const session = await getSession();
|
|
1077
|
+
if (!session?.signingPrivateKey) throw new Error("No active session found");
|
|
1078
|
+
const { signingKeyPair } = await generateUserKeypairs(email, password, deploymentDomain);
|
|
1079
|
+
const identity = unwrapIdentityKey(session.wrappedIdentityKey, signingKeyPair.secretKey);
|
|
1080
|
+
if (!bytesEqual(identity, session.signingPrivateKey)) throw new Error("Incorrect password");
|
|
1081
|
+
return session.signingPrivateKey;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1035
1084
|
// src/auth/login.ts
|
|
1036
1085
|
async function login(params, deps) {
|
|
1037
1086
|
const credentials = await generateLoginCredentials(
|
|
@@ -1042,7 +1091,7 @@ async function login(params, deps) {
|
|
|
1042
1091
|
params.password,
|
|
1043
1092
|
deps.deploymentDomain
|
|
1044
1093
|
);
|
|
1045
|
-
return performLogin(credentials.request, credentials.
|
|
1094
|
+
return performLogin(credentials.request, { password: credentials.passwordPrivateKey }, deps);
|
|
1046
1095
|
}
|
|
1047
1096
|
async function loginWithKey(params, deps) {
|
|
1048
1097
|
const credentials = generateLoginCredentialsFromKey(
|
|
@@ -1052,9 +1101,9 @@ async function loginWithKey(params, deps) {
|
|
|
1052
1101
|
},
|
|
1053
1102
|
params.signingPrivateKey
|
|
1054
1103
|
);
|
|
1055
|
-
return performLogin(credentials.request, credentials.signingPrivateKey, deps);
|
|
1104
|
+
return performLogin(credentials.request, { identity: credentials.signingPrivateKey }, deps);
|
|
1056
1105
|
}
|
|
1057
|
-
async function performLogin(request,
|
|
1106
|
+
async function performLogin(request, signer, deps) {
|
|
1058
1107
|
const response = await deps.fetchClient.POST("/v1/user/login", {
|
|
1059
1108
|
body: request
|
|
1060
1109
|
});
|
|
@@ -1065,10 +1114,12 @@ async function performLogin(request, signingPrivateKey, deps) {
|
|
|
1065
1114
|
}
|
|
1066
1115
|
const data = response.data;
|
|
1067
1116
|
const serverSessionKey = base64ToBytes(data.session_key);
|
|
1117
|
+
const signingPrivateKey = "password" in signer ? identityFromLoginResponse(signer.password, data) : signer.identity;
|
|
1068
1118
|
await saveSession({
|
|
1069
1119
|
signingPrivateKey,
|
|
1070
1120
|
serverSessionKey,
|
|
1071
|
-
userExtId: data.user.external_id ?? void 0
|
|
1121
|
+
userExtId: data.user.external_id ?? void 0,
|
|
1122
|
+
wrappedIdentityKey: data.wrapped_identity_key ?? null
|
|
1072
1123
|
});
|
|
1073
1124
|
deps.session.setAccessToken(data.access_token);
|
|
1074
1125
|
deps.session.setUser(request.email, data.user.external_id ?? void 0);
|
|
@@ -1096,39 +1147,6 @@ async function logout(session) {
|
|
|
1096
1147
|
}
|
|
1097
1148
|
|
|
1098
1149
|
// src/auth/change-password.ts
|
|
1099
|
-
async function changePassword(params, deps) {
|
|
1100
|
-
const credentials = await generatePasswordChangeCredentials(
|
|
1101
|
-
params.email,
|
|
1102
|
-
params.currentPassword,
|
|
1103
|
-
params.newPassword,
|
|
1104
|
-
deps.deploymentDomain
|
|
1105
|
-
);
|
|
1106
|
-
const stored = await getSession();
|
|
1107
|
-
if (!stored) throw new Error("Sign in to change your password");
|
|
1108
|
-
const current = deriveEncryptionKeypairFromSigning({
|
|
1109
|
-
publicKey: stored.signingPrivateKey.slice(32, 64),
|
|
1110
|
-
secretKey: stored.signingPrivateKey
|
|
1111
|
-
});
|
|
1112
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1113
|
-
publicKey: credentials.newSigningPrivateKey.slice(32, 64),
|
|
1114
|
-
secretKey: credentials.newSigningPrivateKey
|
|
1115
|
-
});
|
|
1116
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1117
|
-
const response = await deps.fetchClient.POST("/v1/user/change_password", {
|
|
1118
|
-
body: {
|
|
1119
|
-
...credentials.request,
|
|
1120
|
-
...mailKeys,
|
|
1121
|
-
rewrapped_workspace_keys: params.rewrappedWorkspaceKeys ?? {}
|
|
1122
|
-
}
|
|
1123
|
-
});
|
|
1124
|
-
if (response.error) {
|
|
1125
|
-
throw new Error(
|
|
1126
|
-
`Password change failed: ${typeof response.error === "object" && response.error !== null && "detail" in response.error ? response.error.detail : "Unknown error"}`
|
|
1127
|
-
);
|
|
1128
|
-
}
|
|
1129
|
-
await updateSigningPrivateKey(credentials.newSigningPrivateKey);
|
|
1130
|
-
return { newSigningPrivateKey: credentials.newSigningPrivateKey };
|
|
1131
|
-
}
|
|
1132
1150
|
function passwordChangeErrorMessage(err) {
|
|
1133
1151
|
if (err instanceof Error) return err.message;
|
|
1134
1152
|
if (err && typeof err === "object") {
|
|
@@ -1144,140 +1162,24 @@ function passwordChangeErrorMessage(err) {
|
|
|
1144
1162
|
}
|
|
1145
1163
|
return "Failed to change password";
|
|
1146
1164
|
}
|
|
1147
|
-
async function
|
|
1148
|
-
const
|
|
1149
|
-
const
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
const id = other.external_id;
|
|
1159
|
-
oldSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, oldSecretKey);
|
|
1160
|
-
newSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, newSecretKey);
|
|
1161
|
-
const reEncrypt = async (ciphertext) => encryptMessageWithSharedSecret(
|
|
1162
|
-
await decryptMessageWithSharedSecret(ciphertext, oldSecrets[id]),
|
|
1163
|
-
newSecrets[id]
|
|
1164
|
-
);
|
|
1165
|
-
const content = n.content ? await reEncrypt(n.content) : void 0;
|
|
1166
|
-
const attachments = n.attachments ? await reEncrypt(n.attachments) : void 0;
|
|
1167
|
-
updates.push({
|
|
1168
|
-
external_id: n.external_id,
|
|
1169
|
-
...content !== void 0 ? { content } : {},
|
|
1170
|
-
...attachments !== void 0 ? { attachments } : {}
|
|
1171
|
-
});
|
|
1172
|
-
} catch {
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
if (updates.length === 0) return 0;
|
|
1176
|
-
const patched = await fetchClient.PATCH("/v1/notifications/", { body: { updates } });
|
|
1177
|
-
if (!patched.data) throw new Error("Failed to save re-encrypted messages");
|
|
1178
|
-
return updates.length;
|
|
1179
|
-
}
|
|
1180
|
-
async function rewrapMailKeys(fetchClient, oldPrivateKey, newPublicKey) {
|
|
1181
|
-
const rewrappedMailKeys = {};
|
|
1182
|
-
let mailCursor = 0;
|
|
1183
|
-
while (mailCursor !== null) {
|
|
1184
|
-
const result = await fetchClient.GET(
|
|
1185
|
-
"/v1/mail/native/keys",
|
|
1186
|
-
{
|
|
1187
|
-
params: { query: { cursor: mailCursor } }
|
|
1188
|
-
}
|
|
1189
|
-
);
|
|
1190
|
-
if (!result.data) throw new Error("Could not load mailbox keys for password change");
|
|
1191
|
-
for (const [id, wrapped] of Object.entries(result.data.keys)) {
|
|
1192
|
-
const key = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1193
|
-
try {
|
|
1194
|
-
rewrappedMailKeys[id] = sealedBoxEncrypt(key, newPublicKey);
|
|
1195
|
-
} finally {
|
|
1196
|
-
key.fill(0);
|
|
1197
|
-
}
|
|
1198
|
-
}
|
|
1199
|
-
mailCursor = result.data.next_cursor ?? null;
|
|
1200
|
-
}
|
|
1201
|
-
const connected = await fetchClient.GET("/v1/mail/native/rotation-credentials");
|
|
1202
|
-
if (!connected.data) throw new Error("Could not load mail connections for password change");
|
|
1203
|
-
const rewrappedMailCredentials = {};
|
|
1204
|
-
for (const [id, wrapped] of Object.entries(connected.data)) {
|
|
1205
|
-
const plain = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1206
|
-
try {
|
|
1207
|
-
rewrappedMailCredentials[id] = sealedBoxEncrypt(plain, newPublicKey);
|
|
1208
|
-
} finally {
|
|
1209
|
-
plain.fill(0);
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
return {
|
|
1213
|
-
rewrapped_mail_keys: rewrappedMailKeys,
|
|
1214
|
-
rewrapped_mail_credentials: rewrappedMailCredentials
|
|
1215
|
-
};
|
|
1216
|
-
}
|
|
1217
|
-
async function changePasswordWithRekey(params, deps) {
|
|
1218
|
-
const session = await getSession();
|
|
1219
|
-
if (!session) throw new Error("No active session found");
|
|
1220
|
-
const { request, newSigningPrivateKey } = params.currentPassword ? await generatePasswordChangeCredentials(
|
|
1221
|
-
params.email,
|
|
1222
|
-
params.currentPassword,
|
|
1223
|
-
params.newPassword,
|
|
1224
|
-
deps.deploymentDomain
|
|
1225
|
-
) : await generateRecoveryPasswordChangeCredentials(
|
|
1226
|
-
params.email,
|
|
1227
|
-
session.signingPrivateKey,
|
|
1228
|
-
params.newPassword,
|
|
1165
|
+
async function changePassword(params, deps) {
|
|
1166
|
+
const fromStore = !params.identitySecretKey;
|
|
1167
|
+
const identitySecretKey = params.identitySecretKey ?? (await getSession())?.signingPrivateKey;
|
|
1168
|
+
if (!identitySecretKey) throw new Error("Sign in to change your password");
|
|
1169
|
+
const { request } = await generatePasswordChangeCredentials(
|
|
1170
|
+
{
|
|
1171
|
+
email: params.email,
|
|
1172
|
+
identitySecretKey,
|
|
1173
|
+
newPassword: params.newPassword,
|
|
1174
|
+
currentPassword: params.currentPassword
|
|
1175
|
+
},
|
|
1229
1176
|
deps.deploymentDomain
|
|
1230
1177
|
);
|
|
1231
|
-
const
|
|
1232
|
-
publicKey: session.signingPrivateKey.slice(32, 64),
|
|
1233
|
-
secretKey: session.signingPrivateKey
|
|
1234
|
-
});
|
|
1235
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1236
|
-
publicKey: newSigningPrivateKey.slice(32, 64),
|
|
1237
|
-
secretKey: newSigningPrivateKey
|
|
1238
|
-
});
|
|
1239
|
-
const listed = await deps.fetchClient.GET("/v1/user/workspaces");
|
|
1240
|
-
if (!listed.data) throw new Error("Could not list your workspaces");
|
|
1241
|
-
const rewrapped = {};
|
|
1242
|
-
for (const ws of listed.data.filter((w) => w.is_member)) {
|
|
1243
|
-
if (!ws.wrapped_key) continue;
|
|
1244
|
-
try {
|
|
1245
|
-
rewrapped[ws.external_id] = sealedBoxEncrypt(
|
|
1246
|
-
sealedBoxDecrypt(ws.wrapped_key, current.secretKey),
|
|
1247
|
-
next.publicKey
|
|
1248
|
-
);
|
|
1249
|
-
} catch {
|
|
1250
|
-
throw new Error(`Failed to re-wrap workspace key for ${ws.name || ws.external_id}`);
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
let messagesReEncrypted = 0;
|
|
1254
|
-
if (params.userExtId) {
|
|
1255
|
-
try {
|
|
1256
|
-
messagesReEncrypted = await reEncryptDirectMessages(
|
|
1257
|
-
deps.fetchClient,
|
|
1258
|
-
params.userExtId,
|
|
1259
|
-
current.secretKey,
|
|
1260
|
-
next.secretKey
|
|
1261
|
-
);
|
|
1262
|
-
} catch {
|
|
1263
|
-
}
|
|
1264
|
-
}
|
|
1265
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1266
|
-
const response = await deps.fetchClient.POST("/v1/user/change_password", {
|
|
1267
|
-
body: {
|
|
1268
|
-
...request,
|
|
1269
|
-
rewrapped_workspace_keys: rewrapped,
|
|
1270
|
-
...mailKeys
|
|
1271
|
-
}
|
|
1272
|
-
});
|
|
1178
|
+
const response = await deps.fetchClient.POST("/v1/user/change_password", { body: request });
|
|
1273
1179
|
if (response.error || !response.data)
|
|
1274
1180
|
throw response.error ?? new Error("Failed to change password");
|
|
1275
|
-
await
|
|
1276
|
-
return {
|
|
1277
|
-
newSigningPrivateKey,
|
|
1278
|
-
workspacesUpdated: response.data.workspaces_updated ?? 0,
|
|
1279
|
-
messagesReEncrypted
|
|
1280
|
-
};
|
|
1181
|
+
if (fromStore) await updateWrappedIdentityKey(request.wrapped_identity_key);
|
|
1182
|
+
return { wrappedIdentityKey: request.wrapped_identity_key };
|
|
1281
1183
|
}
|
|
1282
1184
|
|
|
1283
1185
|
// src/client.ts
|
|
@@ -1376,7 +1278,8 @@ function createArbiClient(options) {
|
|
|
1376
1278
|
return {
|
|
1377
1279
|
accessToken: data.access_token,
|
|
1378
1280
|
sessionKey: base64ToBytes(data.session_key),
|
|
1379
|
-
userExtId: data.user.external_id ?? void 0
|
|
1281
|
+
userExtId: data.user.external_id ?? void 0,
|
|
1282
|
+
wrappedIdentityKey: data.wrapped_identity_key ?? null
|
|
1380
1283
|
};
|
|
1381
1284
|
}
|
|
1382
1285
|
};
|
|
@@ -1532,7 +1435,7 @@ exports.buildCallFragment = buildCallFragment;
|
|
|
1532
1435
|
exports.buildWebSocketUrl = buildWebSocketUrl;
|
|
1533
1436
|
exports.bytesToBase64 = bytesToBase64;
|
|
1534
1437
|
exports.canPersistSession = canPersistSession;
|
|
1535
|
-
exports.
|
|
1438
|
+
exports.changePassword = changePassword;
|
|
1536
1439
|
exports.clearAllData = clearAllData;
|
|
1537
1440
|
exports.clearSession = clearSession;
|
|
1538
1441
|
exports.computeSharedSecret = computeSharedSecret;
|
|
@@ -1557,17 +1460,18 @@ exports.encryptFile = encryptFile;
|
|
|
1557
1460
|
exports.encryptMessage = encryptMessage;
|
|
1558
1461
|
exports.encryptMessageWithSharedSecret = encryptMessageWithSharedSecret;
|
|
1559
1462
|
exports.generateCallKey = generateCallKey;
|
|
1463
|
+
exports.generateIdentityKeypair = generateIdentityKeypair;
|
|
1560
1464
|
exports.generateKeyPairs = generateKeyPairs;
|
|
1561
1465
|
exports.generateLoginCredentials = generateLoginCredentials;
|
|
1562
1466
|
exports.generateLoginCredentialsFromKey = generateLoginCredentialsFromKey;
|
|
1563
1467
|
exports.generatePasswordChangeCredentials = generatePasswordChangeCredentials;
|
|
1564
1468
|
exports.generateRandomSigningKeypair = generateRandomSigningKeypair;
|
|
1565
|
-
exports.generateRecoveryPasswordChangeCredentials = generateRecoveryPasswordChangeCredentials;
|
|
1566
1469
|
exports.generateRegistrationCredentials = generateRegistrationCredentials;
|
|
1567
1470
|
exports.generateUserKeypairs = generateUserKeypairs;
|
|
1568
1471
|
exports.getSession = getSession;
|
|
1569
1472
|
exports.getUserEncryptionKeypair = getUserEncryptionKeypair;
|
|
1570
1473
|
exports.hasSession = hasSession;
|
|
1474
|
+
exports.identityFromLoginResponse = identityFromLoginResponse;
|
|
1571
1475
|
exports.initSodium = initSodium;
|
|
1572
1476
|
exports.initializeDatabase = initializeDatabase;
|
|
1573
1477
|
exports.isMessageType = isMessageType;
|
|
@@ -1582,6 +1486,9 @@ exports.sealKeyForSession = sealKeyForSession;
|
|
|
1582
1486
|
exports.sealedBoxDecrypt = sealedBoxDecrypt;
|
|
1583
1487
|
exports.sealedBoxEncrypt = sealedBoxEncrypt;
|
|
1584
1488
|
exports.signMessage = signMessage;
|
|
1585
|
-
exports.
|
|
1489
|
+
exports.unlockIdentityWithPassword = unlockIdentityWithPassword;
|
|
1490
|
+
exports.unwrapIdentityKey = unwrapIdentityKey;
|
|
1491
|
+
exports.updateWrappedIdentityKey = updateWrappedIdentityKey;
|
|
1492
|
+
exports.wrapIdentityKey = wrapIdentityKey;
|
|
1586
1493
|
//# sourceMappingURL=index.cjs.map
|
|
1587
1494
|
//# sourceMappingURL=index.cjs.map
|