mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-30 13:03:53 +01:00
Use a modal to set the unlock pin (#1064)
* Use separate modal to set pin * Remove incorrect label * Fix tab focus for settings and set-pin modals * Remove leftover code * Update jslib
This commit is contained in:
parent
cdac1a4508
commit
ebaf27b7c9
2
jslib
2
jslib
@ -1 +1 @@
|
|||||||
Subproject commit 5f64d956520612a681611a27c5f4f2e5f27b640e
|
Subproject commit a85c45a34ed90b09f59ec27bdba754d66452915e
|
@ -1,4 +1,4 @@
|
|||||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" attr.aria-label="{{'settings' | i18n}}">
|
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" attr.aria-label="{{'settings' | i18n}}" cdkTrapFocus cdkTrapFocusAutoCapture>
|
||||||
<div class="modal-dialog" role="document">
|
<div class="modal-dialog" role="document">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="modal-body form">
|
<div class="modal-body form">
|
||||||
|
@ -18,11 +18,15 @@ import { VaultTimeoutService } from 'jslib-common/abstractions/vaultTimeout.serv
|
|||||||
|
|
||||||
import { ConstantsService } from 'jslib-common/services/constants.service';
|
import { ConstantsService } from 'jslib-common/services/constants.service';
|
||||||
|
|
||||||
|
import { ModalService } from 'jslib-angular/services/modal.service';
|
||||||
|
|
||||||
import { ElectronConstants } from 'jslib-electron/electronConstants';
|
import { ElectronConstants } from 'jslib-electron/electronConstants';
|
||||||
|
|
||||||
import { Utils } from 'jslib-common/misc/utils';
|
import { Utils } from 'jslib-common/misc/utils';
|
||||||
import { isWindowsStore } from 'jslib-electron/utils';
|
import { isWindowsStore } from 'jslib-electron/utils';
|
||||||
|
|
||||||
|
import { SetPinComponent } from '../components/set-pin.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-settings',
|
selector: 'app-settings',
|
||||||
templateUrl: 'settings.component.html',
|
templateUrl: 'settings.component.html',
|
||||||
@ -69,7 +73,8 @@ export class SettingsComponent implements OnInit {
|
|||||||
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
constructor(private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
||||||
private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService,
|
private storageService: StorageService, private vaultTimeoutService: VaultTimeoutService,
|
||||||
private stateService: StateService, private messagingService: MessagingService,
|
private stateService: StateService, private messagingService: MessagingService,
|
||||||
private userService: UserService, private cryptoService: CryptoService) {
|
private userService: UserService, private cryptoService: CryptoService,
|
||||||
|
private modalService: ModalService) {
|
||||||
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
const isMac = this.platformUtilsService.getDevice() === DeviceType.MacOsDesktop;
|
||||||
|
|
||||||
// Workaround to avoid ghosting trays https://github.com/electron/electron/issues/17622
|
// Workaround to avoid ghosting trays https://github.com/electron/electron/issues/17622
|
||||||
@ -188,56 +193,14 @@ export class SettingsComponent implements OnInit {
|
|||||||
|
|
||||||
async updatePin() {
|
async updatePin() {
|
||||||
if (this.pin) {
|
if (this.pin) {
|
||||||
const div = document.createElement('div');
|
const ref = this.modalService.open(SetPinComponent, { allowMultipleModals: true });
|
||||||
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 = '<input type="checkbox" id="master-pass-restart" checked>';
|
|
||||||
label.appendChild(checkboxText);
|
|
||||||
|
|
||||||
div.innerHTML =
|
if (ref == null) {
|
||||||
`<div class="swal2-text">${this.i18nService.t('setYourPinCode')}</div>` +
|
|
||||||
'<input type="text" class="swal2-input" id="pin-val" autocomplete="off" ' +
|
|
||||||
'autocapitalize="none" autocorrect="none" spellcheck="false" inputmode="verbatim">';
|
|
||||||
|
|
||||||
(div.querySelector('#pin-val') as HTMLInputElement).placeholder = this.i18nService.t('pin');
|
|
||||||
div.appendChild(label);
|
|
||||||
|
|
||||||
const submitted = await Swal.fire({
|
|
||||||
heightAuto: false,
|
|
||||||
buttonsStyling: false,
|
|
||||||
html: div,
|
|
||||||
showCancelButton: true,
|
|
||||||
cancelButtonText: this.i18nService.t('cancel'),
|
|
||||||
showConfirmButton: true,
|
|
||||||
confirmButtonText: this.i18nService.t('submit'),
|
|
||||||
});
|
|
||||||
|
|
||||||
let pin: string = null;
|
|
||||||
let masterPassOnRestart: boolean = null;
|
|
||||||
if (submitted.value) {
|
|
||||||
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);
|
|
||||||
if (masterPassOnRestart) {
|
|
||||||
const encPin = await this.cryptoService.encrypt(pin);
|
|
||||||
await this.storageService.save(ConstantsService.protectedPin, encPin.encryptedString);
|
|
||||||
this.vaultTimeoutService.pinProtectedKey = pinProtectedKey;
|
|
||||||
} else {
|
|
||||||
await this.storageService.save(ConstantsService.pinProtectedKey, pinProtectedKey.encryptedString);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.pin = false;
|
this.pin = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.pin = await ref.onClosedPromise();
|
||||||
}
|
}
|
||||||
if (!this.pin) {
|
if (!this.pin) {
|
||||||
await this.cryptoService.clearPinProtectedKey();
|
await this.cryptoService.clearPinProtectedKey();
|
||||||
|
@ -5,6 +5,7 @@ import { ToasterModule } from 'angular2-toaster';
|
|||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
import { ServicesModule } from './services.module';
|
import { ServicesModule } from './services.module';
|
||||||
|
|
||||||
|
import { A11yModule } from '@angular/cdk/a11y';
|
||||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||||
import { ScrollingModule } from '@angular/cdk/scrolling';
|
import { ScrollingModule } from '@angular/cdk/scrolling';
|
||||||
import { DatePipe } from '@angular/common';
|
import { DatePipe } from '@angular/common';
|
||||||
@ -68,6 +69,7 @@ import { SendComponent } from './send/send.component';
|
|||||||
import { NavComponent } from './layout/nav.component';
|
import { NavComponent } from './layout/nav.component';
|
||||||
|
|
||||||
import { PasswordRepromptComponent } from './components/password-reprompt.component';
|
import { PasswordRepromptComponent } from './components/password-reprompt.component';
|
||||||
|
import { SetPinComponent } from './components/set-pin.component';
|
||||||
|
|
||||||
import { registerLocaleData } from '@angular/common';
|
import { registerLocaleData } from '@angular/common';
|
||||||
import localeAf from '@angular/common/locales/af';
|
import localeAf from '@angular/common/locales/af';
|
||||||
@ -171,6 +173,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
ServicesModule,
|
ServicesModule,
|
||||||
ToasterModule.forRoot(),
|
ToasterModule.forRoot(),
|
||||||
ScrollingModule,
|
ScrollingModule,
|
||||||
|
A11yModule,
|
||||||
],
|
],
|
||||||
declarations: [
|
declarations: [
|
||||||
A11yTitleDirective,
|
A11yTitleDirective,
|
||||||
@ -220,6 +223,7 @@ registerLocaleData(localeZhTw, 'zh-TW');
|
|||||||
VaultComponent,
|
VaultComponent,
|
||||||
ViewComponent,
|
ViewComponent,
|
||||||
PasswordRepromptComponent,
|
PasswordRepromptComponent,
|
||||||
|
SetPinComponent,
|
||||||
],
|
],
|
||||||
providers: [DatePipe],
|
providers: [DatePipe],
|
||||||
bootstrap: [AppComponent],
|
bootstrap: [AppComponent],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" aria-labelledby="confirmUserTitle">
|
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true">
|
||||||
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
<div class="modal-dialog modal-dialog-scrollable" role="document">
|
||||||
<form class="modal-content" #form (ngSubmit)="submit()">
|
<form class="modal-content" #form (ngSubmit)="submit()">
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
44
src/app/components/set-pin.component.html
Normal file
44
src/app/components/set-pin.component.html
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<div class="modal fade" tabindex="-1" role="dialog" aria-modal="true" cdkTrapFocus cdkTrapFocusAutoCapture>
|
||||||
|
<div class="modal-dialog modal-dialog-scrollable set-pin-modal" role="document">
|
||||||
|
<form class="modal-content" #form (ngSubmit)="submit()">
|
||||||
|
<div class="modal-body">
|
||||||
|
<div>
|
||||||
|
{{'setYourPinCode' | i18n}}
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="box-content">
|
||||||
|
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||||
|
<div class="row-main">
|
||||||
|
<label for="pin">{{'pin' | i18n}}</label>
|
||||||
|
<input id="pin" type="{{showPin ? 'text' : 'password'}}" name="Pin" class="monospaced"
|
||||||
|
[(ngModel)]="pin" required appInputVerbatim cdkFocusInitial>
|
||||||
|
</div>
|
||||||
|
<div class="action-buttons">
|
||||||
|
<a class="row-btn" href="#" appStopClick appBlurClick
|
||||||
|
appA11yTitle="{{'toggleVisibility' | i18n}}" (click)="toggleVisibility()">
|
||||||
|
<i class="fa fa-lg" aria-hidden="true"
|
||||||
|
[ngClass]="{'fa-eye': !showPin, 'fa-eye-slash': showPin}"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="checkbox">
|
||||||
|
<label for="masterPasswordOnRestart">
|
||||||
|
<input type="checkbox" id="masterPasswordOnRestart" name="MasterPasswordOnRestart"
|
||||||
|
[(ngModel)]="masterPassOnRestart">
|
||||||
|
<span>{{'lockWithMasterPassOnRestart' | i18n}}</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type="submit" class="btn btn-primary btn-submit" appBlurClick>
|
||||||
|
<span>{{'ok' | i18n}}</span>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" data-dismiss="modal">
|
||||||
|
{{'cancel' | i18n}}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
8
src/app/components/set-pin.component.ts
Normal file
8
src/app/components/set-pin.component.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
import { SetPinComponent as BaseSetPinComponent } from 'jslib-angular/components/set-pin.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
templateUrl: 'set-pin.component.html',
|
||||||
|
})
|
||||||
|
export class SetPinComponent extends BaseSetPinComponent { }
|
@ -420,3 +420,9 @@ app-root > #loading {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.set-pin-modal {
|
||||||
|
.box {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user