mirror of
https://github.com/bitwarden/browser
synced 2025-12-19 17:53:39 +00:00
[PM-28813] Implement encryption diagnostics & recovery tool (#17673)
* Implement data recovery tool * Fix tests * Move Sdkloadservice call and use bit action
This commit is contained in:
@@ -43,6 +43,7 @@ export enum FeatureFlag {
|
||||
LinuxBiometricsV2 = "pm-26340-linux-biometrics-v2",
|
||||
UnlockWithMasterPasswordUnlockData = "pm-23246-unlock-with-master-password-unlock-data",
|
||||
NoLogoutOnKdfChange = "pm-23995-no-logout-on-kdf-change",
|
||||
DataRecoveryTool = "pm-28813-data-recovery-tool",
|
||||
ConsolidatedSessionTimeoutComponent = "pm-26056-consolidated-session-timeout-component",
|
||||
|
||||
/* Tools */
|
||||
@@ -149,6 +150,7 @@ export const DefaultFeatureFlagValue = {
|
||||
[FeatureFlag.LinuxBiometricsV2]: FALSE,
|
||||
[FeatureFlag.UnlockWithMasterPasswordUnlockData]: FALSE,
|
||||
[FeatureFlag.NoLogoutOnKdfChange]: FALSE,
|
||||
[FeatureFlag.DataRecoveryTool]: FALSE,
|
||||
[FeatureFlag.ConsolidatedSessionTimeoutComponent]: FALSE,
|
||||
|
||||
/* Platform */
|
||||
|
||||
@@ -7,4 +7,11 @@ export abstract class UserAsymmetricKeysRegenerationService {
|
||||
* @param userId The user id.
|
||||
*/
|
||||
abstract regenerateIfNeeded(userId: UserId): Promise<void>;
|
||||
|
||||
/**
|
||||
* Performs the regeneration of the user's public/private key pair without checking any preconditions.
|
||||
* This should only be used for V1 encryption accounts
|
||||
* @param userId The user id.
|
||||
*/
|
||||
abstract regenerateUserPublicKeyEncryptionKeyPair(userId: UserId): Promise<void>;
|
||||
}
|
||||
|
||||
@@ -370,3 +370,52 @@ describe("regenerateIfNeeded", () => {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("regenerateUserPublicKeyEncryptionKeyPair", () => {
|
||||
let sut: DefaultUserAsymmetricKeysRegenerationService;
|
||||
const userId = "userId" as UserId;
|
||||
|
||||
let keyService: MockProxy<KeyService>;
|
||||
let cipherService: MockProxy<CipherService>;
|
||||
let userAsymmetricKeysRegenerationApiService: MockProxy<UserAsymmetricKeysRegenerationApiService>;
|
||||
let logService: MockProxy<LogService>;
|
||||
let sdkService: MockSdkService;
|
||||
let apiService: MockProxy<ApiService>;
|
||||
let configService: MockProxy<ConfigService>;
|
||||
|
||||
beforeEach(() => {
|
||||
keyService = mock<KeyService>();
|
||||
cipherService = mock<CipherService>();
|
||||
userAsymmetricKeysRegenerationApiService = mock<UserAsymmetricKeysRegenerationApiService>();
|
||||
logService = mock<LogService>();
|
||||
sdkService = new MockSdkService();
|
||||
apiService = mock<ApiService>();
|
||||
configService = mock<ConfigService>();
|
||||
|
||||
sut = new DefaultUserAsymmetricKeysRegenerationService(
|
||||
keyService,
|
||||
cipherService,
|
||||
userAsymmetricKeysRegenerationApiService,
|
||||
logService,
|
||||
sdkService,
|
||||
apiService,
|
||||
configService,
|
||||
);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it("should throw error when user key is not V1 encryption type", async () => {
|
||||
const mockUserKey = {
|
||||
keyB64: "mockKeyB64",
|
||||
inner: () => ({ type: 7 }),
|
||||
} as unknown as UserKey;
|
||||
keyService.userKey$.mockReturnValue(of(mockUserKey));
|
||||
|
||||
await expect(sut.regenerateUserPublicKeyEncryptionKeyPair(userId)).rejects.toThrow(
|
||||
"User key is not V1 encryption type",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -37,7 +37,7 @@ export class DefaultUserAsymmetricKeysRegenerationService
|
||||
if (privateKeyRegenerationFlag) {
|
||||
const shouldRegenerate = await this.shouldRegenerate(userId);
|
||||
if (shouldRegenerate) {
|
||||
await this.regenerateUserAsymmetricKeys(userId);
|
||||
await this.regenerateUserPublicKeyEncryptionKeyPair(userId);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -125,11 +125,14 @@ export class DefaultUserAsymmetricKeysRegenerationService
|
||||
return false;
|
||||
}
|
||||
|
||||
private async regenerateUserAsymmetricKeys(userId: UserId): Promise<void> {
|
||||
async regenerateUserPublicKeyEncryptionKeyPair(userId: UserId): Promise<void> {
|
||||
const userKey = await firstValueFrom(this.keyService.userKey$(userId));
|
||||
if (userKey == null) {
|
||||
throw new Error("User key not found");
|
||||
}
|
||||
if (userKey.inner().type !== EncryptionType.AesCbc256_HmacSha256_B64) {
|
||||
throw new Error("User key is not V1 encryption type");
|
||||
}
|
||||
const makeKeyPairResponse = await firstValueFrom(
|
||||
this.sdkService.client$.pipe(
|
||||
map((sdk) => {
|
||||
|
||||
Reference in New Issue
Block a user