settings and lock options

This commit is contained in:
Kyle Spearrin 2018-02-10 23:24:22 -05:00
parent 692e5b7dbc
commit 132c59f8fc
14 changed files with 278 additions and 77 deletions

View File

@ -1,13 +1,46 @@
<div class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="modal-body form">
<div class="box">
<div class="box-header">
{{'settings' | i18n}}
{{'security' | i18n}}
</div>
<div class="box-content">
Something.
<div class="box-content box-content-padded">
<div class="form-group">
<label for="lockOption">{{'lockOptions' | i18n}}</label>
<select id="lockOption" name="LockOption" [(ngModel)]="lockOption" (change)="save()">
<option *ngFor="let o of lockOptions" [ngValue]="o.value">{{o.name}}</option>
</select>
<small class="help-block">{{'lockOptionsDesc' | i18n}}</small>
</div>
</div>
</div>
<div class="box">
<div class="box-header">
{{'options' | i18n}}
</div>
<div class="box-content box-content-padded">
<div class="form-group">
<div class="checkbox">
<label for="disableGa">
<input id="disableGa" type="checkbox" name="DisableAnalytics"
[(ngModel)]="disableGa" (change)="save()">
{{'disableGa' | i18n}}
</label>
</div>
<small class="help-block">{{'gaDesc' | i18n}}</small>
</div>
<div class="form-group">
<div class="checkbox">
<label for="disableFavicon">
<input id="disableFavicon" type="checkbox" name="DisableFavicon"
[(ngModel)]="disableFavicons" (change)="save()">
{{'disableFavicon' | i18n}}
</label>
</div>
<small class="help-block">{{'disableFaviconDesc' | i18n}}</small>
</div>
</div>
</div>
</div>

View File

@ -9,21 +9,50 @@ import { ToasterService } from 'angular2-toaster';
import { Angulartics2 } from 'angulartics2';
import { I18nService } from 'jslib/abstractions/i18n.service';
import { LockService } from 'jslib/abstractions/lock.service';
import { PlatformUtilsService } from 'jslib/abstractions/platformUtils.service';
import { StorageService } from 'jslib/abstractions/storage.service';
import { ConstantsService } from 'jslib/services/constants.service';
@Component({
selector: 'app-settings',
template: template,
})
export class SettingsComponent implements OnInit {
lockOptions: any[];
lockOption: number = null;
disableGa: boolean = false;
disableFavicons: boolean = false;
constructor(private analytics: Angulartics2, private toasterService: ToasterService,
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService) { }
ngOnInit() {
private i18nService: I18nService, private platformUtilsService: PlatformUtilsService,
private storageService: StorageService, private lockService: LockService) {
this.lockOptions = [
// { name: i18nService.t('immediately'), value: 0 },
{ name: i18nService.t('oneMinute'), value: 1 },
{ name: i18nService.t('fiveMinutes'), value: 5 },
{ name: i18nService.t('fifteenMinutes'), value: 15 },
{ name: i18nService.t('thirtyMinutes'), value: 30 },
{ name: i18nService.t('oneHour'), value: 60 },
{ name: i18nService.t('fourHours'), value: 240 },
// { name: i18nService.t('onIdle'), value: -4 },
{ name: i18nService.t('onSleep'), value: -3 },
// { name: i18nService.t('onLocked'), value: -2 },
{ name: i18nService.t('onRestart'), value: -1 },
{ name: i18nService.t('never'), value: null },
];
}
submit() {
async ngOnInit() {
this.lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey);
this.disableGa = await this.storageService.get<boolean>(ConstantsService.disableGaKey);
this.disableFavicons = await this.storageService.get<boolean>(ConstantsService.disableFaviconKey);
}
async save() {
await this.lockService.setLockOption(this.lockOption != null ? this.lockOption : null);
await this.storageService.save(ConstantsService.disableGaKey, this.disableGa);
await this.storageService.save(ConstantsService.disableFaviconKey, this.disableFavicons);
}
}

View File

