1
0
mirror of https://github.com/bitwarden/jslib synced 2025-12-19 17:53:48 +00:00

[feature] Implement account switching capable services across components and processes

* Replace calls to StorageService and deprecated services with calls to a StateService
This commit is contained in:
addison
2021-11-01 14:03:13 -04:00
parent 52d251db6c
commit 54fa024eb4
29 changed files with 273 additions and 328 deletions

View File

@@ -22,10 +22,10 @@ import { FolderService } from 'jslib-common/abstractions/folder.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { OrganizationService } from 'jslib-common/abstractions/organization.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { Cipher } from 'jslib-common/models/domain/cipher'; import { Cipher } from 'jslib-common/models/domain/cipher';
@@ -87,9 +87,9 @@ export class AddEditComponent implements OnInit {
constructor(protected cipherService: CipherService, protected folderService: FolderService, constructor(protected cipherService: CipherService, protected folderService: FolderService,
protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService, protected stateService: StateService, protected auditService: AuditService, protected stateService: StateService,
protected userService: UserService, protected collectionService: CollectionService, protected collectionService: CollectionService, protected messagingService: MessagingService,
protected messagingService: MessagingService, protected eventService: EventService, protected eventService: EventService, protected policyService: PolicyService,
protected policyService: PolicyService, private logService: LogService) { private logService: LogService, private organizationService: OrganizationService) {
this.typeOptions = [ this.typeOptions = [
{ name: i18nService.t('typeLogin'), value: CipherType.Login }, { name: i18nService.t('typeLogin'), value: CipherType.Login },
{ name: i18nService.t('typeCard'), value: CipherType.Card }, { name: i18nService.t('typeCard'), value: CipherType.Card },
@@ -154,11 +154,11 @@ export class AddEditComponent implements OnInit {
if (await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership)) { if (await this.policyService.policyAppliesToUser(PolicyType.PersonalOwnership)) {
this.allowPersonal = false; this.allowPersonal = false;
} else { } else {
const myEmail = await this.userService.getEmail(); const myEmail = await this.stateService.getEmail();
this.ownershipOptions.push({ name: myEmail, value: null }); this.ownershipOptions.push({ name: myEmail, value: null });
} }
const orgs = await this.userService.getAllOrganizations(); const orgs = await this.organizationService.getAll();
orgs.sort(Utils.getSortFunction(this.i18nService, 'name')).forEach(o => { orgs.sort(Utils.getSortFunction(this.i18nService, 'name')).forEach(o => {
if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) { if (o.enabled && o.status === OrganizationUserStatusType.Confirmed) {
this.ownershipOptions.push({ name: o.name, value: o.id }); this.ownershipOptions.push({ name: o.name, value: o.id });
@@ -185,12 +185,12 @@ export class AddEditComponent implements OnInit {
this.title = this.i18nService.t('addItem'); this.title = this.i18nService.t('addItem');
} }
const addEditCipherInfo: any = await this.stateService.get<any>('addEditCipherInfo'); const addEditCipherInfo: any = await this.stateService.getAddEditCipherInfo();
if (addEditCipherInfo != null) { if (addEditCipherInfo != null) {
this.cipher = addEditCipherInfo.cipher; this.cipher = addEditCipherInfo.cipher;
this.collectionIds = addEditCipherInfo.collectionIds; this.collectionIds = addEditCipherInfo.collectionIds;
} }
await this.stateService.remove('addEditCipherInfo'); await this.stateService.setAddEditCipherInfo(null);
if (this.cipher == null) { if (this.cipher == null) {
if (this.editMode) { if (this.editMode) {
@@ -434,7 +434,7 @@ export class AddEditComponent implements OnInit {
} }
if (this.cipher.organizationId != null) { if (this.cipher.organizationId != null) {
this.collections = this.writeableCollections.filter(c => c.organizationId === this.cipher.organizationId); this.collections = this.writeableCollections.filter(c => c.organizationId === this.cipher.organizationId);
const org = await this.userService.getOrganization(this.cipher.organizationId); const org = await this.organizationService.get(this.cipher.organizationId);
if (org != null) { if (org != null) {
this.cipher.organizationUseTotp = org.useTotp; this.cipher.organizationUseTotp = org.useTotp;
} }

View File

@@ -12,7 +12,7 @@ import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { Cipher } from 'jslib-common/models/domain/cipher'; import { Cipher } from 'jslib-common/models/domain/cipher';
import { ErrorResponse } from 'jslib-common/models/response/errorResponse'; import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
@@ -37,9 +37,9 @@ export class AttachmentsComponent implements OnInit {
emergencyAccessId?: string = null; emergencyAccessId?: string = null;
constructor(protected cipherService: CipherService, protected i18nService: I18nService, constructor(protected cipherService: CipherService, protected i18nService: I18nService,
protected cryptoService: CryptoService, protected userService: UserService, protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
protected platformUtilsService: PlatformUtilsService, protected apiService: ApiService, protected apiService: ApiService, protected win: Window,
protected win: Window, private logService: LogService) { } protected logService: LogService, protected stateService: StateService) { }
async ngOnInit() { async ngOnInit() {
await this.init(); await this.init();
@@ -164,7 +164,7 @@ export class AttachmentsComponent implements OnInit {
this.cipher = await this.cipherDomain.decrypt(); this.cipher = await this.cipherDomain.decrypt();
this.hasUpdatedKey = await this.cryptoService.hasEncKey(); this.hasUpdatedKey = await this.cryptoService.hasEncKey();
const canAccessPremium = await this.userService.canAccessPremium(); const canAccessPremium = await this.stateService.getCanAccessPremium();
this.canAccessAttachments = canAccessPremium || this.cipher.organizationId != null; this.canAccessAttachments = canAccessPremium || this.cipher.organizationId != null;
if (!this.canAccessAttachments) { if (!this.canAccessAttachments) {

View File

@@ -45,7 +45,7 @@ export class AvatarComponent implements OnChanges, OnInit {
} }
private async generate() { private async generate() {
const enableGravatars = await this.stateService.get<boolean>('enableGravatars'); const enableGravatars = await this.stateService.getEnableGravitars();
if (enableGravatars && this.email != null) { if (enableGravatars && this.email != null) {
const hashBytes = await this.cryptoFunctionService.hash(this.email.toLowerCase().trim(), 'md5'); const hashBytes = await this.cryptoFunctionService.hash(this.email.toLowerCase().trim(), 'md5');
const hash = Utils.fromBufferToHex(hashBytes).toLowerCase(); const hash = Utils.fromBufferToHex(hashBytes).toLowerCase();

View File

@@ -6,7 +6,7 @@ import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { EncString } from 'jslib-common/models/domain/encString'; import { EncString } from 'jslib-common/models/domain/encString';
import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions'; import { MasterPasswordPolicyOptions } from 'jslib-common/models/domain/masterPasswordPolicyOptions';
@@ -29,12 +29,12 @@ export class ChangePasswordComponent implements OnInit {
private masterPasswordStrengthTimeout: any; private masterPasswordStrengthTimeout: any;
constructor(protected i18nService: I18nService, protected cryptoService: CryptoService, constructor(protected i18nService: I18nService, protected cryptoService: CryptoService,
protected messagingService: MessagingService, protected userService: UserService, protected messagingService: MessagingService, protected passwordGenerationService: PasswordGenerationService,
protected passwordGenerationService: PasswordGenerationService, protected platformUtilsService: PlatformUtilsService, protected policyService: PolicyService,
protected platformUtilsService: PlatformUtilsService, protected policyService: PolicyService) { } protected stateService: StateService) { }
async ngOnInit() { async ngOnInit() {
this.email = await this.userService.getEmail(); this.email = await this.stateService.getEmail();
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(); this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
} }
@@ -47,12 +47,12 @@ export class ChangePasswordComponent implements OnInit {
return; return;
} }
const email = await this.userService.getEmail(); const email = await this.stateService.getEmail();
if (this.kdf == null) { if (this.kdf == null) {
this.kdf = await this.userService.getKdf(); this.kdf = await this.stateService.getKdfType();
} }
if (this.kdfIterations == null) { if (this.kdfIterations == null) {
this.kdfIterations = await this.userService.getKdfIterations(); this.kdfIterations = await this.stateService.getKdfIterations();
} }
const key = await this.cryptoService.makeKey(this.masterPassword, email.trim().toLowerCase(), const key = await this.cryptoService.makeKey(this.masterPassword, email.trim().toLowerCase(),
this.kdf, this.kdfIterations); this.kdf, this.kdfIterations);

View File

@@ -14,10 +14,7 @@ import { TreeNode } from 'jslib-common/models/domain/treeNode';
import { CollectionService } from 'jslib-common/abstractions/collection.service'; import { CollectionService } from 'jslib-common/abstractions/collection.service';
import { FolderService } from 'jslib-common/abstractions/folder.service'; import { FolderService } from 'jslib-common/abstractions/folder.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
@Directive() @Directive()
export class GroupingsComponent { export class GroupingsComponent {
@@ -50,15 +47,12 @@ export class GroupingsComponent {
selectedCollectionId: string = null; selectedCollectionId: string = null;
private collapsedGroupings: Set<string>; private collapsedGroupings: Set<string>;
private collapsedGroupingsKey: string;
constructor(protected collectionService: CollectionService, protected folderService: FolderService, constructor(protected collectionService: CollectionService, protected folderService: FolderService,
protected storageService: StorageService, protected userService: UserService) { } private stateService: StateService) { }
async load(setLoaded = true) { async load(setLoaded = true) {
const userId = await this.userService.getUserId(); const collapsedGroupings = await this.stateService.getCollapsedGroupings();
this.collapsedGroupingsKey = ConstantsService.collapsedGroupingsKey + '_' + userId;
const collapsedGroupings = await this.storageService.get<string[]>(this.collapsedGroupingsKey);
if (collapsedGroupings == null) { if (collapsedGroupings == null) {
this.collapsedGroupings = new Set<string>(); this.collapsedGroupings = new Set<string>();
} else { } else {
@@ -149,7 +143,7 @@ export class GroupingsComponent {
this.selectedCollectionId = null; this.selectedCollectionId = null;
} }
collapse(grouping: FolderView | CollectionView, idPrefix = '') { async collapse(grouping: FolderView | CollectionView, idPrefix = '') {
if (grouping.id == null) { if (grouping.id == null) {
return; return;
} }
@@ -159,7 +153,7 @@ export class GroupingsComponent {
} else { } else {
this.collapsedGroupings.add(id); this.collapsedGroupings.add(id);
} }
this.storageService.save(this.collapsedGroupingsKey, this.collapsedGroupings); await this.stateService.setCollapsedGroupings(this.collapsedGroupings);
} }
isCollapsed(grouping: FolderView | CollectionView, idPrefix = '') { isCollapsed(grouping: FolderView | CollectionView, idPrefix = '') {

View File

@@ -11,8 +11,6 @@ import { CipherView } from 'jslib-common/models/view/cipherView';
import { EnvironmentService } from 'jslib-common/abstractions/environment.service'; import { EnvironmentService } from 'jslib-common/abstractions/environment.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { Utils } from 'jslib-common/misc/utils'; import { Utils } from 'jslib-common/misc/utils';
const IconMap: any = { const IconMap: any = {
@@ -37,7 +35,7 @@ export class IconComponent implements OnChanges {
private iconsUrl: string; private iconsUrl: string;
constructor(environmentService: EnvironmentService, protected stateService: StateService) { constructor(environmentService: EnvironmentService, private stateService: StateService) {
this.iconsUrl = environmentService.getIconsUrl(); this.iconsUrl = environmentService.getIconsUrl();
} }
@@ -46,7 +44,7 @@ export class IconComponent implements OnChanges {
// to avoid this we reset all state variables. // to avoid this we reset all state variables.
this.image = null; this.image = null;
this.fallbackImage = null; this.fallbackImage = null;
this.imageEnabled = !(await this.stateService.get<boolean>(ConstantsService.disableFaviconKey)); this.imageEnabled = !(await this.stateService.getDisableFavicon());
this.load(); this.load();
} }

View File

@@ -9,12 +9,8 @@ import { LogService } from 'jslib-common/abstractions/log.service';
import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { EncString } from 'jslib-common/models/domain/encString'; import { EncString } from 'jslib-common/models/domain/encString';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey'; import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
@@ -23,6 +19,7 @@ import { PasswordVerificationRequest } from 'jslib-common/models/request/passwor
import { Utils } from 'jslib-common/misc/utils'; import { Utils } from 'jslib-common/misc/utils';
import { HashPurpose } from 'jslib-common/enums/hashPurpose'; import { HashPurpose } from 'jslib-common/enums/hashPurpose';
import { KeySuffixOptions } from 'jslib-common/enums/keySuffixOptions';
@Directive() @Directive()
export class LockComponent implements OnInit { export class LockComponent implements OnInit {
@@ -45,19 +42,18 @@ export class LockComponent implements OnInit {
constructor(protected router: Router, protected i18nService: I18nService, constructor(protected router: Router, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, protected messagingService: MessagingService, protected platformUtilsService: PlatformUtilsService, protected messagingService: MessagingService,
protected userService: UserService, protected cryptoService: CryptoService, protected cryptoService: CryptoService, protected vaultTimeoutService: VaultTimeoutService,
protected storageService: StorageService, protected vaultTimeoutService: VaultTimeoutService,
protected environmentService: EnvironmentService, protected stateService: StateService, protected environmentService: EnvironmentService, protected stateService: StateService,
protected apiService: ApiService, private logService: LogService) { } protected apiService: ApiService, private logService: LogService) { }
async ngOnInit() { async ngOnInit() {
this.pinSet = await this.vaultTimeoutService.isPinLockSet(); this.pinSet = await this.vaultTimeoutService.isPinLockSet();
this.pinLock = (this.pinSet[0] && this.vaultTimeoutService.pinProtectedKey != null) || this.pinSet[1]; this.pinLock = (this.pinSet[0] && (await this.stateService.getEncryptedPinProtected()) != null) || this.pinSet[1];
this.supportsBiometric = await this.platformUtilsService.supportsBiometric(); this.supportsBiometric = await this.platformUtilsService.supportsBiometric();
this.biometricLock = await this.vaultTimeoutService.isBiometricLockSet() && this.biometricLock = await this.vaultTimeoutService.isBiometricLockSet() &&
(await this.cryptoService.hasKeyStored('biometric') || !this.platformUtilsService.supportsSecureStorage()); (await this.cryptoService.hasKeyStored(KeySuffixOptions.Biometric) || !this.platformUtilsService.supportsSecureStorage());
this.biometricText = await this.storageService.get(ConstantsService.biometricText); this.biometricText = await this.stateService.getBiometricText();
this.email = await this.userService.getEmail(); this.email = await this.stateService.getEmail();
const webVaultUrl = this.environmentService.getWebVaultUrl(); const webVaultUrl = this.environmentService.getWebVaultUrl();
const vaultUrl = webVaultUrl === 'https://vault.bitwarden.com' ? 'https://bitwarden.com' : webVaultUrl; const vaultUrl = webVaultUrl === 'https://vault.bitwarden.com' ? 'https://bitwarden.com' : webVaultUrl;
@@ -76,17 +72,17 @@ export class LockComponent implements OnInit {
return; return;
} }
const kdf = await this.userService.getKdf(); const kdf = await this.stateService.getKdfType();
const kdfIterations = await this.userService.getKdfIterations(); const kdfIterations = await this.stateService.getKdfIterations();
if (this.pinLock) { if (this.pinLock) {
let failed = true; let failed = true;
try { try {
if (this.pinSet[0]) { if (this.pinSet[0]) {
const key = await this.cryptoService.makeKeyFromPin(this.pin, this.email, kdf, kdfIterations, const key = await this.cryptoService.makeKeyFromPin(this.pin, this.email, kdf, kdfIterations,
this.vaultTimeoutService.pinProtectedKey); await this.stateService.getDecryptedPinProtected());
const encKey = await this.cryptoService.getEncKey(key); const encKey = await this.cryptoService.getEncKey(key);
const protectedPin = await this.storageService.get<string>(ConstantsService.protectedPin); const protectedPin = await this.stateService.getProtectedPin();
const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey); const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey);
failed = decPin !== this.pin; failed = decPin !== this.pin;
if (!failed) { if (!failed) {
@@ -137,11 +133,11 @@ export class LockComponent implements OnInit {
if (passwordValid) { if (passwordValid) {
if (this.pinSet[0]) { if (this.pinSet[0]) {
const protectedPin = await this.storageService.get<string>(ConstantsService.protectedPin); const protectedPin = await this.stateService.getProtectedPin();
const encKey = await this.cryptoService.getEncKey(key); const encKey = await this.cryptoService.getEncKey(key);
const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey); const decPin = await this.cryptoService.decryptToUtf8(new EncString(protectedPin), encKey);
const pinKey = await this.cryptoService.makePinKey(decPin, this.email, kdf, kdfIterations); const pinKey = await this.cryptoService.makePinKey(decPin, this.email, kdf, kdfIterations);
this.vaultTimeoutService.pinProtectedKey = await this.cryptoService.encrypt(key.key, pinKey); await this.stateService.setDecryptedPinProtected(await this.cryptoService.encrypt(key.key, pinKey));
} }
this.setKeyAndContinue(key); this.setKeyAndContinue(key);
} else { } else {
@@ -164,7 +160,7 @@ export class LockComponent implements OnInit {
return; return;
} }
const success = (await this.cryptoService.getKey('biometric')) != null; const success = (await this.cryptoService.getKey(KeySuffixOptions.Biometric)) != null;
if (success) { if (success) {
await this.doContinue(); await this.doContinue();
@@ -184,10 +180,10 @@ export class LockComponent implements OnInit {
} }
private async doContinue() { private async doContinue() {
this.vaultTimeoutService.biometricLocked = false; await this.stateService.setBiometricLocked(false);
this.vaultTimeoutService.everBeenUnlocked = true; await this.stateService.setEverBeenUnlocked(true);
const disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey); const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.save(ConstantsService.disableFaviconKey, !!disableFavicon); await this.stateService.setDisableFavicon(!!disableFavicon);
this.messagingService.send('unlocked'); this.messagingService.send('unlocked');
if (this.onSuccessfulSubmit != null) { if (this.onSuccessfulSubmit != null) {
this.onSuccessfulSubmit(); this.onSuccessfulSubmit();

View File

@@ -16,19 +16,11 @@ import { LogService } from 'jslib-common/abstractions/log.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { Utils } from 'jslib-common/misc/utils'; import { Utils } from 'jslib-common/misc/utils';
import { CaptchaProtectedComponent } from './captchaProtected.component'; import { CaptchaProtectedComponent } from './captchaProtected.component';
const Keys = {
rememberedEmail: 'rememberedEmail',
rememberEmail: 'rememberEmail',
};
@Directive() @Directive()
export class LoginComponent extends CaptchaProtectedComponent implements OnInit { export class LoginComponent extends CaptchaProtectedComponent implements OnInit {
@Input() email: string = ''; @Input() email: string = '';
@@ -50,19 +42,18 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
platformUtilsService: PlatformUtilsService, i18nService: I18nService, platformUtilsService: PlatformUtilsService, i18nService: I18nService,
protected stateService: StateService, environmentService: EnvironmentService, protected stateService: StateService, environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService, protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, private storageService: StorageService, protected cryptoFunctionService: CryptoFunctionService, protected logService: LogService) {
protected logService: LogService) {
super(environmentService, i18nService, platformUtilsService); super(environmentService, i18nService, platformUtilsService);
} }
async ngOnInit() { async ngOnInit() {
if (this.email == null || this.email === '') { if (this.email == null || this.email === '') {
this.email = await this.storageService.get<string>(Keys.rememberedEmail); this.email = await this.stateService.getRememberedEmail();
if (this.email == null) { if (this.email == null) {
this.email = ''; this.email = '';
} }
} }
this.rememberEmail = await this.storageService.get<boolean>(Keys.rememberEmail); this.rememberEmail = await this.stateService.getRememberEmail();
if (this.rememberEmail == null) { if (this.rememberEmail == null) {
this.rememberEmail = true; this.rememberEmail = true;
} }
@@ -93,11 +84,10 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
try { try {
this.formPromise = this.authService.logIn(this.email, this.masterPassword, this.captchaToken); this.formPromise = this.authService.logIn(this.email, this.masterPassword, this.captchaToken);
const response = await this.formPromise; const response = await this.formPromise;
await this.storageService.save(Keys.rememberEmail, this.rememberEmail);
if (this.rememberEmail) { if (this.rememberEmail) {
await this.storageService.save(Keys.rememberedEmail, this.email); await this.stateService.setRememberedEmail(this.email);
} else { } else {
await this.storageService.remove(Keys.rememberedEmail); await this.stateService.setRememberedEmail(null);
} }
if (this.handleCaptchaRequired(response)) { if (this.handleCaptchaRequired(response)) {
return; return;
@@ -114,8 +104,8 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
this.router.navigate([this.forcePasswordResetRoute]); this.router.navigate([this.forcePasswordResetRoute]);
} }
} else { } else {
const disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey); const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.save(ConstantsService.disableFaviconKey, !!disableFavicon); await this.stateService.setDisableFavicon(!!disableFavicon);
if (this.onSuccessfulLogin != null) { if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin(); this.onSuccessfulLogin();
} }
@@ -151,8 +141,8 @@ export class LoginComponent extends CaptchaProtectedComponent implements OnInit
const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash); const codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
// Save sso params // Save sso params
await this.storageService.save(ConstantsService.ssoStateKey, state); await this.stateService.setSsoState(state);
await this.storageService.save(ConstantsService.ssoCodeVerifierKey, ssoCodeVerifier); await this.stateService.setSsoCodeVerifier(ssoCodeVerifier);
// Build URI // Build URI
const webUrl = this.environmentService.getWebVaultUrl(); const webUrl = this.environmentService.getWebVaultUrl();

View File

@@ -4,7 +4,7 @@ import { ApiService } from 'jslib-common/abstractions/api.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
@Directive() @Directive()
export class PremiumComponent implements OnInit { export class PremiumComponent implements OnInit {
@@ -13,10 +13,11 @@ export class PremiumComponent implements OnInit {
refreshPromise: Promise<any>; refreshPromise: Promise<any>;
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected apiService: ApiService, protected userService: UserService, private logService: LogService) { } protected apiService: ApiService, private logService: LogService,
protected stateService: StateService) { }
async ngOnInit() { async ngOnInit() {
this.isPremium = await this.userService.canAccessPremium(); this.isPremium = await this.stateService.getCanAccessPremium();
} }
async refresh() { async refresh() {
@@ -24,7 +25,7 @@ export class PremiumComponent implements OnInit {
this.refreshPromise = this.apiService.refreshIdentityToken(); this.refreshPromise = this.apiService.refreshIdentityToken();
await this.refreshPromise; await this.refreshPromise;
this.platformUtilsService.showToast('success', null, this.i18nService.t('refreshComplete')); this.platformUtilsService.showToast('success', null, this.i18nService.t('refreshComplete'));
this.isPremium = await this.userService.canAccessPremium(); this.isPremium = await this.stateService.getCanAccessPremium();
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);
} }

View File

@@ -141,7 +141,7 @@ export class RegisterComponent extends CaptchaProtectedComponent implements OnIn
const request = new RegisterRequest(this.email, this.name, hashedPassword, const request = new RegisterRequest(this.email, this.name, hashedPassword,
this.hint, encKey[1].encryptedString, kdf, kdfIterations, this.referenceData, this.captchaToken); this.hint, encKey[1].encryptedString, kdf, kdfIterations, this.referenceData, this.captchaToken);
request.keys = new KeysRequest(keys[0], keys[1].encryptedString); request.keys = new KeysRequest(keys[0], keys[1].encryptedString);
const orgInvite = await this.stateService.get<any>('orgInvitation'); const orgInvite = await this.stateService.getOrganizationInvitation();
if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) { if (orgInvite != null && orgInvite.token != null && orgInvite.organizationUserId != null) {
request.token = orgInvite.token; request.token = orgInvite.token;
request.organizationUserId = orgInvite.organizationUserId; request.organizationUserId = orgInvite.organizationUserId;

View File

@@ -17,7 +17,7 @@ import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { SendService } from 'jslib-common/abstractions/send.service'; import { SendService } from 'jslib-common/abstractions/send.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { SendFileView } from 'jslib-common/models/view/sendFileView'; import { SendFileView } from 'jslib-common/models/view/sendFileView';
import { SendTextView } from 'jslib-common/models/view/sendTextView'; import { SendTextView } from 'jslib-common/models/view/sendTextView';
@@ -57,9 +57,9 @@ export class AddEditComponent implements OnInit {
constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService, constructor(protected i18nService: I18nService, protected platformUtilsService: PlatformUtilsService,
protected environmentService: EnvironmentService, protected datePipe: DatePipe, protected environmentService: EnvironmentService, protected datePipe: DatePipe,
protected sendService: SendService, protected userService: UserService, protected sendService: SendService, protected messagingService: MessagingService,
protected messagingService: MessagingService, protected policyService: PolicyService, protected policyService: PolicyService, private logService: LogService,
private logService: LogService) { protected stateService: StateService) {
this.typeOptions = [ this.typeOptions = [
{ name: i18nService.t('sendTypeFile'), value: SendType.File }, { name: i18nService.t('sendTypeFile'), value: SendType.File },
{ name: i18nService.t('sendTypeText'), value: SendType.Text }, { name: i18nService.t('sendTypeText'), value: SendType.Text },
@@ -108,8 +108,8 @@ export class AddEditComponent implements OnInit {
this.disableHideEmail = await this.policyService.policyAppliesToUser(PolicyType.SendOptions, this.disableHideEmail = await this.policyService.policyAppliesToUser(PolicyType.SendOptions,
p => p.data.disableHideEmail); p => p.data.disableHideEmail);
this.canAccessPremium = await this.userService.canAccessPremium(); this.canAccessPremium = await this.stateService.getCanAccessPremium();
this.emailVerified = await this.userService.getEmailVerified(); this.emailVerified = await this.stateService.getEmailVerified();
if (!this.canAccessPremium || !this.emailVerified) { if (!this.canAccessPremium || !this.emailVerified) {
this.type = SendType.Text; this.type = SendType.Text;
} }

View File

@@ -16,7 +16,6 @@ import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.se
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { SearchService } from 'jslib-common/abstractions/search.service'; import { SearchService } from 'jslib-common/abstractions/search.service';
import { SendService } from 'jslib-common/abstractions/send.service'; import { SendService } from 'jslib-common/abstractions/send.service';
import { UserService } from 'jslib-common/abstractions/user.service';
@Directive() @Directive()
export class SendComponent implements OnInit { export class SendComponent implements OnInit {
@@ -48,8 +47,7 @@ export class SendComponent implements OnInit {
constructor(protected sendService: SendService, protected i18nService: I18nService, constructor(protected sendService: SendService, protected i18nService: I18nService,
protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService, protected platformUtilsService: PlatformUtilsService, protected environmentService: EnvironmentService,
protected ngZone: NgZone, protected searchService: SearchService, protected ngZone: NgZone, protected searchService: SearchService,
protected policyService: PolicyService, protected userService: UserService, protected policyService: PolicyService, private logService: LogService) { }
private logService: LogService) { }
async ngOnInit() { async ngOnInit() {
this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend); this.disableSend = await this.policyService.policyAppliesToUser(PolicyType.DisableSend);

View File

@@ -13,8 +13,8 @@ import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { EncString } from 'jslib-common/models/domain/encString'; import { EncString } from 'jslib-common/models/domain/encString';
import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey'; import { SymmetricCryptoKey } from 'jslib-common/models/domain/symmetricCryptoKey';
@@ -42,12 +42,13 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
onSuccessfulChangePassword: () => Promise<any>; onSuccessfulChangePassword: () => Promise<any>;
successRoute = 'vault'; successRoute = 'vault';
constructor(i18nService: I18nService, cryptoService: CryptoService, messagingService: MessagingService, constructor(i18nService: I18nService, cryptoService: CryptoService,
userService: UserService, passwordGenerationService: PasswordGenerationService, messagingService: MessagingService, passwordGenerationService: PasswordGenerationService,
platformUtilsService: PlatformUtilsService, policyService: PolicyService, protected router: Router, platformUtilsService: PlatformUtilsService, policyService: PolicyService,
private apiService: ApiService, private syncService: SyncService, private route: ActivatedRoute) { protected router: Router, private apiService: ApiService,
super(i18nService, cryptoService, messagingService, userService, passwordGenerationService, private syncService: SyncService, private route: ActivatedRoute, stateService: StateService) {
platformUtilsService, policyService); super(i18nService, cryptoService, messagingService, passwordGenerationService,
platformUtilsService, policyService, stateService);
} }
async ngOnInit() { async ngOnInit() {
@@ -102,7 +103,7 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
if (response == null) { if (response == null) {
throw new Error(this.i18nService.t('resetPasswordOrgKeysError')); throw new Error(this.i18nService.t('resetPasswordOrgKeysError'));
} }
const userId = await this.userService.getUserId(); const userId = await this.stateService.getUserId();
const publicKey = Utils.fromB64ToArray(response.publicKey); const publicKey = Utils.fromB64ToArray(response.publicKey);
// RSA Encrypt user's encKey.key with organization public key // RSA Encrypt user's encKey.key with organization public key
@@ -138,8 +139,8 @@ export class SetPasswordComponent extends BaseChangePasswordComponent {
} }
private async onSetPasswordSuccess(key: SymmetricCryptoKey, encKey: [SymmetricCryptoKey, EncString], keys: [string, EncString]) { private async onSetPasswordSuccess(key: SymmetricCryptoKey, encKey: [SymmetricCryptoKey, EncString], keys: [string, EncString]) {
await this.userService.setInformation(await this.userService.getUserId(), await this.userService.getEmail(), await this.stateService.setKdfType(this.kdf);
this.kdf, this.kdfIterations); await this.stateService.setKdfIterations(this.kdfIterations);
await this.cryptoService.setKey(key); await this.cryptoService.setKey(key);
await this.cryptoService.setEncKey(encKey[1].encryptedString); await this.cryptoService.setEncKey(encKey[1].encryptedString);
await this.cryptoService.setEncPrivateKey(keys[1].encryptedString); await this.cryptoService.setEncPrivateKey(keys[1].encryptedString);

View File

@@ -1,11 +1,7 @@
import { Directive } from '@angular/core'; import { Directive } from '@angular/core';
import { CryptoService } from 'jslib-common/abstractions/crypto.service'; import { CryptoService } from 'jslib-common/abstractions/crypto.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { Utils } from 'jslib-common/misc/utils'; import { Utils } from 'jslib-common/misc/utils';
@@ -18,8 +14,8 @@ export class SetPinComponent {
showPin = false; showPin = false;
masterPassOnRestart = true; masterPassOnRestart = true;
constructor(private modalRef: ModalRef, private cryptoService: CryptoService, private userService: UserService, constructor(private modalRef: ModalRef, private cryptoService: CryptoService,
private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService) { } private stateService: StateService) { }
toggleVisibility() { toggleVisibility() {
this.showPin = !this.showPin; this.showPin = !this.showPin;
@@ -30,18 +26,18 @@ export class SetPinComponent {
this.modalRef.close(false); this.modalRef.close(false);
} }
const kdf = await this.userService.getKdf(); const kdf = await this.stateService.getKdfType();
const kdfIterations = await this.userService.getKdfIterations(); const kdfIterations = await this.stateService.getKdfIterations();
const email = await this.userService.getEmail(); const email = await this.stateService.getEmail();
const pinKey = await this.cryptoService.makePinKey(this.pin, email, kdf, kdfIterations); const pinKey = await this.cryptoService.makePinKey(this.pin, email, kdf, kdfIterations);
const key = await this.cryptoService.getKey(); const key = await this.cryptoService.getKey();
const pinProtectedKey = await this.cryptoService.encrypt(key.key, pinKey); const pinProtectedKey = await this.cryptoService.encrypt(key.key, pinKey);
if (this.masterPassOnRestart) { if (this.masterPassOnRestart) {
const encPin = await this.cryptoService.encrypt(this.pin); const encPin = await this.cryptoService.encrypt(this.pin);
await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString); await this.stateService.setProtectedPin(encPin.encryptedString);
this.vaultTimeoutService.pinProtectedKey = pinProtectedKey; await this.stateService.setDecryptedPinProtected(pinProtectedKey);
} else { } else {
await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString); await this.stateService.setEncryptedPinProtected(pinProtectedKey.encryptedString);
} }
this.modalRef.close(true); this.modalRef.close(true);

View File

@@ -12,8 +12,8 @@ import { CipherService } from 'jslib-common/abstractions/cipher.service';
import { CollectionService } from 'jslib-common/abstractions/collection.service'; import { CollectionService } from 'jslib-common/abstractions/collection.service';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { OrganizationService } from 'jslib-common/abstractions/organization.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { Organization } from 'jslib-common/models/domain/organization'; import { Organization } from 'jslib-common/models/domain/organization';
import { CipherView } from 'jslib-common/models/view/cipherView'; import { CipherView } from 'jslib-common/models/view/cipherView';
@@ -35,8 +35,8 @@ export class ShareComponent implements OnInit {
protected writeableCollections: CollectionView[] = []; protected writeableCollections: CollectionView[] = [];
constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService, constructor(protected collectionService: CollectionService, protected platformUtilsService: PlatformUtilsService,
protected i18nService: I18nService, protected userService: UserService, protected i18nService: I18nService, protected cipherService: CipherService,
protected cipherService: CipherService, private logService: LogService) { } private logService: LogService, protected organizationService: OrganizationService) { }
async ngOnInit() { async ngOnInit() {
await this.load(); await this.load();
@@ -45,7 +45,7 @@ export class ShareComponent implements OnInit {
async load() { async load() {
const allCollections = await this.collectionService.getAllDecrypted(); const allCollections = await this.collectionService.getAllDecrypted();
this.writeableCollections = allCollections.map(c => c).filter(c => !c.readOnly); this.writeableCollections = allCollections.map(c => c).filter(c => !c.readOnly);
const orgs = await this.userService.getAllOrganizations(); const orgs = await this.organizationService.getAll();
this.organizations = orgs.sort(Utils.getSortFunction(this.i18nService, 'name')) this.organizations = orgs.sort(Utils.getSortFunction(this.i18nService, 'name'))
.filter(o => o.enabled && o.status === OrganizationUserStatusType.Confirmed); .filter(o => o.enabled && o.status === OrganizationUserStatusType.Confirmed);

View File

@@ -15,9 +15,6 @@ import { LogService } from 'jslib-common/abstractions/log.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { Utils } from 'jslib-common/misc/utils'; import { Utils } from 'jslib-common/misc/utils';
@@ -47,18 +44,18 @@ export class SsoComponent {
constructor(protected authService: AuthService, protected router: Router, constructor(protected authService: AuthService, protected router: Router,
protected i18nService: I18nService, protected route: ActivatedRoute, protected i18nService: I18nService, protected route: ActivatedRoute,
protected storageService: StorageService, protected stateService: StateService, protected stateService: StateService, protected platformUtilsService: PlatformUtilsService,
protected platformUtilsService: PlatformUtilsService, protected apiService: ApiService, protected apiService: ApiService, protected cryptoFunctionService: CryptoFunctionService,
protected cryptoFunctionService: CryptoFunctionService, protected environmentService: EnvironmentService, protected environmentService: EnvironmentService, protected passwordGenerationService: PasswordGenerationService,
protected passwordGenerationService: PasswordGenerationService, protected logService: LogService) { } protected logService: LogService) { }
async ngOnInit() { async ngOnInit() {
this.route.queryParams.pipe(first()).subscribe(async qParams => { this.route.queryParams.pipe(first()).subscribe(async qParams => {
if (qParams.code != null && qParams.state != null) { if (qParams.code != null && qParams.state != null) {
const codeVerifier = await this.storageService.get<string>(ConstantsService.ssoCodeVerifierKey); const codeVerifier = await this.stateService.getSsoCodeVerifier();
const state = await this.storageService.get<string>(ConstantsService.ssoStateKey); const state = await this.stateService.getSsoState();
await this.storageService.remove(ConstantsService.ssoCodeVerifierKey); await this.stateService.setSsoCodeVerifier(null);
await this.storageService.remove(ConstantsService.ssoStateKey); await this.stateService.setSsoState(null);
if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) { if (qParams.code != null && codeVerifier != null && state != null && this.checkState(state, qParams.state)) {
await this.logIn(qParams.code, codeVerifier, this.getOrgIdentiferFromState(qParams.state)); await this.logIn(qParams.code, codeVerifier, this.getOrgIdentiferFromState(qParams.state));
} }
@@ -106,7 +103,7 @@ export class SsoComponent {
const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions); const codeVerifier = await this.passwordGenerationService.generatePassword(passwordOptions);
const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, 'sha256'); const codeVerifierHash = await this.cryptoFunctionService.hash(codeVerifier, 'sha256');
codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash); codeChallenge = Utils.fromBufferToUrlB64(codeVerifierHash);
await this.storageService.save(ConstantsService.ssoCodeVerifierKey, codeVerifier); await this.stateService.setSsoCodeVerifier(codeVerifier);
} }
if (state == null) { if (state == null) {
@@ -120,7 +117,7 @@ export class SsoComponent {
state += `_identifier=${this.identifier}`; state += `_identifier=${this.identifier}`;
// Save state (regardless of new or existing) // Save state (regardless of new or existing)
await this.storageService.save(ConstantsService.ssoStateKey, state); await this.stateService.setSsoState(state);
let authorizeUrl = this.environmentService.getIdentityUrl() + '/connect/authorize?' + let authorizeUrl = this.environmentService.getIdentityUrl() + '/connect/authorize?' +
'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' + 'client_id=' + this.clientId + '&redirect_uri=' + encodeURIComponent(this.redirectUri) + '&' +
@@ -170,8 +167,8 @@ export class SsoComponent {
this.router.navigate([this.forcePasswordResetRoute]); this.router.navigate([this.forcePasswordResetRoute]);
} }
} else { } else {
const disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey); const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.save(ConstantsService.disableFaviconKey, !!disableFavicon); await this.stateService.setDisableFavicon(!!disableFavicon);
if (this.onSuccessfulLogin != null) { if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin(); this.onSuccessfulLogin();
} }

View File

@@ -20,10 +20,8 @@ import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { TwoFactorProviders } from 'jslib-common/services/auth.service'; import { TwoFactorProviders } from 'jslib-common/services/auth.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import * as DuoWebSDK from 'duo_web_sdk'; import * as DuoWebSDK from 'duo_web_sdk';
import { WebAuthnIFrame } from 'jslib-common/misc/webauthn_iframe'; import { WebAuthnIFrame } from 'jslib-common/misc/webauthn_iframe';
@@ -58,8 +56,7 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
protected i18nService: I18nService, protected apiService: ApiService, protected i18nService: I18nService, protected apiService: ApiService,
protected platformUtilsService: PlatformUtilsService, protected win: Window, protected platformUtilsService: PlatformUtilsService, protected win: Window,
protected environmentService: EnvironmentService, protected stateService: StateService, protected environmentService: EnvironmentService, protected stateService: StateService,
protected storageService: StorageService, protected route: ActivatedRoute, protected route: ActivatedRoute, protected logService: LogService) {
protected logService: LogService) {
this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win); this.webAuthnSupported = this.platformUtilsService.supportsWebAuthn(win);
} }
@@ -179,8 +176,8 @@ export class TwoFactorComponent implements OnInit, OnDestroy {
async doSubmit() { async doSubmit() {
this.formPromise = this.authService.logInTwoFactor(this.selectedProviderType, this.token, this.remember); this.formPromise = this.authService.logInTwoFactor(this.selectedProviderType, this.token, this.remember);
const response: AuthResult = await this.formPromise; const response: AuthResult = await this.formPromise;
const disableFavicon = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey); const disableFavicon = await this.stateService.getDisableFavicon();
await this.stateService.save(ConstantsService.disableFaviconKey, !!disableFavicon); await this.stateService.setDisableFavicon(!!disableFavicon);
if (this.onSuccessfulLogin != null) { if (this.onSuccessfulLogin != null) {
this.onSuccessfulLogin(); this.onSuccessfulLogin();
} }

View File

@@ -8,8 +8,8 @@ import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { ChangePasswordComponent as BaseChangePasswordComponent } from './change-password.component'; import { ChangePasswordComponent as BaseChangePasswordComponent } from './change-password.component';
@@ -30,11 +30,11 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService, constructor(i18nService: I18nService, platformUtilsService: PlatformUtilsService,
passwordGenerationService: PasswordGenerationService, policyService: PolicyService, passwordGenerationService: PasswordGenerationService, policyService: PolicyService,
cryptoService: CryptoService, userService: UserService, cryptoService: CryptoService, messagingService: MessagingService,
messagingService: MessagingService, private apiService: ApiService, private apiService: ApiService, stateService: StateService,
private syncService: SyncService, private logService: LogService) { private syncService: SyncService, private logService: LogService) {
super(i18nService, cryptoService, messagingService, userService, passwordGenerationService, super(i18nService, cryptoService, messagingService, passwordGenerationService,
platformUtilsService, policyService); platformUtilsService, policyService, stateService);
} }
async ngOnInit() { async ngOnInit() {
@@ -49,9 +49,9 @@ export class UpdateTempPasswordComponent extends BaseChangePasswordComponent {
async setupSubmitActions(): Promise<boolean> { async setupSubmitActions(): Promise<boolean> {
this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(); this.enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
this.email = await this.userService.getEmail(); this.email = await this.stateService.getEmail();
this.kdf = await this.userService.getKdf(); this.kdf = await this.stateService.getKdfType();
this.kdfIterations = await this.userService.getKdfIterations(); this.kdfIterations = await this.stateService.getKdfIterations();
return true; return true;
} }

View File

@@ -24,9 +24,9 @@ import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service'; import { PasswordRepromptService } from 'jslib-common/abstractions/passwordReprompt.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { TokenService } from 'jslib-common/abstractions/token.service'; import { TokenService } from 'jslib-common/abstractions/token.service';
import { TotpService } from 'jslib-common/abstractions/totp.service'; import { TotpService } from 'jslib-common/abstractions/totp.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { ErrorResponse } from 'jslib-common/models/response/errorResponse'; import { ErrorResponse } from 'jslib-common/models/response/errorResponse';
@@ -67,9 +67,9 @@ export class ViewComponent implements OnDestroy, OnInit {
protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService, protected cryptoService: CryptoService, protected platformUtilsService: PlatformUtilsService,
protected auditService: AuditService, protected win: Window, protected auditService: AuditService, protected win: Window,
protected broadcasterService: BroadcasterService, protected ngZone: NgZone, protected broadcasterService: BroadcasterService, protected ngZone: NgZone,
protected changeDetectorRef: ChangeDetectorRef, protected userService: UserService, protected changeDetectorRef: ChangeDetectorRef, protected eventService: EventService,
protected eventService: EventService, protected apiService: ApiService, protected apiService: ApiService, protected passwordRepromptService: PasswordRepromptService,
protected passwordRepromptService: PasswordRepromptService, private logService: LogService) { } private logService: LogService, protected stateService: StateService) { }
ngOnInit() { ngOnInit() {
this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => { this.broadcasterService.subscribe(BroadcasterSubscriptionId, (message: any) => {
@@ -96,7 +96,7 @@ export class ViewComponent implements OnDestroy, OnInit {
const cipher = await this.cipherService.get(this.cipherId); const cipher = await this.cipherService.get(this.cipherId);
this.cipher = await cipher.decrypt(); this.cipher = await cipher.decrypt();
this.canAccessPremium = await this.userService.canAccessPremium(); this.canAccessPremium = await this.stateService.getCanAccessPremium();
if (this.cipher.type === CipherType.Login && this.cipher.login.totp && if (this.cipher.type === CipherType.Login && this.cipher.login.totp &&
(cipher.organizationUseTotp || this.canAccessPremium)) { (cipher.organizationUseTotp || this.canAccessPremium)) {

View File

@@ -7,16 +7,16 @@ import {
} from '@angular/router'; } from '@angular/router';
import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { MessagingService } from 'jslib-common/abstractions/messaging.service';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
@Injectable() @Injectable()
export class AuthGuardService implements CanActivate { export class AuthGuardService implements CanActivate {
constructor(private vaultTimeoutService: VaultTimeoutService, private userService: UserService, constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
private router: Router, private messagingService: MessagingService) { } private messagingService: MessagingService, private stateService: StateService) { }
async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) { async canActivate(route: ActivatedRouteSnapshot, routerState: RouterStateSnapshot) {
const isAuthed = await this.userService.isAuthenticated(); const isAuthed = this.stateService.getIsAuthenticated();
if (!isAuthed) { if (!isAuthed) {
this.messagingService.send('authBlocked'); this.messagingService.send('authBlocked');
return false; return false;

View File

@@ -4,29 +4,25 @@ import {
Router, Router,
} from '@angular/router'; } from '@angular/router';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
@Injectable() @Injectable()
export class LockGuardService implements CanActivate { export class LockGuardService implements CanActivate {
constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
protected homepage = 'vault'; private stateService: StateService) { }
constructor(private vaultTimeoutService: VaultTimeoutService, private userService: UserService,
private router: Router) { }
async canActivate() { async canActivate() {
const isAuthed = await this.userService.isAuthenticated(); if (!await this.stateService.getIsAuthenticated()) {
if (isAuthed) { this.router.navigate(['login']);
const locked = await this.vaultTimeoutService.isLocked();
if (locked) {
return true;
} else {
this.router.navigate([this.homepage]);
return false; return false;
} }
}
this.router.navigate(['']); if (!await this.vaultTimeoutService.isLocked()) {
this.router.navigate(['vault']);
return false; return false;
} }
return true;
}
} }

View File

@@ -1,22 +1,21 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { import {
ActivatedRouteSnapshot,
CanActivate, CanActivate,
Router, Router,
} from '@angular/router'; } from '@angular/router';
import { UserService } from 'jslib-common/abstractions/user.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service'; import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.service';
@Injectable() @Injectable()
export class UnauthGuardService implements CanActivate { export class UnauthGuardService implements CanActivate {
protected homepage = 'vault'; protected homepage = 'vault';
constructor(private vaultTimeoutService: VaultTimeoutService, private userService: UserService, constructor(private vaultTimeoutService: VaultTimeoutService, private router: Router,
private router: Router) { } private stateService: StateService) { }
async canActivate() { async canActivate() {
const isAuthed = await this.userService.isAuthenticated(); const isAuthed = await this.stateService.getIsAuthenticated();
if (isAuthed) { if (isAuthed) {
const locked = await this.vaultTimeoutService.isLocked(); const locked = await this.vaultTimeoutService.isLocked();
if (locked) { if (locked) {
@@ -26,7 +25,5 @@ export class UnauthGuardService implements CanActivate {
} }
return false; return false;
} }
return true;
} }
} }

View File

@@ -1,21 +1,18 @@
import { ipcMain, systemPreferences } from 'electron'; import { ipcMain, systemPreferences } from 'electron';
import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { StorageService } from 'jslib-common/abstractions/storage.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
import { BiometricMain } from 'jslib-common/abstractions/biometric.main'; import { BiometricMain } from 'jslib-common/abstractions/biometric.main';
import { ElectronConstants } from './electronConstants'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { StateService } from 'jslib-common/abstractions/state.service';
export default class BiometricDarwinMain implements BiometricMain { export default class BiometricDarwinMain implements BiometricMain {
isError: boolean = false; isError: boolean = false;
constructor(private storageService: StorageService, private i18nservice: I18nService) {} constructor(private i18nservice: I18nService, private stateService: StateService) {}
async init() { async init() {
this.storageService.save(ElectronConstants.enableBiometric, await this.supportsBiometric()); await this.stateService.setEnableBiometric(await this.supportsBiometric());
this.storageService.save(ConstantsService.biometricText, 'unlockWithTouchId'); await this.stateService.setBiometricText('unlockWithTouchId');
this.storageService.save(ElectronConstants.noAutoPromptBiometricsText, 'noAutoPromptTouchId'); await this.stateService.setNoAutoPromptBiometricsText('noAutoPromptTouchId');
ipcMain.on('biometric', async (event: any, message: any) => { ipcMain.on('biometric', async (event: any, message: any) => {
event.returnValue = await this.authenticateBiometric(); event.returnValue = await this.authenticateBiometric();

View File

@@ -1,22 +1,20 @@
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import forceFocus from 'forcefocus'; import forceFocus from 'forcefocus';
import { ElectronConstants } from './electronConstants';
import { WindowMain } from './window.main'; import { WindowMain } from './window.main';
import { BiometricMain } from 'jslib-common/abstractions/biometric.main'; import { BiometricMain } from 'jslib-common/abstractions/biometric.main';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { ConstantsService } from 'jslib-common/services/constants.service';
export default class BiometricWindowsMain implements BiometricMain { export default class BiometricWindowsMain implements BiometricMain {
isError: boolean = false; isError: boolean = false;
private windowsSecurityCredentialsUiModule: any; private windowsSecurityCredentialsUiModule: any;
constructor(private storageService: StorageService, private i18nservice: I18nService, private windowMain: WindowMain, constructor(private i18nservice: I18nService, private windowMain: WindowMain,
private logService: LogService) { } private stateService: StateService, private logService: LogService) { }
async init() { async init() {
this.windowsSecurityCredentialsUiModule = this.getWindowsSecurityCredentialsUiModule(); this.windowsSecurityCredentialsUiModule = this.getWindowsSecurityCredentialsUiModule();
@@ -27,9 +25,9 @@ export default class BiometricWindowsMain implements BiometricMain {
// store error state so we can let the user know on the settings page // store error state so we can let the user know on the settings page
this.isError = true; this.isError = true;
} }
this.storageService.save(ElectronConstants.enableBiometric, supportsBiometric); this.stateService.setEnableBiometric(supportsBiometric);
this.storageService.save(ConstantsService.biometricText, 'unlockWithWindowsHello'); this.stateService.setBiometricText('unlockWithWindowsHello');
this.storageService.save(ElectronConstants.noAutoPromptBiometricsText, 'noAutoPromptWindowsHello'); this.stateService.setNoAutoPromptBiometricsText('noAutoPromptWindowsHello');
ipcMain.on('biometric', async (event: any, message: any) => { ipcMain.on('biometric', async (event: any, message: any) => {
event.returnValue = await this.authenticateBiometric(); event.returnValue = await this.authenticateBiometric();

View File

@@ -1,14 +0,0 @@
export class ElectronConstants {
static readonly enableMinimizeToTrayKey: string = 'enableMinimizeToTray';
static readonly enableCloseToTrayKey: string = 'enableCloseToTray';
static readonly enableTrayKey: string = 'enableTray';
static readonly enableStartToTrayKey: string = 'enableStartToTrayKey';
static readonly enableAlwaysOnTopKey: string = 'enableAlwaysOnTopKey';
static readonly minimizeOnCopyToClipboardKey: string = 'minimizeOnCopyToClipboardKey';
static readonly enableBiometric: string = 'enabledBiometric';
static readonly enableBrowserIntegration: string = 'enableBrowserIntegration';
static readonly enableBrowserIntegrationFingerprint: string = 'enableBrowserIntegrationFingerprint';
static readonly alwaysShowDock: string = 'alwaysShowDock';
static readonly openAtLogin: string = 'openAtLogin';
static readonly noAutoPromptBiometricsText: string = 'noAutoPromptBiometricsText';
}

View File

@@ -2,7 +2,6 @@ import {
app, app,
BrowserWindow, BrowserWindow,
Menu, Menu,
MenuItem,
MenuItemConstructorOptions, MenuItemConstructorOptions,
nativeImage, nativeImage,
Tray, Tray,
@@ -10,9 +9,8 @@ import {
import * as path from 'path'; import * as path from 'path';
import { I18nService } from 'jslib-common/abstractions/i18n.service'; import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { ElectronConstants } from './electronConstants';
import { WindowMain } from './window.main'; import { WindowMain } from './window.main';
export class TrayMain { export class TrayMain {
@@ -24,7 +22,7 @@ export class TrayMain {
private pressedIcon: Electron.NativeImage; private pressedIcon: Electron.NativeImage;
constructor(private windowMain: WindowMain, private i18nService: I18nService, constructor(private windowMain: WindowMain, private i18nService: I18nService,
private storageService: StorageService) { private stateService: StateService) {
if (process.platform === 'win32') { if (process.platform === 'win32') {
this.icon = path.join(__dirname, '/images/icon.ico'); this.icon = path.join(__dirname, '/images/icon.ico');
} else if (process.platform === 'darwin') { } else if (process.platform === 'darwin') {
@@ -55,21 +53,21 @@ export class TrayMain {
} }
this.contextMenu = Menu.buildFromTemplate(menuItemOptions); this.contextMenu = Menu.buildFromTemplate(menuItemOptions);
if (await this.storageService.get<boolean>(ElectronConstants.enableTrayKey)) { if (await this.stateService.getEnableTray()) {
this.showTray(); this.showTray();
} }
} }
setupWindowListeners(win: BrowserWindow) { setupWindowListeners(win: BrowserWindow) {
win.on('minimize', async (e: Event) => { win.on('minimize', async (e: Event) => {
if (await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey)) { if (await this.stateService.getEnableMinimizeToTray()) {
e.preventDefault(); e.preventDefault();
this.hideToTray(); this.hideToTray();
} }
}); });
win.on('close', async (e: Event) => { win.on('close', async (e: Event) => {
if (await this.storageService.get<boolean>(ElectronConstants.enableCloseToTrayKey)) { if (await this.stateService.getEnableCloseToTray()) {
if (!this.windowMain.isQuitting) { if (!this.windowMain.isQuitting) {
e.preventDefault(); e.preventDefault();
this.hideToTray(); this.hideToTray();
@@ -78,7 +76,7 @@ export class TrayMain {
}); });
win.on('show', async (e: Event) => { win.on('show', async (e: Event) => {
const enableTray = await this.storageService.get<boolean>(ElectronConstants.enableTrayKey); const enableTray = await this.stateService.getEnableTray();
if (!enableTray) { if (!enableTray) {
setTimeout(() => this.removeTray(false), 100); setTimeout(() => this.removeTray(false), 100);
} }
@@ -103,7 +101,7 @@ export class TrayMain {
if (this.windowMain.win != null) { if (this.windowMain.win != null) {
this.windowMain.win.hide(); this.windowMain.win.hide();
} }
if (this.isDarwin() && !await this.storageService.get<boolean>(ElectronConstants.alwaysShowDock)) { if (this.isDarwin() && !await this.stateService.getAlwaysShowDock()) {
this.hideDock(); this.hideDock();
} }
} }
@@ -167,7 +165,7 @@ export class TrayMain {
} }
if (this.windowMain.win.isVisible()) { if (this.windowMain.win.isVisible()) {
this.windowMain.win.hide(); this.windowMain.win.hide();
if (this.isDarwin() && !await this.storageService.get<boolean>(ElectronConstants.alwaysShowDock)) { if (this.isDarwin() && !await this.stateService.getAlwaysShowDock()) {
this.hideDock(); this.hideDock();
} }
} else { } else {

View File

@@ -7,9 +7,8 @@ import * as path from 'path';
import * as url from 'url'; import * as url from 'url';
import { LogService } from 'jslib-common/abstractions/log.service'; import { LogService } from 'jslib-common/abstractions/log.service';
import { StorageService } from 'jslib-common/abstractions/storage.service'; import { StateService } from 'jslib-common/abstractions/state.service';
import { ElectronConstants } from './electronConstants';
import { import {
cleanUserAgent, cleanUserAgent,
isDev, isDev,
@@ -17,11 +16,8 @@ import {
isSnapStore, isSnapStore,
} from './utils'; } from './utils';
const mainWindowSizeKey = 'mainWindowSize';
const WindowEventHandlingDelay = 100; const WindowEventHandlingDelay = 100;
const Keys = {
mainWindowSize: 'mainWindowSize',
};
export class WindowMain { export class WindowMain {
win: BrowserWindow; win: BrowserWindow;
isQuitting: boolean = false; isQuitting: boolean = false;
@@ -30,7 +26,7 @@ export class WindowMain {
private windowStates: { [key: string]: any; } = {}; private windowStates: { [key: string]: any; } = {};
private enableAlwaysOnTop: boolean = false; private enableAlwaysOnTop: boolean = false;
constructor(private storageService: StorageService, private logService: LogService, constructor(private stateService: StateService, private logService: LogService,
private hideTitleBar = false, private defaultWidth = 950, private defaultHeight = 600, private hideTitleBar = false, private defaultWidth = 950, private defaultHeight = 600,
private argvCallback: (argv: string[]) => void = null, private argvCallback: (argv: string[]) => void = null,
private createWindowCallback: (win: BrowserWindow) => void) { } private createWindowCallback: (win: BrowserWindow) => void) { }
@@ -81,7 +77,7 @@ export class WindowMain {
// Quit when all windows are closed. // Quit when all windows are closed.
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
// On OS X it is common for applications and their menu bar // On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q // to stay KKKactive until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin' || this.isQuitting || isMacAppStore()) { if (process.platform !== 'darwin' || this.isQuitting || isMacAppStore()) {
app.quit(); app.quit();
} }
@@ -107,18 +103,19 @@ export class WindowMain {
} }
async createWindow(): Promise<void> { async createWindow(): Promise<void> {
this.windowStates[Keys.mainWindowSize] = await this.getWindowState(Keys.mainWindowSize, this.defaultWidth, try {
this.windowStates[mainWindowSizeKey] = await this.getWindowState(mainWindowSizeKey, this.defaultWidth,
this.defaultHeight); this.defaultHeight);
this.enableAlwaysOnTop = await this.storageService.get<boolean>(ElectronConstants.enableAlwaysOnTopKey); this.enableAlwaysOnTop = await this.stateService.getEnableAlwaysOnTop();
// Create the browser window. // Create the browser window.
this.win = new BrowserWindow({ this.win = new BrowserWindow({
width: this.windowStates[Keys.mainWindowSize].width, width: this.windowStates[mainWindowSizeKey].width,
height: this.windowStates[Keys.mainWindowSize].height, height: this.windowStates[mainWindowSizeKey].height,
minWidth: 680, minWidth: 680,
minHeight: 500, minHeight: 500,
x: this.windowStates[Keys.mainWindowSize].x, x: this.windowStates[mainWindowSizeKey].x,
y: this.windowStates[Keys.mainWindowSize].y, y: this.windowStates[mainWindowSizeKey].y,
title: app.name, title: app.name,
icon: process.platform === 'linux' ? path.join(__dirname, '/images/icon.png') : undefined, icon: process.platform === 'linux' ? path.join(__dirname, '/images/icon.png') : undefined,
titleBarStyle: this.hideTitleBar && process.platform === 'darwin' ? 'hiddenInset' : undefined, titleBarStyle: this.hideTitleBar && process.platform === 'darwin' ? 'hiddenInset' : undefined,
@@ -132,7 +129,7 @@ export class WindowMain {
}, },
}); });
if (this.windowStates[Keys.mainWindowSize].isMaximized) { if (this.windowStates[mainWindowSizeKey].isMaximized) {
this.win.maximize(); this.win.maximize();
} }
@@ -158,7 +155,7 @@ export class WindowMain {
// Emitted when the window is closed. // Emitted when the window is closed.
this.win.on('closed', async () => { this.win.on('closed', async () => {
await this.updateWindowState(Keys.mainWindowSize, this.win); await this.updateWindowState(mainWindowSizeKey, this.win);
// Dereference the window object, usually you would store window // Dereference the window object, usually you would store window
// in an array if your app supports multi windows, this is the time // in an array if your app supports multi windows, this is the time
@@ -167,23 +164,23 @@ export class WindowMain {
}); });
this.win.on('close', async () => { this.win.on('close', async () => {
await this.updateWindowState(Keys.mainWindowSize, this.win); await this.updateWindowState(mainWindowSizeKey, this.win);
}); });
this.win.on('maximize', async () => { this.win.on('maximize', async () => {
await this.updateWindowState(Keys.mainWindowSize, this.win); await this.updateWindowState(mainWindowSizeKey, this.win);
}); });
this.win.on('unmaximize', async () => { this.win.on('unmaximize', async () => {
await this.updateWindowState(Keys.mainWindowSize, this.win); await this.updateWindowState(mainWindowSizeKey, this.win);
}); });
this.win.on('resize', () => { this.win.on('resize', () => {
this.windowStateChangeHandler(Keys.mainWindowSize, this.win); this.windowStateChangeHandler(mainWindowSizeKey, this.win);
}); });
this.win.on('move', () => { this.win.on('move', () => {
this.windowStateChangeHandler(Keys.mainWindowSize, this.win); this.windowStateChangeHandler(mainWindowSizeKey, this.win);
}); });
this.win.on('focus', () => { this.win.on('focus', () => {
this.win.webContents.send('messagingService', { this.win.webContents.send('messagingService', {
@@ -195,12 +192,15 @@ export class WindowMain {
if (this.createWindowCallback) { if (this.createWindowCallback) {
this.createWindowCallback(this.win); this.createWindowCallback(this.win);
} }
} catch (e) {
this.logService.error(e);
}
} }
async toggleAlwaysOnTop() { async toggleAlwaysOnTop() {
this.enableAlwaysOnTop = !this.win.isAlwaysOnTop(); this.enableAlwaysOnTop = !this.win.isAlwaysOnTop();
this.win.setAlwaysOnTop(this.enableAlwaysOnTop); this.win.setAlwaysOnTop(this.enableAlwaysOnTop);
await this.storageService.save(ElectronConstants.enableAlwaysOnTopKey, this.enableAlwaysOnTop); await this.stateService.setEnableAlwaysOnTop(this.enableAlwaysOnTop);
} }
private windowStateChangeHandler(configKey: string, win: BrowserWindow) { private windowStateChangeHandler(configKey: string, win: BrowserWindow) {
@@ -219,7 +219,7 @@ export class WindowMain {
const bounds = win.getBounds(); const bounds = win.getBounds();
if (this.windowStates[configKey] == null) { if (this.windowStates[configKey] == null) {
this.windowStates[configKey] = await this.storageService.get<any>(configKey); this.windowStates[configKey] = (await this.stateService.getWindow()).get(configKey);
if (this.windowStates[configKey] == null) { if (this.windowStates[configKey] == null) {
this.windowStates[configKey] = {}; this.windowStates[configKey] = {};
} }
@@ -235,14 +235,19 @@ export class WindowMain {
this.windowStates[configKey].height = bounds.height; this.windowStates[configKey].height = bounds.height;
} }
await this.storageService.save(configKey, this.windowStates[configKey]); const cachedWindow = await this.stateService.getWindow() ?? new Map<string, any>();
cachedWindow.set(configKey, this.windowStates[configKey]);
await this.stateService.setWindow(cachedWindow);
} catch (e) { } catch (e) {
this.logService.error(e); this.logService.error(e);
} }
} }
private async getWindowState(configKey: string, defaultWidth: number, defaultHeight: number) { private async getWindowState(configKey: string, defaultWidth: number, defaultHeight: number) {
let state = await this.storageService.get<any>(configKey); const windowState = await this.stateService.getWindow() ?? new Map<string, any>();
let state = windowState.has(configKey) ?
windowState.get(configKey) :
null;
const isValid = state != null && (this.stateHasBounds(state) || state.isMaximized); const isValid = state != null && (this.stateHasBounds(state) || state.isMaximized);
let displayBounds: Electron.Rectangle = null; let displayBounds: Electron.Rectangle = null;

View File

@@ -1,15 +1,15 @@
import * as chalk from 'chalk'; import * as chalk from 'chalk';
import { StateService } from 'jslib-common/abstractions/state.service';
import { Response } from './models/response'; import { Response } from './models/response';
import { ListResponse } from './models/response/listResponse'; import { ListResponse } from './models/response/listResponse';
import { MessageResponse } from './models/response/messageResponse'; import { MessageResponse } from './models/response/messageResponse';
import { StringResponse } from './models/response/stringResponse'; import { StringResponse } from './models/response/stringResponse';
import { UserService } from 'jslib-common/abstractions/user.service';
export abstract class BaseProgram { export abstract class BaseProgram {
constructor( constructor(
private userService: UserService, private stateService: StateService,
private writeLn: (s: string, finalLine: boolean, error: boolean) => void) { } private writeLn: (s: string, finalLine: boolean, error: boolean) => void) { }
protected processResponse(response: Response, exitImmediately = false, dataProcessor: () => string = null) { protected processResponse(response: Response, exitImmediately = false, dataProcessor: () => string = null) {
@@ -92,15 +92,15 @@ export abstract class BaseProgram {
} }
protected async exitIfAuthed() { protected async exitIfAuthed() {
const authed = await this.userService.isAuthenticated(); const authed = await this.stateService.getIsAuthenticated();
if (authed) { if (authed) {
const email = await this.userService.getEmail(); const email = await this.stateService.getEmail();
this.processResponse(Response.error('You are already logged in as ' + email + '.'), true); this.processResponse(Response.error('You are already logged in as ' + email + '.'), true);
} }
} }
protected async exitIfNotAuthed() { protected async exitIfNotAuthed() {
const authed = await this.userService.isAuthenticated(); const authed = await this.stateService.getIsAuthenticated();
if (!authed) { if (!authed) {
this.processResponse(Response.error('You are not logged in.'), true); this.processResponse(Response.error('You are not logged in.'), true);
} }

View File

@@ -17,8 +17,8 @@ import { I18nService } from 'jslib-common/abstractions/i18n.service';
import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib-common/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.service';
import { PolicyService } from 'jslib-common/abstractions/policy.service'; import { PolicyService } from 'jslib-common/abstractions/policy.service';
import { StateService } from 'jslib-common/abstractions/state.service';
import { SyncService } from 'jslib-common/abstractions/sync.service'; import { SyncService } from 'jslib-common/abstractions/sync.service';
import { UserService } from 'jslib-common/abstractions/user.service';
import { Response } from '../models/response'; import { Response } from '../models/response';
@@ -47,7 +47,7 @@ export class LoginCommand {
protected i18nService: I18nService, protected environmentService: EnvironmentService, protected i18nService: I18nService, protected environmentService: EnvironmentService,
protected passwordGenerationService: PasswordGenerationService, protected passwordGenerationService: PasswordGenerationService,
protected cryptoFunctionService: CryptoFunctionService, protected platformUtilsService: PlatformUtilsService, protected cryptoFunctionService: CryptoFunctionService, protected platformUtilsService: PlatformUtilsService,
protected userService: UserService, protected cryptoService: CryptoService, protected stateService: StateService, protected cryptoService: CryptoService,
protected policyService: PolicyService, clientId: string, private syncService: SyncService) { protected policyService: PolicyService, clientId: string, private syncService: SyncService) {
this.clientId = clientId; this.clientId = clientId;
} }
@@ -285,7 +285,7 @@ export class LoginCommand {
} }
if (this.email == null || this.email === 'undefined') { if (this.email == null || this.email === 'undefined') {
this.email = await this.userService.getEmail(); this.email = await this.stateService.getEmail();
} }
// Get New Master Password // Get New Master Password
@@ -335,8 +335,8 @@ export class LoginCommand {
// Retrieve details for key generation // Retrieve details for key generation
const enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions(); const enforcedPolicyOptions = await this.policyService.getMasterPasswordPolicyOptions();
const kdf = await this.userService.getKdf(); const kdf = await this.stateService.getKdfType();
const kdfIterations = await this.userService.getKdfIterations(); const kdfIterations = await this.stateService.getKdfIterations();
if (enforcedPolicyOptions != null && if (enforcedPolicyOptions != null &&
!this.policyService.evaluateMasterPassword( !this.policyService.evaluateMasterPassword(