@arbidocs/client 0.4.85 → 0.4.87
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 -231
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -82
- package/dist/index.d.ts +111 -82
- package/dist/index.js +131 -229
- 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,40 +1147,6 @@ async function logout(session) {
|
|
|
1096
1147
|
}
|
|
1097
1148
|
|
|
1098
1149
|
// src/auth/change-password.ts
|
|
1099
|
-
var passwordCalls = (client) => client;
|
|
1100
|
-
async function changePassword(params, deps) {
|
|
1101
|
-
const credentials = await generatePasswordChangeCredentials(
|
|
1102
|
-
params.email,
|
|
1103
|
-
params.currentPassword,
|
|
1104
|
-
params.newPassword,
|
|
1105
|
-
deps.deploymentDomain
|
|
1106
|
-
);
|
|
1107
|
-
const stored = await getSession();
|
|
1108
|
-
if (!stored) throw new Error("Sign in to change your password");
|
|
1109
|
-
const current = deriveEncryptionKeypairFromSigning({
|
|
1110
|
-
publicKey: stored.signingPrivateKey.slice(32, 64),
|
|
1111
|
-
secretKey: stored.signingPrivateKey
|
|
1112
|
-
});
|
|
1113
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1114
|
-
publicKey: credentials.newSigningPrivateKey.slice(32, 64),
|
|
1115
|
-
secretKey: credentials.newSigningPrivateKey
|
|
1116
|
-
});
|
|
1117
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1118
|
-
const response = await passwordCalls(deps.fetchClient).POST("/v1/user/change_password", {
|
|
1119
|
-
body: {
|
|
1120
|
-
...credentials.request,
|
|
1121
|
-
...mailKeys,
|
|
1122
|
-
rewrapped_workspace_keys: params.rewrappedWorkspaceKeys ?? {}
|
|
1123
|
-
}
|
|
1124
|
-
});
|
|
1125
|
-
if (response.error) {
|
|
1126
|
-
throw new Error(
|
|
1127
|
-
`Password change failed: ${typeof response.error === "object" && response.error !== null && "detail" in response.error ? response.error.detail : "Unknown error"}`
|
|
1128
|
-
);
|
|
1129
|
-
}
|
|
1130
|
-
await updateSigningPrivateKey(credentials.newSigningPrivateKey);
|
|
1131
|
-
return { newSigningPrivateKey: credentials.newSigningPrivateKey };
|
|
1132
|
-
}
|
|
1133
1150
|
function passwordChangeErrorMessage(err) {
|
|
1134
1151
|
if (err instanceof Error) return err.message;
|
|
1135
1152
|
if (err && typeof err === "object") {
|
|
@@ -1145,140 +1162,24 @@ function passwordChangeErrorMessage(err) {
|
|
|
1145
1162
|
}
|
|
1146
1163
|
return "Failed to change password";
|
|
1147
1164
|
}
|
|
1148
|
-
async function
|
|
1149
|
-
const
|
|
1150
|
-
const
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
const id = other.external_id;
|
|
1160
|
-
oldSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, oldSecretKey);
|
|
1161
|
-
newSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, newSecretKey);
|
|
1162
|
-
const reEncrypt = async (ciphertext) => encryptMessageWithSharedSecret(
|
|
1163
|
-
await decryptMessageWithSharedSecret(ciphertext, oldSecrets[id]),
|
|
1164
|
-
newSecrets[id]
|
|
1165
|
-
);
|
|
1166
|
-
const content = n.content ? await reEncrypt(n.content) : void 0;
|
|
1167
|
-
const attachments = n.attachments ? await reEncrypt(n.attachments) : void 0;
|
|
1168
|
-
updates.push({
|
|
1169
|
-
external_id: n.external_id,
|
|
1170
|
-
...content !== void 0 ? { content } : {},
|
|
1171
|
-
...attachments !== void 0 ? { attachments } : {}
|
|
1172
|
-
});
|
|
1173
|
-
} catch {
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
if (updates.length === 0) return 0;
|
|
1177
|
-
const patched = await fetchClient.PATCH("/v1/notifications/", { body: { updates } });
|
|
1178
|
-
if (!patched.data) throw new Error("Failed to save re-encrypted messages");
|
|
1179
|
-
return updates.length;
|
|
1180
|
-
}
|
|
1181
|
-
async function rewrapMailKeys(fetchClient, oldPrivateKey, newPublicKey) {
|
|
1182
|
-
const rewrappedMailKeys = {};
|
|
1183
|
-
let mailCursor = 0;
|
|
1184
|
-
while (mailCursor !== null) {
|
|
1185
|
-
const result = await fetchClient.GET(
|
|
1186
|
-
"/v1/mail/native/keys",
|
|
1187
|
-
{
|
|
1188
|
-
params: { query: { cursor: mailCursor } }
|
|
1189
|
-
}
|
|
1190
|
-
);
|
|
1191
|
-
if (!result.data) throw new Error("Could not load mailbox keys for password change");
|
|
1192
|
-
for (const [id, wrapped] of Object.entries(result.data.keys)) {
|
|
1193
|
-
const key = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1194
|
-
try {
|
|
1195
|
-
rewrappedMailKeys[id] = sealedBoxEncrypt(key, newPublicKey);
|
|
1196
|
-
} finally {
|
|
1197
|
-
key.fill(0);
|
|
1198
|
-
}
|
|
1199
|
-
}
|
|
1200
|
-
mailCursor = result.data.next_cursor ?? null;
|
|
1201
|
-
}
|
|
1202
|
-
const connected = await passwordCalls(fetchClient).GET("/v1/mail/native/rotation-credentials");
|
|
1203
|
-
if (!connected.data) throw new Error("Could not load mail connections for password change");
|
|
1204
|
-
const rewrappedMailCredentials = {};
|
|
1205
|
-
for (const [id, wrapped] of Object.entries(connected.data)) {
|
|
1206
|
-
const plain = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1207
|
-
try {
|
|
1208
|
-
rewrappedMailCredentials[id] = sealedBoxEncrypt(plain, newPublicKey);
|
|
1209
|
-
} finally {
|
|
1210
|
-
plain.fill(0);
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
return {
|
|
1214
|
-
rewrapped_mail_keys: rewrappedMailKeys,
|
|
1215
|
-
rewrapped_mail_credentials: rewrappedMailCredentials
|
|
1216
|
-
};
|
|
1217
|
-
}
|
|
1218
|
-
async function changePasswordWithRekey(params, deps) {
|
|
1219
|
-
const session = await getSession();
|
|
1220
|
-
if (!session) throw new Error("No active session found");
|
|
1221
|
-
const { request, newSigningPrivateKey } = params.currentPassword ? await generatePasswordChangeCredentials(
|
|
1222
|
-
params.email,
|
|
1223
|
-
params.currentPassword,
|
|
1224
|
-
params.newPassword,
|
|
1225
|
-
deps.deploymentDomain
|
|
1226
|
-
) : await generateRecoveryPasswordChangeCredentials(
|
|
1227
|
-
params.email,
|
|
1228
|
-
session.signingPrivateKey,
|
|
1229
|
-
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
|
+
},
|
|
1230
1176
|
deps.deploymentDomain
|
|
1231
1177
|
);
|
|
1232
|
-
const
|
|
1233
|
-
publicKey: session.signingPrivateKey.slice(32, 64),
|
|
1234
|
-
secretKey: session.signingPrivateKey
|
|
1235
|
-
});
|
|
1236
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1237
|
-
publicKey: newSigningPrivateKey.slice(32, 64),
|
|
1238
|
-
secretKey: newSigningPrivateKey
|
|
1239
|
-
});
|
|
1240
|
-
const listed = await deps.fetchClient.GET("/v1/user/workspaces");
|
|
1241
|
-
if (!listed.data) throw new Error("Could not list your workspaces");
|
|
1242
|
-
const rewrapped = {};
|
|
1243
|
-
for (const ws of listed.data.filter((w) => w.is_member)) {
|
|
1244
|
-
if (!ws.wrapped_key) continue;
|
|
1245
|
-
try {
|
|
1246
|
-
rewrapped[ws.external_id] = sealedBoxEncrypt(
|
|
1247
|
-
sealedBoxDecrypt(ws.wrapped_key, current.secretKey),
|
|
1248
|
-
next.publicKey
|
|
1249
|
-
);
|
|
1250
|
-
} catch {
|
|
1251
|
-
throw new Error(`Failed to re-wrap workspace key for ${ws.name || ws.external_id}`);
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
let messagesReEncrypted = 0;
|
|
1255
|
-
if (params.userExtId) {
|
|
1256
|
-
try {
|
|
1257
|
-
messagesReEncrypted = await reEncryptDirectMessages(
|
|
1258
|
-
deps.fetchClient,
|
|
1259
|
-
params.userExtId,
|
|
1260
|
-
current.secretKey,
|
|
1261
|
-
next.secretKey
|
|
1262
|
-
);
|
|
1263
|
-
} catch {
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1267
|
-
const response = await passwordCalls(deps.fetchClient).POST("/v1/user/change_password", {
|
|
1268
|
-
body: {
|
|
1269
|
-
...request,
|
|
1270
|
-
rewrapped_workspace_keys: rewrapped,
|
|
1271
|
-
...mailKeys
|
|
1272
|
-
}
|
|
1273
|
-
});
|
|
1178
|
+
const response = await deps.fetchClient.POST("/v1/user/change_password", { body: request });
|
|
1274
1179
|
if (response.error || !response.data)
|
|
1275
1180
|
throw response.error ?? new Error("Failed to change password");
|
|
1276
|
-
await
|
|
1277
|
-
return {
|
|
1278
|
-
newSigningPrivateKey,
|
|
1279
|
-
workspacesUpdated: response.data.workspaces_updated ?? 0,
|
|
1280
|
-
messagesReEncrypted
|
|
1281
|
-
};
|
|
1181
|
+
if (fromStore) await updateWrappedIdentityKey(request.wrapped_identity_key);
|
|
1182
|
+
return { wrappedIdentityKey: request.wrapped_identity_key };
|
|
1282
1183
|
}
|
|
1283
1184
|
|
|
1284
1185
|
// src/client.ts
|
|
@@ -1377,7 +1278,8 @@ function createArbiClient(options) {
|
|
|
1377
1278
|
return {
|
|
1378
1279
|
accessToken: data.access_token,
|
|
1379
1280
|
sessionKey: base64ToBytes(data.session_key),
|
|
1380
|
-
userExtId: data.user.external_id ?? void 0
|
|
1281
|
+
userExtId: data.user.external_id ?? void 0,
|
|
1282
|
+
wrappedIdentityKey: data.wrapped_identity_key ?? null
|
|
1381
1283
|
};
|
|
1382
1284
|
}
|
|
1383
1285
|
};
|
|
@@ -1533,7 +1435,7 @@ exports.buildCallFragment = buildCallFragment;
|
|
|
1533
1435
|
exports.buildWebSocketUrl = buildWebSocketUrl;
|
|
1534
1436
|
exports.bytesToBase64 = bytesToBase64;
|
|
1535
1437
|
exports.canPersistSession = canPersistSession;
|
|
1536
|
-
exports.
|
|
1438
|
+
exports.changePassword = changePassword;
|
|
1537
1439
|
exports.clearAllData = clearAllData;
|
|
1538
1440
|
exports.clearSession = clearSession;
|
|
1539
1441
|
exports.computeSharedSecret = computeSharedSecret;
|
|
@@ -1558,17 +1460,18 @@ exports.encryptFile = encryptFile;
|
|
|
1558
1460
|
exports.encryptMessage = encryptMessage;
|
|
1559
1461
|
exports.encryptMessageWithSharedSecret = encryptMessageWithSharedSecret;
|
|
1560
1462
|
exports.generateCallKey = generateCallKey;
|
|
1463
|
+
exports.generateIdentityKeypair = generateIdentityKeypair;
|
|
1561
1464
|
exports.generateKeyPairs = generateKeyPairs;
|
|
1562
1465
|
exports.generateLoginCredentials = generateLoginCredentials;
|
|
1563
1466
|
exports.generateLoginCredentialsFromKey = generateLoginCredentialsFromKey;
|
|
1564
1467
|
exports.generatePasswordChangeCredentials = generatePasswordChangeCredentials;
|
|
1565
1468
|
exports.generateRandomSigningKeypair = generateRandomSigningKeypair;
|
|
1566
|
-
exports.generateRecoveryPasswordChangeCredentials = generateRecoveryPasswordChangeCredentials;
|
|
1567
1469
|
exports.generateRegistrationCredentials = generateRegistrationCredentials;
|
|
1568
1470
|
exports.generateUserKeypairs = generateUserKeypairs;
|
|
1569
1471
|
exports.getSession = getSession;
|
|
1570
1472
|
exports.getUserEncryptionKeypair = getUserEncryptionKeypair;
|
|
1571
1473
|
exports.hasSession = hasSession;
|
|
1474
|
+
exports.identityFromLoginResponse = identityFromLoginResponse;
|
|
1572
1475
|
exports.initSodium = initSodium;
|
|
1573
1476
|
exports.initializeDatabase = initializeDatabase;
|
|
1574
1477
|
exports.isMessageType = isMessageType;
|
|
@@ -1583,6 +1486,9 @@ exports.sealKeyForSession = sealKeyForSession;
|
|
|
1583
1486
|
exports.sealedBoxDecrypt = sealedBoxDecrypt;
|
|
1584
1487
|
exports.sealedBoxEncrypt = sealedBoxEncrypt;
|
|
1585
1488
|
exports.signMessage = signMessage;
|
|
1586
|
-
exports.
|
|
1489
|
+
exports.unlockIdentityWithPassword = unlockIdentityWithPassword;
|
|
1490
|
+
exports.unwrapIdentityKey = unwrapIdentityKey;
|
|
1491
|
+
exports.updateWrappedIdentityKey = updateWrappedIdentityKey;
|
|
1492
|
+
exports.wrapIdentityKey = wrapIdentityKey;
|
|
1587
1493
|
//# sourceMappingURL=index.cjs.map
|
|
1588
1494
|
//# sourceMappingURL=index.cjs.map
|