05/22 Enhance codes and fix bugs

This commit is contained in:
2026-05-22 10:37:26 -04:00
parent 04f7368a95
commit 3231c8eb56
3 changed files with 75 additions and 7 deletions
+17 -5
View File
@@ -339,11 +339,23 @@ const Recover = (() => {
item.enc_data,
item.iv,
);
const { enc_data, iv } = await Crypto.encryptItem(
newVaultKey,
plain,
);
reEncryptedItems.push({ id: item.id, enc_data, iv });
const { enc_data, iv } = await Crypto.encryptItem(newVaultKey, plain);
let encNamePayload = {};
if (item.enc_name && item.iv_name) {
const plainName = await Crypto.decryptName(
_oldVaultKey,
item.enc_name,
item.iv_name,
);
if (plainName) {
const { enc_name, iv_name } = await Crypto.encryptName(
newVaultKey,
plainName,
);
encNamePayload = { enc_name, iv_name };
}
}
reEncryptedItems.push({ id: item.id, enc_data, iv, ...encNamePayload });
} catch {
// Item decryption failed — skip (shouldn't happen if recovery code is correct)
console.warn(`Could not re-encrypt item ${item.id}`);
+43
View File
@@ -3323,6 +3323,48 @@ const Vault = (() => {
reEncrypted.push({ id: item.id, enc_data, iv, ...encNamePayload });
}
// Re-encrypt sharing private key with new vault key so sharing stays functional.
// The private key is stored as AES-GCM ciphertext on the server; rotating the
// vault key without re-encrypting it would leave it permanently unreadable.
let sharingKeyPayload = {};
try {
const sharingRes = await apiFetch("/api/sharing/keys");
if (sharingRes && sharingRes.ok) {
const sharingData = await sharingRes.json();
if (
sharingData.keys_setup &&
sharingData.private_key_enc &&
sharingData.private_key_iv
) {
const b64ToArr = (b64) =>
Uint8Array.from(atob(b64), (c) => c.charCodeAt(0));
const arrToB64 = (arr) =>
btoa(String.fromCharCode(...new Uint8Array(arr)));
const privKeyBytes = await window.crypto.subtle.decrypt(
{
name: "AES-GCM",
iv: b64ToArr(sharingData.private_key_iv),
},
vaultKey,
b64ToArr(sharingData.private_key_enc),
);
const newPrivIv = window.crypto.getRandomValues(new Uint8Array(12));
const reEncPriv = await window.crypto.subtle.encrypt(
{ name: "AES-GCM", iv: newPrivIv },
newVaultKey,
privKeyBytes,
);
sharingKeyPayload = {
sharing_private_key_enc: arrToB64(reEncPriv),
sharing_private_key_iv: arrToB64(newPrivIv),
};
}
}
} catch (err) {
console.warn("[PassKeeper] Could not re-encrypt sharing key:", err);
// Non-fatal — password change continues; user can regenerate sharing keys
}
// Submit atomic password change
const res = await apiFetch("/api/auth/change-password", {
method: "POST",
@@ -3331,6 +3373,7 @@ const Vault = (() => {
new_auth_hash: newAuthHash,
new_enc_key_salt: newEncKeySalt,
items: reEncrypted,
...sharingKeyPayload,
}),
});
if (!res) return;