mirror of https://github.com/keeweb/keeweb
parent
29e5c14009
commit
8fc6f49fb4
|
@ -20,7 +20,6 @@ const AutoType = {
|
|||
enabled: !!(Launcher && Launcher.autoTypeSupported),
|
||||
supportsEventsWithWindowId: !!(Launcher && Launcher.platform() === 'linux'),
|
||||
selectEntryView: false,
|
||||
pendingEvent: null,
|
||||
running: false,
|
||||
|
||||
init() {
|
||||
|
@ -28,10 +27,6 @@ const AutoType = {
|
|||
return;
|
||||
}
|
||||
Events.on('auto-type', (e) => this.handleEvent(e));
|
||||
Events.on('main-window-blur', (e) => this.mainWindowBlur(e));
|
||||
Events.on('main-window-focus', (e) => this.mainWindowFocus(e));
|
||||
Events.on('main-window-will-close', (e) => this.mainWindowWillClose(e));
|
||||
Events.on('closed-open-view', (e) => this.processPendingEvent(e));
|
||||
},
|
||||
|
||||
handleEvent(e) {
|
||||
|
@ -216,16 +211,24 @@ const AutoType = {
|
|||
},
|
||||
|
||||
selectEntryAndRun() {
|
||||
this.getActiveWindowInfo((e, windowInfo) => {
|
||||
this.getActiveWindowInfo(async (e, windowInfo) => {
|
||||
const filter = new AutoTypeFilter(windowInfo, AppModel.instance);
|
||||
const evt = { filter, windowInfo };
|
||||
if (!AppModel.instance.files.hasOpenFiles()) {
|
||||
this.pendingEvent = evt;
|
||||
logger.debug('auto-type event delayed');
|
||||
this.focusMainWindow();
|
||||
} else {
|
||||
this.processEventWithFilter(evt);
|
||||
try {
|
||||
await AppModel.instance.unlockAnyFile();
|
||||
} catch {
|
||||
logger.debug('auto-type event canceled');
|
||||
return;
|
||||
}
|
||||
if (this.selectEntryView) {
|
||||
this.selectEntryView.show();
|
||||
}
|
||||
}
|
||||
logger.debug('processing auto-type event');
|
||||
this.processEventWithFilter(evt);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -264,51 +267,6 @@ const AutoType = {
|
|||
this.selectEntryView.hide();
|
||||
Events.emit('open-file');
|
||||
});
|
||||
},
|
||||
|
||||
mainWindowBlur() {
|
||||
this.mainWindowBlurTimer = setTimeout(() => {
|
||||
// macOS emits focus-blur-focus event in a row when triggering auto-type from minimized state
|
||||
delete this.mainWindowBlurTimer;
|
||||
this.resetPendingEvent();
|
||||
if (this.selectEntryView) {
|
||||
this.selectEntryView.emit('result', undefined);
|
||||
}
|
||||
}, Timeouts.AutoTypeWindowFocusAfterBlur);
|
||||
},
|
||||
|
||||
mainWindowFocus() {
|
||||
if (this.mainWindowBlurTimer) {
|
||||
clearTimeout(this.mainWindowBlurTimer);
|
||||
this.mainWindowBlurTimer = null;
|
||||
}
|
||||
},
|
||||
|
||||
mainWindowWillClose() {
|
||||
this.resetPendingEvent();
|
||||
if (this.selectEntryView) {
|
||||
this.selectEntryView.emit('result', undefined);
|
||||
}
|
||||
},
|
||||
|
||||
resetPendingEvent() {
|
||||
if (this.pendingEvent) {
|
||||
this.pendingEvent = null;
|
||||
logger.debug('auto-type event canceled');
|
||||
}
|
||||
},
|
||||
|
||||
processPendingEvent() {
|
||||
if (this.selectEntryView) {
|
||||
this.selectEntryView.show();
|
||||
}
|
||||
if (!this.pendingEvent) {
|
||||
return;
|
||||
}
|
||||
logger.debug('processing pending auto-type event');
|
||||
const evt = this.pendingEvent;
|
||||
this.pendingEvent = null;
|
||||
this.processEventWithFilter(evt);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ import { MenuModel } from 'models/menu/menu-model';
|
|||
import { PluginManager } from 'plugins/plugin-manager';
|
||||
import { Features } from 'util/features';
|
||||
import { DateFormat } from 'comp/i18n/date-format';
|
||||
import { Launcher } from 'comp/launcher';
|
||||
import { UrlFormat } from 'util/formatting/url-format';
|
||||
import { IdGenerator } from 'util/generators/id-generator';
|
||||
import { Locale } from 'util/locale';
|
||||
|
@ -38,6 +39,8 @@ class AppModel {
|
|||
advancedSearch = null;
|
||||
attachedYubiKeysCount = 0;
|
||||
memoryPasswordStorage = {};
|
||||
fileUnlockPromise = null;
|
||||
hardwareDecryptInProgress = false;
|
||||
|
||||
constructor() {
|
||||
Events.on('refresh', this.refresh.bind(this));
|
||||
|
@ -48,6 +51,9 @@ class AppModel {
|
|||
Events.on('select-entry', this.selectEntry.bind(this));
|
||||
Events.on('unset-keyfile', this.unsetKeyFile.bind(this));
|
||||
Events.on('usb-devices-changed', this.usbDevicesChanged.bind(this));
|
||||
Events.on('main-window-blur', this.mainWindowBlur.bind(this));
|
||||
Events.on('hardware-decrypt-started', this.hardwareDecryptStarted.bind(this));
|
||||
Events.on('hardware-decrypt-finished', this.hardwareDecryptFinished.bind(this));
|
||||
|
||||
this.appLogger = new Logger('app');
|
||||
AppModel.instance = this;
|
||||
|
@ -167,11 +173,21 @@ class AppModel {
|
|||
page: 'file',
|
||||
file
|
||||
});
|
||||
|
||||
this.refresh();
|
||||
|
||||
file.on('reload', this.reloadFile.bind(this));
|
||||
file.on('change', () => Events.emit('file-changed', file));
|
||||
file.on('ejected', () => this.closeFile(file));
|
||||
|
||||
Events.emit('file-opened');
|
||||
|
||||
if (this.fileUnlockPromise) {
|
||||
this.appLogger.info('Running pending file unlock operation');
|
||||
this.fileUnlockPromise.resolve(file);
|
||||
this.fileUnlockPromise = null;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1414,6 +1430,39 @@ class AppModel {
|
|||
this.memoryPasswordStorage = {};
|
||||
}
|
||||
}
|
||||
|
||||
unlockAnyFile() {
|
||||
this.rejectPendingFileUnlockPromise('Replaced with a new operation');
|
||||
return new Promise((resolve, reject) => {
|
||||
this.fileUnlockPromise = { resolve, reject };
|
||||
this.appLogger.info('Pending file unlock operation is set');
|
||||
});
|
||||
}
|
||||
|
||||
rejectPendingFileUnlockPromise(reason) {
|
||||
if (this.fileUnlockPromise) {
|
||||
this.appLogger.info('Cancel pending file unlock operation', reason);
|
||||
this.fileUnlockPromise.reject(new Error(reason));
|
||||
this.fileUnlockPromise = null;
|
||||
}
|
||||
}
|
||||
|
||||
mainWindowBlur() {
|
||||
if (!this.hardwareDecryptInProgress) {
|
||||
this.rejectPendingFileUnlockPromise('Main window blur');
|
||||
}
|
||||
}
|
||||
|
||||
hardwareDecryptStarted() {
|
||||
this.hardwareDecryptInProgress = true;
|
||||
}
|
||||
|
||||
hardwareDecryptFinished() {
|
||||
this.hardwareDecryptInProgress = false;
|
||||
if (!Launcher.isAppFocused()) {
|
||||
this.rejectPendingFileUnlockPromise('App is not focused after hardware decrypt');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { AppModel };
|
||||
|
|
|
@ -171,9 +171,6 @@ class AppView extends View {
|
|||
this.views.open.on('close', () => {
|
||||
this.showEntries();
|
||||
});
|
||||
this.views.open.on('remove', () => {
|
||||
Events.emit('closed-open-view');
|
||||
});
|
||||
}
|
||||
|
||||
showLastOpenFile() {
|
||||
|
|
|
@ -680,13 +680,18 @@ class OpenView extends View {
|
|||
const encryptedPassword = kdbxweb.ProtectedValue.fromBase64(
|
||||
this.encryptedPassword.value
|
||||
);
|
||||
Events.emit('hardware-decrypt-started');
|
||||
NativeModules.hardwareDecrypt(encryptedPassword, touchIdPrompt)
|
||||
.then((password) => {
|
||||
Events.emit('hardware-decrypt-finished');
|
||||
|
||||
this.params.password = password;
|
||||
this.params.encryptedPassword = this.encryptedPassword;
|
||||
this.model.openFile(this.params, (err) => this.openDbComplete(err));
|
||||
})
|
||||
.catch((err) => {
|
||||
Events.emit('hardware-decrypt-finished');
|
||||
|
||||
if (err.message.includes('User refused')) {
|
||||
err.userCanceled = true;
|
||||
} else if (err.message.includes('SecKeyCreateDecryptedData')) {
|
||||
|
|
Loading…
Reference in New Issue