mirror of https://github.com/keeweb/keeweb
displaying matching otp codes in entries
parent
16d303d966
commit
c6ce694dfe
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"plugins": ["prettier", "import"],
|
||||
"plugins": ["prettier", "import", "babel"],
|
||||
"extends": ["standard", "eslint:recommended", "plugin:prettier/recommended"],
|
||||
"rules": {
|
||||
"semi": ["error", "always"],
|
||||
|
@ -15,7 +15,7 @@
|
|||
"no-useless-escape": "off",
|
||||
"no-var": "error",
|
||||
"prefer-const": "error",
|
||||
"no-unused-expressions": "error",
|
||||
"no-unused-expressions": "off",
|
||||
"strict": ["error", "never"],
|
||||
"no-mixed-operators": "off",
|
||||
"prefer-promise-reject-errors": "off",
|
||||
|
@ -49,7 +49,8 @@
|
|||
"import/no-relative-parent-imports": "error",
|
||||
"import/first": "error",
|
||||
"import/no-namespace": "error",
|
||||
"import/no-default-export": "error"
|
||||
"import/no-default-export": "error",
|
||||
"babel/no-unused-expressions": "error"
|
||||
},
|
||||
"parserOptions": {
|
||||
"sourceType": "module",
|
||||
|
|
|
@ -3,10 +3,8 @@ import kdbxweb from 'kdbxweb';
|
|||
import { RuntimeInfo } from 'const/runtime-info';
|
||||
import { Links } from 'const/links';
|
||||
import { DateFormat } from 'util/formatting/date-format';
|
||||
import { MdToHtml } from 'util/formatting/md-to-html';
|
||||
import { StringFormat } from 'util/formatting/string-format';
|
||||
import { Locale } from 'util/locale';
|
||||
import { AppSettingsModel } from 'models/app-settings-model';
|
||||
|
||||
const Templates = {
|
||||
db: require('templates/export/db.hbs'),
|
||||
|
|
|
@ -59,7 +59,7 @@ class View extends EventEmitter {
|
|||
|
||||
Tip.createTips(this.el);
|
||||
|
||||
this.debugLogger && this.debugLogger.debug('Render finished', this.debugLogger.ts(ts));
|
||||
this.debugLogger?.debug('Render finished', this.debugLogger.ts(ts));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ class View extends EventEmitter {
|
|||
eventsMap[event].push({ selector, method });
|
||||
}
|
||||
for (const [event, handlers] of Object.entries(eventsMap)) {
|
||||
this.debugLogger && this.debugLogger.debug('Bind', 'view', event, handlers);
|
||||
this.debugLogger?.debug('Bind', 'view', event, handlers);
|
||||
const listener = e => this.eventListener(e, handlers);
|
||||
this.eventListeners[event] = listener;
|
||||
this.el.addEventListener(event, listener);
|
||||
|
@ -151,8 +151,7 @@ class View extends EventEmitter {
|
|||
this.unbindElementEvents();
|
||||
for (const cfg of this.elementEventListeners) {
|
||||
const els = this.el.querySelectorAll(cfg.selector);
|
||||
this.debugLogger &&
|
||||
this.debugLogger.debug('Bind', 'element', cfg.event, cfg.selector, els.length);
|
||||
this.debugLogger?.debug('Bind', 'element', cfg.event, cfg.selector, els.length);
|
||||
cfg.listener = e => this.eventListener(e, [cfg]);
|
||||
for (const el of els) {
|
||||
el.addEventListener(cfg.event, cfg.listener);
|
||||
|
@ -174,7 +173,7 @@ class View extends EventEmitter {
|
|||
}
|
||||
|
||||
eventListener(e, handlers) {
|
||||
this.debugLogger && this.debugLogger.debug('Listener fired', e.type);
|
||||
this.debugLogger?.debug('Listener fired', e.type);
|
||||
for (const { selector, method } of handlers) {
|
||||
if (selector) {
|
||||
const closest = e.target.closest(selector);
|
||||
|
@ -183,10 +182,10 @@ class View extends EventEmitter {
|
|||
}
|
||||
}
|
||||
if (!this[method]) {
|
||||
this.debugLogger && this.debugLogger.debug('Method not defined', method);
|
||||
this.debugLogger?.debug('Method not defined', method);
|
||||
continue;
|
||||
}
|
||||
this.debugLogger && this.debugLogger.debug('Handling event', e.type, method);
|
||||
this.debugLogger?.debug('Handling event', e.type, method);
|
||||
this[method](e);
|
||||
}
|
||||
}
|
||||
|
@ -202,7 +201,7 @@ class View extends EventEmitter {
|
|||
this.el.remove();
|
||||
this.removed = true;
|
||||
|
||||
this.debugLogger && this.debugLogger.debug('Remove');
|
||||
this.debugLogger?.debug('Remove');
|
||||
}
|
||||
|
||||
removeInnerViews() {
|
||||
|
@ -236,7 +235,7 @@ class View extends EventEmitter {
|
|||
}
|
||||
|
||||
toggle(visible) {
|
||||
this.debugLogger && this.debugLogger.debug(visible ? 'Show' : 'Hide');
|
||||
this.debugLogger?.debug(visible ? 'Show' : 'Hide');
|
||||
if (visible === undefined) {
|
||||
visible = this.hidden;
|
||||
}
|
||||
|
|
|
@ -302,9 +302,37 @@ class AppModel {
|
|||
getEntriesByFilter(filter) {
|
||||
const preparedFilter = this.prepareFilter(filter);
|
||||
const entries = new SearchResultCollection();
|
||||
this.files.forEach(file => {
|
||||
file.forEachEntry(preparedFilter, entry => entries.push(entry));
|
||||
});
|
||||
|
||||
const devicesToMatchOtpEntries = this.files.filter(file => file.external);
|
||||
|
||||
const matchedOtpEntrySet = this.settings.yubiKeyMatchEntries ? new Set() : undefined;
|
||||
|
||||
this.files
|
||||
.filter(file => !file.external)
|
||||
.forEach(file => {
|
||||
file.forEachEntry(preparedFilter, entry => {
|
||||
if (matchedOtpEntrySet) {
|
||||
for (const device of devicesToMatchOtpEntries) {
|
||||
const matchingEntry = device.getMatchingEntry(entry);
|
||||
if (matchingEntry) {
|
||||
matchedOtpEntrySet.add(matchingEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
entries.push(entry);
|
||||
});
|
||||
});
|
||||
|
||||
if (devicesToMatchOtpEntries.length) {
|
||||
for (const device of devicesToMatchOtpEntries) {
|
||||
device.forEachEntry(preparedFilter, entry => {
|
||||
if (!matchedOtpEntrySet || !matchedOtpEntrySet.has(entry)) {
|
||||
entries.push(entry);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
|
@ -382,14 +410,17 @@ class AppModel {
|
|||
getEntryTemplates() {
|
||||
const entryTemplates = [];
|
||||
this.files.forEach(file => {
|
||||
file.forEachEntryTemplate &&
|
||||
file.forEachEntryTemplate(entry => {
|
||||
entryTemplates.push({ file, entry });
|
||||
});
|
||||
file.forEachEntryTemplate?.(entry => {
|
||||
entryTemplates.push({ file, entry });
|
||||
});
|
||||
});
|
||||
return entryTemplates;
|
||||
}
|
||||
|
||||
canCreateEntries() {
|
||||
return this.files.some(f => f.active && !f.readOnly);
|
||||
}
|
||||
|
||||
createNewEntry(args) {
|
||||
const sel = this.getFirstSelectedGroupForCreation();
|
||||
if (args && args.template) {
|
||||
|
@ -1185,8 +1216,18 @@ class AppModel {
|
|||
return device;
|
||||
}
|
||||
|
||||
canCreateEntries() {
|
||||
return this.files.some(f => f.active && !f.readOnly);
|
||||
getMatchingOtpEntry(entry) {
|
||||
if (!this.settings.yubiKeyMatchEntries) {
|
||||
return null;
|
||||
}
|
||||
for (const file of this.files) {
|
||||
if (file.external) {
|
||||
const matchingEntry = file.getMatchingEntry(entry);
|
||||
if (matchingEntry) {
|
||||
return matchingEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ class EntryModel extends Model {
|
|||
this.expires = entry.times.expires ? entry.times.expiryTime : undefined;
|
||||
this.expired = entry.times.expires && entry.times.expiryTime <= new Date();
|
||||
this.historyLength = entry.history.length;
|
||||
this.titleUserLower = `${this.title}:${this.user}`.toLowerCase();
|
||||
this._buildCustomIcon();
|
||||
this._buildSearchText();
|
||||
this._buildSearchTags();
|
||||
|
|
|
@ -4,6 +4,7 @@ import { ExternalEntryCollection } from 'collections/external-entry-collection';
|
|||
class ExternalDeviceModel extends Model {
|
||||
entries = new ExternalEntryCollection();
|
||||
groups = [];
|
||||
entryMap = {};
|
||||
|
||||
close() {}
|
||||
|
||||
|
@ -17,6 +18,20 @@ class ExternalDeviceModel extends Model {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
entryId(title, user) {
|
||||
return `${title}:${user}`.toLowerCase();
|
||||
}
|
||||
|
||||
getMatchingEntry(entry) {
|
||||
return this.entryMap[this.entryId(entry.title, entry.user)];
|
||||
}
|
||||
|
||||
_buildEntryMap() {
|
||||
for (const entry of this.entries) {
|
||||
this.entryMap[entry.id.toLowerCase()] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExternalDeviceModel.defineModelProperties({
|
||||
|
@ -28,7 +43,8 @@ ExternalDeviceModel.defineModelProperties({
|
|||
groups: undefined,
|
||||
name: undefined,
|
||||
shortName: undefined,
|
||||
deviceClassName: undefined
|
||||
deviceClassName: undefined,
|
||||
entryMap: undefined
|
||||
});
|
||||
|
||||
export { ExternalDeviceModel };
|
||||
|
|
|
@ -100,6 +100,9 @@ class YubiKeyOtpModel extends ExternalOtpDeviceModel {
|
|||
if (yubiKeys && yubiKeys.length) {
|
||||
openNextYubiKey();
|
||||
} else {
|
||||
if (openSuccess) {
|
||||
this._openComplete();
|
||||
}
|
||||
callback(openSuccess ? null : openErrors[0]);
|
||||
}
|
||||
});
|
||||
|
@ -135,7 +138,7 @@ class YubiKeyOtpModel extends ExternalOtpDeviceModel {
|
|||
|
||||
this.entries.push(
|
||||
new ExternalOtpEntryModel({
|
||||
id: title + ':' + user,
|
||||
id: this.entryId(title, user),
|
||||
device: this,
|
||||
deviceSubId: serial,
|
||||
icon: 'clock-o',
|
||||
|
@ -145,8 +148,6 @@ class YubiKeyOtpModel extends ExternalOtpDeviceModel {
|
|||
})
|
||||
);
|
||||
}
|
||||
this.active = true;
|
||||
Events.on('usb-devices-changed', this.onUsbDevicesChanged);
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
@ -187,6 +188,12 @@ class YubiKeyOtpModel extends ExternalOtpDeviceModel {
|
|||
});
|
||||
}
|
||||
|
||||
_openComplete() {
|
||||
this.active = true;
|
||||
this._buildEntryMap();
|
||||
Events.on('usb-devices-changed', this.onUsbDevicesChanged);
|
||||
}
|
||||
|
||||
cancelOpen() {
|
||||
logger.info('Cancel open');
|
||||
Events.off('usb-devices-changed', this.onUsbDevicesChanged);
|
||||
|
|
|
@ -468,11 +468,11 @@ class StorageBase {
|
|||
if (token && token.error) {
|
||||
return callback && callback('OAuth code exchange error: ' + token.error);
|
||||
}
|
||||
callback && callback();
|
||||
callback?.();
|
||||
},
|
||||
error: err => {
|
||||
this.logger.error('Error exchanging OAuth code', err);
|
||||
callback && callback('OAuth code exchange error: ' + err);
|
||||
callback?.('OAuth code exchange error: ' + err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -507,7 +507,7 @@ class StorageBase {
|
|||
this._oauthToken = null;
|
||||
}
|
||||
this.logger.error('Error exchanging refresh token', err);
|
||||
callback && callback('Error exchanging refresh token');
|
||||
callback?.('Error exchanging refresh token');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { FieldViewReadOnlyWithOptions } from 'views/fields/field-view-read-only-
|
|||
|
||||
function createDetailsFields(detailsView) {
|
||||
const model = detailsView.model;
|
||||
const otpEntry = detailsView.matchingOtpEntry;
|
||||
|
||||
const fieldViews = [];
|
||||
const fieldViewsAside = [];
|
||||
|
@ -185,18 +186,35 @@ function createDetailsFields(detailsView) {
|
|||
}
|
||||
})
|
||||
);
|
||||
if (otpEntry) {
|
||||
fieldViews.push(
|
||||
new FieldViewOtp({
|
||||
name: '$otp',
|
||||
title: Locale.detOtpField,
|
||||
value() {
|
||||
return otpEntry.otpGenerator;
|
||||
},
|
||||
sequence: '{TOTP}',
|
||||
readonly: true,
|
||||
needsTouch: otpEntry.needsTouch,
|
||||
deviceShortName: otpEntry.device.shortName
|
||||
})
|
||||
);
|
||||
}
|
||||
for (const field of Object.keys(model.fields)) {
|
||||
if (field === 'otp' && model.otpGenerator) {
|
||||
fieldViews.push(
|
||||
FieldViewOtp({
|
||||
name: '$' + field,
|
||||
title: field,
|
||||
value() {
|
||||
return model.otpGenerator;
|
||||
},
|
||||
sequence: '{TOTP}'
|
||||
})
|
||||
);
|
||||
if (!otpEntry) {
|
||||
fieldViews.push(
|
||||
FieldViewOtp({
|
||||
name: '$' + field,
|
||||
title: field,
|
||||
value() {
|
||||
return model.otpGenerator;
|
||||
},
|
||||
sequence: '{TOTP}'
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
fieldViews.push(
|
||||
new FieldViewCustom({
|
||||
|
|
|
@ -120,7 +120,6 @@ class DetailsView extends View {
|
|||
this.template = template;
|
||||
super.render(model);
|
||||
this.setSelectedColor(this.model.color);
|
||||
this.model.initOtpGenerator();
|
||||
this.addFieldViews();
|
||||
this.createScroll({
|
||||
root: this.$el.find('.details__body')[0],
|
||||
|
@ -437,12 +436,25 @@ class DetailsView extends View {
|
|||
|
||||
showEntry(entry) {
|
||||
this.model = entry;
|
||||
this.initOtp();
|
||||
this.render();
|
||||
if (entry && !entry.title && entry.isJustCreated) {
|
||||
this.editTitle();
|
||||
}
|
||||
}
|
||||
|
||||
initOtp() {
|
||||
this.matchingOtpEntry = null;
|
||||
if (!this.model || this.model.external) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.matchingOtpEntry = this.appModel.getMatchingOtpEntry(this.model);
|
||||
|
||||
this.model.initOtpGenerator();
|
||||
this.matchingOtpEntry?.initOtpGenerator();
|
||||
}
|
||||
|
||||
copyKeyPress(editView) {
|
||||
if (!editView || this.isHidden()) {
|
||||
return false;
|
||||
|
@ -948,7 +960,8 @@ class DetailsView extends View {
|
|||
|
||||
autoType(sequence) {
|
||||
const entry = this.model;
|
||||
if (entry.external && (!sequence || sequence.includes('{TOTP}'))) {
|
||||
const hasOtp = sequence?.includes('{TOTP}') || (entry.external && !sequence);
|
||||
if (hasOtp) {
|
||||
const otpField = this.getFieldView('$otp');
|
||||
otpField.refreshOtp(err => {
|
||||
if (!err) {
|
||||
|
|
|
@ -3,7 +3,6 @@ import { View } from 'framework/views/view';
|
|||
import { Scrollable } from 'framework/views/scrollable';
|
||||
import template from 'templates/import-csv.hbs';
|
||||
import { EntryModel } from 'models/entry-model';
|
||||
import { escape } from 'util/fn';
|
||||
|
||||
class ImportCsvView extends View {
|
||||
parent = '.app__body';
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { Events } from 'framework/events';
|
||||
import { View } from 'framework/views/view';
|
||||
import { AppSettingsModel } from 'models/app-settings-model';
|
||||
import { YubiKeyOtpModel } from 'models/external/yubikey-otp-model';
|
||||
import template from 'templates/settings/settings-devices.hbs';
|
||||
import { Links } from 'const/links';
|
||||
import { UsbListener } from 'comp/app/usb-listener';
|
||||
import template from 'templates/settings/settings-devices.hbs';
|
||||
|
||||
class SettingsDevicesView extends View {
|
||||
template = template;
|
||||
|
@ -61,6 +62,7 @@ class SettingsDevicesView extends View {
|
|||
changeYubiKeyMatchEntries(e) {
|
||||
AppSettingsModel.yubiKeyMatchEntries = e.target.checked;
|
||||
this.render();
|
||||
Events.emit('refresh');
|
||||
}
|
||||
|
||||
changeYubiKeyShowChalResp(e) {
|
||||
|
|
|
@ -20,7 +20,7 @@ if (!gotTheLock) {
|
|||
app.quit();
|
||||
}
|
||||
|
||||
perfTimestamps && perfTimestamps.push({ name: 'single instance lock', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'single instance lock', ts: process.hrtime() });
|
||||
|
||||
let openFile = process.argv.filter(arg => /\.kdbx$/i.test(arg))[0];
|
||||
const userDataDir =
|
||||
|
@ -52,7 +52,7 @@ const themeBgColors = {
|
|||
};
|
||||
const defaultBgColor = '#282C34';
|
||||
|
||||
perfTimestamps && perfTimestamps.push({ name: 'defining args', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'defining args', ts: process.hrtime() });
|
||||
|
||||
setDevAppIcon();
|
||||
setEnv();
|
||||
|
@ -71,7 +71,7 @@ app.on('window-all-closed', () => {
|
|||
}
|
||||
});
|
||||
app.on('ready', () => {
|
||||
perfTimestamps && perfTimestamps.push({ name: 'app on ready', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'app on ready', ts: process.hrtime() });
|
||||
appReady = true;
|
||||
setAppOptions();
|
||||
setSystemAppearance();
|
||||
|
@ -155,7 +155,7 @@ app.setGlobalShortcuts = setGlobalShortcuts;
|
|||
|
||||
function setAppOptions() {
|
||||
app.commandLine.appendSwitch('disable-background-timer-throttling');
|
||||
perfTimestamps && perfTimestamps.push({ name: 'setting app options', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting app options', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function readAppSettings() {
|
||||
|
@ -164,8 +164,7 @@ function readAppSettings() {
|
|||
} catch (e) {
|
||||
return null;
|
||||
} finally {
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'reading app settings', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'reading app settings', ts: process.hrtime() });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,8 +174,7 @@ function setSystemAppearance() {
|
|||
electron.systemPreferences.appLevelAppearance = 'dark';
|
||||
}
|
||||
}
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'setting system appearance', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting system appearance', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function createMainWindow() {
|
||||
|
@ -198,17 +196,17 @@ function createMainWindow() {
|
|||
windowOptions.icon = path.join(__dirname, 'icon.png');
|
||||
}
|
||||
mainWindow = new electron.BrowserWindow(windowOptions);
|
||||
perfTimestamps && perfTimestamps.push({ name: 'creating main window', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'creating main window', ts: process.hrtime() });
|
||||
|
||||
setMenu();
|
||||
perfTimestamps && perfTimestamps.push({ name: 'setting menu', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting menu', ts: process.hrtime() });
|
||||
|
||||
mainWindow.loadURL(htmlPath);
|
||||
if (showDevToolsOnStart) {
|
||||
mainWindow.openDevTools({ mode: 'bottom' });
|
||||
}
|
||||
mainWindow.once('ready-to-show', () => {
|
||||
perfTimestamps && perfTimestamps.push({ name: 'main window ready', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'main window ready', ts: process.hrtime() });
|
||||
if (startMinimized) {
|
||||
emitRemoteEvent('launcher-started-minimized');
|
||||
} else {
|
||||
|
@ -216,7 +214,7 @@ function createMainWindow() {
|
|||
}
|
||||
ready = true;
|
||||
notifyOpenFile();
|
||||
perfTimestamps && perfTimestamps.push({ name: 'main window shown', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'main window shown', ts: process.hrtime() });
|
||||
reportStartProfile();
|
||||
});
|
||||
mainWindow.webContents.on('context-menu', onContextMenu);
|
||||
|
@ -242,12 +240,10 @@ function createMainWindow() {
|
|||
mainWindow.on('session-end', () => {
|
||||
emitRemoteEvent('os-lock');
|
||||
});
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'configuring main window', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'configuring main window', ts: process.hrtime() });
|
||||
|
||||
restoreMainWindowPosition();
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'restoring main window position', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'restoring main window position', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function restoreMainWindow() {
|
||||
|
@ -464,8 +460,7 @@ function setGlobalShortcuts(appSettings) {
|
|||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'setting global shortcuts', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting global shortcuts', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function subscribePowerEvents() {
|
||||
|
@ -478,8 +473,7 @@ function subscribePowerEvents() {
|
|||
electron.powerMonitor.on('lock-screen', () => {
|
||||
emitRemoteEvent('os-lock');
|
||||
});
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'subscribing to power events', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'subscribing to power events', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function setEnv() {
|
||||
|
@ -491,7 +485,7 @@ function setEnv() {
|
|||
// https://github.com/electron/electron/issues/9046
|
||||
process.env.XDG_CURRENT_DESKTOP = 'Unity';
|
||||
}
|
||||
perfTimestamps && perfTimestamps.push({ name: 'setting env', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting env', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function restorePreferences() {
|
||||
|
@ -524,7 +518,7 @@ function restorePreferences() {
|
|||
}
|
||||
}
|
||||
|
||||
perfTimestamps && perfTimestamps.push({ name: 'restoring preferences', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'restoring preferences', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function deleteOldTempFiles() {
|
||||
|
@ -541,8 +535,7 @@ function deleteOldTempFiles() {
|
|||
}
|
||||
app.oldTempFilesDeleted = true; // this is added to prevent file deletion on restart
|
||||
}, 1000);
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'deleting old temp files', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'deleting old temp files', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
function deleteRecursive(dir) {
|
||||
|
@ -577,8 +570,7 @@ function hookRequestHeaders() {
|
|||
}
|
||||
callback({ requestHeaders: details.requestHeaders });
|
||||
});
|
||||
perfTimestamps &&
|
||||
perfTimestamps.push({ name: 'setting request handlers', ts: process.hrtime() });
|
||||
perfTimestamps?.push({ name: 'setting request handlers', ts: process.hrtime() });
|
||||
}
|
||||
|
||||
// If a display is disconnected while KeeWeb is minimized, Electron does not
|
||||
|
|
|
@ -5519,6 +5519,14 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"eslint-plugin-babel": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-babel/-/eslint-plugin-babel-5.3.0.tgz",
|
||||
"integrity": "sha512-HPuNzSPE75O+SnxHIafbW5QB45r2w78fxqwK3HmjqIUoPfPzVrq6rD+CINU3yzoDSzEhUkX07VUphbF73Lth/w==",
|
||||
"requires": {
|
||||
"eslint-rule-composer": "^0.3.0"
|
||||
}
|
||||
},
|
||||
"eslint-plugin-es": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.0.tgz",
|
||||
|
@ -5637,6 +5645,11 @@
|
|||
"resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-4.0.1.tgz",
|
||||
"integrity": "sha512-v/KBnfyaOMPmZc/dmc6ozOdWqekGp7bBGq4jLAecEfPGmfKiWS4sA8sC0LqiV9w5qmXAtXVn4M3p1jSyhY85SQ=="
|
||||
},
|
||||
"eslint-rule-composer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz",
|
||||
"integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg=="
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.0.0.tgz",
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
"eslint": "^6.8.0",
|
||||
"eslint-config-prettier": "^6.11.0",
|
||||
"eslint-config-standard": "^14.1.1",
|
||||
"eslint-plugin-babel": "^5.3.0",
|
||||
"eslint-plugin-import": "^2.20.2",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-prettier": "^3.1.3",
|
||||
|
|
Loading…
Reference in New Issue