[Auto-Logout] Implement Vault Timeout Options (#1194)

* Update jslib 31a2574 -> 28e3fff

* Initial commit for vault timeout

* Updated timeout/action retrieval in idle.background

* Cycle saved for idle check

* Await async calls for lock/logout in idle bg

* Updated lock vs log out conditional

Co-authored-by: Vincent Salucci <vsalucci@bitwarden.com>
This commit is contained in:
Vincent Salucci 2020-04-06 10:40:16 -05:00 committed by GitHub
parent f18deddb59
commit e510738a03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 137 additions and 90 deletions

2
jslib

@ -1 +1 @@
Subproject commit 31a257407be7f8f47624b0d021363aaf2cfda2d7 Subproject commit 28e3fff739e64c2dd80d3d98717e2921895d16df

View File

@ -321,8 +321,8 @@
"invalidMasterPassword": { "invalidMasterPassword": {
"message": "Invalid master password" "message": "Invalid master password"
}, },
"lockOptions": { "vaultTimeout": {
"message": "Lock Options" "message": "Vault Timeout"
}, },
"lockNow": { "lockNow": {
"message": "Lock Now" "message": "Lock Now"
@ -1247,5 +1247,12 @@
}, },
"passwordGeneratorPolicyInEffect": { "passwordGeneratorPolicyInEffect": {
"message": "One or more organization policies are affecting your generator settings." "message": "One or more organization policies are affecting your generator settings."
},
"vaultTimeoutAction": {
"message": "Vault Timeout Action"
},
"lock": {
"message": "Lock",
"description": "Verb form: to make secure or inaccesible by"
} }
} }

View File

