pin locking
This commit is contained in:
parent
e0c7cb4bd6
commit
2c91a2004c
13
gulpfile.js
13
gulpfile.js
|
@ -1,9 +1,11 @@
|
|||
const gulp = require('gulp');
|
||||
const googleWebFonts = require('gulp-google-webfonts');
|
||||
const del = require('del');
|
||||
const fs = require('fs');
|
||||
|
||||
const paths = {
|
||||
cssDir: './src/css/',
|
||||
node_modules: './node_modules/',
|
||||
};
|
||||
|
||||
function clean() {
|
||||
|
@ -25,7 +27,16 @@ function cleanupAotIssue() {
|
|||
return del(['./node_modules/@types/uglify-js/node_modules/source-map/source-map.d.ts']);
|
||||
}
|
||||
|
||||
// ref: https://github.com/t4t5/sweetalert/issues/890
|
||||
function fixSweetAlert(cb) {
|
||||
fs.writeFileSync(paths.node_modules + 'sweetalert/typings/sweetalert.d.ts',
|
||||
'import swal, { SweetAlert } from "./core";export default swal;export as namespace swal;');
|
||||
cb();
|
||||
}
|
||||
|
||||
exports.clean = clean;
|
||||
exports.cleanupAotIssue = cleanupAotIssue;
|
||||
exports.webfonts = gulp.series(clean, webfonts);
|
||||
exports['prebuild:renderer'] = gulp.parallel(webfonts, cleanupAotIssue);;
|
||||
exports['prebuild:renderer'] = gulp.parallel(webfonts, cleanupAotIssue);
|
||||
exports.fixSweetAlert = fixSweetAlert;
|
||||
exports.postinstall = fixSweetAlert;
|
||||
|
|
2
jslib
2
jslib
|
@ -1 +1 @@
|
|||
Subproject commit 647b254a71d0af105e1f6f1a1febeb15cd4181fb
|
||||
Subproject commit f67fac3eebc21b8935a54a28b7a21152c8513322
|
|
@ -4279,6 +4279,11 @@
|
|||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"es6-object-assign": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz",
|
||||
"integrity": "sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw="
|
||||
},
|
||||
"es6-symbol": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
|
||||
|
@ -5114,14 +5119,12 @@
|
|||
"balanced-match": {
|
||||
"version": "1.0.0",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
|
@ -5141,8 +5144,7 @@
|
|||
"concat-map": {
|
||||
"version": "0.0.1",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
|
@ -5264,8 +5266,7 @@
|
|||
"inherits": {
|
||||
"version": "2.0.3",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true
|
||||
"dev": true
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
|
@ -5291,7 +5292,6 @@
|
|||
"version": "3.0.4",
|
||||
"bundled": true,
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
}
|
||||
|
@ -9427,6 +9427,11 @@
|
|||
"integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=",
|
||||
"dev": true
|
||||
},
|
||||
"promise-polyfill": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-6.1.0.tgz",
|
||||
"integrity": "sha1-36lpQ+qcEh/KTem1hoyznTRy4Fc="
|
||||
},
|
||||
"prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
|
@ -10880,6 +10885,15 @@
|
|||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"sweetalert": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/sweetalert/-/sweetalert-2.1.2.tgz",
|
||||
"integrity": "sha512-iWx7X4anRBNDa/a+AdTmvAzQtkN1+s4j/JJRWlHpYE8Qimkohs8/XnFcWeYHH2lMA8LRCa5tj2d244If3S/hzA==",
|
||||
"requires": {
|
||||
"es6-object-assign": "^1.1.0",
|
||||
"promise-polyfill": "^6.0.2"
|
||||
}
|
||||
},
|
||||
"symbol-observable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz",
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"sub:update": "git submodule update --remote",
|
||||
"sub:pull": "git submodule foreach git pull origin master",
|
||||
"sub:commit": "npm run sub:pull && git commit -am \"update submodule\"",
|
||||
"postinstall": "./node_modules/.bin/electron-rebuild && npm run sub:init",
|
||||
"postinstall": "./node_modules/.bin/electron-rebuild && npm run sub:init && gulp postinstall",
|
||||
"lint": "tslint src/**/*.ts || true",
|
||||
"lint:fix": "tslint src/**/*.ts --fix",
|
||||
"build": "concurrently -n Main,Rend -c yellow,cyan \"npm run build:main\" \"npm run build:renderer\"",
|
||||
|
@ -258,6 +258,7 @@
|
|||
"nord": "0.2.1",
|
||||
"papaparse": "4.6.0",
|
||||
"rxjs": "6.3.3",
|
||||
"sweetalert": "2.1.2",
|
||||
"zone.js": "0.8.28",
|
||||
"zxcvbn": "4.4.2"
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
<form id="lock-page" (ngSubmit)="submit()">
|
||||
<div class="content">
|
||||
<p><i class="fa fa-lock fa-4x text-muted"></i></p>
|
||||
<p>{{'yourVaultIsLocked' | i18n}}</p>
|
||||
<p>{{(pinLock ? 'yourVaultIsLockedPinCode' : 'yourVaultIsLocked') | i18n}}</p>
|
||||
<div class="box last">
|
||||
<div class="box-content">
|
||||
<div class="box-content-row box-content-row-flex" appBoxRow>
|
||||
<div class="row-main">
|
||||
<div class="row-main" *ngIf="pinLock">
|
||||
<label for="pin">{{'pin' | i18n}}</label>
|
||||
<input id="pin" type="{{showPassword ? 'text' : 'password'}}" name="PIN"
|
||||
class="monospaced" [(ngModel)]="pin" required appAutofocus>
|
||||
</div>
|
||||
<div class="row-main" *ngIf="!pinLock">
|
||||
<label for="masterPassword">{{'masterPass' | i18n}}</label>
|
||||
<input id="masterPassword" type="{{showPassword ? 'text' : 'password'}}" name="MasterPassword"
|
||||
class="monospaced" [(ngModel)]="masterPassword" required appAutofocus>
|
||||
|
|
|
@ -10,6 +10,7 @@ import {
|
|||
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.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';
|
||||
|
@ -30,8 +31,9 @@ export class LockComponent extends BaseLockComponent implements OnDestroy {
|
|||
platformUtilsService: PlatformUtilsService, messagingService: MessagingService,
|
||||
userService: UserService, cryptoService: CryptoService,
|
||||
private ngZone: NgZone, private route: ActivatedRoute,
|
||||
private storageService: StorageService) {
|
||||
super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService);
|
||||
storageService: StorageService, lockService: LockService) {
|
||||
super(router, i18nService, platformUtilsService, messagingService, userService, cryptoService,
|
||||
storageService, lockService);
|
||||
}
|
||||
|
||||
async ngOnInit() {
|
||||
|
|
|
@ -15,6 +15,14 @@
|
|||
</select>
|
||||
<small class="help-block">{{'lockOptionsDesc' | i18n}}</small>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="checkbox">
|
||||
<label for="pin">
|
||||
<input id="pin" type="checkbox" name="PIN" [(ngModel)]="pin" (change)="updatePin()">
|
||||
{{'unlockWithPin' | i18n}}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box">
|
||||
|
|
|
@ -5,15 +5,18 @@ import {
|
|||
|
||||
import { ToasterService } from 'angular2-toaster';
|
||||
import { Angulartics2 } from 'angulartics2';
|
||||
import swal from 'sweetalert';
|
||||
|
||||
import { DeviceType } from 'jslib/enums/deviceType';
|
||||
|
||||
import { CryptoService } from 'jslib/abstractions/crypto.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 { ConstantsService } from 'jslib/services/constants.service';
|
||||
|
||||
|
@ -27,6 +30,7 @@ import { Utils } from 'jslib/misc/utils';
|
|||
})
|
||||
export class SettingsComponent implements OnInit {
|
||||
lockOption: number = null;
|
||||
pin: boolean = null;
|
||||
disableFavicons: boolean = false;
|
||||
enableMinToTray: boolean = false;
|
||||
enableCloseToTray: boolean = false;
|
||||
|
@ -40,9 +44,10 @@ export class SettingsComponent implements OnInit {
|
|||
themeOptions: any[];
|
||||
|
||||
constructor(private analytics: Angulartics2, private toasterService: ToasterService,
|
||||
i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
||||
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
|
||||
private storageService: StorageService, private lockService: LockService,
|
||||
private stateService: StateService, private messagingService: MessagingService) {
|
||||
private stateService: StateService, private messagingService: MessagingService,
|
||||
private userService: UserService, private cryptoService: CryptoService) {
|
||||
this.lockOptions = [
|
||||
// { name: i18nService.t('immediately'), value: 0 },
|
||||
{ name: i18nService.t('oneMinute'), value: 1 },
|
||||
|
@ -77,6 +82,7 @@ export class SettingsComponent implements OnInit {
|
|||
async ngOnInit() {
|
||||
this.showMinToTray = this.platformUtilsService.getDevice() === DeviceType.WindowsDesktop;
|
||||
this.lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey);
|
||||
this.pin = await this.lockService.isPinLockSet();
|
||||
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
|
||||
this.enableMinToTray = await this.storageService.get<boolean>(ElectronConstants.enableMinimizeToTrayKey);
|
||||
this.enableCloseToTray = await this.storageService.get<boolean>(ElectronConstants.enableCloseToTrayKey);
|
||||
|
@ -90,6 +96,31 @@ export class SettingsComponent implements OnInit {
|
|||
await this.lockService.setLockOption(this.lockOption != null ? this.lockOption : null);
|
||||
}
|
||||
|
||||
async updatePin() {
|
||||
if (this.pin) {
|
||||
const pin = await swal({
|
||||
text: this.i18nService.t('setYourPinCode'),
|
||||
content: { element: 'input' },
|
||||
buttons: [this.i18nService.t('cancel'), this.i18nService.t('submit')],
|
||||
});
|
||||
|
||||
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);
|
||||
} else {
|
||||
this.pin = false;
|
||||
}
|
||||
}
|
||||
if (!this.pin) {
|
||||
await this.storageService.remove(ConstantsService.pinProtectedKey);
|
||||
}
|
||||
}
|
||||
|
||||
async saveFavicons() {
|
||||
await this.storageService.save(ConstantsService.disableFaviconKey, this.disableFavicons);
|
||||
await this.stateService.save(ConstantsService.disableFaviconKey, this.disableFavicons);
|
||||
|
|
|
@ -1169,5 +1169,24 @@
|
|||
},
|
||||
"weakMasterPasswordDesc": {
|
||||
"message": "The master password you have chosen is weak. You should use a strong master password (or a passphrase) to properly protect your Bitwarden account. Are you sure you want to use this master password?"
|
||||
},
|
||||
"pin": {
|
||||
"message": "PIN",
|
||||
"description": "PIN code. Ex. The short code (often numeric) that you use to unlock a device."
|
||||
},
|
||||
"unlockWithPin": {
|
||||
"message": "Unlock with PIN"
|
||||
},
|
||||
"setYourPinCode": {
|
||||
"message": "Set your PIN code for unlocking Bitwarden. Your PIN settings will be reset if you ever fully log out of the application."
|
||||
},
|
||||
"pinRequired": {
|
||||
"message": "PIN code is required."
|
||||
},
|
||||
"invalidPin": {
|
||||
"message": "Invalid PIN code."
|
||||
},
|
||||
"yourVaultIsLockedPinCode": {
|
||||
"message": "Your vault is locked. Verify your PIN code to continue."
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,3 +95,53 @@ $fa-font-path: "~font-awesome/fonts";
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SweetAlert
|
||||
|
||||
.swal-modal {
|
||||
border-radius: $border-radius;
|
||||
|
||||
@include themify($themes) {
|
||||
background-color: themed('backgroundColorAlt');
|
||||
color: themed('textColor');
|
||||
}
|
||||
|
||||
.swal-text {
|
||||
font-size: $font-size-base;
|
||||
|
||||
@include themify($themes) {
|
||||
color: themed('textColor');
|
||||
}
|
||||
}
|
||||
|
||||
> .swal-text:first-child {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.swal-content__input, .swal-content__textarea {
|
||||
border: 1px solid #000000;
|
||||
border-radius: $border-radius;
|
||||
@include themify($themes) {
|
||||
border-color: themed('inputBorderColor');
|
||||
color: themed('textColor');
|
||||
background-color: themed('inputBackgroundColor');
|
||||
}
|
||||
}
|
||||
|
||||
.swal-footer {
|
||||
padding: 15px 10px 10px 10px;
|
||||
margin: 0;
|
||||
|
||||
.swal-button {
|
||||
@extend .btn;
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.swal-button--confirm {
|
||||
@extend .btn.primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue