@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.js
CHANGED
|
@@ -365,70 +365,98 @@ async function generateUserKeypairs(username, password, deploymentDomain) {
|
|
|
365
365
|
encryptionKeyPair
|
|
366
366
|
};
|
|
367
367
|
}
|
|
368
|
+
var IDENTITY_WRAP_CONTEXT = "arbi-identity-wrap-v1";
|
|
369
|
+
function identityWrappingKey(passwordSecretKey) {
|
|
370
|
+
return sodium.crypto_generichash(
|
|
371
|
+
32,
|
|
372
|
+
sodium.from_string(IDENTITY_WRAP_CONTEXT),
|
|
373
|
+
passwordSecretKey.slice(0, 32)
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
function generateIdentityKeypair() {
|
|
377
|
+
return generateRandomSigningKeypair();
|
|
378
|
+
}
|
|
379
|
+
function wrapIdentityKey(identitySecretKey, passwordSecretKey) {
|
|
380
|
+
const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES);
|
|
381
|
+
const key = identityWrappingKey(passwordSecretKey);
|
|
382
|
+
try {
|
|
383
|
+
const boxed = sodium.crypto_secretbox_easy(identitySecretKey, nonce, key);
|
|
384
|
+
const out = new Uint8Array(nonce.length + boxed.length);
|
|
385
|
+
out.set(nonce);
|
|
386
|
+
out.set(boxed, nonce.length);
|
|
387
|
+
return base64Encode(out);
|
|
388
|
+
} finally {
|
|
389
|
+
key.fill(0);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
function unwrapIdentityKey(wrapped, passwordSecretKey) {
|
|
393
|
+
if (!wrapped) return passwordSecretKey;
|
|
394
|
+
const bytes = base64Decode(wrapped);
|
|
395
|
+
const nonce = bytes.slice(0, sodium.crypto_secretbox_NONCEBYTES);
|
|
396
|
+
const key = identityWrappingKey(passwordSecretKey);
|
|
397
|
+
try {
|
|
398
|
+
return sodium.crypto_secretbox_open_easy(
|
|
399
|
+
bytes.slice(sodium.crypto_secretbox_NONCEBYTES),
|
|
400
|
+
nonce,
|
|
401
|
+
key
|
|
402
|
+
);
|
|
403
|
+
} catch {
|
|
404
|
+
throw new Error("Incorrect password");
|
|
405
|
+
} finally {
|
|
406
|
+
key.fill(0);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
368
409
|
|
|
369
410
|
// src/crypto/credentials.ts
|
|
411
|
+
function signedNow(email, key) {
|
|
412
|
+
const timestamp = Math.floor(Date.now() / 1e3);
|
|
413
|
+
return { signature: signMessage(`${email}|${timestamp}`, key), timestamp };
|
|
414
|
+
}
|
|
370
415
|
async function generateRegistrationCredentials(registrationData, password, deploymentDomain) {
|
|
371
|
-
const { signingKeyPair } = await generateUserKeypairs(
|
|
416
|
+
const { signingKeyPair: passwordKey } = await generateUserKeypairs(
|
|
372
417
|
registrationData.email,
|
|
373
418
|
password,
|
|
374
419
|
deploymentDomain
|
|
375
420
|
);
|
|
421
|
+
const identity = generateIdentityKeypair();
|
|
376
422
|
const request = {
|
|
377
423
|
...registrationData,
|
|
378
|
-
signing_key: base64Encode(
|
|
424
|
+
signing_key: base64Encode(identity.publicKey),
|
|
425
|
+
login_key: base64Encode(passwordKey.publicKey),
|
|
426
|
+
wrapped_identity_key: wrapIdentityKey(identity.secretKey, passwordKey.secretKey)
|
|
379
427
|
};
|
|
380
|
-
return { request, signingPrivateKey:
|
|
428
|
+
return { request, signingPrivateKey: identity.secretKey };
|
|
381
429
|
}
|
|
382
430
|
async function generateLoginCredentials(loginData, password, deploymentDomain) {
|
|
383
431
|
const { signingKeyPair } = await generateUserKeypairs(loginData.email, password, deploymentDomain);
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const request = {
|
|
388
|
-
...loginData,
|
|
389
|
-
signature,
|
|
390
|
-
timestamp
|
|
432
|
+
return {
|
|
433
|
+
request: { ...loginData, ...signedNow(loginData.email, signingKeyPair.secretKey) },
|
|
434
|
+
passwordPrivateKey: signingKeyPair.secretKey
|
|
391
435
|
};
|
|
392
|
-
return { request, signingPrivateKey: signingKeyPair.secretKey };
|
|
393
436
|
}
|
|
394
437
|
function generateLoginCredentialsFromKey(loginData, signingPrivateKey) {
|
|
395
438
|
if (signingPrivateKey.length !== 64) {
|
|
396
439
|
throw new Error("Invalid signing key: must be exactly 64 bytes");
|
|
397
440
|
}
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
const request = {
|
|
402
|
-
...loginData,
|
|
403
|
-
signature,
|
|
404
|
-
timestamp
|
|
405
|
-
};
|
|
406
|
-
return { request, signingPrivateKey };
|
|
407
|
-
}
|
|
408
|
-
async function generatePasswordChangeCredentials(email, currentPassword, newPassword, deploymentDomain) {
|
|
409
|
-
const currentKeypairs = await generateUserKeypairs(email, currentPassword, deploymentDomain);
|
|
410
|
-
const newKeypairs = await generateUserKeypairs(email, newPassword, deploymentDomain);
|
|
411
|
-
const timestamp = Math.floor(Date.now() / 1e3);
|
|
412
|
-
const message = `${email}|${timestamp}`;
|
|
413
|
-
const signature = signMessage(message, currentKeypairs.signingKeyPair.secretKey);
|
|
414
|
-
const request = {
|
|
415
|
-
signature,
|
|
416
|
-
timestamp,
|
|
417
|
-
new_signing_key: base64Encode(newKeypairs.signingKeyPair.publicKey)
|
|
441
|
+
return {
|
|
442
|
+
request: { ...loginData, ...signedNow(loginData.email, signingPrivateKey) },
|
|
443
|
+
signingPrivateKey
|
|
418
444
|
};
|
|
419
|
-
return { request, newSigningPrivateKey: newKeypairs.signingKeyPair.secretKey };
|
|
420
445
|
}
|
|
421
|
-
async function
|
|
422
|
-
const
|
|
423
|
-
const
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
446
|
+
async function generatePasswordChangeCredentials(params, deploymentDomain) {
|
|
447
|
+
const signer = params.currentPassword ? (await generateUserKeypairs(params.email, params.currentPassword, deploymentDomain)).signingKeyPair.secretKey : params.identitySecretKey;
|
|
448
|
+
const { signingKeyPair: newPasswordKey } = await generateUserKeypairs(
|
|
449
|
+
params.email,
|
|
450
|
+
params.newPassword,
|
|
451
|
+
deploymentDomain
|
|
452
|
+
);
|
|
453
|
+
return {
|
|
454
|
+
request: {
|
|
455
|
+
...signedNow(params.email, signer),
|
|
456
|
+
new_login_key: base64Encode(newPasswordKey.publicKey),
|
|
457
|
+
wrapped_identity_key: wrapIdentityKey(params.identitySecretKey, newPasswordKey.secretKey)
|
|
458
|
+
}
|
|
430
459
|
};
|
|
431
|
-
return { request, newSigningPrivateKey: newKeypairs.signingKeyPair.secretKey };
|
|
432
460
|
}
|
|
433
461
|
|
|
434
462
|
// src/middleware/bearer-auth.ts
|
|
@@ -594,7 +622,8 @@ function createReloginHandler(deps) {
|
|
|
594
622
|
await deps.sessionStorage.saveSession({
|
|
595
623
|
signingPrivateKey: session.signingPrivateKey,
|
|
596
624
|
serverSessionKey: loginResult.sessionKey,
|
|
597
|
-
userExtId: loginResult.userExtId
|
|
625
|
+
userExtId: loginResult.userExtId,
|
|
626
|
+
wrappedIdentityKey: loginResult.wrappedIdentityKey ?? null
|
|
598
627
|
});
|
|
599
628
|
await deps.onReloginSuccess?.({
|
|
600
629
|
email: userEmail,
|
|
@@ -845,6 +874,7 @@ async function saveSession(sessionData) {
|
|
|
845
874
|
encryptedServerSessionKey: encryptedServerSessionKey?.ciphertext,
|
|
846
875
|
serverSessionKeyIV: encryptedServerSessionKey?.iv,
|
|
847
876
|
userExtId: sessionData.userExtId,
|
|
877
|
+
wrappedIdentityKey: sessionData.wrappedIdentityKey ?? null,
|
|
848
878
|
timestamp: Date.now()
|
|
849
879
|
};
|
|
850
880
|
const request = store.put(data);
|
|
@@ -895,7 +925,8 @@ async function getSession() {
|
|
|
895
925
|
resolve({
|
|
896
926
|
signingPrivateKey,
|
|
897
927
|
serverSessionKey,
|
|
898
|
-
userExtId: result.userExtId
|
|
928
|
+
userExtId: result.userExtId,
|
|
929
|
+
wrappedIdentityKey: result.wrappedIdentityKey ?? null
|
|
899
930
|
});
|
|
900
931
|
} catch (error) {
|
|
901
932
|
console.error("[STORAGE] Failed to decrypt session data:", error);
|
|
@@ -911,22 +942,12 @@ async function getSession() {
|
|
|
911
942
|
};
|
|
912
943
|
});
|
|
913
944
|
}
|
|
914
|
-
async function
|
|
915
|
-
await
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
if (!existingSession) {
|
|
919
|
-
throw new Error("No existing session to update");
|
|
920
|
-
}
|
|
921
|
-
await saveSession({
|
|
922
|
-
signingPrivateKey: newSigningPrivateKey,
|
|
923
|
-
serverSessionKey: existingSession.serverSessionKey,
|
|
924
|
-
userExtId: existingSession.userExtId
|
|
925
|
-
});
|
|
926
|
-
} catch (error) {
|
|
927
|
-
console.error("[STORAGE] Failed to update signing private key:", error);
|
|
928
|
-
throw error;
|
|
945
|
+
async function updateWrappedIdentityKey(wrappedIdentityKey) {
|
|
946
|
+
const existingSession = await getSession();
|
|
947
|
+
if (!existingSession) {
|
|
948
|
+
throw new Error("No existing session to update");
|
|
929
949
|
}
|
|
950
|
+
await saveSession({ ...existingSession, wrappedIdentityKey });
|
|
930
951
|
}
|
|
931
952
|
async function clearSession() {
|
|
932
953
|
memorySession = null;
|
|
@@ -1025,6 +1046,34 @@ async function register(params, deps) {
|
|
|
1025
1046
|
return { signingPrivateKey: credentials.signingPrivateKey };
|
|
1026
1047
|
}
|
|
1027
1048
|
|
|
1049
|
+
// src/auth/identity.ts
|
|
1050
|
+
function bytesEqual(a, b) {
|
|
1051
|
+
return a.length === b.length && a.every((byte, i) => byte === b[i]);
|
|
1052
|
+
}
|
|
1053
|
+
function encryptionPublicKeyOf(identitySecretKey) {
|
|
1054
|
+
return base64Encode(
|
|
1055
|
+
deriveEncryptionKeypairFromSigning({
|
|
1056
|
+
publicKey: identitySecretKey.slice(32, 64),
|
|
1057
|
+
secretKey: identitySecretKey
|
|
1058
|
+
}).publicKey
|
|
1059
|
+
);
|
|
1060
|
+
}
|
|
1061
|
+
function identityFromLoginResponse(passwordPrivateKey, response) {
|
|
1062
|
+
const identity = unwrapIdentityKey(response.wrapped_identity_key, passwordPrivateKey);
|
|
1063
|
+
if (encryptionPublicKeyOf(identity) !== response.user.encryption_public_key) {
|
|
1064
|
+
throw new Error("The account key does not match this account");
|
|
1065
|
+
}
|
|
1066
|
+
return identity;
|
|
1067
|
+
}
|
|
1068
|
+
async function unlockIdentityWithPassword(email, password, deploymentDomain) {
|
|
1069
|
+
const session = await getSession();
|
|
1070
|
+
if (!session?.signingPrivateKey) throw new Error("No active session found");
|
|
1071
|
+
const { signingKeyPair } = await generateUserKeypairs(email, password, deploymentDomain);
|
|
1072
|
+
const identity = unwrapIdentityKey(session.wrappedIdentityKey, signingKeyPair.secretKey);
|
|
1073
|
+
if (!bytesEqual(identity, session.signingPrivateKey)) throw new Error("Incorrect password");
|
|
1074
|
+
return session.signingPrivateKey;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1028
1077
|
// src/auth/login.ts
|
|
1029
1078
|
async function login(params, deps) {
|
|
1030
1079
|
const credentials = await generateLoginCredentials(
|
|
@@ -1035,7 +1084,7 @@ async function login(params, deps) {
|
|
|
1035
1084
|
params.password,
|
|
1036
1085
|
deps.deploymentDomain
|
|
1037
1086
|
);
|
|
1038
|
-
return performLogin(credentials.request, credentials.
|
|
1087
|
+
return performLogin(credentials.request, { password: credentials.passwordPrivateKey }, deps);
|
|
1039
1088
|
}
|
|
1040
1089
|
async function loginWithKey(params, deps) {
|
|
1041
1090
|
const credentials = generateLoginCredentialsFromKey(
|
|
@@ -1045,9 +1094,9 @@ async function loginWithKey(params, deps) {
|
|
|
1045
1094
|
},
|
|
1046
1095
|
params.signingPrivateKey
|
|
1047
1096
|
);
|
|
1048
|
-
return performLogin(credentials.request, credentials.signingPrivateKey, deps);
|
|
1097
|
+
return performLogin(credentials.request, { identity: credentials.signingPrivateKey }, deps);
|
|
1049
1098
|
}
|
|
1050
|
-
async function performLogin(request,
|
|
1099
|
+
async function performLogin(request, signer, deps) {
|
|
1051
1100
|
const response = await deps.fetchClient.POST("/v1/user/login", {
|
|
1052
1101
|
body: request
|
|
1053
1102
|
});
|
|
@@ -1058,10 +1107,12 @@ async function performLogin(request, signingPrivateKey, deps) {
|
|
|
1058
1107
|
}
|
|
1059
1108
|
const data = response.data;
|
|
1060
1109
|
const serverSessionKey = base64ToBytes(data.session_key);
|
|
1110
|
+
const signingPrivateKey = "password" in signer ? identityFromLoginResponse(signer.password, data) : signer.identity;
|
|
1061
1111
|
await saveSession({
|
|
1062
1112
|
signingPrivateKey,
|
|
1063
1113
|
serverSessionKey,
|
|
1064
|
-
userExtId: data.user.external_id ?? void 0
|
|
1114
|
+
userExtId: data.user.external_id ?? void 0,
|
|
1115
|
+
wrappedIdentityKey: data.wrapped_identity_key ?? null
|
|
1065
1116
|
});
|
|
1066
1117
|
deps.session.setAccessToken(data.access_token);
|
|
1067
1118
|
deps.session.setUser(request.email, data.user.external_id ?? void 0);
|
|
@@ -1089,40 +1140,6 @@ async function logout(session) {
|
|
|
1089
1140
|
}
|
|
1090
1141
|
|
|
1091
1142
|
// src/auth/change-password.ts
|
|
1092
|
-
var passwordCalls = (client) => client;
|
|
1093
|
-
async function changePassword(params, deps) {
|
|
1094
|
-
const credentials = await generatePasswordChangeCredentials(
|
|
1095
|
-
params.email,
|
|
1096
|
-
params.currentPassword,
|
|
1097
|
-
params.newPassword,
|
|
1098
|
-
deps.deploymentDomain
|
|
1099
|
-
);
|
|
1100
|
-
const stored = await getSession();
|
|
1101
|
-
if (!stored) throw new Error("Sign in to change your password");
|
|
1102
|
-
const current = deriveEncryptionKeypairFromSigning({
|
|
1103
|
-
publicKey: stored.signingPrivateKey.slice(32, 64),
|
|
1104
|
-
secretKey: stored.signingPrivateKey
|
|
1105
|
-
});
|
|
1106
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1107
|
-
publicKey: credentials.newSigningPrivateKey.slice(32, 64),
|
|
1108
|
-
secretKey: credentials.newSigningPrivateKey
|
|
1109
|
-
});
|
|
1110
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1111
|
-
const response = await passwordCalls(deps.fetchClient).POST("/v1/user/change_password", {
|
|
1112
|
-
body: {
|
|
1113
|
-
...credentials.request,
|
|
1114
|
-
...mailKeys,
|
|
1115
|
-
rewrapped_workspace_keys: params.rewrappedWorkspaceKeys ?? {}
|
|
1116
|
-
}
|
|
1117
|
-
});
|
|
1118
|
-
if (response.error) {
|
|
1119
|
-
throw new Error(
|
|
1120
|
-
`Password change failed: ${typeof response.error === "object" && response.error !== null && "detail" in response.error ? response.error.detail : "Unknown error"}`
|
|
1121
|
-
);
|
|
1122
|
-
}
|
|
1123
|
-
await updateSigningPrivateKey(credentials.newSigningPrivateKey);
|
|
1124
|
-
return { newSigningPrivateKey: credentials.newSigningPrivateKey };
|
|
1125
|
-
}
|
|
1126
1143
|
function passwordChangeErrorMessage(err) {
|
|
1127
1144
|
if (err instanceof Error) return err.message;
|
|
1128
1145
|
if (err && typeof err === "object") {
|
|
@@ -1138,140 +1155,24 @@ function passwordChangeErrorMessage(err) {
|
|
|
1138
1155
|
}
|
|
1139
1156
|
return "Failed to change password";
|
|
1140
1157
|
}
|
|
1141
|
-
async function
|
|
1142
|
-
const
|
|
1143
|
-
const
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
const id = other.external_id;
|
|
1153
|
-
oldSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, oldSecretKey);
|
|
1154
|
-
newSecrets[id] ??= await computeSharedSecret(other.encryption_public_key, newSecretKey);
|
|
1155
|
-
const reEncrypt = async (ciphertext) => encryptMessageWithSharedSecret(
|
|
1156
|
-
await decryptMessageWithSharedSecret(ciphertext, oldSecrets[id]),
|
|
1157
|
-
newSecrets[id]
|
|
1158
|
-
);
|
|
1159
|
-
const content = n.content ? await reEncrypt(n.content) : void 0;
|
|
1160
|
-
const attachments = n.attachments ? await reEncrypt(n.attachments) : void 0;
|
|
1161
|
-
updates.push({
|
|
1162
|
-
external_id: n.external_id,
|
|
1163
|
-
...content !== void 0 ? { content } : {},
|
|
1164
|
-
...attachments !== void 0 ? { attachments } : {}
|
|
1165
|
-
});
|
|
1166
|
-
} catch {
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
if (updates.length === 0) return 0;
|
|
1170
|
-
const patched = await fetchClient.PATCH("/v1/notifications/", { body: { updates } });
|
|
1171
|
-
if (!patched.data) throw new Error("Failed to save re-encrypted messages");
|
|
1172
|
-
return updates.length;
|
|
1173
|
-
}
|
|
1174
|
-
async function rewrapMailKeys(fetchClient, oldPrivateKey, newPublicKey) {
|
|
1175
|
-
const rewrappedMailKeys = {};
|
|
1176
|
-
let mailCursor = 0;
|
|
1177
|
-
while (mailCursor !== null) {
|
|
1178
|
-
const result = await fetchClient.GET(
|
|
1179
|
-
"/v1/mail/native/keys",
|
|
1180
|
-
{
|
|
1181
|
-
params: { query: { cursor: mailCursor } }
|
|
1182
|
-
}
|
|
1183
|
-
);
|
|
1184
|
-
if (!result.data) throw new Error("Could not load mailbox keys for password change");
|
|
1185
|
-
for (const [id, wrapped] of Object.entries(result.data.keys)) {
|
|
1186
|
-
const key = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1187
|
-
try {
|
|
1188
|
-
rewrappedMailKeys[id] = sealedBoxEncrypt(key, newPublicKey);
|
|
1189
|
-
} finally {
|
|
1190
|
-
key.fill(0);
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
mailCursor = result.data.next_cursor ?? null;
|
|
1194
|
-
}
|
|
1195
|
-
const connected = await passwordCalls(fetchClient).GET("/v1/mail/native/rotation-credentials");
|
|
1196
|
-
if (!connected.data) throw new Error("Could not load mail connections for password change");
|
|
1197
|
-
const rewrappedMailCredentials = {};
|
|
1198
|
-
for (const [id, wrapped] of Object.entries(connected.data)) {
|
|
1199
|
-
const plain = sealedBoxDecrypt(wrapped, oldPrivateKey);
|
|
1200
|
-
try {
|
|
1201
|
-
rewrappedMailCredentials[id] = sealedBoxEncrypt(plain, newPublicKey);
|
|
1202
|
-
} finally {
|
|
1203
|
-
plain.fill(0);
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
return {
|
|
1207
|
-
rewrapped_mail_keys: rewrappedMailKeys,
|
|
1208
|
-
rewrapped_mail_credentials: rewrappedMailCredentials
|
|
1209
|
-
};
|
|
1210
|
-
}
|
|
1211
|
-
async function changePasswordWithRekey(params, deps) {
|
|
1212
|
-
const session = await getSession();
|
|
1213
|
-
if (!session) throw new Error("No active session found");
|
|
1214
|
-
const { request, newSigningPrivateKey } = params.currentPassword ? await generatePasswordChangeCredentials(
|
|
1215
|
-
params.email,
|
|
1216
|
-
params.currentPassword,
|
|
1217
|
-
params.newPassword,
|
|
1218
|
-
deps.deploymentDomain
|
|
1219
|
-
) : await generateRecoveryPasswordChangeCredentials(
|
|
1220
|
-
params.email,
|
|
1221
|
-
session.signingPrivateKey,
|
|
1222
|
-
params.newPassword,
|
|
1158
|
+
async function changePassword(params, deps) {
|
|
1159
|
+
const fromStore = !params.identitySecretKey;
|
|
1160
|
+
const identitySecretKey = params.identitySecretKey ?? (await getSession())?.signingPrivateKey;
|
|
1161
|
+
if (!identitySecretKey) throw new Error("Sign in to change your password");
|
|
1162
|
+
const { request } = await generatePasswordChangeCredentials(
|
|
1163
|
+
{
|
|
1164
|
+
email: params.email,
|
|
1165
|
+
identitySecretKey,
|
|
1166
|
+
newPassword: params.newPassword,
|
|
1167
|
+
currentPassword: params.currentPassword
|
|
1168
|
+
},
|
|
1223
1169
|
deps.deploymentDomain
|
|
1224
1170
|
);
|
|
1225
|
-
const
|
|
1226
|
-
publicKey: session.signingPrivateKey.slice(32, 64),
|
|
1227
|
-
secretKey: session.signingPrivateKey
|
|
1228
|
-
});
|
|
1229
|
-
const next = deriveEncryptionKeypairFromSigning({
|
|
1230
|
-
publicKey: newSigningPrivateKey.slice(32, 64),
|
|
1231
|
-
secretKey: newSigningPrivateKey
|
|
1232
|
-
});
|
|
1233
|
-
const listed = await deps.fetchClient.GET("/v1/user/workspaces");
|
|
1234
|
-
if (!listed.data) throw new Error("Could not list your workspaces");
|
|
1235
|
-
const rewrapped = {};
|
|
1236
|
-
for (const ws of listed.data.filter((w) => w.is_member)) {
|
|
1237
|
-
if (!ws.wrapped_key) continue;
|
|
1238
|
-
try {
|
|
1239
|
-
rewrapped[ws.external_id] = sealedBoxEncrypt(
|
|
1240
|
-
sealedBoxDecrypt(ws.wrapped_key, current.secretKey),
|
|
1241
|
-
next.publicKey
|
|
1242
|
-
);
|
|
1243
|
-
} catch {
|
|
1244
|
-
throw new Error(`Failed to re-wrap workspace key for ${ws.name || ws.external_id}`);
|
|
1245
|
-
}
|
|
1246
|
-
}
|
|
1247
|
-
let messagesReEncrypted = 0;
|
|
1248
|
-
if (params.userExtId) {
|
|
1249
|
-
try {
|
|
1250
|
-
messagesReEncrypted = await reEncryptDirectMessages(
|
|
1251
|
-
deps.fetchClient,
|
|
1252
|
-
params.userExtId,
|
|
1253
|
-
current.secretKey,
|
|
1254
|
-
next.secretKey
|
|
1255
|
-
);
|
|
1256
|
-
} catch {
|
|
1257
|
-
}
|
|
1258
|
-
}
|
|
1259
|
-
const mailKeys = await rewrapMailKeys(deps.fetchClient, current.secretKey, next.publicKey);
|
|
1260
|
-
const response = await passwordCalls(deps.fetchClient).POST("/v1/user/change_password", {
|
|
1261
|
-
body: {
|
|
1262
|
-
...request,
|
|
1263
|
-
rewrapped_workspace_keys: rewrapped,
|
|
1264
|
-
...mailKeys
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1171
|
+
const response = await deps.fetchClient.POST("/v1/user/change_password", { body: request });
|
|
1267
1172
|
if (response.error || !response.data)
|
|
1268
1173
|
throw response.error ?? new Error("Failed to change password");
|
|
1269
|
-
await
|
|
1270
|
-
return {
|
|
1271
|
-
newSigningPrivateKey,
|
|
1272
|
-
workspacesUpdated: response.data.workspaces_updated ?? 0,
|
|
1273
|
-
messagesReEncrypted
|
|
1274
|
-
};
|
|
1174
|
+
if (fromStore) await updateWrappedIdentityKey(request.wrapped_identity_key);
|
|
1175
|
+
return { wrappedIdentityKey: request.wrapped_identity_key };
|
|
1275
1176
|
}
|
|
1276
1177
|
|
|
1277
1178
|
// src/client.ts
|
|
@@ -1370,7 +1271,8 @@ function createArbiClient(options) {
|
|
|
1370
1271
|
return {
|
|
1371
1272
|
accessToken: data.access_token,
|
|
1372
1273
|
sessionKey: base64ToBytes(data.session_key),
|
|
1373
|
-
userExtId: data.user.external_id ?? void 0
|
|
1274
|
+
userExtId: data.user.external_id ?? void 0,
|
|
1275
|
+
wrappedIdentityKey: data.wrapped_identity_key ?? null
|
|
1374
1276
|
};
|
|
1375
1277
|
}
|
|
1376
1278
|
};
|
|
@@ -1517,6 +1419,6 @@ function isMessageType(msg, type) {
|
|
|
1517
1419
|
return msg.type === type;
|
|
1518
1420
|
}
|
|
1519
1421
|
|
|
1520
|
-
export { API_PREFIX, CALL_KEY_BYTES, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession,
|
|
1422
|
+
export { API_PREFIX, CALL_KEY_BYTES, base64Decode, base64Encode, base64ToBytes, buildCallFragment, buildWebSocketUrl, bytesToBase64, canPersistSession, changePassword, clearAllData, clearSession, computeSharedSecret, createArbiClient, createAuthMessage, createAutoReloginMiddleware, createBearerAuthMiddleware, createContentHash, createReloginHandler, createSessionManager, createWorkspaceReopener, decodeCallKey, decryptCallTitle, decryptFile, decryptMessage, decryptMessageWithSharedSecret, deriveEncryptionKeypairFromSigning, derivePublicKey, encodeCallKey, encryptCallTitle, encryptFile, encryptMessage, encryptMessageWithSharedSecret, generateCallKey, generateIdentityKeypair, generateKeyPairs, generateLoginCredentials, generateLoginCredentialsFromKey, generatePasswordChangeCredentials, generateRandomSigningKeypair, generateRegistrationCredentials, generateUserKeypairs, getSession, getUserEncryptionKeypair, hasSession, identityFromLoginResponse, initSodium, initializeDatabase, isMessageType, openSealedCallKey, parseCallFragment, parseServerMessage, passwordChangeErrorMessage, prewarmKeyPairs, saveSession, sealCallKey, sealKeyForSession, sealedBoxDecrypt, sealedBoxEncrypt, signMessage, unlockIdentityWithPassword, unwrapIdentityKey, updateWrappedIdentityKey, wrapIdentityKey };
|
|
1521
1423
|
//# sourceMappingURL=index.js.map
|
|
1522
1424
|
//# sourceMappingURL=index.js.map
|