rename protectedPin to userKeyEncryptedPin

This commit is contained in:
rr-bw 2024-05-06 13:15:57 -07:00
parent a11aeb8710
commit 2456037db0
No known key found for this signature in database
GPG Key ID: 3FA13C3ADEE51D5D
8 changed files with 165 additions and 140 deletions

View File

@ -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,

View File

@ -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.
*/

View File

@ -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,
);

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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",
},

View File

@ -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;
}