mirror of
https://github.com/bitwarden/browser
synced 2026-02-04 10:43:47 +00:00
Remove unused functions
This commit is contained in:
@@ -22,12 +22,6 @@ import {
|
||||
|
||||
import { KdfConfig } from "../models/kdf-config";
|
||||
|
||||
export class UserPrivateKeyDecryptionFailedError extends Error {
|
||||
constructor() {
|
||||
super("Failed to decrypt the user's private key.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An object containing all the users key needed to decrypt a users personal and organization vaults.
|
||||
*/
|
||||
@@ -67,20 +61,6 @@ export abstract class KeyService {
|
||||
* @param userId The desired user
|
||||
*/
|
||||
abstract setUserKey(key: UserKey, userId: UserId): Promise<void>;
|
||||
/**
|
||||
* Sets the provided user keys and stores any other necessary versions
|
||||
* (such as auto, biometrics, or pin).
|
||||
* Also sets the user's encrypted private key in storage and
|
||||
* clears the decrypted private key from memory
|
||||
* Note: does not clear the private key if null is provided
|
||||
*
|
||||
* @throws Error when userKey, encPrivateKey or userId is null
|
||||
* @throws UserPrivateKeyDecryptionFailedError when the userKey cannot decrypt encPrivateKey
|
||||
* @param userKey The user key to set
|
||||
* @param encPrivateKey An encrypted private key
|
||||
* @param userId The desired user
|
||||
*/
|
||||
abstract setUserKeys(userKey: UserKey, encPrivateKey: string, userId: UserId): Promise<void>;
|
||||
/**
|
||||
* Gets the user key from memory and sets it again,
|
||||
* kicking off a refresh of any additional keys
|
||||
@@ -139,13 +119,6 @@ export abstract class KeyService {
|
||||
* @returns A new user key
|
||||
*/
|
||||
abstract makeUserKeyV1(): Promise<UserKey>;
|
||||
/**
|
||||
* Clears the user's stored version of the user key
|
||||
* @param keySuffix The desired version of the key to clear
|
||||
* @param userId The desired user
|
||||
* @throws Error when userId is null or undefined.
|
||||
*/
|
||||
abstract clearStoredUserKey(keySuffix: KeySuffixOptions, userId: string): Promise<void>;
|
||||
/**
|
||||
* Retrieves the user's master key if it is in state, or derives it from the provided password
|
||||
* @param password The user's master password that will be used to derive a master key if one isn't found
|
||||
@@ -295,28 +268,6 @@ export abstract class KeyService {
|
||||
*/
|
||||
abstract userEncryptedPrivateKey$(userId: UserId): Observable<EncryptedString | null>;
|
||||
|
||||
/**
|
||||
* Gets an observable stream of the given users decrypted private key and public key, guaranteed to be consistent.
|
||||
* Will emit null if the user doesn't have a userkey to decrypt the encrypted private key, or null if the user doesn't have a private key
|
||||
* at all.
|
||||
*
|
||||
* @param userId The user id of the user to get the data for.
|
||||
*/
|
||||
abstract userEncryptionKeyPair$(
|
||||
userId: UserId,
|
||||
): Observable<{ privateKey: UserPrivateKey; publicKey: UserPublicKey } | null>;
|
||||
|
||||
/**
|
||||
* Gets an observable stream of the given users decrypted private key and public key, guaranteed to be consistent.
|
||||
* Will emit null if the user doesn't have a userkey to decrypt the encrypted private key, or null if the user doesn't have a private key
|
||||
* at all.
|
||||
*
|
||||
* @param userId The user id of the user to get the data for.
|
||||
*/
|
||||
abstract userEncryptionKeyPair$(
|
||||
userId: UserId,
|
||||
): Observable<{ privateKey: UserPrivateKey; publicKey: UserPublicKey } | null>;
|
||||
|
||||
/**
|
||||
* Generates a fingerprint phrase for the public key provided.
|
||||
*
|
||||
|
||||
@@ -48,7 +48,6 @@ import {
|
||||
} from "@bitwarden/common/types/key";
|
||||
|
||||
import { KdfConfigService } from "./abstractions/kdf-config.service";
|
||||
import { UserPrivateKeyDecryptionFailedError } from "./abstractions/key.service";
|
||||
import { DefaultKeyService } from "./key.service";
|
||||
import { KdfConfig } from "./models/kdf-config";
|
||||
|
||||
@@ -304,70 +303,6 @@ describe("keyService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("setUserKeys", () => {
|
||||
let mockUserKey: UserKey;
|
||||
let mockEncPrivateKey: EncryptedString;
|
||||
let everHadUserKeyState: FakeSingleUserState<boolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
const mockRandomBytes = new Uint8Array(64) as CsprngArray;
|
||||
mockUserKey = new SymmetricCryptoKey(mockRandomBytes) as UserKey;
|
||||
mockEncPrivateKey = new SymmetricCryptoKey(mockRandomBytes).toString() as EncryptedString;
|
||||
everHadUserKeyState = stateProvider.singleUser.getFake(mockUserId, USER_EVER_HAD_USER_KEY);
|
||||
|
||||
// Initialize storage
|
||||
everHadUserKeyState.nextState(null);
|
||||
|
||||
// Mock private key decryption
|
||||
encryptService.unwrapDecapsulationKey.mockResolvedValue(mockRandomBytes);
|
||||
});
|
||||
|
||||
it("throws if userKey is null", async () => {
|
||||
await expect(
|
||||
keyService.setUserKeys(null as unknown as UserKey, mockEncPrivateKey, mockUserId),
|
||||
).rejects.toThrow("No userKey provided.");
|
||||
});
|
||||
|
||||
it("throws if encPrivateKey is null", async () => {
|
||||
await expect(
|
||||
keyService.setUserKeys(mockUserKey, null as unknown as EncryptedString, mockUserId),
|
||||
).rejects.toThrow("No encPrivateKey provided.");
|
||||
});
|
||||
|
||||
it("throws if userId is null", async () => {
|
||||
await expect(
|
||||
keyService.setUserKeys(mockUserKey, mockEncPrivateKey, null as unknown as UserId),
|
||||
).rejects.toThrow("No userId provided.");
|
||||
});
|
||||
|
||||
it("throws if encPrivateKey cannot be decrypted with the userKey", async () => {
|
||||
encryptService.unwrapDecapsulationKey.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
keyService.setUserKeys(mockUserKey, mockEncPrivateKey, mockUserId),
|
||||
).rejects.toThrow(UserPrivateKeyDecryptionFailedError);
|
||||
});
|
||||
|
||||
// We already have tests for setUserKey, so we just need to test that the correct methods are called
|
||||
it("calls setUserKey with the userKey and userId", async () => {
|
||||
const setUserKeySpy = jest.spyOn(keyService, "setUserKey");
|
||||
|
||||
await keyService.setUserKeys(mockUserKey, mockEncPrivateKey, mockUserId);
|
||||
|
||||
expect(setUserKeySpy).toHaveBeenCalledWith(mockUserKey, mockUserId);
|
||||
});
|
||||
|
||||
// We already have tests for setPrivateKey, so we just need to test that the correct methods are called
|
||||
// TODO: Move those tests into here since `setPrivateKey` will be converted to a private method
|
||||
it("calls setPrivateKey with the encPrivateKey and userId", async () => {
|
||||
const setEncryptedPrivateKeySpy = jest.spyOn(keyService, "setPrivateKey");
|
||||
|
||||
await keyService.setUserKeys(mockUserKey, mockEncPrivateKey, mockUserId);
|
||||
|
||||
expect(setEncryptedPrivateKeySpy).toHaveBeenCalledWith(mockEncPrivateKey, mockUserId);
|
||||
});
|
||||
});
|
||||
|
||||
describe("makeSendKey", () => {
|
||||
const mockRandomBytes = new Uint8Array(16) as CsprngArray;
|
||||
it("calls keyGenerationService with expected hard coded parameters", async () => {
|
||||
@@ -381,45 +316,6 @@ describe("keyService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearStoredUserKey", () => {
|
||||
describe("input validation", () => {
|
||||
const invalidUserIdTestCases = [
|
||||
{ keySuffix: KeySuffixOptions.Auto, userId: null as unknown as UserId },
|
||||
{ keySuffix: KeySuffixOptions.Auto, userId: undefined as unknown as UserId },
|
||||
{ keySuffix: KeySuffixOptions.Pin, userId: null as unknown as UserId },
|
||||
{ keySuffix: KeySuffixOptions.Pin, userId: undefined as unknown as UserId },
|
||||
];
|
||||
test.each(invalidUserIdTestCases)(
|
||||
"throws when keySuffix is $keySuffix and userId is $userId",
|
||||
async ({ keySuffix, userId }) => {
|
||||
await expect(keyService.clearStoredUserKey(keySuffix, userId)).rejects.toThrow(
|
||||
"UserId is required",
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("with Auto key suffix", () => {
|
||||
it("UserKeyAutoUnlock is cleared and pin keys are not cleared", async () => {
|
||||
await keyService.clearStoredUserKey(KeySuffixOptions.Auto, mockUserId);
|
||||
|
||||
expect(stateService.setUserKeyAutoUnlock).toHaveBeenCalledWith(null, {
|
||||
userId: mockUserId,
|
||||
});
|
||||
expect(pinService.clearPinKeyEncryptedUserKeyEphemeral).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("with PIN key suffix", () => {
|
||||
it("pin keys are cleared and user key auto unlock not", async () => {
|
||||
await keyService.clearStoredUserKey(KeySuffixOptions.Pin, mockUserId);
|
||||
|
||||
expect(stateService.setUserKeyAutoUnlock).not.toHaveBeenCalled();
|
||||
expect(pinService.clearPinKeyEncryptedUserKeyEphemeral).toHaveBeenCalledWith(mockUserId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("clearKeys", () => {
|
||||
test.each([null as unknown as UserId, undefined as unknown as UserId])(
|
||||
"throws when the provided userId is %s",
|
||||
@@ -1095,53 +991,6 @@ describe("keyService", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("userEncryptionKeyPair$", () => {
|
||||
type SetupKeysParams = {
|
||||
makeMasterKey: boolean;
|
||||
makeUserKey: boolean;
|
||||
};
|
||||
|
||||
function setupKeys({ makeMasterKey, makeUserKey }: SetupKeysParams): [UserKey, MasterKey] {
|
||||
const userKeyState = stateProvider.singleUser.getFake(mockUserId, USER_KEY);
|
||||
const fakeMasterKey = makeMasterKey ? makeSymmetricCryptoKey<MasterKey>(64) : null;
|
||||
masterPasswordService.masterKeySubject.next(fakeMasterKey);
|
||||
userKeyState.nextState(null);
|
||||
const fakeUserKey = makeUserKey ? makeSymmetricCryptoKey<UserKey>(64) : null;
|
||||
userKeyState.nextState(fakeUserKey);
|
||||
return [fakeUserKey, fakeMasterKey];
|
||||
}
|
||||
|
||||
it("returns null when private key is null", async () => {
|
||||
setupKeys({ makeMasterKey: false, makeUserKey: false });
|
||||
|
||||
keyService.userPrivateKey$ = jest.fn().mockReturnValue(new BehaviorSubject(null));
|
||||
const key = await firstValueFrom(keyService.userEncryptionKeyPair$(mockUserId));
|
||||
expect(key).toEqual(null);
|
||||
});
|
||||
|
||||
it("returns null when private key is undefined", async () => {
|
||||
setupKeys({ makeUserKey: true, makeMasterKey: false });
|
||||
|
||||
keyService.userPrivateKey$ = jest.fn().mockReturnValue(new BehaviorSubject(undefined));
|
||||
const key = await firstValueFrom(keyService.userEncryptionKeyPair$(mockUserId));
|
||||
expect(key).toEqual(null);
|
||||
});
|
||||
|
||||
it("returns keys when private key is defined", async () => {
|
||||
setupKeys({ makeUserKey: false, makeMasterKey: true });
|
||||
|
||||
keyService.userPrivateKey$ = jest.fn().mockReturnValue(new BehaviorSubject("private key"));
|
||||
cryptoFunctionService.rsaExtractPublicKey.mockResolvedValue(
|
||||
Utils.fromUtf8ToArray("public key"),
|
||||
);
|
||||
const key = await firstValueFrom(keyService.userEncryptionKeyPair$(mockUserId));
|
||||
expect(key).toEqual({
|
||||
privateKey: "private key",
|
||||
publicKey: Utils.fromUtf8ToArray("public key"),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("getUserKeyFromStorage", () => {
|
||||
let mockUserKey: UserKey;
|
||||
let validateUserKeySpy: jest.SpyInstance;
|
||||
|
||||
@@ -62,7 +62,6 @@ import { KdfConfigService } from "./abstractions/kdf-config.service";
|
||||
import {
|
||||
CipherDecryptionKeys,
|
||||
KeyService as KeyServiceAbstraction,
|
||||
UserPrivateKeyDecryptionFailedError,
|
||||
} from "./abstractions/key.service";
|
||||
import { KdfConfig } from "./models/kdf-config";
|
||||
|
||||
@@ -105,30 +104,6 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
await this.storeAdditionalKeys(key, userId);
|
||||
}
|
||||
|
||||
async setUserKeys(
|
||||
userKey: UserKey,
|
||||
encPrivateKey: EncryptedString,
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
if (userKey == null) {
|
||||
throw new Error("No userKey provided. Lock the user to clear the key");
|
||||
}
|
||||
if (encPrivateKey == null) {
|
||||
throw new Error("No encPrivateKey provided.");
|
||||
}
|
||||
if (userId == null) {
|
||||
throw new Error("No userId provided.");
|
||||
}
|
||||
|
||||
const decryptedPrivateKey = await this.decryptPrivateKey(encPrivateKey, userKey);
|
||||
if (decryptedPrivateKey == null) {
|
||||
throw new UserPrivateKeyDecryptionFailedError();
|
||||
}
|
||||
|
||||
await this.setUserKey(userKey, userId);
|
||||
await this.setPrivateKey(encPrivateKey, userId);
|
||||
}
|
||||
|
||||
async refreshAdditionalKeys(userId: UserId): Promise<void> {
|
||||
if (userId == null) {
|
||||
throw new Error("UserId is required.");
|
||||
@@ -221,19 +196,6 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
await this.clearAllStoredUserKeys(userId);
|
||||
}
|
||||
|
||||
async clearStoredUserKey(keySuffix: KeySuffixOptions, userId: UserId): Promise<void> {
|
||||
if (userId == null) {
|
||||
throw new Error("UserId is required");
|
||||
}
|
||||
|
||||
if (keySuffix === KeySuffixOptions.Auto) {
|
||||
await this.stateService.setUserKeyAutoUnlock(null, { userId: userId });
|
||||
}
|
||||
if (keySuffix === KeySuffixOptions.Pin) {
|
||||
await this.pinService.clearPinKeyEncryptedUserKeyEphemeral(userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Please use `makeMasterPasswordAuthenticationData`, `unwrapUserKeyFromMasterPasswordUnlockData` or `makeMasterPasswordUnlockData` in @link MasterPasswordService instead.
|
||||
*/
|
||||
@@ -577,7 +539,7 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
}
|
||||
|
||||
// ---HELPERS---
|
||||
async validateUserKey(key: UserKey | MasterKey | null, userId: UserId): Promise<boolean> {
|
||||
async validateUserKey(key: UserKey, userId: UserId): Promise<boolean> {
|
||||
if (key == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -799,21 +761,6 @@ export class DefaultKeyService implements KeyServiceAbstraction {
|
||||
return this.userPrivateKeyHelper$(userId).pipe(map((keys) => keys?.userPrivateKey ?? null));
|
||||
}
|
||||
|
||||
userEncryptionKeyPair$(
|
||||
userId: UserId,
|
||||
): Observable<{ privateKey: UserPrivateKey; publicKey: UserPublicKey } | null> {
|
||||
return this.userPrivateKey$(userId).pipe(
|
||||
switchMap(async (privateKey) => {
|
||||
if (privateKey == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const publicKey = (await this.derivePublicKey(privateKey))!;
|
||||
return { privateKey, publicKey };
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
userEncryptedPrivateKey$(userId: UserId): Observable<EncryptedString | null> {
|
||||
return this.stateProvider.getUser(userId, USER_ENCRYPTED_PRIVATE_KEY).state$;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user