@ -7,8 +7,8 @@ import {
import { ToasterModule } from 'angular2-toaster';
import { DesktopMessagingService } from '../../services/desktopMessaging.service';
import { DesktopPlatformUtilsService } from '../../services/desktopPlatformUtils.service';
import { DesktopRendererMessagingService } from '../../services/desktopRendererMessaging.service';
import { DesktopSecureStorageService } from '../../services/desktopSecureStorage.service';
import { DesktopStorageService } from '../../services/desktopStorage.service';
import { I18nService } from '../../services/i18n.service';
@ -69,7 +69,7 @@ const i18nService = new I18nService(window.navigator.language, './locales');
const utilsService = new UtilsService();
const platformUtilsService = new DesktopPlatformUtilsService(i18nService);
const broadcasterService = new BroadcasterService();
const messagingService = new DesktopMessagingService(broadcasterService);
const messagingService = new DesktopRendererMessagingService(broadcasterService);
const storageService: StorageServiceAbstraction = new DesktopStorageService();
const secureStorageService: StorageServiceAbstraction = new DesktopSecureStorageService();
const constantsService = new ConstantsService({}, 0);

View File

@ -693,5 +693,62 @@
},
"twoStepLogin": {
"message": "Two-step Login"
},
"lockOptions": {
"message": "Lock Options"
},
"lockOptionsDesc": {
"message": "Choose when your vault locks. A locked vault requires that you re-enter your master password to access it again."
},
"immediately": {
"message": "Immediately"
},
"oneMinute": {
"message": "1 minute"
},
"fiveMinutes": {
"message": "5 minutes"
},
"fifteenMinutes": {
"message": "15 minutes"
},
"thirtyMinutes": {
"message": "30 minutes"
},
"oneHour": {
"message": "1 hour"
},
"fourHours": {
"message": "4 hours"
},
"onIdle": {
"message": "On System Idle"
},
"onSleep": {
"message": "On System Sleep"
},
"onLocked": {
"message": "On System Lock"
},
"onRestart": {
"message": "On Restart"
},
"never": {
"message": "Never"
},
"security": {
"message": "Security"
},
"disableGa": {
"message": "Disable Analytics"
},
"gaDesc": {
"message": "We use analytics to better learn how the application is being used so that we can make it better. All data collection is completely anonymous."
},
"disableFavicon": {
"message": "Disable Website Icons"
},
"disableFaviconDesc": {
"message": "Website Icons provide a recognizable image next to each login item in your vault."
}
}

View File

