1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-28 17:27:50 +01:00

Vault Timeout Policy (#2048)

This commit is contained in:
Oscar Hinton 2021-09-14 13:36:34 +02:00 committed by GitHub
parent 63d0b8f9d2
commit 2e6f0f4166
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 135 additions and 29 deletions

2
jslib

@ -1 +1 @@
Subproject commit 5f64d956520612a681611a27c5f4f2e5f27b640e Subproject commit a85c45a34ed90b09f59ec27bdba754d66452915e

View File

@ -1776,5 +1776,27 @@
}, },
"ssoCompleteRegistration": { "ssoCompleteRegistration": {
"message": "In order to complete logging in with SSO, please set a master password to access and protect your vault." "message": "In order to complete logging in with SSO, please set a master password to access and protect your vault."
},
"hours": {
"message": "Hours"
},
"minutes": {
"message": "Minutes"
},
"vaultTimeoutPolicyInEffect": {
"message": "Your organization policies are affecting your vault timeout. Maximum allowed Vault Timeout is $HOURS$ hour(s) and $MINUTES$ minute(s)",
"placeholders": {
"hours": {
"content": "$1",
"example": "5"
},
"minutes": {
"content": "$2",
"example": "5"
}
}
},
"vaultTimeoutToLarge": {
"message": "Your vault timeout exceeds the restrictions set by your organization."
} }
} }

View File

