[bug] Assign client specific account settings during migration (#653)
* [bug] Assign client specific account settings during migration * [refactor] Write State type arguements in consistent order * [style] Ran prettier
This commit is contained in:
parent
ca5c6a9c32
commit
067cd1e0e1
|
@ -360,7 +360,7 @@ import { StateFactory } from "jslib-common/factories/stateFactory";
|
||||||
new StateMigrationService(
|
new StateMigrationService(
|
||||||
storageService,
|
storageService,
|
||||||
secureStorageService,
|
secureStorageService,
|
||||||
new GlobalStateFactory(GlobalState)
|
new StateFactory(GlobalState, Account)
|
||||||
),
|
),
|
||||||
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
deps: [StorageServiceAbstraction, "SECURE_STORAGE"],
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,10 @@ import { GlobalState } from "../models/domain/globalState";
|
||||||
import { AccountFactory } from "./accountFactory";
|
import { AccountFactory } from "./accountFactory";
|
||||||
import { GlobalStateFactory } from "./globalStateFactory";
|
import { GlobalStateFactory } from "./globalStateFactory";
|
||||||
|
|
||||||
export class StateFactory<TAccount extends Account, TGlobal extends GlobalState> {
|
export class StateFactory<
|
||||||
|
TGlobal extends GlobalState = GlobalState,
|
||||||
|
TAccount extends Account = Account
|
||||||
|
> {
|
||||||
private globalStateFactory: GlobalStateFactory<TGlobal>;
|
private globalStateFactory: GlobalStateFactory<TGlobal>;
|
||||||
private accountFactory: AccountFactory<TAccount>;
|
private accountFactory: AccountFactory<TAccount>;
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ import { Account } from "./account";
|
||||||
import { GlobalState } from "./globalState";
|
import { GlobalState } from "./globalState";
|
||||||
|
|
||||||
export class State<
|
export class State<
|
||||||
TAccount extends Account = Account,
|
TGlobalState extends GlobalState = GlobalState,
|
||||||
TGlobalState extends GlobalState = GlobalState
|
TAccount extends Account = Account
|
||||||
> {
|
> {
|
||||||
accounts: { [userId: string]: TAccount } = {};
|
accounts: { [userId: string]: TAccount } = {};
|
||||||
globals: TGlobalState;
|
globals: TGlobalState;
|
||||||
|
|
|
@ -55,14 +55,14 @@ const partialKeys = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export class StateService<
|
export class StateService<
|
||||||
TAccount extends Account = Account,
|
TGlobalState extends GlobalState = GlobalState,
|
||||||
TGlobalState extends GlobalState = GlobalState
|
TAccount extends Account = Account
|
||||||
> implements StateServiceAbstraction<TAccount>
|
> implements StateServiceAbstraction<TAccount>
|
||||||
{
|
{
|
||||||
accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
accounts = new BehaviorSubject<{ [userId: string]: TAccount }>({});
|
||||||
activeAccount = new BehaviorSubject<string>(null);
|
activeAccount = new BehaviorSubject<string>(null);
|
||||||
|
|
||||||
protected state: State<TAccount, TGlobalState> = new State<TAccount, TGlobalState>(
|
protected state: State<TGlobalState, TAccount> = new State<TGlobalState, TAccount>(
|
||||||
this.createGlobals()
|
this.createGlobals()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ export class StateService<
|
||||||
protected secureStorageService: StorageService,
|
protected secureStorageService: StorageService,
|
||||||
protected logService: LogService,
|
protected logService: LogService,
|
||||||
protected stateMigrationService: StateMigrationService,
|
protected stateMigrationService: StateMigrationService,
|
||||||
protected stateFactory: StateFactory<TAccount, TGlobalState>
|
protected stateFactory: StateFactory<TGlobalState, TAccount>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async init(): Promise<void> {
|
async init(): Promise<void> {
|
||||||
|
@ -2233,7 +2233,6 @@ export class StateService<
|
||||||
account.settings = await this.storageService.get<any>(keys.tempAccountSettings);
|
account.settings = await this.storageService.get<any>(keys.tempAccountSettings);
|
||||||
await this.storageService.remove(keys.tempAccountSettings);
|
await this.storageService.remove(keys.tempAccountSettings);
|
||||||
}
|
}
|
||||||
Object.assign(account.settings, this.createAccount().settings);
|
|
||||||
account.settings.environmentUrls = environmentUrls;
|
account.settings.environmentUrls = environmentUrls;
|
||||||
await this.storageService.save(
|
await this.storageService.save(
|
||||||
account.profile.userId,
|
account.profile.userId,
|
||||||
|
|
|
@ -21,6 +21,8 @@ import { ThemeType } from "../enums/themeType";
|
||||||
import { EnvironmentUrls } from "../models/domain/environmentUrls";
|
import { EnvironmentUrls } from "../models/domain/environmentUrls";
|
||||||
|
|
||||||
import { GlobalStateFactory } from "../factories/globalStateFactory";
|
import { GlobalStateFactory } from "../factories/globalStateFactory";
|
||||||
|
import { StateFactory } from "../factories/stateFactory";
|
||||||
|
import { Account, AccountSettings } from "../models/domain/account";
|
||||||
|
|
||||||
// Originally (before January 2022) storage was handled as a flat key/value pair store.
|
// Originally (before January 2022) storage was handled as a flat key/value pair store.
|
||||||
// With the move to a typed object for state storage these keys should no longer be in use anywhere outside of this migration.
|
// With the move to a typed object for state storage these keys should no longer be in use anywhere outside of this migration.
|
||||||
|
@ -128,11 +130,14 @@ const partialKeys = {
|
||||||
masterKey: "_masterkey",
|
masterKey: "_masterkey",
|
||||||
};
|
};
|
||||||
|
|
||||||
export class StateMigrationService<TGlobalState extends GlobalState = GlobalState> {
|
export class StateMigrationService<
|
||||||
|
TGlobalState extends GlobalState = GlobalState,
|
||||||
|
TAccount extends Account = Account
|
||||||
|
> {
|
||||||
constructor(
|
constructor(
|
||||||
protected storageService: StorageService,
|
protected storageService: StorageService,
|
||||||
protected secureStorageService: StorageService,
|
protected secureStorageService: StorageService,
|
||||||
protected globalStateFactory: GlobalStateFactory<TGlobalState>
|
protected stateFactory: StateFactory<TGlobalState, TAccount>
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async needsMigration(): Promise<boolean> {
|
async needsMigration(): Promise<boolean> {
|
||||||
|
@ -177,7 +182,8 @@ export class StateMigrationService<TGlobalState extends GlobalState = GlobalStat
|
||||||
// 1. Check for an existing storage value from the old storage structure OR
|
// 1. Check for an existing storage value from the old storage structure OR
|
||||||
// 2. Check for a value already set by processes that run before migration OR
|
// 2. Check for a value already set by processes that run before migration OR
|
||||||
// 3. Assign the default value
|
// 3. Assign the default value
|
||||||
const globals = (await this.get<GlobalState>(keys.global)) ?? this.globalStateFactory.create();
|
const globals =
|
||||||
|
(await this.get<GlobalState>(keys.global)) ?? this.stateFactory.createGlobal(null);
|
||||||
globals.stateVersion = StateVersion.Two;
|
globals.stateVersion = StateVersion.Two;
|
||||||
globals.environmentUrls =
|
globals.environmentUrls =
|
||||||
(await this.get<EnvironmentUrls>(v1Keys.environmentUrls)) ?? globals.environmentUrls;
|
(await this.get<EnvironmentUrls>(v1Keys.environmentUrls)) ?? globals.environmentUrls;
|
||||||
|
@ -220,46 +226,91 @@ export class StateMigrationService<TGlobalState extends GlobalState = GlobalStat
|
||||||
const userId =
|
const userId =
|
||||||
(await this.get<string>(v1Keys.userId)) ?? (await this.get<string>(v1Keys.entityId));
|
(await this.get<string>(v1Keys.userId)) ?? (await this.get<string>(v1Keys.entityId));
|
||||||
|
|
||||||
|
const defaultAccount = this.stateFactory.createAccount(null);
|
||||||
|
const accountSettings: AccountSettings = {
|
||||||
|
autoConfirmFingerPrints:
|
||||||
|
(await this.get<boolean>(v1Keys.autoConfirmFingerprints)) ??
|
||||||
|
defaultAccount.settings.autoConfirmFingerPrints,
|
||||||
|
autoFillOnPageLoadDefault:
|
||||||
|
(await this.get<boolean>(v1Keys.autoFillOnPageLoadDefault)) ??
|
||||||
|
defaultAccount.settings.autoFillOnPageLoadDefault,
|
||||||
|
biometricLocked: null,
|
||||||
|
biometricUnlock:
|
||||||
|
(await this.get<boolean>(v1Keys.biometricUnlock)) ??
|
||||||
|
defaultAccount.settings.biometricUnlock,
|
||||||
|
clearClipboard:
|
||||||
|
(await this.get<number>(v1Keys.clearClipboard)) ?? defaultAccount.settings.clearClipboard,
|
||||||
|
defaultUriMatch:
|
||||||
|
(await this.get<any>(v1Keys.defaultUriMatch)) ?? defaultAccount.settings.defaultUriMatch,
|
||||||
|
disableAddLoginNotification:
|
||||||
|
(await this.get<boolean>(v1Keys.disableAddLoginNotification)) ??
|
||||||
|
defaultAccount.settings.disableAddLoginNotification,
|
||||||
|
disableAutoBiometricsPrompt:
|
||||||
|
(await this.get<boolean>(v1Keys.disableAutoBiometricsPrompt)) ??
|
||||||
|
defaultAccount.settings.disableAutoBiometricsPrompt,
|
||||||
|
disableAutoTotpCopy:
|
||||||
|
(await this.get<boolean>(v1Keys.disableAutoTotpCopy)) ??
|
||||||
|
defaultAccount.settings.disableAutoTotpCopy,
|
||||||
|
disableBadgeCounter:
|
||||||
|
(await this.get<boolean>(v1Keys.disableBadgeCounter)) ??
|
||||||
|
defaultAccount.settings.disableBadgeCounter,
|
||||||
|
disableChangedPasswordNotification:
|
||||||
|
(await this.get<boolean>(v1Keys.disableChangedPasswordNotification)) ??
|
||||||
|
defaultAccount.settings.disableChangedPasswordNotification,
|
||||||
|
disableContextMenuItem:
|
||||||
|
(await this.get<boolean>(v1Keys.disableContextMenuItem)) ??
|
||||||
|
defaultAccount.settings.disableContextMenuItem,
|
||||||
|
disableGa: (await this.get<boolean>(v1Keys.disableGa)) ?? defaultAccount.settings.disableGa,
|
||||||
|
dontShowCardsCurrentTab:
|
||||||
|
(await this.get<boolean>(v1Keys.dontShowCardsCurrentTab)) ??
|
||||||
|
defaultAccount.settings.dontShowCardsCurrentTab,
|
||||||
|
dontShowIdentitiesCurrentTab:
|
||||||
|
(await this.get<boolean>(v1Keys.dontShowIdentitiesCurrentTab)) ??
|
||||||
|
defaultAccount.settings.dontShowIdentitiesCurrentTab,
|
||||||
|
enableAlwaysOnTop:
|
||||||
|
(await this.get<boolean>(v1Keys.enableAlwaysOnTop)) ??
|
||||||
|
defaultAccount.settings.enableAlwaysOnTop,
|
||||||
|
enableAutoFillOnPageLoad:
|
||||||
|
(await this.get<boolean>(v1Keys.enableAutoFillOnPageLoad)) ??
|
||||||
|
defaultAccount.settings.enableAutoFillOnPageLoad,
|
||||||
|
enableBiometric:
|
||||||
|
(await this.get<boolean>(v1Keys.enableBiometric)) ??
|
||||||
|
defaultAccount.settings.enableBiometric,
|
||||||
|
enableFullWidth:
|
||||||
|
(await this.get<boolean>(v1Keys.enableFullWidth)) ??
|
||||||
|
defaultAccount.settings.enableFullWidth,
|
||||||
|
enableGravitars:
|
||||||
|
(await this.get<boolean>(v1Keys.enableGravatars)) ??
|
||||||
|
defaultAccount.settings.enableGravitars,
|
||||||
|
environmentUrls: globals.environmentUrls ?? defaultAccount.settings.environmentUrls,
|
||||||
|
equivalentDomains:
|
||||||
|
(await this.get<any>(v1Keys.equivalentDomains)) ??
|
||||||
|
defaultAccount.settings.equivalentDomains,
|
||||||
|
minimizeOnCopyToClipboard:
|
||||||
|
(await this.get<boolean>(v1Keys.minimizeOnCopyToClipboard)) ??
|
||||||
|
defaultAccount.settings.minimizeOnCopyToClipboard,
|
||||||
|
neverDomains:
|
||||||
|
(await this.get<any>(v1Keys.neverDomains)) ?? defaultAccount.settings.neverDomains,
|
||||||
|
passwordGenerationOptions:
|
||||||
|
(await this.get<any>(v1Keys.passwordGenerationOptions)) ??
|
||||||
|
defaultAccount.settings.passwordGenerationOptions,
|
||||||
|
pinProtected: {
|
||||||
|
decrypted: null,
|
||||||
|
encrypted: await this.get<string>(v1Keys.pinProtected),
|
||||||
|
},
|
||||||
|
protectedPin: await this.get<string>(v1Keys.protectedPin),
|
||||||
|
settings: userId == null ? null : await this.get<any>(v1KeyPrefixes.settings + userId),
|
||||||
|
vaultTimeout:
|
||||||
|
(await this.get<number>(v1Keys.vaultTimeout)) ?? defaultAccount.settings.vaultTimeout,
|
||||||
|
vaultTimeoutAction:
|
||||||
|
(await this.get<string>(v1Keys.vaultTimeoutAction)) ??
|
||||||
|
defaultAccount.settings.vaultTimeoutAction,
|
||||||
|
};
|
||||||
|
|
||||||
// (userId == null) = no logged in user (so no known userId) and we need to temporarily store account specific settings in state to migrate on first auth
|
// (userId == null) = no logged in user (so no known userId) and we need to temporarily store account specific settings in state to migrate on first auth
|
||||||
// (userId != null) = we have a currently authed user (so known userId) with encrypted data and other key settings we can move, no need to temporarily store account settings
|
// (userId != null) = we have a currently authed user (so known userId) with encrypted data and other key settings we can move, no need to temporarily store account settings
|
||||||
if (userId == null) {
|
if (userId == null) {
|
||||||
await this.set(keys.tempAccountSettings, {
|
await this.set(keys.tempAccountSettings, accountSettings);
|
||||||
autoConfirmFingerPrints: await this.get<boolean>(v1Keys.autoConfirmFingerprints),
|
|
||||||
autoFillOnPageLoadDefault: await this.get<boolean>(v1Keys.autoFillOnPageLoadDefault),
|
|
||||||
biometricLocked: null,
|
|
||||||
biometricUnlock: await this.get<boolean>(v1Keys.biometricUnlock),
|
|
||||||
clearClipboard: await this.get<number>(v1Keys.clearClipboard),
|
|
||||||
defaultUriMatch: await this.get<any>(v1Keys.defaultUriMatch),
|
|
||||||
disableAddLoginNotification: await this.get<boolean>(v1Keys.disableAddLoginNotification),
|
|
||||||
disableAutoBiometricsPrompt: await this.get<boolean>(v1Keys.disableAutoBiometricsPrompt),
|
|
||||||
disableAutoTotpCopy: await this.get<boolean>(v1Keys.disableAutoTotpCopy),
|
|
||||||
disableBadgeCounter: await this.get<boolean>(v1Keys.disableBadgeCounter),
|
|
||||||
disableChangedPasswordNotification: await this.get<boolean>(
|
|
||||||
v1Keys.disableChangedPasswordNotification
|
|
||||||
),
|
|
||||||
disableContextMenuItem: await this.get<boolean>(v1Keys.disableContextMenuItem),
|
|
||||||
disableGa: await this.get<boolean>(v1Keys.disableGa),
|
|
||||||
dontShowCardsCurrentTab: await this.get<boolean>(v1Keys.dontShowCardsCurrentTab),
|
|
||||||
dontShowIdentitiesCurrentTab: await this.get<boolean>(v1Keys.dontShowIdentitiesCurrentTab),
|
|
||||||
enableAlwaysOnTop: await this.get<boolean>(v1Keys.enableAlwaysOnTop),
|
|
||||||
enableAutoFillOnPageLoad: await this.get<boolean>(v1Keys.enableAutoFillOnPageLoad),
|
|
||||||
enableBiometric: await this.get<boolean>(v1Keys.enableBiometric),
|
|
||||||
enableFullWidth: await this.get<boolean>(v1Keys.enableFullWidth),
|
|
||||||
enableGravitars: await this.get<boolean>(v1Keys.enableGravatars),
|
|
||||||
environmentUrls: globals.environmentUrls,
|
|
||||||
equivalentDomains: await this.get<any>(v1Keys.equivalentDomains),
|
|
||||||
minimizeOnCopyToClipboard: await this.get<boolean>(v1Keys.minimizeOnCopyToClipboard),
|
|
||||||
neverDomains: await this.get<any>(v1Keys.neverDomains),
|
|
||||||
passwordGenerationOptions: await this.get<any>(v1Keys.passwordGenerationOptions),
|
|
||||||
pinProtected: {
|
|
||||||
decrypted: null,
|
|
||||||
encrypted: await this.get<string>(v1Keys.pinProtected),
|
|
||||||
},
|
|
||||||
protectedPin: await this.get<string>(v1Keys.protectedPin),
|
|
||||||
settings: null,
|
|
||||||
vaultTimeout: await this.get<number>(v1Keys.vaultTimeout),
|
|
||||||
vaultTimeoutAction: await this.get<string>(v1Keys.vaultTimeoutAction),
|
|
||||||
});
|
|
||||||
await this.set(keys.global, globals);
|
await this.set(keys.global, globals);
|
||||||
await this.set(keys.authenticatedAccounts, []);
|
await this.set(keys.authenticatedAccounts, []);
|
||||||
await this.set(keys.activeUserId, null);
|
await this.set(keys.activeUserId, null);
|
||||||
|
@ -350,43 +401,7 @@ export class StateMigrationService<TGlobalState extends GlobalState = GlobalStat
|
||||||
userId: userId,
|
userId: userId,
|
||||||
usesKeyConnector: null,
|
usesKeyConnector: null,
|
||||||
},
|
},
|
||||||
settings: {
|
settings: accountSettings,
|
||||||
autoConfirmFingerPrints: await this.get<boolean>(v1Keys.autoConfirmFingerprints),
|
|
||||||
autoFillOnPageLoadDefault: await this.get<boolean>(v1Keys.autoFillOnPageLoadDefault),
|
|
||||||
biometricLocked: null,
|
|
||||||
biometricUnlock: await this.get<boolean>(v1Keys.biometricUnlock),
|
|
||||||
clearClipboard: await this.get<number>(v1Keys.clearClipboard),
|
|
||||||
defaultUriMatch: await this.get<any>(v1Keys.defaultUriMatch),
|
|
||||||
disableAddLoginNotification: await this.get<boolean>(v1Keys.disableAddLoginNotification),
|
|
||||||
disableAutoBiometricsPrompt: await this.get<boolean>(v1Keys.disableAutoBiometricsPrompt),
|
|
||||||
disableAutoTotpCopy: await this.get<boolean>(v1Keys.disableAutoTotpCopy),
|
|
||||||
disableBadgeCounter: await this.get<boolean>(v1Keys.disableBadgeCounter),
|
|
||||||
disableChangedPasswordNotification: await this.get<boolean>(
|
|
||||||
v1Keys.disableChangedPasswordNotification
|
|
||||||
),
|
|
||||||
disableContextMenuItem: await this.get<boolean>(v1Keys.disableContextMenuItem),
|
|
||||||
disableGa: await this.get<boolean>(v1Keys.disableGa),
|
|
||||||
dontShowCardsCurrentTab: await this.get<boolean>(v1Keys.dontShowCardsCurrentTab),
|
|
||||||
dontShowIdentitiesCurrentTab: await this.get<boolean>(v1Keys.dontShowIdentitiesCurrentTab),
|
|
||||||
enableAlwaysOnTop: await this.get<boolean>(v1Keys.enableAlwaysOnTop),
|
|
||||||
enableAutoFillOnPageLoad: await this.get<boolean>(v1Keys.enableAutoFillOnPageLoad),
|
|
||||||
enableBiometric: await this.get<boolean>(v1Keys.enableBiometric),
|
|
||||||
enableFullWidth: await this.get<boolean>(v1Keys.enableFullWidth),
|
|
||||||
enableGravitars: await this.get<boolean>(v1Keys.enableGravatars),
|
|
||||||
environmentUrls: globals.environmentUrls,
|
|
||||||
equivalentDomains: await this.get<any>(v1Keys.equivalentDomains),
|
|
||||||
minimizeOnCopyToClipboard: await this.get<boolean>(v1Keys.minimizeOnCopyToClipboard),
|
|
||||||
neverDomains: await this.get<any>(v1Keys.neverDomains),
|
|
||||||
passwordGenerationOptions: await this.get<any>(v1Keys.passwordGenerationOptions),
|
|
||||||
pinProtected: {
|
|
||||||
decrypted: null,
|
|
||||||
encrypted: await this.get<string>(v1Keys.pinProtected),
|
|
||||||
},
|
|
||||||
protectedPin: await this.get<string>(v1Keys.protectedPin),
|
|
||||||
settings: await this.get<any>(v1KeyPrefixes.settings + userId),
|
|
||||||
vaultTimeout: await this.get<number>(v1Keys.vaultTimeout),
|
|
||||||
vaultTimeoutAction: await this.get<string>(v1Keys.vaultTimeoutAction),
|
|
||||||
},
|
|
||||||
tokens: {
|
tokens: {
|
||||||
accessToken: await this.get<string>(v1Keys.accessToken),
|
accessToken: await this.get<string>(v1Keys.accessToken),
|
||||||
decodedToken: null,
|
decodedToken: null,
|
||||||
|
|
Loading…
Reference in New Issue