@ -2,8 +2,11 @@ import { BrowserWindow } from 'electron';
import { MenuMain } from './main/menu.main';
import { MessagingMain } from './main/messaging.main';
import { PowerMonitorMain } from './main/powerMonitor.main';
import { WindowMain } from './main/window.main';
import { DesktopMainMessagingService } from './services/desktopMainMessaging.service';
import { DesktopStorageService } from './services/desktopStorage.service';
import { I18nService } from './services/i18n.service';
const args = process.argv.slice(1);
@ -15,16 +18,22 @@ if (watch) {
require('electron-reload')(__dirname, {});
}
const i18nService = new I18nService('en', './locales/');
const windowMain = new WindowMain(dev);
const messagingMain = new MessagingMain(windowMain);
const menuMain = new MenuMain(windowMain, i18nService);
const i18nService = new I18nService('en', './locales/');
const storageService = new DesktopStorageService();
const messagingService = new DesktopMainMessagingService(windowMain, messagingMain);
const menuMain = new MenuMain(windowMain, i18nService, messagingService);
const powerMonitorMain = new PowerMonitorMain(storageService, messagingService);
windowMain.init().then(() => {
messagingMain.init();
return i18nService.init();
}).then(() => {
menuMain.init();
powerMonitorMain.init();
}, (e: any) => {
// tslint:disable-next-line
console.log(e);

View File

@ -10,21 +10,21 @@ import {
import { WindowMain } from './window.main';
import { I18nService } from '../services/i18n.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { I18nService } from 'jslib/abstractions/i18n.service';
export class MenuMain {
constructor(private windowMain: WindowMain, private i18nService: I18nService) { }
constructor(private windowMain: WindowMain, private i18nService: I18nService,
private messagingService: MessagingService) { }
init() {
const self = this;
const template: MenuItemConstructorOptions[] = [
{
label: this.i18nService.t('file'),
submenu: [
{
label: this.i18nService.t('addNewLogin'),
click: () => self.send('newLogin'),
click: () => this.messagingService.send('newLogin'),
accelerator: 'CmdOrCtrl+N',
},
{
@ -32,34 +32,34 @@ export class MenuMain {
submenu: [
{
label: this.i18nService.t('typeLogin'),
click: () => self.send('newLogin'),
click: () => this.messagingService.send('newLogin'),
accelerator: 'Alt+L',
},
{
label: this.i18nService.t('typeCard'),
click: () => self.send('newCard'),
click: () => this.messagingService.send('newCard'),
accelerator: 'Alt+C',
},
{
label: this.i18nService.t('typeIdentity'),
click: () => self.send('newIdentity'),
click: () => this.messagingService.send('newIdentity'),
accelerator: 'Alt+I',
},
{
label: this.i18nService.t('typeSecureNote'),
click: () => self.send('newSecureNote'),
click: () => this.messagingService.send('newSecureNote'),
accelerator: 'Alt+S',
},
],
},
{
label: this.i18nService.t('addNewFolder'),
click: () => self.send('newFolder'),
click: () => this.messagingService.send('newFolder'),
},
{ type: 'separator' },
{
label: this.i18nService.t('syncVault'),
click: () => self.send('syncVault'),
click: () => this.messagingService.send('syncVault'),
},
],
},
@ -80,12 +80,12 @@ export class MenuMain {
submenu: [
{
label: this.i18nService.t('passwordGenerator'),
click: () => self.send('openPasswordGenerator'),
click: () => this.messagingService.send('openPasswordGenerator'),
accelerator: 'CmdOrCtrl+G',
},
{
label: this.i18nService.t('searchVault'),
click: () => self.send('focusSearch'),
click: () => this.messagingService.send('focusSearch'),
accelerator: 'CmdOrCtrl+F',
},
{ type: 'separator' },
@ -105,15 +105,15 @@ export class MenuMain {
submenu: [
{
label: this.i18nService.t('premiumMembership'),
click: () => self.send('premiumMembership'),
click: () => this.messagingService.send('premiumMembership'),
},
{
label: this.i18nService.t('changeMasterPass'),
click: () => {
const result = dialog.showMessageBox(self.windowMain.win, {
title: self.i18nService.t('changeMasterPass'),
message: self.i18nService.t('changeMasterPasswordConfirmation'),
buttons: [self.i18nService.t('yes'), self.i18nService.t('no')],
const result = dialog.showMessageBox(this.windowMain.win, {
title: this.i18nService.t('changeMasterPass'),
message: this.i18nService.t('changeMasterPasswordConfirmation'),
buttons: [this.i18nService.t('yes'), this.i18nService.t('no')],
cancelId: 1,
defaultId: 0,
noLink: true,
@ -126,10 +126,10 @@ export class MenuMain {
{
label: this.i18nService.t('changeEmail'),
click: () => {
const result = dialog.showMessageBox(self.windowMain.win, {
title: self.i18nService.t('changeEmail'),
message: self.i18nService.t('changeEmailConfirmation'),
buttons: [self.i18nService.t('yes'), self.i18nService.t('no')],
const result = dialog.showMessageBox(this.windowMain.win, {
title: this.i18nService.t('changeEmail'),
message: this.i18nService.t('changeEmailConfirmation'),
buttons: [this.i18nService.t('yes'), this.i18nService.t('no')],
cancelId: 1,
defaultId: 0,
noLink: true,
@ -142,10 +142,10 @@ export class MenuMain {
{
label: this.i18nService.t('twoStepLogin'),
click: () => {
const result = dialog.showMessageBox(self.windowMain.win, {
title: self.i18nService.t('twoStepLogin'),
message: self.i18nService.t('twoStepLoginConfirmation'),
buttons: [self.i18nService.t('yes'), self.i18nService.t('no')],
const result = dialog.showMessageBox(this.windowMain.win, {
title: this.i18nService.t('twoStepLogin'),
message: this.i18nService.t('twoStepLoginConfirmation'),
buttons: [this.i18nService.t('yes'), this.i18nService.t('no')],
cancelId: 1,
defaultId: 0,
noLink: true,
@ -159,16 +159,16 @@ export class MenuMain {
{
label: this.i18nService.t('logOut'),
click: () => {
const result = dialog.showMessageBox(self.windowMain.win, {
title: self.i18nService.t('logOut'),
message: self.i18nService.t('logOutConfirmation'),
buttons: [self.i18nService.t('logOut'), self.i18nService.t('cancel')],
const result = dialog.showMessageBox(this.windowMain.win, {
title: this.i18nService.t('logOut'),
message: this.i18nService.t('logOutConfirmation'),
buttons: [this.i18nService.t('logOut'), this.i18nService.t('cancel')],
cancelId: 1,
defaultId: 0,
noLink: true,
});
if (result === 0) {
self.send('logout');
this.messagingService.send('logout');
}
},
},
@ -294,11 +294,11 @@ export class MenuMain {
{ type: 'separator' },
{
label: this.i18nService.t('settings'),
click: () => self.send('openSettings'),
click: () => this.messagingService.send('openSettings'),
},
{
label: this.i18nService.t('lockNow'),
click: () => self.send('lockVault'),
click: () => this.messagingService.send('lockVault'),
accelerator: 'CmdOrCtrl+L',
},
];
@ -338,11 +338,4 @@ export class MenuMain {
const menu = Menu.buildFromTemplate(template);
Menu.setApplicationMenu(menu);
}
send(command: string, message?: any) {
this.windowMain.win.webContents.send('messagingService', {
command: command,
message: message,
});
}
}

View File

@ -13,22 +13,7 @@ export class MessagingMain {
init() {
this.scheduleNextSync();
ipcMain.on('messagingService', async (event: any, message: any) => {
switch (message.command) {
case 'loggedIn':
break;
case 'logout':
break;
case 'syncCompleted':
break;
case 'scheduleNextSync':
this.scheduleNextSync();
break;
default:
break;
}
});
ipcMain.on('messagingService', async (event: any, message: any) => this.onMessage(message));
/*
ipcMain.on('keytar', async (event: any, message: any) => {
@ -53,6 +38,22 @@ export class MessagingMain {
*/
}
onMessage(message: any) {
switch (message.command) {
case 'loggedIn':
break;
case 'logout':
break;
case 'syncCompleted':
break;
case 'scheduleNextSync':
this.scheduleNextSync();
break;
default:
break;
}
}
private scheduleNextSync() {
if (this.syncTimeout) {
global.clearTimeout(this.syncTimeout);

View File

@ -0,0 +1,24 @@
import { powerMonitor } from 'electron';
import { ConstantsService } from 'jslib/services/constants.service';
import { MessagingService } from 'jslib/abstractions/messaging.service';
import { StorageService } from 'jslib/abstractions/storage.service';
export class PowerMonitorMain {
constructor(private storageService: StorageService, private messagingService: MessagingService) { }
init() {
// System sleep
powerMonitor.on('suspend', async () => {
const lockOption = await this.storageService.get<number>(ConstantsService.lockOptionKey);
if (lockOption === -3) {
this.messagingService.send('lockVault');
}
});
// TODO: System idle
// TODO: System locked
}
}

View File

@ -21,6 +21,10 @@
border-radius: $border-radius;
box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2);
&.box-content-padded {
padding: 10px 15px;
}
.box-content-row {
display: block;
padding: 10px 15px;

View File

@ -1,5 +1,9 @@
@import "variables.scss";
small {
font-size: $font-size-small;
}
.text-primary {
color: $brand-primary !important;
}
@ -116,12 +120,45 @@
}
}
@keyframes spin {
from {
transform: rotate(0deg);
form, .form {
.form-group {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
label {
display: inline-block;
margin-bottom: 2px;
}
input, select, textarea {
border: 1px solid darken($border-color-dark, 7%);
border-radius: $border-radius;
display: block;
}
}
to {
transform: rotate(360deg);
.checkbox {
position: relative;
display: block;
padding-left: 18px;
label {
margin-bottom: 0;
}
input[type="checkbox"] {
position: absolute;
margin-top: 4px;
margin-left: -18px;
}
}
.help-block {
margin-top: 3px;
color: $text-muted;
display: block;
}
}

View File

@ -0,0 +1,14 @@
import { MessagingService } from 'jslib/abstractions';
import { MessagingMain } from '../main/messaging.main';
import { WindowMain } from '../main/window.main';
export class DesktopMainMessagingService implements MessagingService {
constructor(private windowMain: WindowMain, private messagingMain: MessagingMain) { }
send(subscriber: string, arg: any = {}) {
const message = Object.assign({}, { command: subscriber }, arg);
this.windowMain.win.webContents.send('messagingService', message);
this.messagingMain.onMessage(message);
}
}

View File

@ -4,7 +4,7 @@ import { MessagingService } from 'jslib/abstractions';
import { BroadcasterService } from '../app/services/broadcaster.service';
export class DesktopMessagingService implements MessagingService {
export class DesktopRendererMessagingService implements MessagingService {
constructor(private broadcasterService: BroadcasterService) {
ipcRenderer.on('messagingService', async (event: any, message: any) => {
if (message.command) {

View File

@ -7,7 +7,7 @@ export class DesktopSecureStorageService implements StorageService {
action: 'getPassword',
key: key,
});
return Promise.resolve(val ? JSON.parse(val) as T : null);
return Promise.resolve(val != null ? JSON.parse(val) as T : null);
}
async save(key: string, obj: any): Promise<any> {

View File

@ -7,7 +7,7 @@ const store = new Store();
export class DesktopStorageService implements StorageService {
get<T>(key: string): Promise<T> {
const val = store.get(key) as T;
return Promise.resolve(val ? val : null);
return Promise.resolve(val != null ? val : null);
}
save(key: string, obj: any): Promise<any> {