2021-05-08 11:38:23 +02:00
|
|
|
import * as kdbxweb from 'kdbxweb';
|
2019-09-16 20:42:33 +02:00
|
|
|
import { View } from 'framework/views/view';
|
2019-09-16 22:57:56 +02:00
|
|
|
import { Events } from 'framework/events';
|
2019-09-15 14:16:32 +02:00
|
|
|
import { Storage } from 'storage';
|
|
|
|
import { DropboxChooser } from 'comp/app/dropbox-chooser';
|
|
|
|
import { FocusDetector } from 'comp/browser/focus-detector';
|
|
|
|
import { KeyHandler } from 'comp/browser/key-handler';
|
|
|
|
import { SecureInput } from 'comp/browser/secure-input';
|
|
|
|
import { Launcher } from 'comp/launcher';
|
|
|
|
import { Alerts } from 'comp/ui/alerts';
|
2020-04-15 16:50:01 +02:00
|
|
|
import { UsbListener } from 'comp/app/usb-listener';
|
2020-05-24 18:39:56 +02:00
|
|
|
import { YubiKey } from 'comp/app/yubikey';
|
2019-09-15 14:16:32 +02:00
|
|
|
import { Keys } from 'const/keys';
|
|
|
|
import { Comparators } from 'util/data/comparators';
|
|
|
|
import { Features } from 'util/features';
|
|
|
|
import { UrlFormat } from 'util/formatting/url-format';
|
|
|
|
import { Locale } from 'util/locale';
|
|
|
|
import { Logger } from 'util/logger';
|
|
|
|
import { InputFx } from 'util/ui/input-fx';
|
|
|
|
import { OpenConfigView } from 'views/open-config-view';
|
|
|
|
import { StorageFileListView } from 'views/storage-file-list-view';
|
2020-05-24 20:02:49 +02:00
|
|
|
import { OpenChalRespView } from 'views/open-chal-resp-view';
|
2020-04-23 19:55:52 +02:00
|
|
|
import { omit } from 'util/fn';
|
2019-10-17 19:52:34 +02:00
|
|
|
import { GeneratorView } from 'views/generator-view';
|
2021-02-03 20:30:59 +01:00
|
|
|
import { NativeModules } from 'comp/launcher/native-modules';
|
2019-09-16 17:43:57 +02:00
|
|
|
import template from 'templates/open.hbs';
|
2017-01-31 07:50:28 +01:00
|
|
|
|
|
|
|
const logger = new Logger('open-view');
|
|
|
|
|
2019-09-16 17:43:57 +02:00
|
|
|
class OpenView extends View {
|
|
|
|
parent = '.app__body';
|
2019-10-12 08:20:44 +02:00
|
|
|
modal = 'open';
|
2015-10-17 23:49:24 +02:00
|
|
|
|
2019-09-16 17:43:57 +02:00
|
|
|
template = template;
|
|
|
|
|
|
|
|
events = {
|
2015-11-05 21:58:33 +01:00
|
|
|
'change .open__file-ctrl': 'fileSelected',
|
|
|
|
'click .open__icon-open': 'openFile',
|
|
|
|
'click .open__icon-new': 'createNew',
|
|
|
|
'click .open__icon-demo': 'createDemo',
|
2020-04-19 18:52:21 +02:00
|
|
|
'click .open__icon-yubikey': 'openYubiKey',
|
2016-03-09 21:52:19 +01:00
|
|
|
'click .open__icon-more': 'toggleMore',
|
2016-03-13 17:08:25 +01:00
|
|
|
'click .open__icon-storage': 'openStorage',
|
2016-03-13 18:33:25 +01:00
|
|
|
'click .open__icon-settings': 'openSettings',
|
2019-09-16 21:49:21 +02:00
|
|
|
'click .open__pass-input[readonly]': 'openFile',
|
2015-11-05 21:58:33 +01:00
|
|
|
'input .open__pass-input': 'inputInput',
|
|
|
|
'keydown .open__pass-input': 'inputKeydown',
|
2016-02-18 19:57:18 +01:00
|
|
|
'keyup .open__pass-input': 'inputKeyup',
|
2015-11-05 21:58:33 +01:00
|
|
|
'keypress .open__pass-input': 'inputKeypress',
|
2015-11-06 21:14:47 +01:00
|
|
|
'click .open__pass-enter-btn': 'openDb',
|
2015-11-05 21:58:33 +01:00
|
|
|
'click .open__settings-key-file': 'openKeyFile',
|
2020-05-24 18:39:56 +02:00
|
|
|
'click .open__settings-yubikey': 'selectYubiKeyChalResp',
|
2015-11-07 20:02:45 +01:00
|
|
|
'click .open__last-item': 'openLast',
|
2019-10-17 19:52:34 +02:00
|
|
|
'click .open__icon-generate': 'toggleGenerator',
|
2021-04-26 11:51:24 +02:00
|
|
|
'click .open__message-cancel-btn': 'openMessageCancelClick',
|
2019-09-16 17:43:57 +02:00
|
|
|
dragover: 'dragover',
|
|
|
|
dragleave: 'dragleave',
|
|
|
|
drop: 'drop'
|
|
|
|
};
|
|
|
|
|
|
|
|
params = null;
|
|
|
|
passwordInput = null;
|
|
|
|
busy = false;
|
|
|
|
currentSelectedIndex = -1;
|
2021-02-03 20:30:59 +01:00
|
|
|
encryptedPassword = null;
|
2019-09-16 17:43:57 +02:00
|
|
|
|
|
|
|
constructor(model) {
|
|
|
|
super(model);
|
2020-05-09 20:15:46 +02:00
|
|
|
window.$ = $;
|
2019-09-16 17:43:57 +02:00
|
|
|
this.resetParams();
|
2015-11-05 21:58:33 +01:00
|
|
|
this.passwordInput = new SecureInput();
|
2019-10-08 20:09:06 +02:00
|
|
|
this.onKey(Keys.DOM_VK_Z, this.undoKeyPress, KeyHandler.SHORTCUT_ACTION, 'open');
|
|
|
|
this.onKey(Keys.DOM_VK_TAB, this.tabKeyPress, null, 'open');
|
|
|
|
this.onKey(Keys.DOM_VK_ENTER, this.enterKeyPress, null, 'open');
|
|
|
|
this.onKey(Keys.DOM_VK_RETURN, this.enterKeyPress, null, 'open');
|
|
|
|
this.onKey(Keys.DOM_VK_DOWN, this.moveOpenFileSelectionDown, null, 'open');
|
|
|
|
this.onKey(Keys.DOM_VK_UP, this.moveOpenFileSelectionUp, null, 'open');
|
2019-09-16 22:57:56 +02:00
|
|
|
this.listenTo(Events, 'main-window-focus', this.windowFocused.bind(this));
|
2020-04-15 16:50:01 +02:00
|
|
|
this.listenTo(Events, 'usb-devices-changed', this.usbDevicesChanged.bind(this));
|
2021-04-26 11:51:24 +02:00
|
|
|
this.listenTo(Events, 'unlock-message-changed', this.unlockMessageChanged.bind(this));
|
2019-09-18 23:37:57 +02:00
|
|
|
this.once('remove', () => {
|
2019-09-16 17:43:57 +02:00
|
|
|
this.passwordInput.reset();
|
|
|
|
});
|
2020-04-23 18:47:46 +02:00
|
|
|
this.listenTo(Events, 'user-idle', this.userIdle);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-17 21:57:32 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
render() {
|
2015-10-17 23:49:24 +02:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2017-01-31 07:50:28 +01:00
|
|
|
const storageProviders = [];
|
2020-04-17 20:58:47 +02:00
|
|
|
if (this.model.settings.canOpenStorage) {
|
2020-06-01 16:53:51 +02:00
|
|
|
Object.keys(Storage).forEach((name) => {
|
2020-04-17 20:58:47 +02:00
|
|
|
const prv = Storage[name];
|
|
|
|
if (!prv.system && prv.enabled) {
|
|
|
|
storageProviders.push(prv);
|
2020-04-15 17:26:10 +02:00
|
|
|
}
|
2020-04-17 20:58:47 +02:00
|
|
|
});
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
|
2020-04-15 17:26:10 +02:00
|
|
|
const showMore =
|
|
|
|
storageProviders.length ||
|
|
|
|
this.model.settings.canOpenSettings ||
|
|
|
|
this.model.settings.canOpenGenerator;
|
2019-08-16 23:05:39 +02:00
|
|
|
const showLogo =
|
|
|
|
!showMore &&
|
2019-09-17 19:50:42 +02:00
|
|
|
!this.model.settings.canOpen &&
|
|
|
|
!this.model.settings.canCreate &&
|
|
|
|
!(this.model.settings.canOpenDemo && !this.model.settings.demoOpened);
|
2020-06-06 13:30:35 +02:00
|
|
|
const hasYubiKeys = !!UsbListener.attachedYubiKeys;
|
2020-04-19 18:52:21 +02:00
|
|
|
const canOpenYubiKey =
|
2020-05-23 19:07:45 +02:00
|
|
|
hasYubiKeys &&
|
2020-04-19 18:52:21 +02:00
|
|
|
this.model.settings.canOpenOtpDevice &&
|
|
|
|
this.model.settings.yubiKeyShowIcon &&
|
2020-05-05 21:26:41 +02:00
|
|
|
!this.model.files.get('yubikey');
|
2020-05-23 19:26:54 +02:00
|
|
|
const canUseChalRespYubiKey = hasYubiKeys && this.model.settings.yubiKeyShowChalResp;
|
2020-04-19 18:52:21 +02:00
|
|
|
|
2019-09-16 17:43:57 +02:00
|
|
|
super.render({
|
2016-03-13 10:54:16 +01:00
|
|
|
lastOpenFiles: this.getLastOpenFiles(),
|
2017-04-16 17:00:35 +02:00
|
|
|
canOpenKeyFromDropbox: !Launcher && Storage.dropbox.enabled,
|
2019-09-17 19:50:42 +02:00
|
|
|
demoOpened: this.model.settings.demoOpened,
|
2019-08-18 10:17:09 +02:00
|
|
|
storageProviders,
|
2021-04-26 11:51:24 +02:00
|
|
|
unlockMessageRes: this.model.unlockMessageRes,
|
2019-09-17 19:50:42 +02:00
|
|
|
canOpen: this.model.settings.canOpen,
|
|
|
|
canOpenDemo: this.model.settings.canOpenDemo,
|
|
|
|
canOpenSettings: this.model.settings.canOpenSettings,
|
2020-04-15 17:26:10 +02:00
|
|
|
canOpenGenerator: this.model.settings.canOpenGenerator,
|
2019-09-17 19:50:42 +02:00
|
|
|
canCreate: this.model.settings.canCreate,
|
|
|
|
canRemoveLatest: this.model.settings.canRemoveLatest,
|
2020-04-19 18:52:21 +02:00
|
|
|
canOpenYubiKey,
|
2020-05-23 19:26:54 +02:00
|
|
|
canUseChalRespYubiKey,
|
2019-08-18 10:17:09 +02:00
|
|
|
showMore,
|
|
|
|
showLogo
|
2016-03-13 10:54:16 +01:00
|
|
|
});
|
2015-11-05 21:58:33 +01:00
|
|
|
this.inputEl = this.$el.find('.open__pass-input');
|
|
|
|
this.passwordInput.setElement(this.inputEl);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
resetParams() {
|
|
|
|
this.params = {
|
|
|
|
id: null,
|
|
|
|
name: '',
|
|
|
|
storage: null,
|
|
|
|
path: null,
|
|
|
|
keyFileName: null,
|
|
|
|
keyFileData: null,
|
|
|
|
keyFilePath: null,
|
|
|
|
fileData: null,
|
2019-11-08 19:07:38 +01:00
|
|
|
rev: null,
|
2020-05-24 20:31:03 +02:00
|
|
|
opts: null,
|
|
|
|
chalResp: null
|
2019-09-16 17:43:57 +02:00
|
|
|
};
|
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
windowFocused() {
|
2019-02-04 19:20:12 +01:00
|
|
|
this.inputEl.focus();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.checkIfEncryptedPasswordDateIsValid();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2019-02-04 19:20:12 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
focusInput(focusOnMobile) {
|
2019-09-15 08:11:11 +02:00
|
|
|
if (FocusDetector.hasFocus() && (focusOnMobile || !Features.isMobile)) {
|
2019-01-14 08:56:33 +01:00
|
|
|
this.inputEl.focus();
|
2016-05-13 14:09:21 +02:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-05-13 14:09:21 +02:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
getLastOpenFiles() {
|
2020-06-01 16:53:51 +02:00
|
|
|
return this.model.fileInfos.map((fileInfo) => {
|
2020-11-25 18:20:53 +01:00
|
|
|
let icon = 'file-alt';
|
2019-09-17 21:39:06 +02:00
|
|
|
const storage = Storage[fileInfo.storage];
|
2016-03-27 08:14:15 +02:00
|
|
|
if (storage && storage.icon) {
|
|
|
|
icon = storage.icon;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
return {
|
2019-09-17 21:39:06 +02:00
|
|
|
id: fileInfo.id,
|
|
|
|
name: fileInfo.name,
|
|
|
|
path: this.getDisplayedPath(fileInfo),
|
2020-11-25 18:20:53 +01:00
|
|
|
icon
|
2015-12-06 21:32:41 +01:00
|
|
|
};
|
2015-11-07 20:02:45 +01:00
|
|
|
});
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
getDisplayedPath(fileInfo) {
|
2019-09-17 21:39:06 +02:00
|
|
|
const storage = fileInfo.storage;
|
2017-02-04 23:51:17 +01:00
|
|
|
if (storage === 'file' || storage === 'webdav') {
|
2019-09-17 21:39:06 +02:00
|
|
|
return fileInfo.path;
|
2017-02-04 23:51:17 +01:00
|
|
|
}
|
|
|
|
return null;
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
showLocalFileAlert() {
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.skipOpenLocalWarn) {
|
2016-02-23 07:08:57 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
Alerts.alert({
|
|
|
|
header: Locale.openLocalFile,
|
|
|
|
body: Locale.openLocalFileBody,
|
2020-12-04 16:48:48 +01:00
|
|
|
icon: 'file-alt',
|
2016-02-23 07:08:57 +01:00
|
|
|
buttons: [
|
2019-08-16 23:05:39 +02:00
|
|
|
{ result: 'skip', title: Locale.openLocalFileDontShow, error: true },
|
|
|
|
{ result: 'ok', title: Locale.alertOk }
|
2016-02-23 07:08:57 +01:00
|
|
|
],
|
|
|
|
click: '',
|
|
|
|
esc: '',
|
|
|
|
enter: '',
|
2020-06-01 16:53:51 +02:00
|
|
|
success: (res) => {
|
2016-07-17 13:30:38 +02:00
|
|
|
this.focusInput();
|
2016-02-23 07:08:57 +01:00
|
|
|
if (res === 'skip') {
|
2019-09-17 19:50:42 +02:00
|
|
|
this.model.settings.skipOpenLocalWarn = true;
|
2016-02-23 07:08:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-02-23 07:08:57 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
fileSelected(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const file = e.target.files[0];
|
2015-11-06 21:14:47 +01:00
|
|
|
if (file) {
|
2021-03-19 18:56:36 +01:00
|
|
|
if (this.model.settings.canImportCsv && /\.csv$/.test(file.name)) {
|
|
|
|
Events.emit('import-csv-requested', file);
|
|
|
|
} else if (this.model.settings.canImportXml && /\.xml$/.test(file.name)) {
|
|
|
|
this.setFile(file, null, this.showLocalFileAlert.bind(this));
|
|
|
|
} else {
|
|
|
|
this.processFile(file, (success) => {
|
|
|
|
if (success && !file.path && this.reading === 'fileData') {
|
|
|
|
this.showLocalFileAlert();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
processFile(file, complete) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const reader = new FileReader();
|
2020-06-01 16:53:51 +02:00
|
|
|
reader.onload = (e) => {
|
2017-01-31 07:50:28 +01:00
|
|
|
let success = false;
|
2016-03-01 04:29:20 +01:00
|
|
|
switch (this.reading) {
|
2019-08-25 12:46:53 +02:00
|
|
|
case 'fileData': {
|
|
|
|
const format = this.getOpenFileFormat(e.target.result);
|
|
|
|
switch (format) {
|
|
|
|
case 'kdbx':
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.fileData = e.target.result;
|
|
|
|
this.params.name = file.name.replace(/(.+)\.\w+$/i, '$1');
|
|
|
|
this.params.path = file.path || null;
|
|
|
|
this.params.storage = file.path ? 'file' : null;
|
|
|
|
this.params.rev = null;
|
|
|
|
if (!this.params.keyFileData) {
|
|
|
|
this.params.keyFileName = null;
|
|
|
|
}
|
2021-02-03 20:30:59 +01:00
|
|
|
this.encryptedPassword = null;
|
2019-08-25 12:46:53 +02:00
|
|
|
this.displayOpenFile();
|
|
|
|
this.displayOpenKeyFile();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2019-08-25 12:46:53 +02:00
|
|
|
success = true;
|
|
|
|
break;
|
|
|
|
case 'xml':
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.fileXml = kdbxweb.ByteUtils.bytesToString(e.target.result);
|
|
|
|
this.params.name = file.name.replace(/\.\w+$/i, '');
|
|
|
|
this.params.path = null;
|
|
|
|
this.params.storage = null;
|
|
|
|
this.params.rev = null;
|
2021-02-03 20:30:59 +01:00
|
|
|
this.encryptedPassword = null;
|
2019-08-25 12:46:53 +02:00
|
|
|
this.importDbWithXml();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2019-08-25 12:46:53 +02:00
|
|
|
success = true;
|
|
|
|
break;
|
|
|
|
case 'kdb':
|
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openWrongFile,
|
|
|
|
body: Locale.openKdbFileBody
|
|
|
|
});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openWrongFile,
|
|
|
|
body: Locale.openWrongFileBody
|
|
|
|
});
|
|
|
|
break;
|
2016-03-04 19:45:37 +01:00
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
break;
|
2019-08-25 12:46:53 +02:00
|
|
|
}
|
2016-03-04 20:21:34 +01:00
|
|
|
case 'keyFileData':
|
2016-03-01 04:29:20 +01:00
|
|
|
this.params.keyFileData = e.target.result;
|
|
|
|
this.params.keyFileName = file.name;
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.rememberKeyFiles === 'path') {
|
2016-12-11 14:39:59 +01:00
|
|
|
this.params.keyFilePath = file.path;
|
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
this.displayOpenKeyFile();
|
2016-03-04 20:21:34 +01:00
|
|
|
success = true;
|
|
|
|
break;
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
|
|
|
if (complete) {
|
2016-03-04 20:21:34 +01:00
|
|
|
complete(success);
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
};
|
|
|
|
reader.onerror = () => {
|
2015-12-17 19:25:25 +01:00
|
|
|
Alerts.error({ header: Locale.openFailedRead });
|
2015-11-06 21:14:47 +01:00
|
|
|
if (complete) {
|
|
|
|
complete(false);
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
};
|
2016-03-01 22:17:19 +01:00
|
|
|
if (this.reading === 'fileXml') {
|
|
|
|
reader.readAsText(file);
|
|
|
|
} else {
|
|
|
|
reader.readAsArrayBuffer(file);
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-25 12:46:53 +02:00
|
|
|
getOpenFileFormat(fileData) {
|
|
|
|
if (fileData.byteLength < 8) {
|
|
|
|
return undefined;
|
2016-03-04 19:45:37 +01:00
|
|
|
}
|
2019-08-25 12:46:53 +02:00
|
|
|
const fileSig = new Uint32Array(fileData, 0, 2);
|
|
|
|
if (fileSig[0] === kdbxweb.Consts.Signatures.FileMagic) {
|
|
|
|
if (fileSig[1] === kdbxweb.Consts.Signatures.Sig2Kdb) {
|
|
|
|
return 'kdb';
|
|
|
|
} else if (fileSig[1] === kdbxweb.Consts.Signatures.Sig2Kdbx) {
|
|
|
|
return 'kdbx';
|
|
|
|
} else {
|
|
|
|
return undefined;
|
|
|
|
}
|
2019-09-17 19:50:42 +02:00
|
|
|
} else if (this.model.settings.canImportXml) {
|
2019-08-25 12:46:53 +02:00
|
|
|
try {
|
|
|
|
const str = kdbxweb.ByteUtils.bytesToString(fileSig).trim();
|
|
|
|
if (str.startsWith('<?xml')) {
|
|
|
|
return 'xml';
|
|
|
|
}
|
|
|
|
} catch (e) {}
|
|
|
|
return undefined;
|
|
|
|
} else {
|
|
|
|
return undefined;
|
2016-03-04 19:45:37 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-04 19:45:37 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
displayOpenFile() {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.$el.addClass('open--file');
|
2020-05-23 19:07:45 +02:00
|
|
|
this.$el.find('.open__settings-key-file,.open__settings-yubikey').removeClass('hide');
|
2015-11-06 21:14:47 +01:00
|
|
|
this.inputEl[0].removeAttribute('readonly');
|
2015-12-17 19:25:25 +01:00
|
|
|
this.inputEl[0].setAttribute('placeholder', Locale.openPassFor + ' ' + this.params.name);
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
displayOpenKeyFile() {
|
2016-04-06 23:13:44 +02:00
|
|
|
this.$el.toggleClass('open--key-file', !!this.params.keyFileName);
|
2019-08-16 23:05:39 +02:00
|
|
|
this.$el
|
|
|
|
.find('.open__settings-key-file-name')
|
|
|
|
.text(this.params.keyFileName || this.params.keyFilePath || Locale.openKeyFile);
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2020-05-30 08:10:19 +02:00
|
|
|
displayOpenChalResp() {
|
|
|
|
this.$el
|
|
|
|
.find('.open__settings-yubikey')
|
|
|
|
.toggleClass('open__settings-yubikey--active', !!this.params.chalResp);
|
|
|
|
}
|
|
|
|
|
2021-02-03 20:30:59 +01:00
|
|
|
displayOpenDeviceOwnerAuth() {
|
|
|
|
const available = !!this.encryptedPassword;
|
|
|
|
const passEmpty = !this.passwordInput.length;
|
|
|
|
const canUseEncryptedPassword = available && passEmpty;
|
|
|
|
this.el
|
|
|
|
.querySelector('.open__pass-enter-btn')
|
|
|
|
.classList.toggle('open__pass-enter-btn--touch-id', canUseEncryptedPassword);
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
setFile(file, keyFile, fileReadyCallback) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.reading = 'fileData';
|
2020-06-01 16:53:51 +02:00
|
|
|
this.processFile(file, (success) => {
|
2015-11-06 21:14:47 +01:00
|
|
|
if (success && keyFile) {
|
|
|
|
this.reading = 'keyFileData';
|
|
|
|
this.processFile(keyFile);
|
|
|
|
}
|
2016-03-04 20:21:34 +01:00
|
|
|
if (success && typeof fileReadyCallback === 'function') {
|
|
|
|
fileReadyCallback();
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
});
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openFile() {
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.canOpen === false) {
|
2017-11-26 19:21:16 +01:00
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-11-07 20:02:45 +01:00
|
|
|
this.openAny('fileData');
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openKeyFile(e) {
|
2015-11-06 21:14:47 +01:00
|
|
|
if ($(e.target).hasClass('open__settings-key-file-dropbox')) {
|
|
|
|
this.openKeyFileFromDropbox();
|
2015-12-06 21:32:41 +01:00
|
|
|
} else if (!this.busy && this.params.name) {
|
2016-12-11 14:39:59 +01:00
|
|
|
if (this.params.keyFileName) {
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileData = null;
|
2016-12-11 14:39:59 +01:00
|
|
|
this.params.keyFilePath = null;
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileName = '';
|
2015-11-06 21:14:47 +01:00
|
|
|
this.$el.removeClass('open--key-file');
|
2016-04-06 23:13:44 +02:00
|
|
|
this.$el.find('.open__settings-key-file-name').text(Locale.openKeyFile);
|
2015-11-06 21:14:47 +01:00
|
|
|
} else {
|
|
|
|
this.openAny('keyFileData');
|
|
|
|
}
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openKeyFileFromDropbox() {
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
2017-04-16 17:00:35 +02:00
|
|
|
new DropboxChooser((err, res) => {
|
2015-11-08 21:23:12 +01:00
|
|
|
if (err) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params.keyFileData = res.data;
|
|
|
|
this.params.keyFileName = res.name;
|
2015-11-06 21:14:47 +01:00
|
|
|
this.displayOpenKeyFile();
|
2017-04-16 17:00:35 +02:00
|
|
|
}).choose();
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openAny(reading, ext) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.reading = reading;
|
2015-12-06 21:32:41 +01:00
|
|
|
this.params[reading] = null;
|
2017-02-05 22:01:46 +01:00
|
|
|
|
2019-08-16 23:05:39 +02:00
|
|
|
const fileInput = this.$el
|
|
|
|
.find('.open__file-ctrl')
|
|
|
|
.attr('accept', ext || '')
|
|
|
|
.val(null);
|
2017-02-22 01:12:42 +01:00
|
|
|
|
2017-04-12 00:06:44 +02:00
|
|
|
if (Launcher && Launcher.openFileChooser) {
|
2017-03-19 00:30:29 +01:00
|
|
|
Launcher.openFileChooser((err, file) => {
|
|
|
|
if (err) {
|
2017-04-10 23:51:03 +02:00
|
|
|
logger.error('Error opening file chooser', err);
|
2017-03-19 00:30:29 +01:00
|
|
|
} else {
|
|
|
|
this.processFile(file);
|
|
|
|
}
|
2017-04-12 00:06:44 +02:00
|
|
|
});
|
2017-02-05 22:01:46 +01:00
|
|
|
} else {
|
2017-02-22 01:12:42 +01:00
|
|
|
fileInput.click();
|
2017-02-05 22:01:46 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openLast(e) {
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2020-06-01 16:53:51 +02:00
|
|
|
const id = $(e.target).closest('.open__last-item').data('id').toString();
|
2015-12-06 21:32:41 +01:00
|
|
|
if ($(e.target).is('.open__last-item-icon-del')) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const fileInfo = this.model.fileInfos.get(id);
|
2019-09-17 21:39:06 +02:00
|
|
|
if (!fileInfo.storage || fileInfo.modified) {
|
2016-02-23 07:08:57 +01:00
|
|
|
Alerts.yesno({
|
|
|
|
header: Locale.openRemoveLastQuestion,
|
2019-09-17 21:39:06 +02:00
|
|
|
body: fileInfo.modified
|
2019-08-16 23:05:39 +02:00
|
|
|
? Locale.openRemoveLastQuestionModBody
|
|
|
|
: Locale.openRemoveLastQuestionBody,
|
2019-08-18 08:05:38 +02:00
|
|
|
buttons: [
|
|
|
|
{ result: 'yes', title: Locale.alertYes },
|
|
|
|
{ result: '', title: Locale.alertNo }
|
|
|
|
],
|
2016-07-17 13:30:38 +02:00
|
|
|
success: () => {
|
|
|
|
this.removeFile(id);
|
2016-02-23 07:08:57 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.removeFile(id);
|
2015-12-06 21:32:41 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-02-05 22:01:46 +01:00
|
|
|
|
2017-04-14 23:22:33 +02:00
|
|
|
const fileInfo = this.model.fileInfos.get(id);
|
2019-03-28 22:31:53 +01:00
|
|
|
this.showOpenFileInfo(fileInfo, true);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
removeFile(id) {
|
2016-02-23 07:08:57 +01:00
|
|
|
this.model.removeFileInfo(id);
|
|
|
|
this.$el.find('.open__last-item[data-id="' + id + '"]').remove();
|
2019-09-16 17:43:57 +02:00
|
|
|
this.resetParams();
|
2016-02-23 07:08:57 +01:00
|
|
|
this.render();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-02-23 07:08:57 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
inputKeydown(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const code = e.keyCode || e.which;
|
2015-12-08 19:02:50 +01:00
|
|
|
if (code === Keys.DOM_VK_RETURN) {
|
2015-11-06 21:14:47 +01:00
|
|
|
this.openDb();
|
|
|
|
} else if (code === Keys.DOM_VK_CAPS_LOCK) {
|
2016-02-18 19:57:18 +01:00
|
|
|
this.toggleCapsLockWarning(false);
|
2015-11-06 21:14:47 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
inputKeyup(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const code = e.keyCode || e.which;
|
2016-02-18 19:57:18 +01:00
|
|
|
if (code === Keys.DOM_VK_CAPS_LOCK) {
|
|
|
|
this.toggleCapsLockWarning(false);
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-02-18 19:57:18 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
inputKeypress(e) {
|
2017-01-31 07:50:28 +01:00
|
|
|
const charCode = e.keyCode || e.which;
|
|
|
|
const ch = String.fromCharCode(charCode);
|
|
|
|
const lower = ch.toLowerCase();
|
|
|
|
const upper = ch.toUpperCase();
|
2015-11-06 21:14:47 +01:00
|
|
|
if (lower !== upper && !e.shiftKey) {
|
|
|
|
this.toggleCapsLockWarning(ch !== lower);
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2021-02-03 20:30:59 +01:00
|
|
|
inputInput() {
|
|
|
|
this.displayOpenDeviceOwnerAuth();
|
|
|
|
}
|
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
toggleCapsLockWarning(on) {
|
2016-02-18 19:57:18 +01:00
|
|
|
this.$el.find('.open__pass-warning').toggleClass('invisible', !on);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-06 21:14:47 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
dragover(e) {
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.canOpen === false) {
|
2016-08-21 20:23:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
e.preventDefault();
|
2018-08-22 09:59:13 +02:00
|
|
|
e.stopPropagation();
|
2019-09-16 21:49:21 +02:00
|
|
|
const dt = e.dataTransfer;
|
2019-08-18 08:05:38 +02:00
|
|
|
if (
|
|
|
|
!dt.types ||
|
|
|
|
(dt.types.indexOf ? dt.types.indexOf('Files') === -1 : !dt.types.contains('Files'))
|
|
|
|
) {
|
2018-08-22 09:59:13 +02:00
|
|
|
dt.dropEffect = 'none';
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
dt.dropEffect = 'copy';
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
|
|
|
if (!this.$el.hasClass('open--drag')) {
|
|
|
|
this.$el.addClass('open--drag');
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
dragleave() {
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.canOpen === false) {
|
2016-08-21 20:23:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2016-07-17 13:30:38 +02:00
|
|
|
this.dragTimeout = setTimeout(() => {
|
2015-12-06 21:32:41 +01:00
|
|
|
this.$el.removeClass('open--drag');
|
2016-07-17 13:30:38 +02:00
|
|
|
}, 100);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
drop(e) {
|
2019-09-17 19:50:42 +02:00
|
|
|
if (this.model.settings.canOpen === false) {
|
2016-08-21 20:23:09 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
e.preventDefault();
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
if (this.dragTimeout) {
|
|
|
|
clearTimeout(this.dragTimeout);
|
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-12-06 21:32:41 +01:00
|
|
|
this.$el.removeClass('open--drag');
|
2019-09-16 21:49:21 +02:00
|
|
|
const files = [...(e.target.files || e.dataTransfer.files)];
|
2020-06-01 16:53:51 +02:00
|
|
|
const dataFile = files.find((file) => /\.kdbx$/i.test(file.name));
|
2020-12-10 19:10:18 +01:00
|
|
|
const keyFile = files.find((file) => /\.keyx?$/i.test(file.name));
|
2015-12-06 21:32:41 +01:00
|
|
|
if (dataFile) {
|
2019-08-18 08:05:38 +02:00
|
|
|
this.setFile(
|
|
|
|
dataFile,
|
|
|
|
keyFile,
|
|
|
|
dataFile.path ? null : this.showLocalFileAlert.bind(this)
|
|
|
|
);
|
2019-09-25 23:24:38 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.model.settings.canImportXml) {
|
2020-06-01 16:53:51 +02:00
|
|
|
const xmlFile = files.find((file) => /\.xml$/i.test(file.name));
|
2019-08-25 12:46:53 +02:00
|
|
|
if (xmlFile) {
|
|
|
|
this.setFile(xmlFile, null, this.showLocalFileAlert.bind(this));
|
2019-09-25 23:24:38 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (this.model.settings.canImportCsv) {
|
2020-06-01 16:53:51 +02:00
|
|
|
const csvFile = files.find((file) => /\.csv$/i.test(file.name));
|
2019-09-25 23:24:38 +02:00
|
|
|
if (csvFile) {
|
|
|
|
Events.emit('import-csv-requested', csvFile);
|
2019-08-25 12:46:53 +02:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
|
2017-12-23 21:47:31 +01:00
|
|
|
undoKeyPress(e) {
|
2017-11-26 21:00:45 +01:00
|
|
|
e.preventDefault();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2017-11-26 21:00:45 +01:00
|
|
|
|
2017-12-23 21:47:31 +01:00
|
|
|
tabKeyPress() {
|
|
|
|
this.$el.addClass('open--show-focus');
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2017-12-23 21:47:31 +01:00
|
|
|
|
|
|
|
enterKeyPress(e) {
|
|
|
|
const el = this.$el.find('[tabindex]:focus');
|
|
|
|
if (el.length) {
|
|
|
|
el.trigger('click', e);
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2017-12-23 21:47:31 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
showOpenFileInfo(fileInfo, fileWasClicked) {
|
2015-12-07 20:07:56 +01:00
|
|
|
if (this.busy || !fileInfo) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = fileInfo.id;
|
2019-09-17 21:39:06 +02:00
|
|
|
this.params.storage = fileInfo.storage;
|
|
|
|
this.params.path = fileInfo.path;
|
|
|
|
this.params.name = fileInfo.name;
|
2015-12-07 20:07:56 +01:00
|
|
|
this.params.fileData = null;
|
|
|
|
this.params.rev = null;
|
2019-09-17 21:39:06 +02:00
|
|
|
this.params.keyFileName = fileInfo.keyFileName;
|
|
|
|
this.params.keyFilePath = fileInfo.keyFilePath;
|
2017-03-26 11:15:36 +02:00
|
|
|
this.params.keyFileData = null;
|
2019-11-08 19:07:38 +01:00
|
|
|
this.params.opts = fileInfo.opts;
|
2020-05-30 08:10:19 +02:00
|
|
|
this.params.chalResp = fileInfo.chalResp;
|
2021-02-03 20:30:59 +01:00
|
|
|
this.setEncryptedPassword(fileInfo);
|
|
|
|
|
2015-12-07 20:07:56 +01:00
|
|
|
this.displayOpenFile();
|
2016-04-06 23:13:44 +02:00
|
|
|
this.displayOpenKeyFile();
|
2020-05-30 08:10:19 +02:00
|
|
|
this.displayOpenChalResp();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2017-05-26 00:11:10 +02:00
|
|
|
|
2019-03-28 22:31:53 +01:00
|
|
|
if (fileWasClicked) {
|
|
|
|
this.focusInput(true);
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
showOpenLocalFile(path, keyFilePath) {
|
2015-12-07 20:07:56 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = 'file';
|
|
|
|
this.params.path = path;
|
|
|
|
this.params.name = path.match(/[^/\\]*$/)[0];
|
|
|
|
this.params.rev = null;
|
|
|
|
this.params.fileData = null;
|
2021-02-03 20:30:59 +01:00
|
|
|
this.encryptedPassword = null;
|
2015-12-07 20:07:56 +01:00
|
|
|
this.displayOpenFile();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2017-12-03 20:31:54 +01:00
|
|
|
if (keyFilePath) {
|
|
|
|
const parsed = Launcher.parsePath(keyFilePath);
|
|
|
|
this.params.keyFileName = parsed.file;
|
|
|
|
this.params.keyFilePath = keyFilePath;
|
|
|
|
this.params.keyFileData = null;
|
|
|
|
this.displayOpenKeyFile();
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
createDemo() {
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
2016-03-12 12:22:35 +01:00
|
|
|
this.closeConfig();
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.model.createDemoFile()) {
|
2019-09-16 17:43:57 +02:00
|
|
|
this.emit('close');
|
2015-12-06 21:32:41 +01:00
|
|
|
}
|
2019-09-17 19:50:42 +02:00
|
|
|
if (!this.model.settings.demoOpened) {
|
|
|
|
this.model.settings.demoOpened = true;
|
2016-03-13 10:54:16 +01:00
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
createNew() {
|
2015-12-06 21:32:41 +01:00
|
|
|
if (!this.busy) {
|
|
|
|
this.model.createNewFile();
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openDb() {
|
2016-06-05 16:49:00 +02:00
|
|
|
if (this.params.id && this.model.files.get(this.params.id)) {
|
2019-09-16 17:43:57 +02:00
|
|
|
this.emit('close');
|
2016-06-05 12:25:50 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-12-08 22:00:31 +01:00
|
|
|
if (this.busy || !this.params.name) {
|
|
|
|
return;
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2015-12-08 22:00:31 +01:00
|
|
|
this.$el.toggleClass('open--opening', true);
|
|
|
|
this.inputEl.attr('disabled', 'disabled');
|
|
|
|
this.busy = true;
|
|
|
|
this.params.password = this.passwordInput.value;
|
2021-02-03 20:30:59 +01:00
|
|
|
if (this.encryptedPassword && !this.params.password.length) {
|
|
|
|
logger.debug('Encrypting password using hardware decryption');
|
|
|
|
const touchIdPrompt = Locale.bioOpenAuthPrompt.replace('{}', this.params.name);
|
|
|
|
const encryptedPassword = kdbxweb.ProtectedValue.fromBase64(
|
|
|
|
this.encryptedPassword.value
|
|
|
|
);
|
2021-04-26 11:20:20 +02:00
|
|
|
Events.emit('hardware-decrypt-started');
|
2021-02-03 20:30:59 +01:00
|
|
|
NativeModules.hardwareDecrypt(encryptedPassword, touchIdPrompt)
|
|
|
|
.then((password) => {
|
2021-04-26 11:20:20 +02:00
|
|
|
Events.emit('hardware-decrypt-finished');
|
|
|
|
|
2021-02-03 20:30:59 +01:00
|
|
|
this.params.password = password;
|
|
|
|
this.params.encryptedPassword = this.encryptedPassword;
|
|
|
|
this.model.openFile(this.params, (err) => this.openDbComplete(err));
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
2021-04-26 11:20:20 +02:00
|
|
|
Events.emit('hardware-decrypt-finished');
|
|
|
|
|
2021-02-03 20:30:59 +01:00
|
|
|
if (err.message.includes('User refused')) {
|
|
|
|
err.userCanceled = true;
|
2021-04-02 18:47:04 +02:00
|
|
|
} else if (err.message.includes('SecKeyCreateDecryptedData')) {
|
|
|
|
err.maybeTouchIdChanged = true;
|
2021-02-03 20:30:59 +01:00
|
|
|
}
|
2021-04-02 18:47:04 +02:00
|
|
|
logger.error('Error in hardware decryption', err);
|
2021-02-03 20:30:59 +01:00
|
|
|
this.openDbComplete(err);
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.params.encryptedPassword = null;
|
|
|
|
this.afterPaint(() => {
|
|
|
|
this.model.openFile(this.params, (err) => this.openDbComplete(err));
|
|
|
|
});
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-11-07 20:02:45 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openDbComplete(err) {
|
2015-12-06 21:32:41 +01:00
|
|
|
this.busy = false;
|
|
|
|
this.$el.toggleClass('open--opening', false);
|
2021-02-03 20:30:59 +01:00
|
|
|
const showInputError = err && !err.userCanceled;
|
|
|
|
this.inputEl.removeAttr('disabled').toggleClass('input--error', !!showInputError);
|
2015-12-06 21:32:41 +01:00
|
|
|
if (err) {
|
2015-12-12 09:53:50 +01:00
|
|
|
logger.error('Error opening file', err);
|
2019-03-28 22:31:53 +01:00
|
|
|
this.focusInput(true);
|
2015-12-06 21:32:41 +01:00
|
|
|
this.inputEl[0].selectionStart = 0;
|
|
|
|
this.inputEl[0].selectionEnd = this.inputEl.val().length;
|
2016-08-13 18:22:55 +02:00
|
|
|
if (err.code === 'InvalidKey') {
|
|
|
|
InputFx.shake(this.inputEl);
|
2020-05-30 16:02:02 +02:00
|
|
|
} else if (err.userCanceled) {
|
|
|
|
// nothing to do
|
2016-08-13 18:22:55 +02:00
|
|
|
} else {
|
2016-07-31 09:47:56 +02:00
|
|
|
if (err.notFound) {
|
|
|
|
err = Locale.openErrorFileNotFound;
|
|
|
|
}
|
2021-04-02 18:47:04 +02:00
|
|
|
let alertBody = Locale.openErrorDescription;
|
|
|
|
if (err.maybeTouchIdChanged) {
|
|
|
|
alertBody += '\n' + Locale.openErrorDescriptionMaybeTouchIdChanged;
|
|
|
|
}
|
2016-03-15 20:08:08 +01:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openError,
|
2021-04-02 18:47:04 +02:00
|
|
|
body: alertBody,
|
2020-11-11 23:08:08 +01:00
|
|
|
pre: this.errorToString(err)
|
2016-03-15 20:08:08 +01:00
|
|
|
});
|
|
|
|
}
|
2015-12-06 21:32:41 +01:00
|
|
|
} else {
|
2019-09-16 17:43:57 +02:00
|
|
|
this.emit('close');
|
2015-11-07 20:02:45 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-01 04:29:20 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
importDbWithXml() {
|
2016-03-01 04:29:20 +01:00
|
|
|
if (this.busy || !this.params.name) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.$el.toggleClass('open--opening', true);
|
|
|
|
this.inputEl.attr('disabled', 'disabled');
|
|
|
|
this.busy = true;
|
2019-08-16 23:05:39 +02:00
|
|
|
this.afterPaint(() =>
|
2020-06-01 16:53:51 +02:00
|
|
|
this.model.importFileWithXml(this.params, (err) => {
|
2019-08-16 23:05:39 +02:00
|
|
|
if (err) {
|
|
|
|
this.params.name = '';
|
|
|
|
this.params.fileXml = null;
|
|
|
|
}
|
|
|
|
this.openDbComplete(err);
|
|
|
|
})
|
|
|
|
);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-09 21:52:19 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
toggleMore() {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.closeConfig();
|
2016-03-09 21:52:19 +01:00
|
|
|
this.$el.find('.open__icons--lower').toggleClass('hide');
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openSettings() {
|
2019-09-16 22:57:56 +02:00
|
|
|
Events.emit('toggle-settings');
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-13 18:33:25 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openStorage(e) {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
2020-06-01 16:53:51 +02:00
|
|
|
const storage = Storage[$(e.target).closest('.open__icon').data('storage')];
|
2016-03-13 17:08:25 +01:00
|
|
|
if (!storage) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (storage.needShowOpenConfig && storage.needShowOpenConfig()) {
|
|
|
|
this.showConfig(storage);
|
|
|
|
} else if (storage.list) {
|
|
|
|
this.listStorage(storage);
|
|
|
|
} else {
|
|
|
|
Alerts.notImplemented();
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-13 17:08:25 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
listStorage(storage, config) {
|
2016-03-13 17:08:25 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.closeConfig();
|
2017-01-31 07:50:28 +01:00
|
|
|
const icon = this.$el.find('.open__icon-storage[data-storage=' + storage.name + ']');
|
2016-07-17 13:30:38 +02:00
|
|
|
this.busy = true;
|
2016-03-13 17:08:25 +01:00
|
|
|
icon.toggleClass('flip3d', true);
|
2017-11-26 17:26:58 +01:00
|
|
|
storage.list(config && config.dir, (err, files) => {
|
2016-03-13 17:08:25 +01:00
|
|
|
icon.toggleClass('flip3d', false);
|
2016-07-17 13:30:38 +02:00
|
|
|
this.busy = false;
|
2016-03-13 17:08:25 +01:00
|
|
|
if (err || !files) {
|
2017-06-11 19:41:56 +02:00
|
|
|
err = err ? err.toString() : '';
|
2020-03-17 19:45:38 +01:00
|
|
|
if (err === 'browser-auth-started') {
|
|
|
|
return;
|
|
|
|
}
|
2017-11-27 19:00:39 +01:00
|
|
|
if (err.lastIndexOf('OAuth', 0) !== 0 && !Alerts.alertDisplayed) {
|
2017-06-11 19:41:56 +02:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openError,
|
2020-04-23 19:55:52 +02:00
|
|
|
body: Locale.openListErrorBody,
|
|
|
|
pre: err.toString()
|
2017-06-11 19:41:56 +02:00
|
|
|
});
|
|
|
|
}
|
2016-03-13 17:08:25 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-11-26 17:26:58 +01:00
|
|
|
if (!files.length) {
|
2016-03-14 06:16:33 +01:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openNothingFound,
|
2017-04-16 17:00:35 +02:00
|
|
|
body: Locale.openNothingFoundBody
|
2016-03-14 06:16:33 +01:00
|
|
|
});
|
2016-03-13 17:08:25 +01:00
|
|
|
return;
|
|
|
|
}
|
2017-11-26 17:26:58 +01:00
|
|
|
|
|
|
|
const fileNameComparator = Comparators.stringComparator('path', true);
|
|
|
|
files.sort((x, y) => {
|
|
|
|
if (x.dir !== y.dir) {
|
|
|
|
return !!y.dir - !!x.dir;
|
|
|
|
}
|
|
|
|
return fileNameComparator(x, y);
|
|
|
|
});
|
|
|
|
if (config && config.dir) {
|
|
|
|
files.unshift({
|
|
|
|
path: config.prevDir,
|
|
|
|
name: '..',
|
|
|
|
dir: true
|
|
|
|
});
|
|
|
|
}
|
2020-11-11 18:44:57 +01:00
|
|
|
const listView = new StorageFileListView({ files });
|
2020-06-01 16:53:51 +02:00
|
|
|
listView.on('selected', (file) => {
|
2017-11-26 17:26:58 +01:00
|
|
|
if (file.dir) {
|
|
|
|
this.listStorage(storage, {
|
|
|
|
dir: file.path,
|
2020-11-11 18:44:57 +01:00
|
|
|
prevDir: (config && config.dir) || ''
|
2017-11-26 17:26:58 +01:00
|
|
|
});
|
|
|
|
} else {
|
|
|
|
this.openStorageFile(storage, file);
|
|
|
|
}
|
|
|
|
});
|
2016-03-13 17:08:25 +01:00
|
|
|
Alerts.alert({
|
|
|
|
header: Locale.openSelectFile,
|
|
|
|
body: Locale.openSelectFileBody,
|
2020-11-25 20:10:37 +01:00
|
|
|
icon: storage.icon || 'file-alt',
|
2019-08-16 23:05:39 +02:00
|
|
|
buttons: [{ result: '', title: Locale.alertCancel }],
|
2016-03-13 17:08:25 +01:00
|
|
|
esc: '',
|
|
|
|
click: '',
|
2017-11-26 17:26:58 +01:00
|
|
|
view: listView
|
2016-03-13 17:08:25 +01:00
|
|
|
});
|
|
|
|
});
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-13 17:08:25 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
openStorageFile(storage, file) {
|
2016-03-13 17:08:25 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = storage.name;
|
|
|
|
this.params.path = file.path;
|
2019-09-15 08:11:11 +02:00
|
|
|
this.params.name = UrlFormat.getDataFileName(file.name);
|
2016-03-13 17:08:25 +01:00
|
|
|
this.params.rev = file.rev;
|
|
|
|
this.params.fileData = null;
|
2021-02-03 20:30:59 +01:00
|
|
|
this.encryptedPassword = null;
|
2016-03-13 17:08:25 +01:00
|
|
|
this.displayOpenFile();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
showConfig(storage) {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.views.openConfig) {
|
|
|
|
this.views.openConfig.remove();
|
|
|
|
}
|
2019-09-17 23:44:17 +02:00
|
|
|
const config = {
|
|
|
|
id: storage.name,
|
|
|
|
name: Locale[storage.name] || storage.name,
|
|
|
|
icon: storage.icon,
|
|
|
|
buttons: true,
|
|
|
|
...storage.getOpenConfig()
|
|
|
|
};
|
2019-09-15 23:24:53 +02:00
|
|
|
this.views.openConfig = new OpenConfigView(config, {
|
|
|
|
parent: '.open__config-wrap'
|
|
|
|
});
|
2016-03-12 12:22:35 +01:00
|
|
|
this.views.openConfig.on('cancel', this.closeConfig.bind(this));
|
|
|
|
this.views.openConfig.on('apply', this.applyConfig.bind(this));
|
2019-09-15 23:24:53 +02:00
|
|
|
this.views.openConfig.render();
|
2016-03-13 17:08:25 +01:00
|
|
|
this.$el.find('.open__pass-area').addClass('hide');
|
|
|
|
this.$el.find('.open__icons--lower').addClass('hide');
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
closeConfig() {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy) {
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
}
|
|
|
|
if (this.views.openConfig) {
|
|
|
|
this.views.openConfig.remove();
|
|
|
|
delete this.views.openConfig;
|
|
|
|
}
|
|
|
|
this.$el.find('.open__pass-area').removeClass('hide');
|
|
|
|
this.$el.find('.open__config').addClass('hide');
|
2016-05-13 14:09:21 +02:00
|
|
|
this.focusInput();
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
applyConfig(config) {
|
2016-03-12 12:22:35 +01:00
|
|
|
if (this.busy || !config) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.busy = true;
|
|
|
|
this.views.openConfig.setDisabled(true);
|
2017-01-31 07:50:28 +01:00
|
|
|
const storage = Storage[config.storage];
|
2016-03-12 12:22:35 +01:00
|
|
|
this.storageWaitId = Math.random();
|
2017-01-31 07:50:28 +01:00
|
|
|
const path = config.path;
|
2019-09-18 07:12:06 +02:00
|
|
|
const opts = omit(config, ['path', 'storage']);
|
2017-01-31 07:50:28 +01:00
|
|
|
const req = {
|
2016-03-12 17:49:52 +01:00
|
|
|
waitId: this.storageWaitId,
|
|
|
|
storage: config.storage,
|
2019-08-18 10:17:09 +02:00
|
|
|
path,
|
|
|
|
opts
|
2016-03-12 17:49:52 +01:00
|
|
|
};
|
2016-03-13 17:45:55 +01:00
|
|
|
if (storage.applyConfig) {
|
|
|
|
storage.applyConfig(opts, this.storageApplyConfigComplete.bind(this, req));
|
|
|
|
} else {
|
|
|
|
storage.stat(path, opts, this.storageStatComplete.bind(this, req));
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-13 17:45:55 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
storageApplyConfigComplete(req, err) {
|
2016-03-13 17:45:55 +01:00
|
|
|
if (this.storageWaitId !== req.waitId) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
if (err) {
|
|
|
|
this.views.openConfig.setDisabled(false);
|
|
|
|
this.views.openConfig.setError(err);
|
|
|
|
} else {
|
|
|
|
this.closeConfig();
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2016-03-12 12:22:35 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
storageStatComplete(req, err, stat) {
|
2016-03-12 17:49:52 +01:00
|
|
|
if (this.storageWaitId !== req.waitId) {
|
2016-03-12 12:22:35 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.storageWaitId = null;
|
|
|
|
this.busy = false;
|
|
|
|
if (err) {
|
2016-03-12 17:49:52 +01:00
|
|
|
this.views.openConfig.setDisabled(false);
|
2016-03-12 12:22:35 +01:00
|
|
|
this.views.openConfig.setError(err);
|
2016-03-12 17:49:52 +01:00
|
|
|
} else {
|
|
|
|
this.closeConfig();
|
|
|
|
this.params.id = null;
|
|
|
|
this.params.storage = req.storage;
|
|
|
|
this.params.path = req.path;
|
|
|
|
this.params.opts = req.opts;
|
2019-09-15 08:11:11 +02:00
|
|
|
this.params.name = UrlFormat.getDataFileName(req.path);
|
2016-03-12 17:49:52 +01:00
|
|
|
this.params.rev = stat.rev;
|
|
|
|
this.params.fileData = null;
|
2021-02-03 20:30:59 +01:00
|
|
|
this.encryptedPassword = null;
|
2016-03-12 17:49:52 +01:00
|
|
|
this.displayOpenFile();
|
2021-02-03 20:30:59 +01:00
|
|
|
this.displayOpenDeviceOwnerAuth();
|
2016-03-12 12:22:35 +01:00
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2018-12-28 08:14:36 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
moveOpenFileSelection(steps) {
|
2018-12-28 19:11:45 +01:00
|
|
|
const lastOpenFiles = this.getLastOpenFiles();
|
2019-08-18 08:05:38 +02:00
|
|
|
if (
|
|
|
|
this.currentSelectedIndex + steps >= 0 &&
|
|
|
|
this.currentSelectedIndex + steps <= lastOpenFiles.length - 1
|
|
|
|
) {
|
2018-12-28 08:14:36 +01:00
|
|
|
this.currentSelectedIndex = this.currentSelectedIndex + steps;
|
|
|
|
}
|
|
|
|
|
2019-03-02 17:14:38 +01:00
|
|
|
const lastOpenFile = lastOpenFiles[this.currentSelectedIndex];
|
|
|
|
if (!lastOpenFile) {
|
|
|
|
return;
|
|
|
|
}
|
2018-12-28 08:14:36 +01:00
|
|
|
const fileInfo = this.model.fileInfos.get(lastOpenFiles[this.currentSelectedIndex].id);
|
|
|
|
this.showOpenFileInfo(fileInfo);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2018-12-28 08:14:36 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
moveOpenFileSelectionDown() {
|
2018-12-28 08:14:36 +01:00
|
|
|
this.moveOpenFileSelection(1);
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2018-12-28 08:14:36 +01:00
|
|
|
|
2019-08-18 10:17:09 +02:00
|
|
|
moveOpenFileSelectionUp() {
|
2018-12-28 08:14:36 +01:00
|
|
|
this.moveOpenFileSelection(-1);
|
2018-12-28 19:11:45 +01:00
|
|
|
}
|
2019-10-17 19:52:34 +02:00
|
|
|
|
|
|
|
toggleGenerator(e) {
|
|
|
|
e.stopPropagation();
|
|
|
|
if (this.views.gen) {
|
|
|
|
this.views.gen.remove();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const el = this.$el.find('.open__icon-generate');
|
|
|
|
const rect = el[0].getBoundingClientRect();
|
2019-10-26 19:19:06 +02:00
|
|
|
const pos = {
|
|
|
|
left: rect.left,
|
|
|
|
top: rect.top
|
|
|
|
};
|
|
|
|
if (Features.isMobile) {
|
|
|
|
pos.left = '50vw';
|
|
|
|
pos.top = '50vh';
|
|
|
|
pos.transform = 'translate(-50%, -50%)';
|
|
|
|
}
|
2019-10-17 19:52:34 +02:00
|
|
|
const generator = new GeneratorView({
|
|
|
|
copy: true,
|
|
|
|
noTemplateEditor: true,
|
2019-10-26 19:19:06 +02:00
|
|
|
pos
|
2019-10-17 19:52:34 +02:00
|
|
|
});
|
|
|
|
generator.render();
|
|
|
|
generator.once('remove', () => {
|
|
|
|
delete this.views.gen;
|
|
|
|
});
|
|
|
|
this.views.gen = generator;
|
|
|
|
}
|
2020-04-15 16:50:01 +02:00
|
|
|
|
2020-04-23 18:47:46 +02:00
|
|
|
userIdle() {
|
|
|
|
this.inputEl.val('');
|
|
|
|
this.passwordInput.reset();
|
2020-05-10 19:44:29 +02:00
|
|
|
this.passwordInput.setElement(this.inputEl);
|
2020-04-23 18:47:46 +02:00
|
|
|
}
|
2020-04-23 20:26:52 +02:00
|
|
|
|
2020-04-15 16:50:01 +02:00
|
|
|
usbDevicesChanged() {
|
2020-05-23 19:26:54 +02:00
|
|
|
if (this.model.settings.canOpenOtpDevice) {
|
2020-06-06 13:30:35 +02:00
|
|
|
const hasYubiKeys = !!UsbListener.attachedYubiKeys;
|
2020-05-11 19:29:39 +02:00
|
|
|
|
2020-05-23 19:26:54 +02:00
|
|
|
const showOpenIcon = hasYubiKeys && this.model.settings.yubiKeyShowIcon;
|
|
|
|
this.$el.find('.open__icon-yubikey').toggleClass('hide', !showOpenIcon);
|
|
|
|
|
|
|
|
const showChallengeResponseIcon =
|
|
|
|
hasYubiKeys && this.model.settings.yubiKeyShowChalResp;
|
2020-05-23 19:07:45 +02:00
|
|
|
this.$el
|
|
|
|
.find('.open__settings-yubikey')
|
2020-05-23 19:26:54 +02:00
|
|
|
.toggleClass('open__settings-yubikey--present', !!showChallengeResponseIcon);
|
2020-05-11 19:29:39 +02:00
|
|
|
|
2020-04-29 18:17:26 +02:00
|
|
|
if (!hasYubiKeys && this.busy && this.otpDevice) {
|
|
|
|
this.otpDevice.cancelOpen();
|
|
|
|
}
|
2020-04-19 18:52:21 +02:00
|
|
|
}
|
2020-04-15 16:50:01 +02:00
|
|
|
}
|
|
|
|
|
2020-04-19 18:52:21 +02:00
|
|
|
openYubiKey() {
|
2020-04-15 16:50:01 +02:00
|
|
|
if (this.busy && this.otpDevice) {
|
|
|
|
this.otpDevice.cancelOpen();
|
|
|
|
}
|
|
|
|
if (!this.busy) {
|
|
|
|
this.busy = true;
|
|
|
|
this.inputEl.attr('disabled', 'disabled');
|
2020-04-19 20:55:38 +02:00
|
|
|
const icon = this.$el.find('.open__icon-yubikey');
|
2020-04-15 16:50:01 +02:00
|
|
|
icon.toggleClass('flip3d', true);
|
2020-04-19 20:55:38 +02:00
|
|
|
|
2020-06-01 16:53:51 +02:00
|
|
|
YubiKey.checkToolStatus().then((status) => {
|
2020-05-24 18:39:56 +02:00
|
|
|
if (status !== 'ok') {
|
2020-04-19 20:55:38 +02:00
|
|
|
icon.toggleClass('flip3d', false);
|
|
|
|
this.inputEl.removeAttr('disabled');
|
|
|
|
this.busy = false;
|
|
|
|
return Events.emit('toggle-settings', 'devices');
|
2020-04-15 16:50:01 +02:00
|
|
|
}
|
2020-06-01 16:53:51 +02:00
|
|
|
this.otpDevice = this.model.openOtpDevice((err) => {
|
2020-05-24 18:39:56 +02:00
|
|
|
if (err && !YubiKey.aborted) {
|
2020-04-19 20:55:38 +02:00
|
|
|
Alerts.error({
|
|
|
|
header: Locale.openError,
|
2020-04-23 20:50:53 +02:00
|
|
|
body: Locale.openErrorDescription,
|
2020-11-11 23:08:08 +01:00
|
|
|
pre: this.errorToString(err)
|
2020-04-19 20:55:38 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
this.otpDevice = null;
|
|
|
|
icon.toggleClass('flip3d', false);
|
|
|
|
this.inputEl.removeAttr('disabled');
|
|
|
|
this.busy = false;
|
|
|
|
});
|
2020-04-15 16:50:01 +02:00
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
2020-05-24 18:39:56 +02:00
|
|
|
|
|
|
|
selectYubiKeyChalResp() {
|
|
|
|
if (this.busy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-24 20:31:03 +02:00
|
|
|
if (this.params.chalResp) {
|
|
|
|
this.params.chalResp = null;
|
|
|
|
this.el
|
|
|
|
.querySelector('.open__settings-yubikey')
|
|
|
|
.classList.remove('open__settings-yubikey--active');
|
2020-05-30 08:10:19 +02:00
|
|
|
this.focusInput();
|
2020-05-24 20:31:03 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-05-24 20:02:49 +02:00
|
|
|
const chalRespView = new OpenChalRespView();
|
2020-05-30 08:10:19 +02:00
|
|
|
chalRespView.on('select', ({ vid, pid, serial, slot }) => {
|
|
|
|
this.params.chalResp = { vid, pid, serial, slot };
|
2020-05-24 20:31:03 +02:00
|
|
|
this.el
|
|
|
|
.querySelector('.open__settings-yubikey')
|
|
|
|
.classList.add('open__settings-yubikey--active');
|
2020-05-30 08:10:19 +02:00
|
|
|
this.focusInput();
|
2020-05-24 20:02:49 +02:00
|
|
|
});
|
2020-05-24 18:39:56 +02:00
|
|
|
|
2020-05-24 20:02:49 +02:00
|
|
|
Alerts.alert({
|
|
|
|
header: Locale.openChalRespHeader,
|
2020-11-25 18:20:53 +01:00
|
|
|
icon: 'usb-token',
|
2020-05-24 20:02:49 +02:00
|
|
|
buttons: [{ result: '', title: Locale.alertCancel }],
|
|
|
|
esc: '',
|
|
|
|
click: '',
|
|
|
|
view: chalRespView
|
2020-05-24 18:39:56 +02:00
|
|
|
});
|
|
|
|
}
|
2020-11-11 23:08:08 +01:00
|
|
|
|
|
|
|
errorToString(err) {
|
|
|
|
const str = err.toString();
|
|
|
|
if (str !== {}.toString()) {
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
if (err.ykError && err.code) {
|
|
|
|
return Locale.yubiKeyErrorWithCode.replace('{}', err.code);
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
}
|
2021-02-03 20:30:59 +01:00
|
|
|
|
|
|
|
setEncryptedPassword(fileInfo) {
|
|
|
|
this.encryptedPassword = null;
|
|
|
|
if (!fileInfo.id) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
switch (this.model.settings.deviceOwnerAuth) {
|
|
|
|
case 'memory':
|
|
|
|
this.encryptedPassword = this.model.getMemoryPassword(fileInfo.id);
|
|
|
|
break;
|
|
|
|
case 'file':
|
|
|
|
this.encryptedPassword = {
|
|
|
|
value: fileInfo.encryptedPassword,
|
|
|
|
date: fileInfo.encryptedPasswordDate
|
|
|
|
};
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
this.checkIfEncryptedPasswordDateIsValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
checkIfEncryptedPasswordDateIsValid() {
|
|
|
|
if (this.encryptedPassword) {
|
|
|
|
const maxDate = new Date(this.encryptedPassword.date);
|
|
|
|
maxDate.setMinutes(
|
|
|
|
maxDate.getMinutes() + this.model.settings.deviceOwnerAuthTimeoutMinutes
|
|
|
|
);
|
|
|
|
if (maxDate < new Date()) {
|
|
|
|
this.encryptedPassword = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-26 11:51:24 +02:00
|
|
|
|
|
|
|
unlockMessageChanged(unlockMessageRes) {
|
|
|
|
const messageEl = this.el.querySelector('.open__message');
|
|
|
|
messageEl.classList.toggle('hide', !unlockMessageRes);
|
|
|
|
|
|
|
|
if (unlockMessageRes) {
|
|
|
|
const contentEl = this.el.querySelector('.open__message-content');
|
|
|
|
contentEl.innerText = Locale[unlockMessageRes];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
openMessageCancelClick() {
|
|
|
|
this.model.rejectPendingFileUnlockPromise('User canceled');
|
|
|
|
}
|
2019-09-16 17:43:57 +02:00
|
|
|
}
|
2015-10-17 23:49:24 +02:00
|
|
|
|
2019-09-15 14:16:32 +02:00
|
|
|
export { OpenView };
|