diff --git a/src/app/accounts/settings.component.html b/src/app/accounts/settings.component.html index 2852e6f137..297f0f02fc 100644 --- a/src/app/accounts/settings.component.html +++ b/src/app/accounts/settings.component.html @@ -7,14 +7,7 @@ {{'security' | i18n}}
-
- - - {{'vaultTimeoutDesc' | i18n}} -
+
diff --git a/src/app/accounts/settings.component.ts b/src/app/accounts/settings.component.ts index 47b5114da1..93305726b3 100644 --- a/src/app/accounts/settings.component.ts +++ b/src/app/accounts/settings.component.ts @@ -2,8 +2,8 @@ import { Component, OnInit, } from '@angular/core'; - -import Swal from 'sweetalert2/src/sweetalert2.js'; +import { FormControl } from '@angular/forms'; +import { debounceTime } from 'rxjs/operators'; import { DeviceType } from 'jslib-common/enums/deviceType'; @@ -13,7 +13,6 @@ import { MessagingService } from 'jslib-common/abstractions/messaging.service'; import { PlatformUtilsService } from 'jslib-common/abstractions/platformUtils.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 { ConstantsService } from 'jslib-common/services/constants.service'; @@ -32,7 +31,6 @@ import { SetPinComponent } from '../components/set-pin.component'; templateUrl: 'settings.component.html', }) export class SettingsComponent implements OnInit { - vaultTimeout: number = null; vaultTimeoutAction: string; pin: boolean = null; disableFavicons: boolean = false; @@ -70,11 +68,12 @@ export class SettingsComponent implements OnInit { startToTrayText: string; startToTrayDescText: string; + vaultTimeout: FormControl = new FormControl(null); + constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService, private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService, private stateService: StateService, private messagingService: MessagingService, - private userService: UserService, private cryptoService: CryptoService, - private modalService: ModalService) { + private cryptoService: CryptoService, private modalService: ModalService) { const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop; // Workaround to avoid ghosting trays https://github.com/electron/electron/issues/17622 @@ -117,6 +116,10 @@ export class SettingsComponent implements OnInit { { name: i18nService.t('never'), value: null }, ]); + this.vaultTimeout.valueChanges.pipe(debounceTime(500)).subscribe(() => { + this.saveVaultTimeoutOptions(); + }); + const localeOptions: any[] = []; i18nService.supportedTranslationLocales.forEach(locale => { let name = locale; @@ -149,7 +152,7 @@ export class SettingsComponent implements OnInit { async ngOnInit() { this.showMinToTray = this.platformUtilsService.getDevice() !== DeviceType.LinuxDesktop; - this.vaultTimeout = await this.storageService.get(ConstantsService.vaultTimeoutKey); + this.vaultTimeout.setValue(await this.vaultTimeoutService.getVaultTimeout()); this.vaultTimeoutAction = await this.storageService.get(ConstantsService.vaultTimeoutActionKey); const pinSet = await this.vaultTimeoutService.isPinLockSet(); this.pin = pinSet[0] || pinSet[1]; @@ -187,8 +190,18 @@ export class SettingsComponent implements OnInit { return; } } - await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout != null ? this.vaultTimeout : null, - this.vaultTimeoutAction); + + // Avoid saving 0 since it's useless as a timeout value. + if (this.vaultTimeout.value === 0) { + return; + } + + if (!this.vaultTimeout.valid) { + this.platformUtilsService.showToast('error', null, this.i18nService.t('vaultTimeoutTooLarge')); + return; + } + + await this.vaultTimeoutService.setVaultTimeoutOptions(this.vaultTimeout.value, this.vaultTimeoutAction); } async updatePin() { diff --git a/src/app/accounts/vault-timeout-input.component.html b/src/app/accounts/vault-timeout-input.component.html new file mode 100644 index 0000000000..f959adffc6 --- /dev/null +++ b/src/app/accounts/vault-timeout-input.component.html @@ -0,0 +1,24 @@ + + {{'vaultTimeoutPolicyInEffect' | i18n : vaultTimeoutPolicyHours : vaultTimeoutPolicyMinutes}} + + +
+
+ + + {{'vaultTimeoutDesc' | i18n}} +
+
+
+ + +
+
+ + +
+
+
+
diff --git a/src/app/accounts/vault-timeout-input.component.ts b/src/app/accounts/vault-timeout-input.component.ts new file mode 100644 index 0000000000..47335e51c4 --- /dev/null +++ b/src/app/accounts/vault-timeout-input.component.ts @@ -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 { +} diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 501ba8564f..1895d07f64 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -28,6 +28,7 @@ import { SsoComponent } from './accounts/sso.component'; import { TwoFactorOptionsComponent } from './accounts/two-factor-options.component'; import { TwoFactorComponent } from './accounts/two-factor.component'; import { UpdateTempPasswordComponent } from './accounts/update-temp-password.component'; +import { VaultTimeoutInputComponent } from './accounts/vault-timeout-input.component'; import { CalloutComponent } from 'jslib-angular/components/callout.component'; import { IconComponent } from 'jslib-angular/components/icon.component'; @@ -224,6 +225,7 @@ registerLocaleData(localeZhTw, 'zh-TW'); ViewComponent, PasswordRepromptComponent, SetPinComponent, + VaultTimeoutInputComponent, ], providers: [DatePipe], bootstrap: [AppComponent], diff --git a/src/app/services.module.ts b/src/app/services.module.ts index 1f4c8a5545..6ff5a5af42 100644 --- a/src/app/services.module.ts +++ b/src/app/services.module.ts @@ -120,7 +120,7 @@ const sendService = new SendService(cryptoService, userService, apiService, file const policyService = new PolicyService(userService, storageService); const vaultTimeoutService = new VaultTimeoutService(cipherService, folderService, collectionService, cryptoService, platformUtilsService, storageService, messagingService, searchService, userService, tokenService, - null, async () => messagingService.send('logout', { expired: false })); + policyService, null, async () => messagingService.send('logout', { expired: false })); const syncService = new SyncService(userService, apiService, settingsService, folderService, cipherService, cryptoService, collectionService, storageService, messagingService, policyService, sendService, async (expired: boolean) => messagingService.send('logout', { expired: expired })); diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json index 8e26db4204..1610f8ef9b 100644 --- a/src/locales/en/messages.json +++ b/src/locales/en/messages.json @@ -1703,6 +1703,28 @@ "updateMasterPasswordWarning": { "message": "Your Master Password was recently changed by an administrator in your organization. In order to access the vault, you must update it now. Proceeding will log you out of your current session, requiring you to log back in. Active sessions on other devices may continue to remain active for up to one hour." }, + "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" + } + } + }, + "vaultTimeoutTooLarge": { + "message": "Your vault timeout exceeds the restrictions set by your organization." + }, "resetPasswordPolicyAutoEnroll": { "message": "Automatic Enrollment" }, diff --git a/src/scss/grid.scss b/src/scss/grid.scss new file mode 100644 index 0000000000..81d5ee2a2b --- /dev/null +++ b/src/scss/grid.scss @@ -0,0 +1,10 @@ +.row { + display: flex; + margin: 0 -15px; +} + +.col { + flex-basis: 0; + flex-grow: 1; + padding: 0 15px; +} diff --git a/src/scss/misc.scss b/src/scss/misc.scss index 819fbbd9cb..d9699e8153 100644 --- a/src/scss/misc.scss +++ b/src/scss/misc.scss @@ -253,6 +253,11 @@ form, .form { border-color: themed('inputBorderColor'); } } + + input[type=text], input[type=number] { + padding: 5px; + width: 100%; + } } .checkbox { diff --git a/src/scss/styles.scss b/src/scss/styles.scss index c75e55a93a..968100e119 100644 --- a/src/scss/styles.scss +++ b/src/scss/styles.scss @@ -1,6 +1,7 @@ @import "../css/webfonts.css"; @import "variables.scss"; @import "base.scss"; +@import "grid.scss"; @import "pages.scss"; @import "vault.scss"; @import "list.scss";