rename protectedPin to userKeyEncryptedPin
This commit is contained in:
parent
a11aeb8710
commit
2456037db0
|
@ -48,8 +48,8 @@ export class SetPinComponent implements OnInit {
|
|||
const userId = (await firstValueFrom(this.accountService.activeAccount$))?.id;
|
||||
const userKey = await this.cryptoService.getUserKey();
|
||||
|
||||
const protectedPin = await this.pinService.createProtectedPin(pin, userKey);
|
||||
await this.pinService.setProtectedPin(protectedPin.encryptedString, userId);
|
||||
const userKeyEncryptedPin = await this.pinService.createUserKeyEncryptedPin(pin, userKey);
|
||||
await this.pinService.setUserKeyEncryptedPin(userKeyEncryptedPin.encryptedString, userId);
|
||||
|
||||
const pinKeyEncryptedUserKey = await this.pinService.createPinKeyEncryptedUserKey(
|
||||
pin,
|
||||
|
|
|
@ -15,7 +15,7 @@ export abstract class PinServiceAbstraction {
|
|||
abstract getPinKeyEncryptedUserKey: (userId: UserId) => Promise<EncString>;
|
||||
|
||||
/**
|
||||
* Clears the UserKey, encrypted by the PinKey
|
||||
* Clears the UserKey, encrypted by the PinKey.
|
||||
*/
|
||||
abstract clearPinKeyEncryptedUserKey(userId: UserId): Promise<void>;
|
||||
|
||||
|
@ -25,10 +25,19 @@ export abstract class PinServiceAbstraction {
|
|||
abstract getPinKeyEncryptedUserKeyEphemeral: (userId: UserId) => Promise<EncString>;
|
||||
|
||||
/**
|
||||
* Clears the ephemeral (stored in memory) version of the UserKey, encrypted by the PinKey
|
||||
* Clears the ephemeral (stored in memory) version of the UserKey, encrypted by the PinKey.
|
||||
*/
|
||||
abstract clearPinKeyEncryptedUserKeyEphemeral(userId: UserId): Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a pinKeyEncryptedUserKey from the provided PIN and UserKey.
|
||||
*/
|
||||
abstract createPinKeyEncryptedUserKey: (
|
||||
pin: string,
|
||||
userKey: UserKey,
|
||||
userId: UserId,
|
||||
) => Promise<EncString>;
|
||||
|
||||
/**
|
||||
* Stores the UserKey, encrypted by the PinKey.
|
||||
* @param storeEphemeralVersion If true, the method stores an ephemeral version via the private {@link setPinKeyEncryptedUserKeyEphemeral} method.
|
||||
|
@ -43,12 +52,20 @@ export abstract class PinServiceAbstraction {
|
|||
/**
|
||||
* Gets the user's PIN, encrypted by the UserKey.
|
||||
*/
|
||||
abstract getProtectedPin: (userId: UserId) => Promise<string>;
|
||||
abstract getUserKeyEncryptedPin: (userId: UserId) => Promise<string>;
|
||||
|
||||
/**
|
||||
* Sets the user's PIN, encrypted by the UserKey.
|
||||
*/
|
||||
abstract setProtectedPin: (protectedPin: string, userId: UserId) => Promise<void>;
|
||||
abstract setUserKeyEncryptedPin: (
|
||||
userKeyEncryptedPin: EncryptedString,
|
||||
userId: UserId,
|
||||
) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Creates a PIN, encrypted by the UserKey.
|
||||
*/
|
||||
abstract createUserKeyEncryptedPin: (pin: string, userKey: UserKey) => Promise<EncString>;
|
||||
|
||||
/**
|
||||
* Gets the old MasterKey, encrypted by the PinKey (formerly called `pinProtected`),
|
||||
|
@ -61,17 +78,6 @@ export abstract class PinServiceAbstraction {
|
|||
*/
|
||||
abstract clearOldPinKeyEncryptedMasterKey: (userId: UserId) => Promise<void>;
|
||||
|
||||
/**
|
||||
* Makes a pinKeyEncryptedUserKey from the provided PIN and UserKey.
|
||||
*/
|
||||
abstract createPinKeyEncryptedUserKey: (
|
||||
pin: string,
|
||||
userKey: UserKey,
|
||||
userId: UserId,
|
||||
) => Promise<EncString>;
|
||||
|
||||
abstract createProtectedPin: (pin: string, userKey: UserKey) => Promise<EncString>;
|
||||
|
||||
/**
|
||||
* Makes a PinKey from the provided PIN.
|
||||
*/
|
||||
|
|
|
@ -55,10 +55,17 @@ export const PIN_KEY_ENCRYPTED_USER_KEY_EPHEMERAL = new UserKeyDefinition<Encryp
|
|||
},
|
||||
);
|
||||
|
||||
export const PROTECTED_PIN = new UserKeyDefinition<string>(PIN_DISK, "protectedPin", {
|
||||
deserializer: (jsonValue) => jsonValue,
|
||||
clearOn: ["logout"],
|
||||
});
|
||||
/**
|
||||
* The PIN, encrypted by the UserKey
|
||||
*/
|
||||
export const USER_KEY_ENCRYPTED_PIN = new UserKeyDefinition<EncryptedString>(
|
||||
PIN_DISK,
|
||||
"userKeyEncryptedPin",
|
||||
{
|
||||
deserializer: (jsonValue) => jsonValue,
|
||||
clearOn: ["logout"],
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* The old MasterKey, encrypted by the PinKey (formerly called `pinProtected`),
|
||||
|
@ -154,46 +161,6 @@ export class PinService implements PinServiceAbstraction {
|
|||
await this.stateProvider.setUserState(PIN_KEY_ENCRYPTED_USER_KEY_EPHEMERAL, null, userId);
|
||||
}
|
||||
|
||||
async storePinKeyEncryptedUserKey(
|
||||
pinKeyEncryptedUserKey: EncString,
|
||||
storeAsEphemeral: boolean,
|
||||
userId: UserId,
|
||||
) {
|
||||
this.validateUserId(userId, "Cannot store pinKeyEncryptedUserKey.");
|
||||
|
||||
if (storeAsEphemeral) {
|
||||
await this.setPinKeyEncryptedUserKeyEphemeral(pinKeyEncryptedUserKey, userId);
|
||||
} else {
|
||||
await this.setPinKeyEncryptedUserKey(pinKeyEncryptedUserKey, userId);
|
||||
}
|
||||
}
|
||||
|
||||
async getProtectedPin(userId: UserId): Promise<string> {
|
||||
this.validateUserId(userId, "Cannot get protectedPin.");
|
||||
|
||||
return await firstValueFrom(this.stateProvider.getUserState$(PROTECTED_PIN, userId));
|
||||
}
|
||||
|
||||
async setProtectedPin(protectedPin: string, userId: UserId): Promise<void> {
|
||||
this.validateUserId(userId, "Cannot set protectedPin.");
|
||||
|
||||
await this.stateProvider.setUserState(PROTECTED_PIN, protectedPin, userId);
|
||||
}
|
||||
|
||||
async getOldPinKeyEncryptedMasterKey(userId: UserId): Promise<EncryptedString> {
|
||||
this.validateUserId(userId, "Cannot get oldPinKeyEncryptedMasterKey.");
|
||||
|
||||
return await firstValueFrom(
|
||||
this.stateProvider.getUserState$(OLD_PIN_KEY_ENCRYPTED_MASTER_KEY, userId),
|
||||
);
|
||||
}
|
||||
|
||||
async clearOldPinKeyEncryptedMasterKey(userId: UserId): Promise<void> {
|
||||
this.validateUserId(userId, "Cannot clear oldPinKeyEncryptedMasterKey.");
|
||||
|
||||
await this.stateProvider.setUserState(OLD_PIN_KEY_ENCRYPTED_MASTER_KEY, null, userId);
|
||||
}
|
||||
|
||||
async createPinKeyEncryptedUserKey(
|
||||
pin: string,
|
||||
userKey: UserKey,
|
||||
|
@ -215,13 +182,56 @@ export class PinService implements PinServiceAbstraction {
|
|||
return await this.encryptService.encrypt(userKey.key, pinKey);
|
||||
}
|
||||
|
||||
async createProtectedPin(pin: string, userKey: UserKey) {
|
||||
async storePinKeyEncryptedUserKey(
|
||||
pinKeyEncryptedUserKey: EncString,
|
||||
storeAsEphemeral: boolean,
|
||||
userId: UserId,
|
||||
) {
|
||||
this.validateUserId(userId, "Cannot store pinKeyEncryptedUserKey.");
|
||||
|
||||
if (storeAsEphemeral) {
|
||||
await this.setPinKeyEncryptedUserKeyEphemeral(pinKeyEncryptedUserKey, userId);
|
||||
} else {
|
||||
await this.setPinKeyEncryptedUserKey(pinKeyEncryptedUserKey, userId);
|
||||
}
|
||||
}
|
||||
|
||||
async getUserKeyEncryptedPin(userId: UserId): Promise<string> {
|
||||
this.validateUserId(userId, "Cannot get userKeyEncryptedPin.");
|
||||
|
||||
return await firstValueFrom(this.stateProvider.getUserState$(USER_KEY_ENCRYPTED_PIN, userId));
|
||||
}
|
||||
|
||||
async setUserKeyEncryptedPin(
|
||||
userKeyEncryptedPin: EncryptedString,
|
||||
userId: UserId,
|
||||
): Promise<void> {
|
||||
this.validateUserId(userId, "Cannot set userKeyEncryptedPin.");
|
||||
|
||||
await this.stateProvider.setUserState(USER_KEY_ENCRYPTED_PIN, userKeyEncryptedPin, userId);
|
||||
}
|
||||
|
||||
async createUserKeyEncryptedPin(pin: string, userKey: UserKey) {
|
||||
if (!userKey) {
|
||||
throw new Error("No UserKey provided. Cannot create protectedPin.");
|
||||
throw new Error("No UserKey provided. Cannot create userKeyEncryptedPin.");
|
||||
}
|
||||
return await this.encryptService.encrypt(pin, userKey);
|
||||
}
|
||||
|
||||
async getOldPinKeyEncryptedMasterKey(userId: UserId): Promise<EncryptedString> {
|
||||
this.validateUserId(userId, "Cannot get oldPinKeyEncryptedMasterKey.");
|
||||
|
||||
return await firstValueFrom(
|
||||
this.stateProvider.getUserState$(OLD_PIN_KEY_ENCRYPTED_MASTER_KEY, userId),
|
||||
);
|
||||
}
|
||||
|
||||
async clearOldPinKeyEncryptedMasterKey(userId: UserId): Promise<void> {
|
||||
this.validateUserId(userId, "Cannot clear oldPinKeyEncryptedMasterKey.");
|
||||
|
||||
await this.stateProvider.setUserState(OLD_PIN_KEY_ENCRYPTED_MASTER_KEY, null, userId);
|
||||
}
|
||||
|
||||
async makePinKey(pin: string, salt: string, kdfConfig: KdfConfig): Promise<PinKey> {
|
||||
const pinKey = await this.keyGenerationService.deriveKeyFromPassword(pin, salt, kdfConfig);
|
||||
return (await this.keyGenerationService.stretchKey(pinKey)) as PinKey;
|
||||
|
@ -232,7 +242,7 @@ export class PinService implements PinServiceAbstraction {
|
|||
|
||||
// we can't check the protected pin for both because old accounts only
|
||||
// used it for MP on Restart
|
||||
const aProtectedPinIsSet = !!(await this.getProtectedPin(userId));
|
||||
const aUserKeyEncryptedPinIsSet = !!(await this.getUserKeyEncryptedPin(userId));
|
||||
const aPinKeyEncryptedUserKeyIsSet = !!(await this.getPinKeyEncryptedUserKey(userId));
|
||||
const anOldPinKeyEncryptedMasterKeyIsSet =
|
||||
!!(await this.getOldPinKeyEncryptedMasterKey(userId));
|
||||
|
@ -240,7 +250,7 @@ export class PinService implements PinServiceAbstraction {
|
|||
if (aPinKeyEncryptedUserKeyIsSet || anOldPinKeyEncryptedMasterKeyIsSet) {
|
||||
return "PERSISTENT";
|
||||
} else if (
|
||||
aProtectedPinIsSet &&
|
||||
aUserKeyEncryptedPinIsSet &&
|
||||
!aPinKeyEncryptedUserKeyIsSet &&
|
||||
!anOldPinKeyEncryptedMasterKeyIsSet
|
||||
) {
|
||||
|
@ -363,8 +373,8 @@ export class PinService implements PinServiceAbstraction {
|
|||
userId,
|
||||
);
|
||||
|
||||
const protectedPin = await this.createProtectedPin(pin, userKey);
|
||||
await this.setProtectedPin(protectedPin.encryptedString, userId);
|
||||
const userKeyEncryptedPin = await this.createUserKeyEncryptedPin(pin, userKey);
|
||||
await this.setUserKeyEncryptedPin(userKeyEncryptedPin.encryptedString, userId);
|
||||
|
||||
await this.clearOldPinKeyEncryptedMasterKey(userId);
|
||||
|
||||
|
@ -447,9 +457,9 @@ export class PinService implements PinServiceAbstraction {
|
|||
private async validatePin(userKey: UserKey, pin: string, userId: UserId): Promise<boolean> {
|
||||
this.validateUserId(userId, "Cannot validate PIN.");
|
||||
|
||||
const protectedPin = await this.getProtectedPin(userId);
|
||||
const userKeyEncryptedPin = await this.getUserKeyEncryptedPin(userId);
|
||||
const decryptedPin = await this.encryptService.decryptToUtf8(
|
||||
new EncString(protectedPin),
|
||||
new EncString(userKeyEncryptedPin),
|
||||
userKey,
|
||||
);
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ import { LogService } from "@bitwarden/common/platform/abstractions/log.service"
|
|||
import { StateService } from "@bitwarden/common/platform/abstractions/state.service";
|
||||
import { DEFAULT_KDF_CONFIG } from "@bitwarden/common/platform/enums";
|
||||
import { Utils } from "@bitwarden/common/platform/misc/utils";
|
||||
import { EncString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { EncString, EncryptedString } from "@bitwarden/common/platform/models/domain/enc-string";
|
||||
import { SymmetricCryptoKey } from "@bitwarden/common/platform/models/domain/symmetric-crypto-key";
|
||||
import {
|
||||
FakeAccountService,
|
||||
|
@ -23,7 +23,7 @@ import {
|
|||
PIN_KEY_ENCRYPTED_USER_KEY,
|
||||
PIN_KEY_ENCRYPTED_USER_KEY_EPHEMERAL,
|
||||
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
|
||||
PROTECTED_PIN,
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
PinLockType,
|
||||
} from "./pin.service.implementation";
|
||||
|
||||
|
@ -46,8 +46,8 @@ describe("PinService", () => {
|
|||
const mockPinKey = new SymmetricCryptoKey(randomBytes(32)) as PinKey; // TODO-rr-bw: verify 32 is correct
|
||||
const mockUserEmail = "user@example.com";
|
||||
const mockPin = "1234";
|
||||
const mockProtectedPin = "protectedPin";
|
||||
const mockProtectedPinEncString = new EncString(mockProtectedPin);
|
||||
const mockUserKeyEncryptedPin = "userKeyEncryptedPin" as EncryptedString;
|
||||
const mockUserKeyEncryptedPinEncString = new EncString(mockUserKeyEncryptedPin);
|
||||
|
||||
// Note: both pinKeyEncryptedUserKeys use encryptionType: 2 (AesCbc256_HmacSha256_B64)
|
||||
const pinKeyEncryptedUserKeyEphemeral = new EncString(
|
||||
|
@ -101,11 +101,11 @@ describe("PinService", () => {
|
|||
await expect(
|
||||
sut.createPinKeyEncryptedUserKey(mockPin, mockUserKey, undefined),
|
||||
).rejects.toThrow("User ID is required. Cannot create pinKeyEncryptedUserKey.");
|
||||
await expect(sut.getProtectedPin(undefined)).rejects.toThrow(
|
||||
"User ID is required. Cannot get protectedPin.",
|
||||
await expect(sut.getUserKeyEncryptedPin(undefined)).rejects.toThrow(
|
||||
"User ID is required. Cannot get userKeyEncryptedPin.",
|
||||
);
|
||||
await expect(sut.setProtectedPin(mockProtectedPin, undefined)).rejects.toThrow(
|
||||
"User ID is required. Cannot set protectedPin.",
|
||||
await expect(sut.setUserKeyEncryptedPin(mockUserKeyEncryptedPin, undefined)).rejects.toThrow(
|
||||
"User ID is required. Cannot set userKeyEncryptedPin.",
|
||||
);
|
||||
await expect(sut.getOldPinKeyEncryptedMasterKey(undefined)).rejects.toThrow(
|
||||
"User ID is required. Cannot get oldPinKeyEncryptedMasterKey.",
|
||||
|
@ -221,41 +221,44 @@ describe("PinService", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("protectedPin methods", () => {
|
||||
describe("getProtectedPin()", () => {
|
||||
it("should get the protectedPin of the specified userId", async () => {
|
||||
await sut.getProtectedPin(mockUserId);
|
||||
describe("userKeyEncryptedPin methods", () => {
|
||||
describe("getUserKeyEncryptedPin()", () => {
|
||||
it("should get the userKeyEncryptedPin of the specified userId", async () => {
|
||||
await sut.getUserKeyEncryptedPin(mockUserId);
|
||||
|
||||
expect(stateProvider.mock.getUserState$).toHaveBeenCalledWith(PROTECTED_PIN, mockUserId);
|
||||
});
|
||||
});
|
||||
|
||||
describe("setProtectedPin()", () => {
|
||||
it("should set the protectedPin of the specified userId", async () => {
|
||||
await sut.setProtectedPin(mockProtectedPin, mockUserId);
|
||||
|
||||
expect(stateProvider.mock.setUserState).toHaveBeenCalledWith(
|
||||
PROTECTED_PIN,
|
||||
mockProtectedPin,
|
||||
expect(stateProvider.mock.getUserState$).toHaveBeenCalledWith(
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
mockUserId,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createProtectedPin()", () => {
|
||||
describe("setUserKeyEncryptedPin()", () => {
|
||||
it("should set the userKeyEncryptedPin of the specified userId", async () => {
|
||||
await sut.setUserKeyEncryptedPin(mockUserKeyEncryptedPin, mockUserId);
|
||||
|
||||
expect(stateProvider.mock.setUserState).toHaveBeenCalledWith(
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
mockUserKeyEncryptedPin,
|
||||
mockUserId,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("createUserKeyEncryptedPin()", () => {
|
||||
it("should throw an error if a userKey is not provided", async () => {
|
||||
await expect(sut.createProtectedPin(mockPin, undefined)).rejects.toThrow(
|
||||
"No UserKey provided. Cannot create protectedPin.",
|
||||
await expect(sut.createUserKeyEncryptedPin(mockPin, undefined)).rejects.toThrow(
|
||||
"No UserKey provided. Cannot create userKeyEncryptedPin.",
|
||||
);
|
||||
});
|
||||
|
||||
it("should create a protectedPin from the provided PIN and userKey", async () => {
|
||||
encryptService.encrypt.mockResolvedValue(mockProtectedPinEncString);
|
||||
it("should create a userKeyEncryptedPin from the provided PIN and userKey", async () => {
|
||||
encryptService.encrypt.mockResolvedValue(mockUserKeyEncryptedPinEncString);
|
||||
|
||||
const result = await sut.createProtectedPin(mockPin, mockUserKey);
|
||||
const result = await sut.createUserKeyEncryptedPin(mockPin, mockUserKey);
|
||||
|
||||
expect(encryptService.encrypt).toHaveBeenCalledWith(mockPin, mockUserKey);
|
||||
expect(result).toEqual(mockProtectedPinEncString);
|
||||
expect(result).toEqual(mockUserKeyEncryptedPinEncString);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -302,7 +305,7 @@ describe("PinService", () => {
|
|||
|
||||
describe("getPinLockType()", () => {
|
||||
it("should return 'PERSISTENT' if a pinKeyEncryptedUserKey (persistent version) is found", async () => {
|
||||
sut.getProtectedPin = jest.fn().mockResolvedValue(null);
|
||||
sut.getUserKeyEncryptedPin = jest.fn().mockResolvedValue(null);
|
||||
sut.getPinKeyEncryptedUserKey = jest.fn().mockResolvedValue(pinKeyEncryptedUserKeyPersistant);
|
||||
|
||||
const result = await sut.getPinLockType(mockUserId);
|
||||
|
@ -311,7 +314,7 @@ describe("PinService", () => {
|
|||
});
|
||||
|
||||
it("should return 'PERSISTENT' if an old oldPinKeyEncryptedMasterKey is found", async () => {
|
||||
sut.getProtectedPin = jest.fn().mockResolvedValue(null);
|
||||
sut.getUserKeyEncryptedPin = jest.fn().mockResolvedValue(null);
|
||||
sut.getPinKeyEncryptedUserKey = jest.fn().mockResolvedValue(null);
|
||||
sut.getOldPinKeyEncryptedMasterKey = jest
|
||||
.fn()
|
||||
|
@ -322,8 +325,8 @@ describe("PinService", () => {
|
|||
expect(result).toBe("PERSISTENT");
|
||||
});
|
||||
|
||||
it("should return 'EPHEMERAL' if neither a pinKeyEncryptedUserKey (persistent version) nor an old oldPinKeyEncryptedMasterKey are found, but a protectedPin is found", async () => {
|
||||
sut.getProtectedPin = jest.fn().mockResolvedValue(mockProtectedPin);
|
||||
it("should return 'EPHEMERAL' if neither a pinKeyEncryptedUserKey (persistent version) nor an old oldPinKeyEncryptedMasterKey are found, but a userKeyEncryptedPin is found", async () => {
|
||||
sut.getUserKeyEncryptedPin = jest.fn().mockResolvedValue(mockUserKeyEncryptedPin);
|
||||
sut.getPinKeyEncryptedUserKey = jest.fn().mockResolvedValue(null);
|
||||
sut.getOldPinKeyEncryptedMasterKey = jest.fn().mockResolvedValue(null);
|
||||
|
||||
|
@ -332,8 +335,8 @@ describe("PinService", () => {
|
|||
expect(result).toBe("EPHEMERAL");
|
||||
});
|
||||
|
||||
it("should return 'DISABLED' if ALL three of these are NOT found: protectedPin, pinKeyEncryptedUserKey (persistent version), oldPinKeyEncryptedMasterKey", async () => {
|
||||
sut.getProtectedPin = jest.fn().mockResolvedValue(null);
|
||||
it("should return 'DISABLED' if ALL three of these are NOT found: userKeyEncryptedPin, pinKeyEncryptedUserKey (persistent version), oldPinKeyEncryptedMasterKey", async () => {
|
||||
sut.getUserKeyEncryptedPin = jest.fn().mockResolvedValue(null);
|
||||
sut.getPinKeyEncryptedUserKey = jest.fn().mockResolvedValue(null);
|
||||
sut.getOldPinKeyEncryptedMasterKey = jest.fn().mockResolvedValue(null);
|
||||
|
||||
|
@ -382,7 +385,7 @@ describe("PinService", () => {
|
|||
mockDecryptUserKeyFn();
|
||||
}
|
||||
|
||||
sut.getProtectedPin = jest.fn().mockResolvedValue(mockProtectedPin);
|
||||
sut.getUserKeyEncryptedPin = jest.fn().mockResolvedValue(mockUserKeyEncryptedPin);
|
||||
encryptService.decryptToUtf8.mockResolvedValue(mockPin);
|
||||
}
|
||||
|
||||
|
@ -399,8 +402,11 @@ describe("PinService", () => {
|
|||
|
||||
await sut.storePinKeyEncryptedUserKey(pinKeyEncryptedUserKeyPersistant, false, mockUserId);
|
||||
|
||||
sut.createProtectedPin = jest.fn().mockResolvedValue(mockProtectedPinEncString);
|
||||
await sut.setProtectedPin(mockProtectedPinEncString.encryptedString, mockUserId);
|
||||
sut.createUserKeyEncryptedPin = jest.fn().mockResolvedValue(mockUserKeyEncryptedPinEncString);
|
||||
await sut.setUserKeyEncryptedPin(
|
||||
mockUserKeyEncryptedPinEncString.encryptedString,
|
||||
mockUserId,
|
||||
);
|
||||
|
||||
await sut.clearOldPinKeyEncryptedMasterKey(mockUserId);
|
||||
|
||||
|
|
|
@ -254,15 +254,15 @@ describe("cryptoService", () => {
|
|||
});
|
||||
|
||||
describe("Pin Key refresh", () => {
|
||||
const protectedPin =
|
||||
const userKeyEncryptedPin =
|
||||
"2.jcow2vTUePO+CCyokcIfVw==|DTBNlJ5yVsV2Bsk3UU3H6Q==|YvFBff5gxWqM+UsFB6BKimKxhC32AtjF3IStpU1Ijwg=";
|
||||
const encString = new EncString(
|
||||
"2.jcow2vTUePO+CCyokcIfVw==|DTBNlJ5yVsV2Bsk3UU3H6Q==|YvFBff5gxWqM+UsFB6BKimKxhC32AtjF3IStpU1Ijwg=",
|
||||
);
|
||||
|
||||
it("sets a pinKeyEncryptedUserKey if a ProtectedPin and pinKeyEncryptedUserKey is set", async () => {
|
||||
it("sets a pinKeyEncryptedUserKey if a UserKeyEncryptedPin and pinKeyEncryptedUserKey is set", async () => {
|
||||
pinService.createPinKeyEncryptedUserKey.mockResolvedValue(encString);
|
||||
pinService.getProtectedPin.mockResolvedValue(protectedPin);
|
||||
pinService.getUserKeyEncryptedPin.mockResolvedValue(userKeyEncryptedPin);
|
||||
pinService.getPinKeyEncryptedUserKey.mockResolvedValue(
|
||||
new EncString(
|
||||
"2.OdGNE3L23GaDZGvu9h2Brw==|/OAcNnrYwu0rjiv8+RUr3Tc+Ef8fV035Tm1rbTxfEuC+2LZtiCAoIvHIZCrM/V1PWnb/pHO2gh9+Koks04YhX8K29ED4FzjeYP8+YQD/dWo=|+12xTcIK/UVRsOyawYudPMHb6+lCHeR2Peq1pQhPm0A=",
|
||||
|
@ -278,9 +278,9 @@ describe("cryptoService", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("sets a pinKeyEncryptedUserKeyEphemeral if a ProtectedPin is set, but a pinKeyEncryptedUserKey is not set", async () => {
|
||||
it("sets a pinKeyEncryptedUserKeyEphemeral if a UserKeyEncryptedPin is set, but a pinKeyEncryptedUserKey is not set", async () => {
|
||||
pinService.createPinKeyEncryptedUserKey.mockResolvedValue(encString);
|
||||
pinService.getProtectedPin.mockResolvedValue(protectedPin);
|
||||
pinService.getUserKeyEncryptedPin.mockResolvedValue(userKeyEncryptedPin);
|
||||
pinService.getPinKeyEncryptedUserKey.mockResolvedValue(null);
|
||||
|
||||
await cryptoService.setUserKey(mockUserKey, mockUserId);
|
||||
|
@ -292,8 +292,8 @@ describe("cryptoService", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("clears the pinKeyEncryptedUserKey and pinKeyEncryptedUserKeyEphemeral if the ProtectedPin is not set", async () => {
|
||||
pinService.getProtectedPin.mockResolvedValue(null);
|
||||
it("clears the pinKeyEncryptedUserKey and pinKeyEncryptedUserKeyEphemeral if the UserKeyEncryptedPin is not set", async () => {
|
||||
pinService.getUserKeyEncryptedPin.mockResolvedValue(null);
|
||||
|
||||
await cryptoService.setUserKey(mockUserKey, mockUserId);
|
||||
|
||||
|
|
|
@ -518,7 +518,7 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||
|
||||
await this.pinService.clearPinKeyEncryptedUserKey(userId);
|
||||
await this.pinService.clearPinKeyEncryptedUserKeyEphemeral(userId);
|
||||
await this.pinService.setProtectedPin(null, userId);
|
||||
await this.pinService.setUserKeyEncryptedPin(null, userId);
|
||||
await this.clearDeprecatedKeys(KeySuffixOptions.Pin, userId);
|
||||
}
|
||||
|
||||
|
@ -741,9 +741,9 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||
|
||||
const storePin = await this.shouldStoreKey(KeySuffixOptions.Pin, userId);
|
||||
if (storePin) {
|
||||
// Decrypt protectedPin with user key
|
||||
// Decrypt userKeyEncryptedPin with user key
|
||||
const pin = await this.encryptService.decryptToUtf8(
|
||||
new EncString(await this.pinService.getProtectedPin(userId)),
|
||||
new EncString(await this.pinService.getUserKeyEncryptedPin(userId)),
|
||||
key,
|
||||
);
|
||||
|
||||
|
@ -778,8 +778,8 @@ export class CryptoService implements CryptoServiceAbstraction {
|
|||
break;
|
||||
}
|
||||
case KeySuffixOptions.Pin: {
|
||||
const protectedPin = await this.pinService.getProtectedPin(userId);
|
||||
shouldStoreKey = !!protectedPin;
|
||||
const userKeyEncryptedPin = await this.pinService.getUserKeyEncryptedPin(userId);
|
||||
shouldStoreKey = !!userKeyEncryptedPin;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import { mockMigrationHelper } from "../migration-helper.spec";
|
|||
import {
|
||||
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
|
||||
PIN_KEY_ENCRYPTED_USER_KEY,
|
||||
PROTECTED_PIN,
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
PinStateMigrator,
|
||||
} from "./61-move-pin-state-to-providers";
|
||||
|
||||
|
@ -31,7 +31,7 @@ function preMigrationState() {
|
|||
"AccountOne": {
|
||||
settings: {
|
||||
pinKeyEncryptedUserKey: "AccountOne_pinKeyEncryptedUserKey",
|
||||
protectedPin: "AccountOne_protectedPin",
|
||||
protectedPin: "AccountOne_userKeyEncryptedPin", // note the name change
|
||||
pinProtected: {
|
||||
encrypted: "AccountOne_oldPinKeyEncryptedMasterKey", // note the name change
|
||||
},
|
||||
|
@ -51,7 +51,7 @@ function preMigrationState() {
|
|||
function postMigrationState() {
|
||||
return {
|
||||
user_AccountOne_pinUnlock_pinKeyEncryptedUserKey: "AccountOne_pinKeyEncryptedUserKey",
|
||||
user_AccountOne_pinUnlock_protectedPin: "AccountOne_protectedPin",
|
||||
user_AccountOne_pinUnlock_userKeyEncryptedPin: "AccountOne_userKeyEncryptedPin",
|
||||
user_AccountOne_pinUnlock_oldPinKeyEncryptedMasterKey: "AccountOne_oldPinKeyEncryptedMasterKey",
|
||||
authenticatedAccounts: ["AccountOne", "AccountTwo"],
|
||||
global: {
|
||||
|
@ -108,7 +108,7 @@ describe("PinStateMigrator", () => {
|
|||
expect(helper.set).not.toHaveBeenCalledWith("AccountTwo");
|
||||
});
|
||||
|
||||
it("should set the properties (pinKeyEncryptedUserKey, protectedPin, oldPinKeyEncryptedMasterKey) under the new key definitions", async () => {
|
||||
it("should set the properties (pinKeyEncryptedUserKey, userKeyEncryptedPin, oldPinKeyEncryptedMasterKey) under the new key definitions", async () => {
|
||||
await sut.migrate(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||
|
@ -119,8 +119,8 @@ describe("PinStateMigrator", () => {
|
|||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||
"AccountOne",
|
||||
PROTECTED_PIN,
|
||||
"AccountOne_protectedPin",
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
"AccountOne_userKeyEncryptedPin",
|
||||
);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||
|
@ -139,11 +139,11 @@ describe("PinStateMigrator", () => {
|
|||
sut = new PinStateMigrator(60, 61);
|
||||
});
|
||||
|
||||
it("should null out the previously migrated values (pinKeyEncryptedUserKey, protectedPin, oldPinKeyEncryptedMasterKey)", async () => {
|
||||
it("should null out the previously migrated values (pinKeyEncryptedUserKey, userKeyEncryptedPin, oldPinKeyEncryptedMasterKey)", async () => {
|
||||
await sut.rollback(helper);
|
||||
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("AccountOne", PIN_KEY_ENCRYPTED_USER_KEY, null);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("AccountOne", PROTECTED_PIN, null);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith("AccountOne", USER_KEY_ENCRYPTED_PIN, null);
|
||||
expect(helper.setToUser).toHaveBeenCalledWith(
|
||||
"AccountOne",
|
||||
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
|
||||
|
@ -158,9 +158,9 @@ describe("PinStateMigrator", () => {
|
|||
expect(helper.set).toHaveBeenCalledWith("AccountOne", {
|
||||
settings: {
|
||||
pinKeyEncryptedUserKey: "AccountOne_pinKeyEncryptedUserKey",
|
||||
protectedPin: "AccountOne_protectedPin",
|
||||
protectedPin: "AccountOne_userKeyEncryptedPin",
|
||||
pinProtected: {
|
||||
encrypted: "AccountOne_oldPinKeyEncryptedMasterKey", // note the name change
|
||||
encrypted: "AccountOne_oldPinKeyEncryptedMasterKey",
|
||||
},
|
||||
otherStuff: "otherStuff2",
|
||||
},
|
||||
|
|
|
@ -4,7 +4,7 @@ import { Migrator } from "../migrator";
|
|||
type ExpectedAccountState = {
|
||||
settings?: {
|
||||
pinKeyEncryptedUserKey?: string; // EncryptedString
|
||||
protectedPin?: string;
|
||||
protectedPin?: string; // EncryptedString
|
||||
pinProtected?: {
|
||||
encrypted?: string;
|
||||
};
|
||||
|
@ -18,9 +18,9 @@ export const PIN_KEY_ENCRYPTED_USER_KEY: KeyDefinitionLike = {
|
|||
key: "pinKeyEncryptedUserKey",
|
||||
};
|
||||
|
||||
export const PROTECTED_PIN: KeyDefinitionLike = {
|
||||
export const USER_KEY_ENCRYPTED_PIN: KeyDefinitionLike = {
|
||||
stateDefinition: PIN_STATE,
|
||||
key: "protectedPin",
|
||||
key: "userKeyEncryptedPin",
|
||||
};
|
||||
|
||||
export const OLD_PIN_KEY_ENCRYPTED_MASTER_KEY: KeyDefinitionLike = {
|
||||
|
@ -45,14 +45,14 @@ export class PinStateMigrator extends Migrator<60, 61> {
|
|||
updatedAccount = true;
|
||||
}
|
||||
|
||||
// Migrate protectedPin
|
||||
// Migrate protectedPin (to USER_KEY_ENCRYPTED_PIN)
|
||||
if (account?.settings?.protectedPin != null) {
|
||||
await helper.setToUser(userId, PROTECTED_PIN, account.settings.protectedPin);
|
||||
await helper.setToUser(userId, USER_KEY_ENCRYPTED_PIN, account.settings.protectedPin);
|
||||
delete account.settings.protectedPin;
|
||||
updatedAccount = true;
|
||||
}
|
||||
|
||||
// Migrate pinProtected
|
||||
// Migrate pinProtected (to OLD_PIN_KEY_ENCRYPTED_MASTER_KEY)
|
||||
if (account?.settings?.pinProtected?.encrypted != null) {
|
||||
await helper.setToUser(
|
||||
userId,
|
||||
|
@ -83,7 +83,10 @@ export class PinStateMigrator extends Migrator<60, 61> {
|
|||
userId,
|
||||
PIN_KEY_ENCRYPTED_USER_KEY,
|
||||
);
|
||||
const accountProtectedPin = await helper.getFromUser<string>(userId, PROTECTED_PIN);
|
||||
const accountUserKeyEncryptedPin = await helper.getFromUser<string>(
|
||||
userId,
|
||||
USER_KEY_ENCRYPTED_PIN,
|
||||
);
|
||||
const accountOldPinKeyEncryptedMasterKey = await helper.getFromUser<string>(
|
||||
userId,
|
||||
OLD_PIN_KEY_ENCRYPTED_MASTER_KEY,
|
||||
|
@ -99,9 +102,9 @@ export class PinStateMigrator extends Migrator<60, 61> {
|
|||
updatedAccount = true;
|
||||
}
|
||||
|
||||
if (accountProtectedPin != null) {
|
||||
account.settings.protectedPin = accountProtectedPin;
|
||||
await helper.setToUser(userId, PROTECTED_PIN, null);
|
||||
if (accountUserKeyEncryptedPin != null) {
|
||||
account.settings.protectedPin = accountUserKeyEncryptedPin;
|
||||
await helper.setToUser(userId, USER_KEY_ENCRYPTED_PIN, null);
|
||||
updatedAccount = true;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue