keeweb/app/scripts/views/settings/settings-file-view.js

781 lines
27 KiB
JavaScript
Raw Normal View History

2019-09-15 14:16:32 +02:00
import kdbxweb from 'kdbxweb';
2019-09-16 20:42:33 +02:00
import { View } from 'framework/views/view';
2019-09-15 14:16:32 +02:00
import { Storage } from 'storage';
import { Shortcuts } from 'comp/app/shortcuts';
import { Launcher } from 'comp/launcher';
import { Alerts } from 'comp/ui/alerts';
2020-05-31 14:13:08 +02:00
import { YubiKey } from 'comp/app/yubikey';
import { UsbListener } from 'comp/app/usb-listener';
2019-09-15 14:16:32 +02:00
import { Links } from 'const/links';
import { AppSettingsModel } from 'models/app-settings-model';
2020-11-27 18:38:11 +01:00
import { DateFormat } from 'comp/i18n/date-format';
2019-09-15 14:16:32 +02:00
import { UrlFormat } from 'util/formatting/url-format';
2019-09-27 07:37:26 +02:00
import { PasswordPresenter } from 'util/formatting/password-presenter';
2019-09-15 14:16:32 +02:00
import { Locale } from 'util/locale';
import { Features } from 'util/features';
2019-09-15 14:16:32 +02:00
import { FileSaver } from 'util/ui/file-saver';
import { OpenConfigView } from 'views/open-config-view';
2020-04-23 19:55:52 +02:00
import { omit } from 'util/fn';
2019-09-16 20:40:20 +02:00
import template from 'templates/settings/settings-file.hbs';
2015-10-17 23:49:24 +02:00
2016-08-16 22:11:54 +02:00
const DefaultBackupPath = 'Backups/{name}.{date}.bak';
2016-08-16 22:55:17 +02:00
const DefaultBackupSchedule = '1w';
2016-08-16 22:11:54 +02:00
2019-09-16 20:40:20 +02:00
class SettingsFileView extends View {
template = template;
2020-05-31 14:13:08 +02:00
yubiKeys = [];
2015-10-17 23:49:24 +02:00
2019-09-16 20:40:20 +02:00
events = {
2015-12-08 20:18:35 +01:00
'click .settings__file-button-save-default': 'saveDefault',
2016-03-26 09:57:58 +01:00
'click .settings__file-button-save-choose': 'toggleChooser',
2015-11-07 21:37:54 +01:00
'click .settings__file-button-close': 'closeFile',
2016-03-26 09:57:58 +01:00
'click .settings__file-save-to-file': 'saveToFile',
'click .settings__file-save-to-xml': 'saveToXml',
2019-09-08 20:28:02 +02:00
'click .settings__file-save-to-html': 'saveToHtml',
2016-03-26 09:57:58 +01:00
'click .settings__file-save-to-storage': 'saveToStorage',
2015-10-24 18:43:30 +02:00
'change #settings__file-key-file': 'keyFileChange',
2015-12-15 18:42:44 +01:00
'click #settings__file-file-select-link': 'triggerSelectFile',
2015-10-24 18:43:30 +02:00
'change #settings__file-file-select': 'fileSelected',
2015-10-22 22:51:40 +02:00
'focus #settings__file-master-pass': 'focusMasterPass',
'input #settings__file-master-pass': 'changeMasterPass',
2015-10-24 18:43:30 +02:00
'blur #settings__file-master-pass': 'blurMasterPass',
2018-08-27 18:15:23 +02:00
'focus #settings__file-confirm-master-pass': 'focusConfirmMasterPass',
'blur #settings__file-confirm-master-pass': 'blurConfirmMasterPass',
'input #settings__file-name': 'changeName',
'input #settings__file-def-user': 'changeDefUser',
2016-08-16 22:55:17 +02:00
'change #settings__file-backup-enabled': 'changeBackupEnabled',
'input #settings__file-backup-path': 'changeBackupPath',
'change #settings__file-backup-storage': 'changeBackupStorage',
'change #settings__file-backup-schedule': 'changeBackupSchedule',
'click .settings__file-button-backup': 'backupFile',
2015-10-24 18:43:30 +02:00
'change #settings__file-trash': 'changeTrash',
2020-03-15 15:54:06 +01:00
'change #settings__file-hist-type': 'changeHistoryMode',
'input #settings__file-hist-len': 'changeHistoryLength',
'input #settings__file-hist-size': 'changeHistorySize',
'change #settings__file-format-version': 'changeFormatVersion',
'change #settings__file-kdf': 'changeKdf',
2016-07-03 18:46:43 +02:00
'input #settings__file-key-rounds': 'changeKeyRounds',
2017-01-31 23:18:58 +01:00
'input #settings__file-key-change-force': 'changeKeyChangeForce',
2020-05-31 14:13:08 +02:00
'input .settings__input-kdf': 'changeKdfParameter',
'change #settings__file-yubikey': 'changeYubiKey'
2019-09-16 20:40:20 +02:00
};
2015-10-18 16:02:00 +02:00
2019-09-16 20:40:20 +02:00
constructor(model, options) {
super(model, options);
2019-09-17 21:39:06 +02:00
const watchedProps = ['syncing', 'syncError', 'syncDate'];
for (const prop of watchedProps) {
this.listenTo(this.model, 'change:' + prop, () => {
setTimeout(() => this.render(), 0);
});
}
2020-05-31 14:13:08 +02:00
this.refreshYubiKeys(false);
2019-09-16 20:40:20 +02:00
}
2015-10-23 22:12:12 +02:00
2019-08-18 10:17:09 +02:00
render() {
2017-01-31 07:50:28 +01:00
const storageProviders = [];
2019-09-17 21:39:06 +02:00
const fileStorage = this.model.storage;
let canBackup = false;
2020-06-01 16:53:51 +02:00
Object.keys(Storage).forEach((name) => {
2017-01-31 07:50:28 +01:00
const prv = Storage[name];
2017-05-23 18:30:17 +02:00
if (!canBackup && prv.backup && prv.enabled) {
canBackup = true;
}
2016-08-20 10:58:03 +02:00
if (!prv.system && prv.enabled) {
2016-08-21 18:07:59 +02:00
storageProviders.push({
2019-08-16 23:05:39 +02:00
name: prv.name,
icon: prv.icon,
own: name === fileStorage,
backup: prv.backup
2016-08-21 18:07:59 +02:00
});
2016-03-26 09:57:58 +01:00
}
});
2016-07-17 13:30:38 +02:00
storageProviders.sort((x, y) => (x.uipos || Infinity) - (y.uipos || Infinity));
2019-09-17 21:39:06 +02:00
const backup = this.model.backup;
2020-05-31 14:13:08 +02:00
const selectedYubiKey = this.model.chalResp
? `${this.model.chalResp.serial}:${this.model.chalResp.slot}`
: '';
const showYubiKeyBlock =
!!this.model.chalResp ||
(Launcher && AppSettingsModel.enableUsb && AppSettingsModel.yubiKeyShowChalResp);
2020-05-31 14:13:08 +02:00
const yubiKeys = [];
if (showYubiKeyBlock) {
for (const yk of this.yubiKeys) {
2020-06-02 12:23:22 +02:00
for (const slot of yk.slots.filter((s) => s.valid)) {
2020-05-31 14:13:08 +02:00
yubiKeys.push({
value: `${yk.serial}:${slot.number}`,
2020-05-31 14:13:08 +02:00
fullName: yk.fullName,
vid: yk.vid,
pid: yk.pid,
serial: yk.serial,
2020-06-02 12:23:22 +02:00
slot: slot.number
2020-05-31 14:13:08 +02:00
});
}
}
2020-06-01 16:53:51 +02:00
if (selectedYubiKey && !yubiKeys.some((yk) => yk.value === selectedYubiKey)) {
2020-05-31 14:13:08 +02:00
yubiKeys.push({
value: selectedYubiKey,
fullName: `YubiKey ${this.model.chalResp.serial}`,
vid: this.model.chalResp.vid,
pid: this.model.chalResp.pid,
serial: this.model.chalResp.serial,
slot: this.model.chalResp.slot
});
}
}
2019-09-16 20:40:20 +02:00
super.render({
cmd: Shortcuts.actionShortcutSymbol(true),
2015-10-25 17:27:34 +01:00
supportFiles: !!Launcher,
2015-10-23 23:21:21 +02:00
desktopLink: Links.Desktop,
2019-09-17 21:39:06 +02:00
name: this.model.name,
path: this.model.path,
storage: this.model.storage,
syncing: this.model.syncing,
syncError: this.model.syncError,
syncDate: DateFormat.dtStr(this.model.syncDate),
2019-09-27 07:37:26 +02:00
password: PasswordPresenter.present(this.model.passwordLength),
2019-09-17 21:39:06 +02:00
defaultUser: this.model.defaultUser,
recycleBinEnabled: this.model.recycleBinEnabled,
2016-08-21 18:46:44 +02:00
backupEnabled: backup && backup.enabled,
2016-08-16 22:11:54 +02:00
backupStorage: backup && backup.storage,
2019-08-18 08:05:38 +02:00
backupPath:
2019-09-17 21:39:06 +02:00
(backup && backup.path) || DefaultBackupPath.replace('{name}', this.model.name),
2016-08-16 22:55:17 +02:00
backupSchedule: backup ? backup.schedule : DefaultBackupSchedule,
2019-09-17 21:39:06 +02:00
historyMaxItems: this.model.historyMaxItems,
historyMaxSize: Math.round(this.model.historyMaxSize / 1024 / 1024),
formatVersion: this.model.formatVersion,
kdfName: this.model.kdfName,
keyEncryptionRounds: this.model.keyEncryptionRounds,
keyChangeForce: this.model.keyChangeForce > 0 ? this.model.keyChangeForce : null,
kdfParameters: this.kdfParametersToUi(this.model.kdfParameters),
2019-08-18 10:17:09 +02:00
storageProviders,
canBackup,
canSaveTo: AppSettingsModel.canSaveTo,
2019-09-17 19:50:42 +02:00
canExportXml: AppSettingsModel.canExportXml,
2020-05-31 14:13:08 +02:00
canExportHtml: AppSettingsModel.canExportHtml,
showYubiKeyBlock,
selectedYubiKey,
yubiKeys
2015-10-18 16:02:00 +02:00
});
2019-09-17 21:39:06 +02:00
if (!this.model.created) {
this.$el.find('.settings__file-master-pass-warning').toggle(this.model.passwordChanged);
2019-08-18 08:05:38 +02:00
this.$el
.find('#settings__file-master-pass-warning-text')
.text(Locale.setFilePassChanged);
2015-10-24 18:43:30 +02:00
}
this.renderKeyFileSelect();
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
kdfParametersToUi(kdfParameters) {
2019-08-18 08:05:38 +02:00
return kdfParameters
2019-09-17 23:44:17 +02:00
? { ...kdfParameters, memory: Math.round(kdfParameters.memory / 1024) }
2019-08-18 08:05:38 +02:00
: null;
2019-09-16 20:40:20 +02:00
}
2017-01-31 23:18:58 +01:00
2019-08-18 10:17:09 +02:00
renderKeyFileSelect() {
2019-09-17 21:39:06 +02:00
const keyFileName = this.model.keyFileName;
const oldKeyFileName = this.model.oldKeyFileName;
const keyFileChanged = this.model.keyFileChanged;
2017-01-31 07:50:28 +01:00
const sel = this.$el.find('#settings__file-key-file');
2020-05-09 20:15:46 +02:00
sel.empty();
2015-10-24 18:43:30 +02:00
if (keyFileName && keyFileChanged) {
2019-08-16 23:05:39 +02:00
const text =
keyFileName !== 'Generated'
? Locale.setFileUseKeyFile + ' ' + keyFileName
: Locale.setFileUseGenKeyFile;
2020-06-01 16:53:51 +02:00
$('<option/>').val('ex').text(text).appendTo(sel);
2015-10-24 18:43:30 +02:00
}
if (oldKeyFileName) {
2019-08-16 23:05:39 +02:00
const useText = keyFileChanged
? Locale.setFileUseOldKeyFile
: Locale.setFileUseKeyFile + ' ' + oldKeyFileName;
2020-06-01 16:53:51 +02:00
$('<option/>').val('old').text(useText).appendTo(sel);
2015-10-24 18:43:30 +02:00
}
2020-06-01 16:53:51 +02:00
$('<option/>').val('gen').text(Locale.setFileGenKeyFile).appendTo(sel);
$('<option/>').val('none').text(Locale.setFileDontUseKeyFile).appendTo(sel);
2015-10-24 18:43:30 +02:00
if (keyFileName && keyFileChanged) {
sel.val('ex');
} else if (!keyFileName) {
sel.val('none');
} else if (oldKeyFileName && keyFileName === oldKeyFileName && !keyFileChanged) {
sel.val('old');
}
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
validatePassword(continueCallback) {
2019-09-17 21:39:06 +02:00
if (!this.model.passwordLength) {
2015-12-08 19:02:50 +01:00
Alerts.yesno({
2015-12-17 19:25:25 +01:00
header: Locale.setFileEmptyPass,
body: Locale.setFileEmptyPassBody,
2016-07-17 13:30:38 +02:00
success: () => {
2015-12-08 20:18:35 +01:00
continueCallback();
2015-12-08 19:02:50 +01:00
},
2016-07-17 13:30:38 +02:00
cancel: () => {
this.$el.find('#settings__file-master-pass').focus();
2015-12-08 19:02:50 +01:00
}
2015-10-24 18:43:30 +02:00
});
return false;
}
return true;
2019-09-16 20:40:20 +02:00
}
2015-10-18 16:02:00 +02:00
2019-08-18 10:17:09 +02:00
save(arg) {
2015-12-08 22:00:31 +01:00
if (!arg) {
arg = {};
}
arg.startedByUser = true;
if (!arg.skipValidation) {
2017-01-31 07:50:28 +01:00
const isValid = this.validatePassword(() => {
2015-12-08 22:00:31 +01:00
arg.skipValidation = true;
2016-07-17 13:30:38 +02:00
this.save(arg);
2015-12-08 22:00:31 +01:00
});
if (!isValid) {
return;
}
}
this.appModel.syncFile(this.model, arg);
2019-09-16 20:40:20 +02:00
}
2015-12-08 22:00:31 +01:00
2019-08-18 10:17:09 +02:00
saveDefault() {
2015-12-08 22:00:31 +01:00
this.save();
2019-09-16 20:40:20 +02:00
}
2015-12-08 20:18:35 +01:00
2019-08-18 10:17:09 +02:00
toggleChooser() {
2016-03-26 09:57:58 +01:00
this.$el.find('.settings__file-save-choose').toggleClass('hide');
2019-09-16 20:40:20 +02:00
}
2016-03-26 09:57:58 +01:00
2019-08-18 10:17:09 +02:00
saveToFile(skipValidation) {
2015-12-08 20:18:35 +01:00
if (skipValidation !== true && !this.validatePassword(this.saveToFile.bind(this, true))) {
2015-10-24 18:43:30 +02:00
return;
}
2019-09-17 21:39:06 +02:00
const fileName = this.model.name + '.kdbx';
if (Launcher && !this.model.storage) {
2020-06-01 16:53:51 +02:00
Launcher.getSaveFileName(fileName, (path) => {
2015-12-10 22:31:47 +01:00
if (path) {
2019-08-18 10:17:09 +02:00
this.save({ storage: 'file', path });
2015-12-10 22:31:47 +01:00
}
});
} else {
2020-06-01 16:53:51 +02:00
this.model.getData((data) => {
2016-08-20 10:01:33 +02:00
if (!data) {
return;
}
2015-12-10 22:31:47 +01:00
if (Launcher) {
2020-06-01 16:53:51 +02:00
Launcher.getSaveFileName(fileName, (path) => {
2015-12-10 22:31:47 +01:00
if (path) {
2020-06-01 16:53:51 +02:00
Storage.file.save(path, null, data, (err) => {
2015-12-10 22:31:47 +01:00
if (err) {
Alerts.error({
2015-12-17 19:25:25 +01:00
header: Locale.setFileSaveError,
2020-04-23 19:55:52 +02:00
body: Locale.setFileSaveErrorBody + ' ' + path + ':',
pre: err
2015-12-10 22:31:47 +01:00
});
}
});
}
});
} else {
2019-08-16 23:05:39 +02:00
const blob = new Blob([data], { type: 'application/octet-stream' });
2015-12-10 22:31:47 +01:00
FileSaver.saveAs(blob, fileName);
}
});
}
2019-09-16 20:40:20 +02:00
}
2015-10-18 16:02:00 +02:00
2019-08-18 10:17:09 +02:00
saveToXml() {
Alerts.yesno({
2020-05-06 18:37:37 +02:00
header: Locale.setFileExportRaw,
body: Locale.setFileExportRawBody,
success: () => {
2020-06-01 16:53:51 +02:00
this.model.getXml((xml) => {
const blob = new Blob([xml], { type: 'text/xml' });
FileSaver.saveAs(blob, this.model.name + '.xml');
});
}
2016-07-17 13:30:38 +02:00
});
2019-09-16 20:40:20 +02:00
}
2015-10-18 16:02:00 +02:00
2019-09-08 20:28:02 +02:00
saveToHtml() {
Alerts.yesno({
2020-05-06 18:37:37 +02:00
header: Locale.setFileExportRaw,
body: Locale.setFileExportRawBody,
success: () => {
2020-06-01 16:53:51 +02:00
this.model.getHtml((html) => {
const blob = new Blob([html], { type: 'text/html' });
FileSaver.saveAs(blob, this.model.name + '.html');
});
}
2019-09-08 20:28:02 +02:00
});
2019-09-16 20:40:20 +02:00
}
2019-09-08 20:28:02 +02:00
2019-08-18 10:17:09 +02:00
saveToStorage(e) {
2019-09-17 21:39:06 +02:00
if (this.model.syncing || this.model.demo) {
2016-03-26 09:57:58 +01:00
return;
}
2020-06-01 16:53:51 +02:00
const storageName = $(e.target).closest('.settings__file-save-to-storage').data('storage');
2017-01-31 07:50:28 +01:00
const storage = Storage[storageName];
2016-03-26 09:57:58 +01:00
if (!storage) {
return;
}
2019-09-17 21:39:06 +02:00
if (this.model.storage === storageName) {
2016-07-17 13:30:38 +02:00
this.save();
2016-03-27 18:38:33 +02:00
} else {
if (!storage.list) {
2017-11-27 22:11:00 +01:00
if (storage.getOpenConfig) {
2019-09-17 23:44:17 +02:00
const config = {
id: storage.name,
name: Locale[storage.name] || storage.name,
icon: storage.icon,
buttons: false,
...storage.getOpenConfig()
};
2019-09-15 23:24:53 +02:00
const openConfigView = new OpenConfigView(config);
2017-11-27 22:11:00 +01:00
Alerts.alert({
header: '',
body: '',
2020-11-25 20:10:37 +01:00
icon: storage.icon || 'file-alt',
2017-11-27 22:11:00 +01:00
buttons: [Alerts.buttons.ok, Alerts.buttons.cancel],
esc: '',
opaque: true,
view: openConfigView,
success: () => {
const storageConfig = openConfigView.getData();
if (!storageConfig) {
return;
}
2019-09-18 07:12:06 +02:00
const opts = omit(storageConfig, ['path', 'storage']);
2017-11-27 22:11:00 +01:00
if (opts && Object.keys(opts).length) {
2019-09-17 21:39:06 +02:00
this.model.opts = opts;
2017-11-27 22:11:00 +01:00
}
this.save({ storage: storageName, path: storageConfig.path, opts });
}
2016-03-27 20:39:16 +02:00
});
} else {
Alerts.notImplemented();
}
return;
2016-03-27 18:38:33 +02:00
}
2019-09-17 21:39:06 +02:00
this.model.syncing = true;
2017-11-26 17:26:58 +01:00
storage.list('', (err, files) => {
2019-09-17 21:39:06 +02:00
this.model.syncing = false;
2016-03-27 18:38:33 +02:00
if (err) {
return;
}
2019-09-17 21:39:06 +02:00
const expName = this.model.name.toLowerCase();
2019-09-18 20:42:17 +02:00
const existingFile = [...files].find(
2020-06-01 16:53:51 +02:00
(file) =>
2019-09-15 08:11:11 +02:00
!file.dir && UrlFormat.getDataFileName(file.name).toLowerCase() === expName
2019-09-18 20:42:17 +02:00
);
2016-03-27 18:38:33 +02:00
if (existingFile) {
Alerts.yesno({
header: Locale.setFileAlreadyExists,
2020-04-23 19:55:52 +02:00
body: Locale.setFileAlreadyExistsBody.replace('{}', this.model.name),
2016-07-17 13:30:38 +02:00
success: () => {
2019-09-17 21:39:06 +02:00
this.model.syncing = true;
2020-06-01 16:53:51 +02:00
storage.remove(existingFile.path, (err) => {
2019-09-17 21:39:06 +02:00
this.model.syncing = false;
2016-03-27 18:38:33 +02:00
if (!err) {
2019-08-16 23:05:39 +02:00
this.save({ storage: storageName });
2016-03-27 18:38:33 +02:00
}
});
}
});
} else {
2019-08-16 23:05:39 +02:00
this.save({ storage: storageName });
2016-03-27 18:38:33 +02:00
}
});
}
2019-09-16 20:40:20 +02:00
}
2016-03-26 09:57:58 +01:00
2019-08-18 10:17:09 +02:00
closeFile() {
2019-09-17 21:39:06 +02:00
if (this.model.modified) {
2015-11-07 21:37:54 +01:00
Alerts.yesno({
2015-12-17 19:25:25 +01:00
header: Locale.setFileUnsaved,
body: Locale.setFileUnsavedBody,
2015-11-07 21:37:54 +01:00
buttons: [
2019-08-16 23:05:39 +02:00
{ result: 'close', title: Locale.setFileCloseNoSave, error: true },
{ result: '', title: Locale.setFileDontClose }
2015-11-07 21:37:54 +01:00
],
2020-06-01 16:53:51 +02:00
success: (result) => {
2015-11-07 21:37:54 +01:00
if (result === 'close') {
2016-07-17 13:30:38 +02:00
this.closeFileNoCheck();
2015-11-07 21:37:54 +01:00
}
}
});
} else {
this.closeFileNoCheck();
}
2019-09-16 20:40:20 +02:00
}
2015-11-07 21:37:54 +01:00
2019-08-18 10:17:09 +02:00
closeFileNoCheck() {
2015-12-08 20:18:35 +01:00
this.appModel.closeFile(this.model);
2019-09-16 20:40:20 +02:00
}
2015-11-07 21:37:54 +01:00
2019-08-18 10:17:09 +02:00
keyFileChange(e) {
2015-10-22 20:03:44 +02:00
switch (e.target.value) {
2015-10-24 18:43:30 +02:00
case 'old':
this.selectOldKeyFile();
2015-10-22 20:03:44 +02:00
break;
case 'gen':
this.generateKeyFile();
break;
2015-10-24 18:43:30 +02:00
case 'none':
2015-10-22 20:03:44 +02:00
this.clearKeyFile();
break;
}
2019-09-16 20:40:20 +02:00
}
2015-10-22 20:03:44 +02:00
2019-08-18 10:17:09 +02:00
selectOldKeyFile() {
2015-10-24 18:43:30 +02:00
this.model.resetKeyFile();
this.renderKeyFileSelect();
2019-09-16 20:40:20 +02:00
}
2015-10-22 20:03:44 +02:00
2019-08-18 10:17:09 +02:00
generateKeyFile() {
2017-01-31 07:50:28 +01:00
const keyFile = this.model.generateAndSetKeyFile();
2019-08-16 23:05:39 +02:00
const blob = new Blob([keyFile], { type: 'application/octet-stream' });
2019-09-17 21:39:06 +02:00
FileSaver.saveAs(blob, this.model.name + '.key');
2015-10-24 18:43:30 +02:00
this.renderKeyFileSelect();
2019-09-16 20:40:20 +02:00
}
2015-10-22 20:03:44 +02:00
2019-08-18 10:17:09 +02:00
clearKeyFile() {
2015-10-24 18:43:30 +02:00
this.model.removeKeyFile();
this.renderKeyFileSelect();
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
triggerSelectFile() {
2015-10-24 18:43:30 +02:00
this.$el.find('#settings__file-file-select').click();
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02: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];
const reader = new FileReader();
2020-06-01 16:53:51 +02:00
reader.onload = (e) => {
2017-01-31 07:50:28 +01:00
const res = e.target.result;
2015-10-24 18:43:30 +02:00
this.model.setKeyFile(res, file.name);
this.renderKeyFileSelect();
2016-07-17 13:30:38 +02:00
};
2015-10-24 18:43:30 +02:00
reader.readAsArrayBuffer(file);
2019-09-16 20:40:20 +02:00
}
2015-10-22 22:39:30 +02:00
2019-08-18 10:17:09 +02:00
focusMasterPass(e) {
2015-12-12 16:43:43 +01:00
e.target.value = '';
2015-10-23 22:12:12 +02:00
e.target.setAttribute('type', 'text');
2019-09-17 21:39:06 +02:00
this.model.passwordChanged = false;
2019-09-16 20:40:20 +02:00
}
2015-10-22 22:51:40 +02:00
2019-08-18 10:17:09 +02:00
changeMasterPass(e) {
2015-10-22 22:51:40 +02:00
if (!e.target.value) {
2015-10-24 18:43:30 +02:00
this.model.resetPassword();
this.$el.find('.settings__file-master-pass-warning').hide();
2015-10-23 22:12:12 +02:00
} else {
2018-08-29 01:10:54 +02:00
this.$el.find('#settings__file-confirm-master-pass-group').show();
2019-08-18 08:05:38 +02:00
this.$el
.find('#settings__file-master-pass-warning-text')
.text(Locale.setFilePassChange);
2019-09-17 21:39:06 +02:00
if (!this.model.created) {
2015-10-24 18:43:30 +02:00
this.$el.find('.settings__file-master-pass-warning').show();
}
2015-10-22 22:51:40 +02:00
}
2019-09-16 20:40:20 +02:00
}
2019-08-18 10:17:09 +02:00
blurMasterPass(e) {
if (!e.target.value) {
this.model.resetPassword();
2018-08-29 01:10:54 +02:00
this.resetConfirmMasterPass();
2019-09-27 07:37:26 +02:00
e.target.value = PasswordPresenter.present(this.model.passwordLength);
this.$el.find('.settings__file-master-pass-warning').hide();
}
2015-10-23 22:12:12 +02:00
e.target.setAttribute('type', 'password');
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
resetConfirmMasterPass() {
2018-08-29 01:10:54 +02:00
this.$el.find('#settings__file-confirm-master-pass').val('');
this.$el.find('#settings__file-confirm-master-pass-group').hide();
2018-08-30 20:31:39 +02:00
this.$el.find('#settings__file-master-pass-warning-text').text(Locale.setFilePassChange);
2019-09-16 20:40:20 +02:00
}
2018-08-29 01:10:54 +02:00
2019-08-18 10:17:09 +02:00
focusConfirmMasterPass(e) {
2018-08-27 18:15:23 +02:00
e.target.value = '';
e.target.setAttribute('type', 'text');
2019-09-16 20:40:20 +02:00
}
2018-08-27 18:15:23 +02:00
2019-08-18 10:17:09 +02:00
blurConfirmMasterPass(e) {
2018-08-27 18:15:23 +02:00
e.target.setAttribute('type', 'password');
2018-08-30 20:31:39 +02:00
const masterPassword = this.$el.find('#settings__file-master-pass').val();
const confirmPassword = e.target.value;
if (masterPassword === confirmPassword) {
2019-08-18 08:05:38 +02:00
this.$el
.find('#settings__file-master-pass-warning-text')
.text(Locale.setFilePassChanged);
2018-08-30 20:31:39 +02:00
this.$el.find('.settings__file-confirm-master-pass-warning').hide();
this.model.setPassword(kdbxweb.ProtectedValue.fromString(confirmPassword));
} else {
2019-08-18 08:05:38 +02:00
this.$el
.find('#settings__file-master-pass-warning-text')
.text(Locale.setFilePassChange);
2018-08-30 20:31:39 +02:00
this.$el.find('.settings__file-confirm-master-pass-warning').show();
this.model.resetPassword();
}
2019-09-16 20:40:20 +02:00
}
2018-08-27 18:15:23 +02:00
2019-08-18 10:17:09 +02:00
changeName(e) {
2017-01-31 07:50:28 +01:00
const value = $.trim(e.target.value);
2015-10-24 18:43:30 +02:00
if (!value) {
return;
}
this.model.setName(value);
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
changeDefUser(e) {
2017-01-31 07:50:28 +01:00
const value = $.trim(e.target.value);
2015-10-24 18:43:30 +02:00
this.model.setDefaultUser(value);
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
changeBackupEnabled(e) {
2017-01-31 07:50:28 +01:00
const enabled = e.target.checked;
2019-09-17 21:39:06 +02:00
let backup = this.model.backup;
2016-08-16 22:55:17 +02:00
if (!backup) {
2019-08-18 10:17:09 +02:00
backup = { enabled, schedule: DefaultBackupSchedule };
2019-09-17 21:39:06 +02:00
const defaultPath = DefaultBackupPath.replace('{name}', this.model.name);
2016-08-16 22:55:17 +02:00
if (Launcher) {
backup.storage = 'file';
2016-08-21 18:07:59 +02:00
backup.path = Launcher.getDocumentsPath(defaultPath);
2016-08-16 22:55:17 +02:00
} else {
2016-08-21 18:07:59 +02:00
backup.storage = 'dropbox';
backup.path = defaultPath;
2016-08-16 22:55:17 +02:00
}
2019-09-17 21:39:06 +02:00
// } else if (this.model.storage === 'webdav') {
2016-08-21 18:07:59 +02:00
// backup.storage = 'webdav';
2019-09-17 21:39:06 +02:00
// backup.path = this.model.path + '.{date}.bak';
// } else if (this.model.storage) {
// backup.storage = this.model.storage;
// backup.path = DefaultBackupPath.replace('{name}', this.model.name);
2016-08-21 18:07:59 +02:00
// } else {
// Object.keys(Storage).forEach(name => {
// var prv = Storage[name];
// if (!backup.storage && !prv.system && prv.enabled) {
// backup.storage = name;
// }
// });
// if (!backup.storage) {
// e.target.checked = false;
// return;
// }
2019-09-17 21:39:06 +02:00
// backup.path = DefaultBackupPath.replace('{name}', this.model.name);
2016-08-21 18:07:59 +02:00
// }
2016-08-16 22:55:17 +02:00
this.$el.find('#settings__file-backup-storage').val(backup.storage);
this.$el.find('#settings__file-backup-path').val(backup.path);
}
2016-08-16 22:11:54 +02:00
this.$el.find('.settings__file-backups').toggleClass('hide', !enabled);
2016-08-16 22:55:17 +02:00
backup.enabled = enabled;
2016-08-16 23:24:08 +02:00
this.setBackup(backup);
2019-09-16 20:40:20 +02:00
}
2016-08-16 22:55:17 +02:00
2019-08-18 10:17:09 +02:00
changeBackupPath(e) {
2019-09-17 21:39:06 +02:00
const backup = this.model.backup;
2016-08-16 22:55:17 +02:00
backup.path = e.target.value.trim();
2016-08-16 23:24:08 +02:00
this.setBackup(backup);
2019-09-16 20:40:20 +02:00
}
2016-08-16 22:55:17 +02:00
2019-08-18 10:17:09 +02:00
changeBackupStorage(e) {
2019-09-17 21:39:06 +02:00
const backup = this.model.backup;
2016-08-16 22:55:17 +02:00
backup.storage = e.target.value;
2016-08-16 23:24:08 +02:00
this.setBackup(backup);
2019-09-16 20:40:20 +02:00
}
2016-08-16 22:55:17 +02:00
2019-08-18 10:17:09 +02:00
changeBackupSchedule(e) {
2019-09-17 21:39:06 +02:00
const backup = this.model.backup;
2016-08-16 22:55:17 +02:00
backup.schedule = e.target.value;
2016-08-16 23:24:08 +02:00
this.setBackup(backup);
2019-09-16 20:40:20 +02:00
}
2016-08-16 23:24:08 +02:00
2019-08-18 10:17:09 +02:00
setBackup(backup) {
2019-09-17 21:39:06 +02:00
this.model.backup = backup;
2016-08-16 23:24:08 +02:00
this.appModel.setFileBackup(this.model.id, backup);
2019-09-16 20:40:20 +02:00
}
2016-08-16 22:55:17 +02:00
2019-08-18 10:17:09 +02:00
backupFile() {
2016-08-20 10:01:33 +02:00
if (this.backupInProgress) {
return;
}
2017-01-31 07:50:28 +01:00
const backupButton = this.$el.find('.settings__file-button-backup');
2016-08-20 10:01:33 +02:00
backupButton.text(Locale.setFileBackupNowWorking);
2020-06-01 16:53:51 +02:00
this.model.getData((data) => {
2016-08-20 10:01:33 +02:00
if (!data) {
this.backupInProgress = false;
backupButton.text(Locale.setFileBackupNow);
return;
}
2020-06-01 16:53:51 +02:00
this.appModel.backupFile(this.model, data, (err) => {
2016-08-20 10:01:33 +02:00
this.backupInProgress = false;
backupButton.text(Locale.setFileBackupNow);
if (err) {
2019-01-02 09:52:36 +01:00
let title = '';
let description = '';
if (err.isDir) {
title = Locale.setFileBackupErrorIsDir;
description = Locale.setFileBackupErrorIsDirDescription;
} else {
title = Locale.setFileBackupError;
description = Locale.setFileBackupErrorDescription;
}
2016-08-20 10:01:33 +02:00
Alerts.error({
2019-08-18 10:17:09 +02:00
title,
2020-04-23 19:55:52 +02:00
body: description,
pre: err.toString()
2019-01-02 09:52:36 +01:00
});
2016-08-20 10:01:33 +02:00
}
});
});
2019-09-16 20:40:20 +02:00
}
2016-08-16 22:11:54 +02:00
2019-08-18 10:17:09 +02:00
changeTrash(e) {
2015-10-24 18:43:30 +02:00
this.model.setRecycleBinEnabled(e.target.checked);
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2019-08-18 10:17:09 +02:00
changeHistoryLength(e) {
if (!e.target.validity.valid) {
return;
}
2017-01-31 07:50:28 +01:00
const value = +e.target.value;
2015-10-24 18:43:30 +02:00
if (isNaN(value)) {
2019-09-17 21:39:06 +02:00
e.target.value = this.model.historyMaxItems;
2015-10-24 18:43:30 +02:00
return;
}
this.model.setHistoryMaxItems(value);
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
2020-03-15 15:54:06 +01:00
changeHistoryMode(e) {
let value = +e.target.value;
if (value > 0) {
value = 10;
}
this.model.setHistoryMaxItems(value);
this.render();
}
2019-08-18 10:17:09 +02:00
changeHistorySize(e) {
if (!e.target.validity.valid) {
return;
}
2017-01-31 07:50:28 +01:00
const value = +e.target.value;
2015-10-24 18:43:30 +02:00
if (isNaN(value)) {
2019-09-17 21:39:06 +02:00
e.target.value = this.model.historyMaxSize / 1024 / 1024;
2015-10-24 18:43:30 +02:00
return;
}
this.model.setHistoryMaxSize(value * 1024 * 1024);
2019-09-16 20:40:20 +02:00
}
2015-10-24 18:43:30 +02:00
changeFormatVersion(e) {
const version = +e.target.value;
this.model.setFormatVersion(version);
this.render();
2019-09-16 20:40:20 +02:00
}
changeKdf(e) {
this.model.setKdf(e.target.value);
this.render();
2019-09-16 20:40:20 +02:00
}
2019-08-18 10:17:09 +02:00
changeKeyRounds(e) {
if (!e.target.validity.valid) {
return;
}
2017-01-31 07:50:28 +01:00
const value = +e.target.value;
2015-10-24 18:43:30 +02:00
if (isNaN(value)) {
2019-09-17 21:39:06 +02:00
e.target.value = this.model.keyEncryptionRounds;
2015-10-24 18:43:30 +02:00
return;
}
this.model.setKeyEncryptionRounds(value);
2019-09-16 20:40:20 +02:00
}
2016-07-03 18:46:43 +02:00
2019-08-18 10:17:09 +02:00
changeKeyChangeForce(e) {
if (!e.target.validity.valid) {
return;
}
2017-01-31 07:50:28 +01:00
let value = Math.round(e.target.value);
2016-07-03 18:46:43 +02:00
if (isNaN(value) || value <= 0) {
value = -1;
}
this.model.setKeyChange(true, value);
2019-09-16 20:40:20 +02:00
}
2017-01-31 23:18:58 +01:00
2019-08-18 10:17:09 +02:00
changeKdfParameter(e) {
if (!e.target.validity.valid) {
return;
}
2017-01-31 23:18:58 +01:00
const field = $(e.target).data('field');
const mul = $(e.target).data('mul') || 1;
const value = e.target.value * mul;
if (isNaN(value)) {
2019-09-17 21:39:06 +02:00
e.target.value = Math.round(this.model.kdfParameters[field] / mul);
2017-01-31 23:18:58 +01:00
return;
}
if (value > 0) {
this.model.setKdfParameter(field, value);
}
2015-10-17 23:49:24 +02:00
}
2020-05-31 14:13:08 +02:00
refreshYubiKeys(userInitiated) {
if (!Launcher || !AppSettingsModel.enableUsb || !AppSettingsModel.yubiKeyShowChalResp) {
2020-05-31 14:13:08 +02:00
return;
}
if (!UsbListener.attachedYubiKeys) {
2020-05-31 14:13:08 +02:00
if (this.yubiKeys.length) {
this.yubiKeys = [];
this.render();
}
}
YubiKey.list((err, yubiKeys) => {
if (err || this.removed) {
2020-05-31 14:13:08 +02:00
return;
}
this.yubiKeys = yubiKeys;
this.render();
if (
userInitiated &&
UsbListener.attachedYubiKeys &&
!yubiKeys.length &&
Features.isMac
) {
Alerts.error({
body: Locale.setFileYubiKeyErrorEmptyMac
});
}
2020-05-31 14:13:08 +02:00
});
}
changeYubiKey(e) {
let chalResp = null;
const value = e.target.value;
if (value === 'refresh') {
this.render();
this.refreshYubiKeys(true);
return;
}
2020-05-31 14:13:08 +02:00
if (value) {
const option = e.target.selectedOptions[0];
const vid = +option.dataset.vid;
const pid = +option.dataset.pid;
const serial = +option.dataset.serial;
const slot = +option.dataset.slot;
chalResp = { vid, pid, serial, slot };
}
Alerts.yesno({
header: Locale.setFileYubiKeyHeader,
body: Locale.setFileYubiKeyBody,
success: () => {
this.model.setChallengeResponse(chalResp);
},
cancel: () => {
this.render();
}
});
}
2019-09-16 20:40:20 +02:00
}
2015-10-17 23:49:24 +02:00
2019-09-15 14:16:32 +02:00
export { SettingsFileView };