1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-06 00:13:28 +00:00

[PM-22516] Fix cipher key decryption to handle new error-based API instead of null returns (#15124)

* Replace null check in cipher key decryption

* Handle decryption error properly in user asymmetric key regeneration service
This commit is contained in:
SmithThe4th
2025-06-23 09:11:52 -04:00
committed by GitHub
parent 54d7d27221
commit e253e05c45
3 changed files with 83 additions and 11 deletions

View File

@@ -68,6 +68,68 @@ describe("Cipher DTO", () => {
});
});
it("Decrypt should handle cipher key error", async () => {
const cipher = new Cipher();
cipher.id = "id";
cipher.organizationId = "orgId";
cipher.folderId = "folderId";
cipher.edit = true;
cipher.viewPassword = true;
cipher.organizationUseTotp = true;
cipher.favorite = false;
cipher.revisionDate = new Date("2022-01-31T12:00:00.000Z");
cipher.type = CipherType.Login;
cipher.name = mockEnc("EncryptedString");
cipher.notes = mockEnc("EncryptedString");
cipher.creationDate = new Date("2022-01-01T12:00:00.000Z");
cipher.deletedDate = null;
cipher.reprompt = CipherRepromptType.None;
cipher.key = mockEnc("EncKey");
cipher.permissions = new CipherPermissionsApi();
const loginView = new LoginView();
loginView.username = "username";
loginView.password = "password";
const login = mock<Login>();
login.decrypt.mockResolvedValue(loginView);
cipher.login = login;
const keyService = mock<KeyService>();
const encryptService = mock<EncryptService>();
const cipherService = mock<CipherService>();
encryptService.unwrapSymmetricKey.mockRejectedValue(new Error("Failed to unwrap key"));
(window as any).bitwardenContainerService = new ContainerService(keyService, encryptService);
const cipherView = await cipher.decrypt(
await cipherService.getKeyForCipherKeyDecryption(cipher, mockUserId),
);
expect(cipherView).toMatchObject({
id: "id",
organizationId: "orgId",
folderId: "folderId",
name: "[error: cannot decrypt]",
type: 1,
favorite: false,
organizationUseTotp: true,
edit: true,
viewPassword: true,
decryptionFailure: true,
collectionIds: undefined,
revisionDate: new Date("2022-01-31T12:00:00.000Z"),
creationDate: new Date("2022-01-01T12:00:00.000Z"),
deletedDate: null,
reprompt: 0,
localData: undefined,
permissions: new CipherPermissionsApi(),
});
expect(login.decrypt).not.toHaveBeenCalled();
});
describe("LoginCipher", () => {
let cipherData: CipherData;

View File

@@ -145,14 +145,15 @@ export class Cipher extends Domain implements Decryptable<CipherView> {
if (this.key != null) {
const encryptService = Utils.getContainerService().getEncryptService();
const cipherKey = await encryptService.unwrapSymmetricKey(this.key, encKey);
if (cipherKey == null) {
try {
const cipherKey = await encryptService.unwrapSymmetricKey(this.key, encKey);
encKey = cipherKey;
bypassValidation = false;
} catch {
model.name = "[error: cannot decrypt]";
model.decryptionFailure = true;
return model;
}
encKey = cipherKey;
bypassValidation = false;
}
await this.decryptObj<Cipher, CipherView>(

View File

@@ -162,17 +162,26 @@ export class DefaultUserAsymmetricKeysRegenerationService
const ciphers = await this.cipherService.getAll(userId);
const cipher = ciphers.find((cipher) => cipher.organizationId == null);
if (cipher != null) {
try {
await cipher.decrypt(userKey);
return true;
} catch (error) {
if (!cipher) {
return false;
}
try {
const cipherView = await cipher.decrypt(userKey);
if (cipherView.decryptionFailure) {
this.logService.error(
"[UserAsymmetricKeyRegeneration] User Symmetric Key validation error: " + error,
"[UserAsymmetricKeyRegeneration] User Symmetric Key validation error: Cipher decryption failed",
);
return false;
}
return true;
} catch (error) {
this.logService.error(
"[UserAsymmetricKeyRegeneration] User Symmetric Key validation error: " + error,
);
return false;
}
return false;
}
}