@ -4,9 +4,9 @@ import MainBackground from './main.background';
import { Analytics } from 'jslib/misc'; import { Analytics } from 'jslib/misc';
import { LockService } from 'jslib/abstractions/lock.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
export default class CommandsBackground { export default class CommandsBackground {
private isSafari: boolean; private isSafari: boolean;
@ -15,7 +15,7 @@ export default class CommandsBackground {
constructor(private main: MainBackground, private passwordGenerationService: PasswordGenerationService, constructor(private main: MainBackground, private passwordGenerationService: PasswordGenerationService,
private platformUtilsService: PlatformUtilsService, private analytics: Analytics, private platformUtilsService: PlatformUtilsService, private analytics: Analytics,
private lockService: LockService) { private vaultTimeoutService: VaultTimeoutService) {
this.isSafari = this.platformUtilsService.isSafari(); this.isSafari = this.platformUtilsService.isSafari();
this.isEdge = this.platformUtilsService.isEdge(); this.isEdge = this.platformUtilsService.isEdge();
this.isVivaldi = this.platformUtilsService.isVivaldi(); this.isVivaldi = this.platformUtilsService.isVivaldi();
@ -69,7 +69,7 @@ export default class CommandsBackground {
} }
private async autoFillLogin(tab?: any) { private async autoFillLogin(tab?: any) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }

View File

@ -6,10 +6,10 @@ import { Analytics } from 'jslib/misc';
import { CipherService } from 'jslib/abstractions/cipher.service'; import { CipherService } from 'jslib/abstractions/cipher.service';
import { EventService } from 'jslib/abstractions/event.service'; import { EventService } from 'jslib/abstractions/event.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { TotpService } from 'jslib/abstractions/totp.service'; import { TotpService } from 'jslib/abstractions/totp.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { EventType } from 'jslib/enums/eventType'; import { EventType } from 'jslib/enums/eventType';
@ -18,7 +18,7 @@ export default class ContextMenusBackground {
constructor(private main: MainBackground, private cipherService: CipherService, constructor(private main: MainBackground, private cipherService: CipherService,
private passwordGenerationService: PasswordGenerationService, private analytics: Analytics, private passwordGenerationService: PasswordGenerationService, private analytics: Analytics,
private platformUtilsService: PlatformUtilsService, private lockService: LockService, private platformUtilsService: PlatformUtilsService, private vaultTimeoutService: VaultTimeoutService,
private eventService: EventService, private totpService: TotpService) { private eventService: EventService, private totpService: TotpService) {
this.contextMenus = chrome.contextMenus; this.contextMenus = chrome.contextMenus;
} }
@ -61,7 +61,7 @@ export default class ContextMenusBackground {
return; return;
} }
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }

View File

@ -1,8 +1,8 @@
import { ConstantsService } from 'jslib/services/constants.service'; import { ConstantsService } from 'jslib/services/constants.service';
import { import {
LockService,
StorageService, StorageService,
VaultTimeoutService,
} from 'jslib/abstractions'; } from 'jslib/abstractions';
import { NotificationsService } from 'jslib/abstractions/notifications.service'; import { NotificationsService } from 'jslib/abstractions/notifications.service';
@ -13,7 +13,7 @@ export default class IdleBackground {
private idleTimer: number = null; private idleTimer: number = null;
private idleState = 'active'; private idleState = 'active';
constructor(private lockService: LockService, private storageService: StorageService, constructor(private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService,
private notificationsService: NotificationsService) { private notificationsService: NotificationsService) {
this.idle = chrome.idle || (browser != null ? browser.idle : null); this.idle = chrome.idle || (browser != null ? browser.idle : null);
} }
@ -39,10 +39,15 @@ export default class IdleBackground {
if (this.idle.onStateChanged) { if (this.idle.onStateChanged) {
this.idle.onStateChanged.addListener(async (newState: string) => { this.idle.onStateChanged.addListener(async (newState: string) => {
if (newState === 'locked') { if (newState === 'locked') { // If the screen is locked or the screensaver activates
const lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey); const timeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
if (lockOption === -2) { if (timeout === -2) { // On System Lock vault timeout option
this.lockService.lock(true); const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
if (action === 'lock') {
await this.vaultTimeoutService.lock(true);
} else {
await this.vaultTimeoutService.logOut();
}
} }
} }
}); });

View File

@ -11,13 +11,13 @@ import {
CryptoService, CryptoService,
EnvironmentService, EnvironmentService,
FolderService, FolderService,
LockService,
PasswordGenerationService, PasswordGenerationService,
SettingsService, SettingsService,
SyncService, SyncService,
TokenService, TokenService,
TotpService, TotpService,
UserService, UserService,
VaultTimeoutService,
} from 'jslib/services'; } from 'jslib/services';
import { EventService } from 'jslib/services/event.service'; import { EventService } from 'jslib/services/event.service';
import { ExportService } from 'jslib/services/export.service'; import { ExportService } from 'jslib/services/export.service';
@ -37,7 +37,6 @@ import {
EnvironmentService as EnvironmentServiceAbstraction, EnvironmentService as EnvironmentServiceAbstraction,
FolderService as FolderServiceAbstraction, FolderService as FolderServiceAbstraction,
I18nService as I18nServiceAbstraction, I18nService as I18nServiceAbstraction,
LockService as LockServiceAbstraction,
MessagingService as MessagingServiceAbstraction, MessagingService as MessagingServiceAbstraction,
PasswordGenerationService as PasswordGenerationServiceAbstraction, PasswordGenerationService as PasswordGenerationServiceAbstraction,
PlatformUtilsService as PlatformUtilsServiceAbstraction, PlatformUtilsService as PlatformUtilsServiceAbstraction,
@ -47,6 +46,7 @@ import {
TokenService as TokenServiceAbstraction, TokenService as TokenServiceAbstraction,
TotpService as TotpServiceAbstraction, TotpService as TotpServiceAbstraction,
UserService as UserServiceAbstraction, UserService as UserServiceAbstraction,
VaultTimeoutService as VaultTimeoutServiceAbstraction,
} from 'jslib/abstractions'; } from 'jslib/abstractions';
import { EventService as EventServiceAbstraction } from 'jslib/abstractions/event.service'; import { EventService as EventServiceAbstraction } from 'jslib/abstractions/event.service';
import { ExportService as ExportServiceAbstraction } from 'jslib/abstractions/export.service'; import { ExportService as ExportServiceAbstraction } from 'jslib/abstractions/export.service';
@ -94,7 +94,7 @@ export default class MainBackground {
cipherService: CipherServiceAbstraction; cipherService: CipherServiceAbstraction;
folderService: FolderServiceAbstraction; folderService: FolderServiceAbstraction;
collectionService: CollectionServiceAbstraction; collectionService: CollectionServiceAbstraction;
lockService: LockServiceAbstraction; vaultTimeoutService: VaultTimeoutServiceAbstraction;
syncService: SyncServiceAbstraction; syncService: SyncServiceAbstraction;
passwordGenerationService: PasswordGenerationServiceAbstraction; passwordGenerationService: PasswordGenerationServiceAbstraction;
totpService: TotpServiceAbstraction; totpService: TotpServiceAbstraction;
@ -156,9 +156,9 @@ export default class MainBackground {
this.i18nService); this.i18nService);
this.searchService = new SearchService(this.cipherService, this.platformUtilsService); this.searchService = new SearchService(this.cipherService, this.platformUtilsService);
this.policyService = new PolicyService(this.userService, this.storageService); this.policyService = new PolicyService(this.userService, this.storageService);
this.lockService = new LockService(this.cipherService, this.folderService, this.collectionService, this.vaultTimeoutService = new VaultTimeoutService(this.cipherService, this.folderService,
this.cryptoService, this.platformUtilsService, this.storageService, this.messagingService, this.collectionService, this.cryptoService, this.platformUtilsService, this.storageService,
this.searchService, this.userService, async () => { this.messagingService, this.searchService, this.userService, async () => {
if (this.notificationsService != null) { if (this.notificationsService != null) {
this.notificationsService.updateConnection(false); this.notificationsService.updateConnection(false);
} }
@ -168,7 +168,7 @@ export default class MainBackground {
this.systemService.startProcessReload(); this.systemService.startProcessReload();
await this.systemService.clearPendingClipboard(); await this.systemService.clearPendingClipboard();
} }
}); }, async () => await this.logout(false));
this.syncService = new SyncService(this.userService, this.apiService, this.settingsService, this.syncService = new SyncService(this.userService, this.apiService, this.settingsService,
this.folderService, this.cipherService, this.cryptoService, this.collectionService, this.folderService, this.cipherService, this.cryptoService, this.collectionService,
this.storageService, this.messagingService, this.policyService, this.storageService, this.messagingService, this.policyService,
@ -184,12 +184,12 @@ export default class MainBackground {
this.auditService = new AuditService(cryptoFunctionService, this.apiService); this.auditService = new AuditService(cryptoFunctionService, this.apiService);
this.exportService = new ExportService(this.folderService, this.cipherService, this.apiService); this.exportService = new ExportService(this.folderService, this.cipherService, this.apiService);
this.notificationsService = new NotificationsService(this.userService, this.syncService, this.appIdService, this.notificationsService = new NotificationsService(this.userService, this.syncService, this.appIdService,
this.apiService, this.lockService, () => this.logout(true)); this.apiService, this.vaultTimeoutService, () => this.logout(true));
this.environmentService = new EnvironmentService(this.apiService, this.storageService, this.environmentService = new EnvironmentService(this.apiService, this.storageService,
this.notificationsService); this.notificationsService);
this.analytics = new Analytics(window, () => BrowserApi.gaFilter(), this.platformUtilsService, this.analytics = new Analytics(window, () => BrowserApi.gaFilter(), this.platformUtilsService,
this.storageService, this.appIdService); this.storageService, this.appIdService);
this.systemService = new SystemService(this.storageService, this.lockService, this.systemService = new SystemService(this.storageService, this.vaultTimeoutService,
this.messagingService, this.platformUtilsService, () => { this.messagingService, this.platformUtilsService, () => {
const forceWindowReload = this.platformUtilsService.isSafari() || const forceWindowReload = this.platformUtilsService.isSafari() ||
this.platformUtilsService.isFirefox() || this.platformUtilsService.isOpera(); this.platformUtilsService.isFirefox() || this.platformUtilsService.isOpera();
@ -205,18 +205,19 @@ export default class MainBackground {
// Background // Background
this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService, this.runtimeBackground = new RuntimeBackground(this, this.autofillService, this.cipherService,
this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService, this.platformUtilsService as BrowserPlatformUtilsService, this.storageService, this.i18nService,
this.analytics, this.notificationsService, this.systemService, this.lockService); this.analytics, this.notificationsService, this.systemService, this.vaultTimeoutService);
this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService, this.commandsBackground = new CommandsBackground(this, this.passwordGenerationService,
this.platformUtilsService, this.analytics, this.lockService); this.platformUtilsService, this.analytics, this.vaultTimeoutService);
if (!this.isSafari) { if (!this.isSafari) {
this.tabsBackground = new TabsBackground(this); this.tabsBackground = new TabsBackground(this);
this.contextMenusBackground = new ContextMenusBackground(this, this.cipherService, this.contextMenusBackground = new ContextMenusBackground(this, this.cipherService,
this.passwordGenerationService, this.analytics, this.platformUtilsService, this.lockService, this.passwordGenerationService, this.analytics, this.platformUtilsService, this.vaultTimeoutService,
this.eventService, this.totpService); this.eventService, this.totpService);
this.idleBackground = new IdleBackground(this.lockService, this.storageService, this.notificationsService); this.idleBackground = new IdleBackground(this.vaultTimeoutService, this.storageService,
this.notificationsService);
this.webRequestBackground = new WebRequestBackground(this.platformUtilsService, this.cipherService, this.webRequestBackground = new WebRequestBackground(this.platformUtilsService, this.cipherService,
this.lockService); this.vaultTimeoutService);
this.windowsBackground = new WindowsBackground(this); this.windowsBackground = new WindowsBackground(this);
} }
} }
@ -226,7 +227,7 @@ export default class MainBackground {
this.analytics.ga('send', 'pageview', '/background.html'); this.analytics.ga('send', 'pageview', '/background.html');
this.containerService.attachToWindow(window); this.containerService.attachToWindow(window);
await (this.lockService as LockService).init(true); await (this.vaultTimeoutService as VaultTimeoutService).init(true);
await (this.i18nService as I18nService).init(); await (this.i18nService as I18nService).init();
await (this.eventService as EventService).init(true); await (this.eventService as EventService).init(true);
await this.runtimeBackground.init(); await this.runtimeBackground.init();
@ -258,7 +259,7 @@ export default class MainBackground {
} }
const isAuthenticated = await this.userService.isAuthenticated(); const isAuthenticated = await this.userService.isAuthenticated();
const locked = await this.lockService.isLocked(); const locked = await this.vaultTimeoutService.isLocked();
let suffix = ''; let suffix = '';
if (!isAuthenticated) { if (!isAuthenticated) {
@ -311,7 +312,7 @@ export default class MainBackground {
this.collectionService.clear(userId), this.collectionService.clear(userId),
this.policyService.clear(userId), this.policyService.clear(userId),
this.passwordGenerationService.clear(), this.passwordGenerationService.clear(),
this.lockService.clear(), this.vaultTimeoutService.clear(),
]); ]);
this.searchService.clearIndex(); this.searchService.clearIndex();
@ -330,7 +331,7 @@ export default class MainBackground {
return; return;
} }
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@ -378,8 +379,8 @@ export default class MainBackground {
return; return;
} }
const currentLockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey); const currentVaultTimeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
if (currentLockOption == null) { if (currentVaultTimeout == null) {
return; return;
} }
@ -482,7 +483,7 @@ export default class MainBackground {
this.actionSetBadgeBackgroundColor(this.sidebarAction); this.actionSetBadgeBackgroundColor(this.sidebarAction);
this.menuOptionsLoaded = []; this.menuOptionsLoaded = [];
const locked = await this.lockService.isLocked(); const locked = await this.vaultTimeoutService.isLocked();
if (!locked) { if (!locked) {
try { try {
const ciphers = await this.cipherService.getAllDecryptedForUrl(url); const ciphers = await this.cipherService.getAllDecryptedForUrl(url);

View File

@ -11,9 +11,9 @@ import { I18nService } from 'jslib/abstractions/i18n.service';
import { Analytics } from 'jslib/misc'; import { Analytics } from 'jslib/misc';
import { CipherService } from 'jslib/abstractions/cipher.service'; import { CipherService } from 'jslib/abstractions/cipher.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { StorageService } from 'jslib/abstractions/storage.service'; import { StorageService } from 'jslib/abstractions/storage.service';
import { SystemService } from 'jslib/abstractions/system.service'; import { SystemService } from 'jslib/abstractions/system.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { BrowserApi } from '../browser/browserApi'; import { BrowserApi } from '../browser/browserApi';
@ -37,7 +37,7 @@ export default class RuntimeBackground {
private cipherService: CipherService, private platformUtilsService: BrowserPlatformUtilsService, private cipherService: CipherService, private platformUtilsService: BrowserPlatformUtilsService,
private storageService: StorageService, private i18nService: I18nService, private storageService: StorageService, private i18nService: I18nService,
private analytics: Analytics, private notificationsService: NotificationsService, private analytics: Analytics, private notificationsService: NotificationsService,
private systemService: SystemService, private lockService: LockService) { private systemService: SystemService, private vaultTimeoutService: VaultTimeoutService) {
this.isSafari = this.platformUtilsService.isSafari(); this.isSafari = this.platformUtilsService.isSafari();
this.runtime = this.isSafari ? {} : chrome.runtime; this.runtime = this.isSafari ? {} : chrome.runtime;
@ -127,7 +127,7 @@ export default class RuntimeBackground {
await this.main.reseedStorage(); await this.main.reseedStorage();
break; break;
case 'collectPageDetailsResponse': case 'collectPageDetailsResponse':
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
switch (msg.sender) { switch (msg.sender) {
@ -183,7 +183,7 @@ export default class RuntimeBackground {
} }
private async saveAddLogin(tab: any) { private async saveAddLogin(tab: any) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@ -223,7 +223,7 @@ export default class RuntimeBackground {
} }
private async saveChangePassword(tab: any) { private async saveChangePassword(tab: any) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@ -276,7 +276,7 @@ export default class RuntimeBackground {
} }
private async addLogin(loginInfo: any, tab: any) { private async addLogin(loginInfo: any, tab: any) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@ -322,7 +322,7 @@ export default class RuntimeBackground {
} }
private async changedPassword(changeData: any, tab: any) { private async changedPassword(changeData: any, tab: any) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
return; return;
} }
@ -400,10 +400,16 @@ export default class RuntimeBackground {
} }
private async setDefaultSettings() { private async setDefaultSettings() {
// Default lock options to "on restart". // Default timeout option to "on restart".
const currentLockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey); const currentVaultTimeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
if (currentLockOption == null) { if (currentVaultTimeout == null) {
await this.storageService.save(ConstantsService.lockOptionKey, -1); await this.storageService.save(ConstantsService.vaultTimeoutKey, -1);
}
// Default action to "lock".
const currentVaultTimeoutAction = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
if (currentVaultTimeoutAction == null) {
await this.storageService.save(ConstantsService.vaultTimeoutActionKey, 'lock');
} }
} }

View File

@ -1,6 +1,6 @@
import { CipherService } from 'jslib/abstractions/cipher.service'; import { CipherService } from 'jslib/abstractions/cipher.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
export default class WebRequestBackground { export default class WebRequestBackground {
private pendingAuthRequests: any[] = []; private pendingAuthRequests: any[] = [];
@ -8,7 +8,7 @@ export default class WebRequestBackground {
private isFirefox: boolean; private isFirefox: boolean;
constructor(platformUtilsService: PlatformUtilsService, private cipherService: CipherService, constructor(platformUtilsService: PlatformUtilsService, private cipherService: CipherService,
private lockService: LockService) { private vaultTimeoutService: VaultTimeoutService) {
this.webRequest = (window as any).chrome.webRequest; this.webRequest = (window as any).chrome.webRequest;
this.isFirefox = platformUtilsService.isFirefox(); this.isFirefox = platformUtilsService.isFirefox();
} }
@ -44,7 +44,7 @@ export default class WebRequestBackground {
} }
private async resolveAuthCredentials(domain: string, success: Function, error: Function) { private async resolveAuthCredentials(domain: string, success: Function, error: Function) {
if (await this.lockService.isLocked()) { if (await this.vaultTimeoutService.isLocked()) {
error(); error();
return; return;
} }

View File

@ -4,12 +4,12 @@ import { Router } from '@angular/router';
import { CryptoService } from 'jslib/abstractions/crypto.service'; import { CryptoService } from 'jslib/abstractions/crypto.service';
import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service';
import { I18nService } from 'jslib/abstractions/i18n.service'; import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { MessagingService } from 'jslib/abstractions/messaging.service'; import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StateService } from 'jslib/abstractions/state.service'; import { StateService } from 'jslib/abstractions/state.service';
import { StorageService } from 'jslib/abstractions/storage.service'; import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { LockComponent as BaseLockComponent } from 'jslib/angular/components/lock.component'; import { LockComponent as BaseLockComponent } from 'jslib/angular/components/lock.component';
@ -21,10 +21,10 @@ export class LockComponent extends BaseLockComponent {
constructor(router: Router, i18nService: I18nService, constructor(router: Router, i18nService: I18nService,
platformUtilsService: PlatformUtilsService, messagingService: MessagingService, platformUtilsService: PlatformUtilsService, messagingService: MessagingService,
userService: UserService, cryptoService: CryptoService, userService: UserService, cryptoService: CryptoService,
storageService: StorageService, lockService: LockService, storageService: StorageService, vaultTimeoutService: VaultTimeoutService,
environmentService: EnvironmentService, stateService: StateService) { environmentService: EnvironmentService, stateService: StateService) {
super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService, super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService,
storageService, lockService, environmentService, stateService); storageService, vaultTimeoutService, environmentService, stateService);
this.successRoute = '/tabs/current'; this.successRoute = '/tabs/current';
} }

View File

@ -6,12 +6,13 @@ import {
Router, Router,
} from '@angular/router'; } from '@angular/router';
import { LockService } from 'jslib/abstractions/lock.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
@Injectable() @Injectable()
export class LaunchGuardService implements CanActivate { export class LaunchGuardService implements CanActivate {
constructor(private lockService: LockService, private userService: UserService, private router: Router) { } constructor(private vaultTimeoutService: VaultTimeoutService, private userService: UserService,
private router: Router) { }
async canActivate() { async canActivate() {
if (BrowserApi.getBackgroundPage() == null) { if (BrowserApi.getBackgroundPage() == null) {
@ -28,7 +29,7 @@ export class LaunchGuardService implements CanActivate {
return true; return true;
} }
const locked = await this.lockService.isLocked(); const locked = await this.vaultTimeoutService.isLocked();
if (locked) { if (locked) {
this.router.navigate(['lock']); this.router.navigate(['lock']);
} else { } else {

View File

@ -26,7 +26,6 @@ import { EventService } from 'jslib/abstractions/event.service';
import { ExportService } from 'jslib/abstractions/export.service'; import { ExportService } from 'jslib/abstractions/export.service';
import { FolderService } from 'jslib/abstractions/folder.service'; import { FolderService } from 'jslib/abstractions/folder.service';
import { I18nService } from 'jslib/abstractions/i18n.service'; import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { MessagingService } from 'jslib/abstractions/messaging.service'; import { MessagingService } from 'jslib/abstractions/messaging.service';
import { NotificationsService } from 'jslib/abstractions/notifications.service'; import { NotificationsService } from 'jslib/abstractions/notifications.service';
import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service'; import { PasswordGenerationService } from 'jslib/abstractions/passwordGeneration.service';
@ -40,6 +39,7 @@ import { SyncService } from 'jslib/abstractions/sync.service';
import { TokenService } from 'jslib/abstractions/token.service'; import { TokenService } from 'jslib/abstractions/token.service';
import { TotpService } from 'jslib/abstractions/totp.service'; import { TotpService } from 'jslib/abstractions/totp.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
import { AutofillService } from '../../services/abstractions/autofill.service'; import { AutofillService } from '../../services/abstractions/autofill.service';
import BrowserMessagingService from '../../services/browserMessaging.service'; import BrowserMessagingService from '../../services/browserMessaging.service';
@ -146,11 +146,15 @@ export function initFactory(i18nService: I18nService, storageService: StorageSer
{ provide: SyncService, useFactory: getBgService<SyncService>('syncService'), deps: [] }, { provide: SyncService, useFactory: getBgService<SyncService>('syncService'), deps: [] },
{ provide: UserService, useFactory: getBgService<UserService>('userService'), deps: [] }, { provide: UserService, useFactory: getBgService<UserService>('userService'), deps: [] },
{ provide: SettingsService, useFactory: getBgService<SettingsService>('settingsService'), deps: [] }, { provide: SettingsService, useFactory: getBgService<SettingsService>('settingsService'), deps: [] },
{ provide: LockService, useFactory: getBgService<LockService>('lockService'), deps: [] },
{ provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] }, { provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] },
{ provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] }, { provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] },
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] }, { provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
{ provide: ExportService, useFactory: getBgService<ExportService>('exportService'), deps: [] }, { provide: ExportService, useFactory: getBgService<ExportService>('exportService'), deps: [] },
{
provide: VaultTimeoutService,
useFactory: getBgService<VaultTimeoutService>('vaultTimeoutService'),
deps: [],
},
{ {
provide: NotificationsService, provide: NotificationsService,
useFactory: getBgService<NotificationsService>('notificationsService'), useFactory: getBgService<NotificationsService>('notificationsService'),

View File

@ -25,10 +25,17 @@
<div class="box-header">{{'security' | i18n}}</div> <div class="box-header">{{'security' | i18n}}</div>
<div class="box-content single-line"> <div class="box-content single-line">
<div class="box-content-row display-block" appBoxRow> <div class="box-content-row display-block" appBoxRow>
<label for="lockOption">{{'lockOptions' | i18n}}</label> <label for="vaultTimeout">{{'vaultTimeout' | i18n}}</label>
<select #lockOptionsSelect id="lockOption" name="LockOptions" [ngModel]="lockOption" <select #vaultTimeoutSelect id="vaultTimeout" name="VaultTimeouts" [ngModel]="vaultTimeout"
(ngModelChange)="saveLockOption($event)"> (ngModelChange)="saveVaultTimeout($event)">
<option *ngFor="let o of lockOptions" [ngValue]="o.value">{{o.name}}</option> <option *ngFor="let o of vaultTimeouts" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row display-block" appBoxRow>
<label for="vaultTimeoutAction">{{'vaultTimeoutAction' | i18n}}</label>
<select id="vaultTimeoutAction" name="VaultTimeoutActions" [ngModel]="vaultTimeoutAction"
(ngModelChange)="saveVaultTimeoutAction($event)">
<option *ngFor="let o of vaultTimeoutActions" [ngValue]="o.value">{{o.name}}</option>
</select> </select>
</div> </div>
<div class="box-content-row box-content-row-checkbox" appBoxRow> <div class="box-content-row box-content-row-checkbox" appBoxRow>

View File

@ -18,11 +18,11 @@ import { ConstantsService } from 'jslib/services/constants.service';
import { CryptoService } from 'jslib/abstractions/crypto.service'; import { CryptoService } from 'jslib/abstractions/crypto.service';
import { EnvironmentService } from 'jslib/abstractions/environment.service'; import { EnvironmentService } from 'jslib/abstractions/environment.service';
import { I18nService } from 'jslib/abstractions/i18n.service'; import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { MessagingService } from 'jslib/abstractions/messaging.service'; import { MessagingService } from 'jslib/abstractions/messaging.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service'; import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service'; import { StorageService } from 'jslib/abstractions/storage.service';
import { UserService } from 'jslib/abstractions/user.service'; import { UserService } from 'jslib/abstractions/user.service';
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
const RateUrls = { const RateUrls = {
[DeviceType.ChromeExtension]: [DeviceType.ChromeExtension]:
@ -44,14 +44,16 @@ const RateUrls = {
templateUrl: 'settings.component.html', templateUrl: 'settings.component.html',
}) })
export class SettingsComponent implements OnInit { export class SettingsComponent implements OnInit {
@ViewChild('lockOptionsSelect', { read: ElementRef }) lockOptionsSelectRef: ElementRef; @ViewChild('vaultTimeoutSelect', { read: ElementRef }) vaultTimeoutSelectRef: ElementRef;
lockOptions: any[]; vaultTimeouts: any[];
lockOption: number = null; vaultTimeout: number = null;
vaultTimeoutActions: any[];
vaultTimeoutAction: string;
pin: boolean = null; pin: boolean = null;
previousLockOption: number = null; previousVaultTimeout: number = null;
constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
private analytics: Angulartics2, private lockService: LockService, private analytics: Angulartics2, private vaultTimeoutService: VaultTimeoutService,
private storageService: StorageService, public messagingService: MessagingService, private storageService: StorageService, public messagingService: MessagingService,
private router: Router, private environmentService: EnvironmentService, private router: Router, private environmentService: EnvironmentService,
private cryptoService: CryptoService, private userService: UserService) { private cryptoService: CryptoService, private userService: UserService) {
@ -61,7 +63,7 @@ export class SettingsComponent implements OnInit {
const showOnLocked = !this.platformUtilsService.isFirefox() && !this.platformUtilsService.isEdge() const showOnLocked = !this.platformUtilsService.isFirefox() && !this.platformUtilsService.isEdge()
&& !this.platformUtilsService.isSafari(); && !this.platformUtilsService.isSafari();
this.lockOptions = [ this.vaultTimeouts = [
{ name: this.i18nService.t('immediately'), value: 0 }, { name: this.i18nService.t('immediately'), value: 0 },
{ name: this.i18nService.t('oneMinute'), value: 1 }, { name: this.i18nService.t('oneMinute'), value: 1 },
{ name: this.i18nService.t('fiveMinutes'), value: 5 }, { name: this.i18nService.t('fiveMinutes'), value: 5 },
@ -74,47 +76,61 @@ export class SettingsComponent implements OnInit {
]; ];
if (showOnLocked) { if (showOnLocked) {
this.lockOptions.push({ name: this.i18nService.t('onLocked'), value: -2 }); this.vaultTimeouts.push({ name: this.i18nService.t('onLocked'), value: -2 });
} }
this.lockOptions.push({ name: this.i18nService.t('onRestart'), value: -1 }); this.vaultTimeouts.push({ name: this.i18nService.t('onRestart'), value: -1 });
this.lockOptions.push({ name: this.i18nService.t('never'), value: null }); this.vaultTimeouts.push({ name: this.i18nService.t('never'), value: null });
let option = await this.storageService.get<number>(ConstantsService.lockOptionKey); this.vaultTimeoutActions = [
if (option != null) { { name: this.i18nService.t('lock'), value: 'lock' },
if (option === -2 && !showOnLocked) { { name: this.i18nService.t('logOut'), value: 'logOut' },
option = -1; ];
}
this.lockOption = option;
}
this.previousLockOption = this.lockOption;
const pinSet = await this.lockService.isPinLockSet(); let timeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
if (timeout != null) {
if (timeout === -2 && !showOnLocked) {
timeout = -1;
}
this.vaultTimeout = timeout;
}
this.previousVaultTimeout = this.vaultTimeout;
const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
this.vaultTimeoutAction = action == null ? 'lock' : action;
const pinSet = await this.vaultTimeoutService.isPinLockSet();
this.pin = pinSet[0] || pinSet[1]; this.pin = pinSet[0] || pinSet[1];
} }
async saveLockOption(newValue: number) { async saveVaultTimeout(newValue: number) {
if (newValue == null) { if (newValue == null) {
const confirmed = await this.platformUtilsService.showDialog( const confirmed = await this.platformUtilsService.showDialog(
this.i18nService.t('neverLockWarning'), null, this.i18nService.t('neverLockWarning'), null,
this.i18nService.t('yes'), this.i18nService.t('cancel'), 'warning'); this.i18nService.t('yes'), this.i18nService.t('cancel'), 'warning');
if (!confirmed) { if (!confirmed) {
this.lockOptions.forEach((option: any, i) => { this.vaultTimeouts.forEach((option: any, i) => {
if (option.value === this.lockOption) { if (option.value === this.vaultTimeout) {
this.lockOptionsSelectRef.nativeElement.value = i + ': ' + this.lockOption; this.vaultTimeoutSelectRef.nativeElement.value = i + ': ' + this.vaultTimeout;
} }
}); });
return; return;
} }
} }
this.previousLockOption = this.lockOption; this.previousVaultTimeout = this.vaultTimeout;
this.lockOption = newValue; this.vaultTimeout = newValue;
await this.lockService.setLockOption(this.lockOption != null ? this.lockOption : null); await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null,
if (this.previousLockOption == null) { this.vaultTimeoutAction);
if (this.previousVaultTimeout == null) {
this.messagingService.send('bgReseedStorage'); this.messagingService.send('bgReseedStorage');
} }
} }
async saveVaultTimeoutAction(newValue: string) {
this.vaultTimeoutAction = newValue;
await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null,
this.vaultTimeoutAction);
}
async updatePin() { async updatePin() {
if (this.pin) { if (this.pin) {
const div = document.createElement('div'); const div = document.createElement('div');
@ -160,7 +176,7 @@ export class SettingsComponent implements OnInit {
if (masterPassOnRestart) { if (masterPassOnRestart) {
const encPin = await this.cryptoService.encrypt(pin); const encPin = await this.cryptoService.encrypt(pin);
await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString); await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString);
this.lockService.pinProtectedKey = pinProtectedKey; this.vaultTimeoutService.pinProtectedKey = pinProtectedKey;
} else { } else {
await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString); await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString);
} }
@ -170,13 +186,13 @@ export class SettingsComponent implements OnInit {
} }
if (!this.pin) { if (!this.pin) {
await this.cryptoService.clearPinProtectedKey(); await this.cryptoService.clearPinProtectedKey();
await this.lockService.clear(); await this.vaultTimeoutService.clear();
} }
} }
async lock() { async lock() {
this.analytics.eventTrack.next({ action: 'Lock Now' }); this.analytics.eventTrack.next({ action: 'Lock Now' });
await this.lockService.lock(true); await this.vaultTimeoutService.lock(true);
} }
async logOut() { async logOut() {