diff --git a/jslib b/jslib index f67fac3eeb..43872f82cc 160000 --- a/jslib +++ b/jslib @@ -1 +1 @@ -Subproject commit f67fac3eebc21b8935a54a28b7a21152c8513322 +Subproject commit 43872f82ccd7453926c75240ecde196151e89ce9 diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json index bfe5ee0cb9..2f54129096 100644 --- a/src/_locales/en/messages.json +++ b/src/_locales/en/messages.json @@ -1191,5 +1191,8 @@ }, "yourVaultIsLockedPinCode": { "message": "Your vault is locked. Verify your PIN code to continue." + }, + "lockWithMasterPassOnRestart": { + "message": "Lock with master password on browser restart" } } diff --git a/src/background/idle.background.ts b/src/background/idle.background.ts index 8054c5a95f..2c066c4aa7 100644 --- a/src/background/idle.background.ts +++ b/src/background/idle.background.ts @@ -42,7 +42,7 @@ export default class IdleBackground { if (newState === 'locked') { const lockOption = await this.storageService.get(ConstantsService.lockOptionKey); if (lockOption === -2) { - this.lockService.lock(); + this.lockService.lock(true); } } }); diff --git a/src/background/main.background.ts b/src/background/main.background.ts index 8228943a44..46243b36cd 100644 --- a/src/background/main.background.ts +++ b/src/background/main.background.ts @@ -160,7 +160,7 @@ export default class MainBackground { this.auditService = new AuditService(cryptoFunctionService, this.apiService); this.exportService = new ExportService(this.folderService, this.cipherService, this.apiService); this.notificationsService = new NotificationsService(this.userService, this.syncService, this.appIdService, - this.apiService, this.cryptoService, () => this.logout(true)); + this.apiService, this.lockService, () => this.logout(true)); this.environmentService = new EnvironmentService(this.apiService, this.storageService, this.notificationsService); this.analytics = new Analytics(window, () => BrowserApi.gaFilter(), this.platformUtilsService, @@ -223,12 +223,12 @@ export default class MainBackground { } const isAuthenticated = await this.userService.isAuthenticated(); - const hasKey = await this.cryptoService.hasKey(); + const locked = await this.lockService.isLocked(); let suffix = ''; if (!isAuthenticated) { suffix = '_gray'; - } else if (!hasKey) { + } else if (locked) { suffix = '_locked'; } @@ -273,8 +273,10 @@ export default class MainBackground { this.folderService.clear(userId), this.collectionService.clear(userId), this.passwordGenerationService.clear(), + this.lockService.clear(), ]); + this.lockService.pinLocked = false; this.searchService.clearIndex(); this.messagingService.send('doneLoggingOut', { expired: expired }); diff --git a/src/popup/scss/plugins.scss b/src/popup/scss/plugins.scss index b3a096c59f..8a22a5c73e 100644 --- a/src/popup/scss/plugins.scss +++ b/src/popup/scss/plugins.scss @@ -121,6 +121,7 @@ $fa-font-path: "~font-awesome/fonts"; .swal-content { margin: 15px 0 0 0; padding: 0 10px; + font-size: $font-size-base; .swal-text { &:last-child { @@ -132,6 +133,17 @@ $fa-font-path: "~font-awesome/fonts"; padding-left: 0; padding-right: 0; } + + label.checkbox { + margin-top: 10px; + display: flex; + text-align: left; + align-items: top; + + input { + margin: 3px 5px 0 1px; + } + } } i.swal-custom-icon { diff --git a/src/popup/services/launch-guard.service.ts b/src/popup/services/launch-guard.service.ts index f58e335910..b4bec3b155 100644 --- a/src/popup/services/launch-guard.service.ts +++ b/src/popup/services/launch-guard.service.ts @@ -6,12 +6,12 @@ import { Router, } from '@angular/router'; -import { CryptoService } from 'jslib/abstractions/crypto.service'; +import { LockService } from 'jslib/abstractions/lock.service'; import { UserService } from 'jslib/abstractions/user.service'; @Injectable() export class LaunchGuardService implements CanActivate { - constructor(private cryptoService: CryptoService, private userService: UserService, private router: Router) { } + constructor(private lockService: LockService, private userService: UserService, private router: Router) { } async canActivate() { if (BrowserApi.getBackgroundPage() == null) { @@ -28,8 +28,8 @@ export class LaunchGuardService implements CanActivate { return true; } - const hasKey = await this.cryptoService.hasKey(); - if (!hasKey) { + const locked = await this.lockService.isLocked(); + if (locked) { this.router.navigate(['lock']); } else { this.router.navigate(['tabs/current']); diff --git a/src/popup/settings/settings.component.ts b/src/popup/settings/settings.component.ts index d6823c4b44..f91655fb5f 100644 --- a/src/popup/settings/settings.component.ts +++ b/src/popup/settings/settings.component.ts @@ -89,7 +89,8 @@ export class SettingsComponent implements OnInit { } this.previousLockOption = this.lockOption; - this.pin = await this.lockService.isPinLockSet(); + const pinSet = await this.lockService.isPinLockSet(); + this.pin = pinSet[0] || pinSet[1]; } async saveLockOption(newValue: number) { @@ -116,31 +117,55 @@ export class SettingsComponent implements OnInit { async updatePin() { if (this.pin) { - const pin = await swal({ + const div = document.createElement('div'); + const label = document.createElement('label'); + label.className = 'checkbox'; + const checkboxText = document.createElement('span'); + const restartText = document.createTextNode(this.i18nService.t('lockWithMasterPassOnRestart')); + checkboxText.appendChild(restartText); + label.innerHTML = ''; + label.appendChild(checkboxText); + div.innerHTML = ''; + (div.querySelector('#pin-val') as HTMLInputElement).placeholder = this.i18nService.t('pin'); + div.appendChild(label); + + const submitted = await swal({ text: this.i18nService.t('setYourPinCode'), - content: { element: 'input' }, + content: { element: div }, buttons: [this.i18nService.t('cancel'), this.i18nService.t('submit')], }); + let pin: string = null; + let masterPassOnRestart: boolean = null; + if (submitted) { + pin = (document.getElementById('pin-val') as HTMLInputElement).value; + masterPassOnRestart = (document.getElementById('master-pass-restart') as HTMLInputElement).checked; + } if (pin != null && pin.trim() !== '') { - const kdf = await this.userService.getKdf(); - const kdfIterations = await this.userService.getKdfIterations(); - const email = await this.userService.getEmail(); - const pinKey = await this.cryptoService.makePinKey(pin, email, kdf, kdfIterations); - const key = await this.cryptoService.getKey(); - const pinProtectedKey = await this.cryptoService.encrypt(key.key, pinKey); - await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString); + if (masterPassOnRestart) { + const encPin = await this.cryptoService.encrypt(pin); + await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString); + } else { + const kdf = await this.userService.getKdf(); + const kdfIterations = await this.userService.getKdfIterations(); + const email = await this.userService.getEmail(); + const pinKey = await this.cryptoService.makePinKey(pin, email, kdf, kdfIterations); + const key = await this.cryptoService.getKey(); + const pinProtectedKey = await this.cryptoService.encrypt(key.key, pinKey); + await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString); + } } else { this.pin = false; } } if (!this.pin) { await this.storageService.remove(ConstantsService.pinProtectedKey); + await this.storageService.remove(ConstantsService.protectedPin); } } async lock() { this.analytics.eventTrack.next({ action: 'Lock Now' }); - await this.lockService.lock(); + await this.lockService.lock(true); this.router.navigate(['lock']); }