@ -197,7 +197,7 @@ export default class MainBackground {
this.policyService = new PolicyService(this.userService, this.storageService); this.policyService = new PolicyService(this.userService, this.storageService);
this.vaultTimeoutService = new VaultTimeoutService(this.cipherService, this.folderService, this.vaultTimeoutService = new VaultTimeoutService(this.cipherService, this.folderService,
this.collectionService, this.cryptoService, this.platformUtilsService, this.storageService, this.collectionService, this.cryptoService, this.platformUtilsService, this.storageService,
this.messagingService, this.searchService, this.userService, this.tokenService, this.messagingService, this.searchService, this.userService, this.tokenService, this.policyService,
async () => { async () => {
if (this.notificationsService != null) { if (this.notificationsService != null) {
this.notificationsService.updateConnection(false); this.notificationsService.updateConnection(false);

View File

@ -37,6 +37,7 @@ import { OptionsComponent } from './settings/options.component';
import { PremiumComponent } from './settings/premium.component'; import { PremiumComponent } from './settings/premium.component';
import { SettingsComponent } from './settings/settings.component'; import { SettingsComponent } from './settings/settings.component';
import { SyncComponent } from './settings/sync.component'; import { SyncComponent } from './settings/sync.component';
import { VaultTimeoutInputComponent } from './settings/vault-timeout-input.component';
import { AddEditComponent } from './vault/add-edit.component'; import { AddEditComponent } from './vault/add-edit.component';
import { AttachmentsComponent } from './vault/attachments.component'; import { AttachmentsComponent } from './vault/attachments.component';
@ -242,6 +243,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
UpdateTempPasswordComponent, UpdateTempPasswordComponent,
ViewComponent, ViewComponent,
PasswordRepromptComponent, PasswordRepromptComponent,
VaultTimeoutInputComponent,
], ],
entryComponents: [], entryComponents: [],
providers: [ providers: [

View File

@ -200,6 +200,13 @@
} }
} }
&.last:last-child:before {
border-bottom: 1px solid #000000;
@include themify($themes) {
border-bottom-color: themed('boxBorderColor');
}
}
&:after { &:after {
content: ""; content: "";
display: table; display: table;

11
src/popup/scss/grid.scss Normal file
View File

@ -0,0 +1,11 @@
.row {
display: flex;
margin: 0 -15px;
width: 100%;
}
.col {
flex-basis: 0;
flex-grow: 1;
padding: 0 15px;
}

View File

@ -1,6 +1,7 @@
@import "../css/webfonts.css"; @import "../css/webfonts.css";
@import "variables.scss"; @import "variables.scss";
@import "base.scss"; @import "base.scss";
@import "grid.scss";
@import "box.scss"; @import "box.scss";
@import "buttons.scss"; @import "buttons.scss";
@import "misc.scss"; @import "misc.scss";

View File

@ -28,13 +28,7 @@
<div class="box list"> <div class="box list">
<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> <app-vault-timeout-input [vaultTimeouts]="vaultTimeouts" [formControl]="vaultTimeout" ngDefaultControl></app-vault-timeout-input>
<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> <div class="box-content-row display-block" appBoxRow>
<label for="vaultTimeoutAction">{{'vaultTimeoutAction' | i18n}}</label> <label for="vaultTimeoutAction">{{'vaultTimeoutAction' | i18n}}</label>
<select #vaultTimeoutActionSelect id="vaultTimeoutAction" name="VaultTimeoutActions" <select #vaultTimeoutActionSelect id="vaultTimeoutAction" name="VaultTimeoutActions"

View File

@ -1,12 +1,13 @@
import Swal from 'sweetalert2/src/sweetalert2.js';
import { import {
Component, Component,
ElementRef, ElementRef,
OnInit, OnInit,
ViewChild, ViewChild,
} from '@angular/core'; } from '@angular/core';
import { FormControl } from '@angular/forms';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { ToasterService } from 'angular2-toaster';
import Swal from 'sweetalert2/src/sweetalert2.js';
import { BrowserApi } from '../../browser/browserApi'; import { BrowserApi } from '../../browser/browserApi';
@ -44,10 +45,8 @@ const RateUrls = {
templateUrl: 'settings.component.html', templateUrl: 'settings.component.html',
}) })
export class SettingsComponent implements OnInit { export class SettingsComponent implements OnInit {
@ViewChild('vaultTimeoutSelect', { read: ElementRef, static: true }) vaultTimeoutSelectRef: ElementRef;
@ViewChild('vaultTimeoutActionSelect', { read: ElementRef, static: true }) vaultTimeoutActionSelectRef: ElementRef; @ViewChild('vaultTimeoutActionSelect', { read: ElementRef, static: true }) vaultTimeoutActionSelectRef: ElementRef;
vaultTimeouts: any[]; vaultTimeouts: any[];
vaultTimeout: number = null;
vaultTimeoutActions: any[]; vaultTimeoutActions: any[];
vaultTimeoutAction: string; vaultTimeoutAction: string;
pin: boolean = null; pin: boolean = null;
@ -55,11 +54,14 @@ export class SettingsComponent implements OnInit {
biometric: boolean = false; biometric: boolean = false;
previousVaultTimeout: number = null; previousVaultTimeout: number = null;
vaultTimeout: FormControl = new FormControl(null);
constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService, constructor(private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService, private storageService: StorageService,
public messagingService: MessagingService, private router: Router, public messagingService: MessagingService, private router: Router,
private environmentService: EnvironmentService, private cryptoService: CryptoService, private environmentService: EnvironmentService, private cryptoService: CryptoService,
private userService: UserService, private popupUtilsService: PopupUtilsService) { private userService: UserService, private popupUtilsService: PopupUtilsService,
private toasterService: ToasterService) {
} }
async ngOnInit() { async ngOnInit() {
@ -89,14 +91,18 @@ export class SettingsComponent implements OnInit {
{ name: this.i18nService.t('logOut'), value: 'logOut' }, { name: this.i18nService.t('logOut'), value: 'logOut' },
]; ];
let timeout = await this.storageService.get<number>(ConstantsService.vaultTimeoutKey); let timeout = await this.vaultTimeoutService.getVaultTimeout();
if (timeout != null) { if (timeout != null) {
if (timeout === -2 && !showOnLocked) { if (timeout === -2 && !showOnLocked) {
timeout = -1; timeout = -1;
} }
this.vaultTimeout = timeout; this.vaultTimeout.setValue(timeout);
} }
this.previousVaultTimeout = this.vaultTimeout; this.previousVaultTimeout = this.vaultTimeout.value;
this.vaultTimeout.valueChanges.subscribe(value => {
this.saveVaultTimeout(value);
});
const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey); const action = await this.storageService.get<string>(ConstantsService.vaultTimeoutActionKey);
this.vaultTimeoutAction = action == null ? 'lock' : action; this.vaultTimeoutAction = action == null ? 'lock' : action;
@ -113,18 +119,19 @@ export class SettingsComponent implements OnInit {
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.vaultTimeouts.forEach((option: any, i) => { this.vaultTimeout.setValue(this.previousVaultTimeout);
if (option.value === this.vaultTimeout) {
this.vaultTimeoutSelectRef.nativeElement.value = i + ': ' + this.vaultTimeout;
}
});
return; return;
} }
} }
this.previousVaultTimeout = this.vaultTimeout;
this.vaultTimeout = newValue; if (!this.vaultTimeout.valid) {
await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null, this.toasterService.popAsync('error', null, this.i18nService.t('vaultTimeoutToLarge'));
this.vaultTimeoutAction); return;
}
this.previousVaultTimeout = this.vaultTimeout.value;
await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout.value, this.vaultTimeoutAction);
if (this.previousVaultTimeout == null) { if (this.previousVaultTimeout == null) {
this.messagingService.send('bgReseedStorage'); this.messagingService.send('bgReseedStorage');
} }
@ -145,9 +152,14 @@ export class SettingsComponent implements OnInit {
return; return;
} }
} }
if (!this.vaultTimeout.valid) {
this.toasterService.popAsync('error', null, this.i18nService.t('vaultTimeoutToLarge'));
return;
}
this.vaultTimeoutAction = newValue; this.vaultTimeoutAction = newValue;
await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null, await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout.value, this.vaultTimeoutAction);
this.vaultTimeoutAction);
} }
async updatePin() { async updatePin() {

View File

@ -0,0 +1,29 @@
<app-callout type="info" *ngIf="vaultTimeoutPolicy">
{{'vaultTimeoutPolicyInEffect' | i18n : vaultTimeoutPolicyHours : vaultTimeoutPolicyMinutes}}
</app-callout>
<div [formGroup]="form">
<div class="box-content-row last display-block" appBoxRow>
<label for="vaultTimeout">{{'vaultTimeout' | i18n}}</label>
<select id="vaultTimeout" name="VaultTimeout" formControlName="vaultTimeout" class="form-control">
<option *ngFor="let o of vaultTimeouts" [ngValue]="o.value">{{o.name}}</option>
</select>
</div>
<div class="box-content-row last" *ngIf="showCustom">
<div formGroupName="custom" class="row">
<div class="col">
<div class="display-block" appBoxRow>
<label for="customVaultTimeout">{{'hours' | i18n }}</label>
<input id="hours" class="form-control" type="number" min="0" name="hours" formControlName="hours">
</div>
</div>
<div class="col">
<div class="display-block" appBoxRow>
<label for="customVaultTimeout">{{'minutes' | i18n }}</label>
<input id="minutes" class="form-control" type="number" min="0" max="59" name="minutes"
formControlName="minutes">
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,28 @@
import { Component } from '@angular/core';
import {
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
} from '@angular/forms';
import {
VaultTimeoutInputComponent as VaultTimeoutInputComponentBase
} from 'jslib-angular/components/settings/vault-timeout-input.component';
@Component({
selector: 'app-vault-timeout-input',
templateUrl: 'vault-timeout-input.component.html',
providers: [
{
provide: NG_VALUE_ACCESSOR,
multi: true,
useExisting: VaultTimeoutInputComponent,
},
{
provide: NG_VALIDATORS,
multi: true,
useExisting: VaultTimeoutInputComponent,
},
],
})
export class VaultTimeoutInputComponent extends VaultTimeoutInputComponentBase {
}