+
-
- Something.
+
+
+
+
+ {{'lockOptionsDesc' | i18n}}
+
+
+
+
diff --git a/src/app/accounts/settings.component.ts b/src/app/accounts/settings.component.ts
index 82f51af037..5cbf17f2ee 100644
--- a/src/app/accounts/settings.component.ts
+++ b/src/app/accounts/settings.component.ts
@@ -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
(ConstantsService.lockOptionKey);
+ this.disableGa = await this.storageService.get(ConstantsService.disableGaKey);
+ this.disableFavicons = await this.storageService.get(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);
}
}
diff --git a/src/app/services/services.module.ts b/src/app/services/services.module.ts
index dfc61be4f8..dd6d41d2bd 100644
--- a/src/app/services/services.module.ts
+++ b/src/app/services/services.module.ts
@@ -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);
diff --git a/src/locales/en/messages.json b/src/locales/en/messages.json
index 1e1b31d839..39b6beadcc 100644
--- a/src/locales/en/messages.json
+++ b/src/locales/en/messages.json
@@ -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."
}
}
diff --git a/src/main.ts b/src/main.ts
index 8df070924b..fc959e2bf0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -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);
diff --git a/src/main/menu.main.ts b/src/main/menu.main.ts
index d4709c86e1..79d812fc49 100644
--- a/src/main/menu.main.ts
+++ b/src/main/menu.main.ts
@@ -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,
- });
- }
}
diff --git a/src/main/messaging.main.ts b/src/main/messaging.main.ts
index 129c3d7488..caa203f7a9 100644
--- a/src/main/messaging.main.ts
+++ b/src/main/messaging.main.ts
@@ -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);
diff --git a/src/main/powerMonitor.main.ts b/src/main/powerMonitor.main.ts
new file mode 100644
index 0000000000..41698e761f
--- /dev/null
+++ b/src/main/powerMonitor.main.ts
@@ -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(ConstantsService.lockOptionKey);
+ if (lockOption === -3) {
+ this.messagingService.send('lockVault');
+ }
+ });
+
+ // TODO: System idle
+
+ // TODO: System locked
+ }
+}
diff --git a/src/scss/box.scss b/src/scss/box.scss
index 6b33725a0b..30cce4aac8 100644
--- a/src/scss/box.scss
+++ b/src/scss/box.scss
@@ -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;
diff --git a/src/scss/misc.scss b/src/scss/misc.scss
index 754c045880..1f97f2877c 100644
--- a/src/scss/misc.scss
+++ b/src/scss/misc.scss
@@ -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;
}
}
diff --git a/src/services/desktopMainMessaging.service.ts b/src/services/desktopMainMessaging.service.ts
new file mode 100644
index 0000000000..eb58e6362f
--- /dev/null
+++ b/src/services/desktopMainMessaging.service.ts
@@ -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);
+ }
+}
diff --git a/src/services/desktopMessaging.service.ts b/src/services/desktopRendererMessaging.service.ts
similarity index 89%
rename from src/services/desktopMessaging.service.ts
rename to src/services/desktopRendererMessaging.service.ts
index a814c41fcf..3c7f7024e7 100644
--- a/src/services/desktopMessaging.service.ts
+++ b/src/services/desktopRendererMessaging.service.ts
@@ -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) {
diff --git a/src/services/desktopSecureStorage.service.ts b/src/services/desktopSecureStorage.service.ts
index f858a43014..968e6bb0f8 100644
--- a/src/services/desktopSecureStorage.service.ts
+++ b/src/services/desktopSecureStorage.service.ts
@@ -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 {
diff --git a/src/services/desktopStorage.service.ts b/src/services/desktopStorage.service.ts
index 557b5d2fd0..b6cdd137d0 100644
--- a/src/services/desktopStorage.service.ts
+++ b/src/services/desktopStorage.service.ts
@@ -7,7 +7,7 @@ const store = new Store();
export class DesktopStorageService implements StorageService {
get(key: string): Promise {
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 {