mirror of
https://github.com/bitwarden/browser
synced 2025-12-21 02:33:46 +00:00
[Auto-Logout] Implement Vault Timeout Options (#1194)
* Update jslib31a2574->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:
@@ -4,12 +4,12 @@ import { Router } from '@angular/router';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { LockService } from 'jslib/abstractions/lock.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StateService } from 'jslib/abstractions/state.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.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';
|
||||
|
||||
@@ -21,10 +21,10 @@ export class LockComponent extends BaseLockComponent {
|
||||
constructor(router: Router, i18nService: I18nService,
|
||||
platformUtilsService: PlatformUtilsService, messagingService: MessagingService,
|
||||
userService: UserService, cryptoService: CryptoService,
|
||||
storageService: StorageService, lockService: LockService,
|
||||
storageService: StorageService, vaultTimeoutService: VaultTimeoutService,
|
||||
environmentService: EnvironmentService, stateService: StateService) {
|
||||
super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService,
|
||||
storageService, lockService, environmentService, stateService);
|
||||
storageService, vaultTimeoutService, environmentService, stateService);
|
||||
this.successRoute = '/tabs/current';
|
||||
}
|
||||
|
||||
|
||||
@@ -6,12 +6,13 @@ import {
|
||||
Router,
|
||||
} from '@angular/router';
|
||||
|
||||
import { LockService } from 'jslib/abstractions/lock.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
@Injectable()
|
||||
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() {
|
||||
if (BrowserApi.getBackgroundPage() == null) {
|
||||
@@ -28,7 +29,7 @@ export class LaunchGuardService implements CanActivate {
|
||||
return true;
|
||||
}
|
||||
|
||||
const locked = await this.lockService.isLocked();
|
||||
const locked = await this.vaultTimeoutService.isLocked();
|
||||
if (locked) {
|
||||
this.router.navigate(['lock']);
|
||||
} else {
|
||||
|
||||
@@ -26,7 +26,6 @@ import { EventService } from 'jslib/abstractions/event.service';
|
||||
import { ExportService } from 'jslib/abstractions/export.service';
|
||||
import { FolderService } from 'jslib/abstractions/folder.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { LockService } from 'jslib/abstractions/lock.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { NotificationsService } from 'jslib/abstractions/notifications.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 { TotpService } from 'jslib/abstractions/totp.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
import { AutofillService } from '../../services/abstractions/autofill.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: UserService, useFactory: getBgService<UserService>('userService'), deps: [] },
|
||||
{ provide: SettingsService, useFactory: getBgService<SettingsService>('settingsService'), deps: [] },
|
||||
{ provide: LockService, useFactory: getBgService<LockService>('lockService'), deps: [] },
|
||||
{ provide: StorageService, useFactory: getBgService<StorageService>('storageService'), deps: [] },
|
||||
{ provide: AppIdService, useFactory: getBgService<AppIdService>('appIdService'), deps: [] },
|
||||
{ provide: AutofillService, useFactory: getBgService<AutofillService>('autofillService'), deps: [] },
|
||||
{ provide: ExportService, useFactory: getBgService<ExportService>('exportService'), deps: [] },
|
||||
{
|
||||
provide: VaultTimeoutService,
|
||||
useFactory: getBgService<VaultTimeoutService>('vaultTimeoutService'),
|
||||
deps: [],
|
||||
},
|
||||
{
|
||||
provide: NotificationsService,
|
||||
useFactory: getBgService<NotificationsService>('notificationsService'),
|
||||
|
||||
@@ -25,10 +25,17 @@
|
||||
<div class="box-header">{{'security' | i18n}}</div>
|
||||
<div class="box-content single-line">
|
||||
<div class="box-content-row display-block" appBoxRow>
|
||||
<label for="lockOption">{{'lockOptions' | i18n}}</label>
|
||||
<select #lockOptionsSelect id="lockOption" name="LockOptions" [ngModel]="lockOption"
|
||||
(ngModelChange)="saveLockOption($event)">
|
||||
<option *ngFor="let o of lockOptions" [ngValue]="o.value">{{o.name}}</option>
|
||||
<label for="vaultTimeout">{{'vaultTimeout' | i18n}}</label>
|
||||
<select #vaultTimeoutSelect id="vaultTimeout" name="VaultTimeouts" [ngModel]="vaultTimeout"
|
||||
(ngModelChange)="saveVaultTimeout($event)">
|
||||
<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>
|
||||
</div>
|
||||
<div class="box-content-row box-content-row-checkbox" appBoxRow>
|
||||
|
||||
@@ -18,11 +18,11 @@ import { ConstantsService } from 'jslib/services/constants.service';
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.service';
|
||||
import { EnvironmentService } from 'jslib/abstractions/environment.service';
|
||||
import { I18nService } from 'jslib/abstractions/i18n.service';
|
||||
import { LockService } from 'jslib/abstractions/lock.service';
|
||||
import { MessagingService } from 'jslib/abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
|
||||
import { StorageService } from 'jslib/abstractions/storage.service';
|
||||
import { UserService } from 'jslib/abstractions/user.service';
|
||||
import { VaultTimeoutService } from 'jslib/abstractions/vaultTimeout.service';
|
||||
|
||||
const RateUrls = {
|
||||
[DeviceType.ChromeExtension]:
|
||||
@@ -44,14 +44,16 @@ const RateUrls = {
|
||||
templateUrl: 'settings.component.html',
|
||||
})
|
||||
export class SettingsComponent implements OnInit {
|
||||
@ViewChild('lockOptionsSelect', { read: ElementRef }) lockOptionsSelectRef: ElementRef;
|
||||
lockOptions: any[];
|
||||
lockOption: number = null;
|
||||
@ViewChild('vaultTimeoutSelect', { read: ElementRef }) vaultTimeoutSelectRef: ElementRef;
|
||||
vaultTimeouts: any[];
|
||||
vaultTimeout: number = null;
|
||||
vaultTimeoutActions: any[];
|
||||
vaultTimeoutAction: string;
|
||||
pin: boolean = null;
|
||||
previousLockOption: number = null;
|
||||
previousVaultTimeout: number = null;
|
||||
|
||||
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 router: Router, private environmentService: EnvironmentService,
|
||||
private cryptoService: CryptoService, private userService: UserService) {
|
||||
@@ -61,7 +63,7 @@ export class SettingsComponent implements OnInit {
|
||||
const showOnLocked = !this.platformUtilsService.isFirefox() && !this.platformUtilsService.isEdge()
|
||||
&& !this.platformUtilsService.isSafari();
|
||||
|
||||
this.lockOptions = [
|
||||
this.vaultTimeouts = [
|
||||
{ name: this.i18nService.t('immediately'), value: 0 },
|
||||
{ name: this.i18nService.t('oneMinute'), value: 1 },
|
||||
{ name: this.i18nService.t('fiveMinutes'), value: 5 },
|
||||
@@ -74,47 +76,61 @@ export class SettingsComponent implements OnInit {
|
||||
];
|
||||
|
||||
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.lockOptions.push({ name: this.i18nService.t('never'), value: null });
|
||||
this.vaultTimeouts.push({ name: this.i18nService.t('onRestart'), value: -1 });
|
||||
this.vaultTimeouts.push({ name: this.i18nService.t('never'), value: null });
|
||||
|
||||
let option = await this.storageService.get<number>(ConstantsService.lockOptionKey);
|
||||
if (option != null) {
|
||||
if (option === -2 && !showOnLocked) {
|
||||
option = -1;
|
||||
this.vaultTimeoutActions = [
|
||||
{ name: this.i18nService.t('lock'), value: 'lock' },
|
||||
{ name: this.i18nService.t('logOut'), value: 'logOut' },
|
||||
];
|
||||
|
||||
let timeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey);
|
||||
if (timeout != null) {
|
||||
if (timeout === -2 && !showOnLocked) {
|
||||
timeout = -1;
|
||||
}
|
||||
this.lockOption = option;
|
||||
this.vaultTimeout = timeout;
|
||||
}
|
||||
this.previousLockOption = this.lockOption;
|
||||
this.previousVaultTimeout = this.vaultTimeout;
|
||||
const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
|
||||
this.vaultTimeoutAction = action == null ? 'lock' : action;
|
||||
|
||||
const pinSet = await this.lockService.isPinLockSet();
|
||||
const pinSet = await this.vaultTimeoutService.isPinLockSet();
|
||||
this.pin = pinSet[0] || pinSet[1];
|
||||
}
|
||||
|
||||
async saveLockOption(newValue: number) {
|
||||
async saveVaultTimeout(newValue: number) {
|
||||
if (newValue == null) {
|
||||
const confirmed = await this.platformUtilsService.showDialog(
|
||||
this.i18nService.t('neverLockWarning'), null,
|
||||
this.i18nService.t('yes'), this.i18nService.t('cancel'), 'warning');
|
||||
if (!confirmed) {
|
||||
this.lockOptions.forEach((option: any, i) => {
|
||||
if (option.value === this.lockOption) {
|
||||
this.lockOptionsSelectRef.nativeElement.value = i + ': ' + this.lockOption;
|
||||
this.vaultTimeouts.forEach((option: any, i) => {
|
||||
if (option.value === this.vaultTimeout) {
|
||||
this.vaultTimeoutSelectRef.nativeElement.value = i + ': ' + this.vaultTimeout;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.previousLockOption = this.lockOption;
|
||||
this.lockOption = newValue;
|
||||
await this.lockService.setLockOption(this.lockOption != null ? this.lockOption : null);
|
||||
if (this.previousLockOption == null) {
|
||||
this.previousVaultTimeout = this.vaultTimeout;
|
||||
this.vaultTimeout = newValue;
|
||||
await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null,
|
||||
this.vaultTimeoutAction);
|
||||
if (this.previousVaultTimeout == null) {
|
||||
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() {
|
||||
if (this.pin) {
|
||||
const div = document.createElement('div');
|
||||
@@ -160,7 +176,7 @@ export class SettingsComponent implements OnInit {
|
||||
if (masterPassOnRestart) {
|
||||
const encPin = await this.cryptoService.encrypt(pin);
|
||||
await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString);
|
||||
this.lockService.pinProtectedKey = pinProtectedKey;
|
||||
this.vaultTimeoutService.pinProtectedKey = pinProtectedKey;
|
||||
} else {
|
||||
await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString);
|
||||
}
|
||||
@@ -170,13 +186,13 @@ export class SettingsComponent implements OnInit {
|
||||
}
|
||||
if (!this.pin) {
|
||||
await this.cryptoService.clearPinProtectedKey();
|
||||
await this.lockService.clear();
|
||||
await this.vaultTimeoutService.clear();
|
||||
}
|
||||
}
|
||||
|
||||
async lock() {
|
||||
this.analytics.eventTrack.next({ action: 'Lock Now' });
|
||||
await this.lockService.lock(true);
|
||||
await this.vaultTimeoutService.lock(true);
|
||||
}
|
||||
|
||||
async logOut() {
|
||||
|
||||
Reference in New Issue
Block a user