[MM-54742] Force secure keyboard entry off when window loses focus and when servers switch (#2869)
* [MM-54742] Force secure keyboard entry off when window loses focus and when servers switch * Fix for when window is not focused, added tests
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
|||||||
SHOW_NEW_SERVER_MODAL,
|
SHOW_NEW_SERVER_MODAL,
|
||||||
SHOW_REMOVE_SERVER_MODAL,
|
SHOW_REMOVE_SERVER_MODAL,
|
||||||
SWITCH_SERVER,
|
SWITCH_SERVER,
|
||||||
|
TOGGLE_SECURE_INPUT,
|
||||||
UPDATE_SERVER_ORDER,
|
UPDATE_SERVER_ORDER,
|
||||||
UPDATE_SHORTCUT_MENU,
|
UPDATE_SHORTCUT_MENU,
|
||||||
UPDATE_TAB_ORDER,
|
UPDATE_TAB_ORDER,
|
||||||
@@ -87,6 +88,7 @@ export class ServerViewState {
|
|||||||
ServerManager.getServerLog(serverId, 'WindowManager').error('Cannot find server in config');
|
ServerManager.getServerLog(serverId, 'WindowManager').error('Cannot find server in config');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
ipcMain.emit(TOGGLE_SECURE_INPUT, null, false);
|
||||||
this.currentServerId = serverId;
|
this.currentServerId = serverId;
|
||||||
const nextView = ServerManager.getLastActiveTabForServer(serverId);
|
const nextView = ServerManager.getLastActiveTabForServer(serverId);
|
||||||
if (waitForViewToExist) {
|
if (waitForViewToExist) {
|
||||||
|
@@ -1,6 +1,8 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See LICENSE.txt for license information.
|
// See LICENSE.txt for license information.
|
||||||
|
|
||||||
|
import {app} from 'electron';
|
||||||
|
|
||||||
import {getLocalURLString, getLocalPreload} from 'main/utils';
|
import {getLocalURLString, getLocalPreload} from 'main/utils';
|
||||||
import ServerManager from 'common/servers/serverManager';
|
import ServerManager from 'common/servers/serverManager';
|
||||||
import MainWindow from 'main/windows/mainWindow';
|
import MainWindow from 'main/windows/mainWindow';
|
||||||
@@ -9,8 +11,15 @@ import ModalManager from 'main/views/modalManager';
|
|||||||
import {
|
import {
|
||||||
handleWelcomeScreenModal,
|
handleWelcomeScreenModal,
|
||||||
handleMainWindowIsShown,
|
handleMainWindowIsShown,
|
||||||
|
handleToggleSecureInput,
|
||||||
} from './intercom';
|
} from './intercom';
|
||||||
|
|
||||||
|
jest.mock('electron', () => ({
|
||||||
|
app: {
|
||||||
|
setSecureKeyboardEntryEnabled: jest.fn(),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
jest.mock('app/serverViewState', () => ({}));
|
jest.mock('app/serverViewState', () => ({}));
|
||||||
jest.mock('common/config', () => ({
|
jest.mock('common/config', () => ({
|
||||||
setServers: jest.fn(),
|
setServers: jest.fn(),
|
||||||
@@ -73,4 +82,38 @@ describe('main/app/intercom', () => {
|
|||||||
expect(ModalManager.addModal).not.toHaveBeenCalled();
|
expect(ModalManager.addModal).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('handleToggleSecureInput', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
MainWindow.get.mockReturnValue({
|
||||||
|
isFocused: () => true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fire for OSes that are not macOS', () => {
|
||||||
|
const originalPlatform = process.platform;
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: 'linux',
|
||||||
|
});
|
||||||
|
|
||||||
|
handleToggleSecureInput({}, true);
|
||||||
|
|
||||||
|
Object.defineProperty(process, 'platform', {
|
||||||
|
value: originalPlatform,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(app.setSecureKeyboardEntryEnabled).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not fire if window is not focused', () => {
|
||||||
|
MainWindow.get.mockReturnValue({isFocused: () => false});
|
||||||
|
handleToggleSecureInput({}, true);
|
||||||
|
|
||||||
|
expect(app.setSecureKeyboardEntryEnabled).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@@ -153,6 +153,11 @@ export function handleToggleSecureInput(event: IpcMainEvent, secureInput: boolea
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't allow this to turn on if the main window isn't focused
|
||||||
|
if (secureInput && !MainWindow.get()?.isFocused()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Enforce macOS to restrict processes from reading the keyboard input when in a password field
|
// Enforce macOS to restrict processes from reading the keyboard input when in a password field
|
||||||
log.debug('handleToggleSecureInput', secureInput);
|
log.debug('handleToggleSecureInput', secureInput);
|
||||||
app.setSecureKeyboardEntryEnabled(secureInput);
|
app.setSecureKeyboardEntryEnabled(secureInput);
|
||||||
|
@@ -376,14 +376,21 @@ window.addEventListener('resize', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let isPasswordBox = false;
|
let isPasswordBox = false;
|
||||||
|
const shouldSecureInput = (element, force = false) => {
|
||||||
window.addEventListener('focusin', (event) => {
|
const targetIsPasswordBox = (element && element.tagName === 'INPUT' && element.type === 'password');
|
||||||
const targetIsPasswordBox = event.target.tagName === 'INPUT' && event.target.type === 'password';
|
if (targetIsPasswordBox && (!isPasswordBox || force)) {
|
||||||
if (targetIsPasswordBox && !isPasswordBox) {
|
|
||||||
ipcRenderer.send(TOGGLE_SECURE_INPUT, true);
|
ipcRenderer.send(TOGGLE_SECURE_INPUT, true);
|
||||||
} else if (!targetIsPasswordBox && isPasswordBox) {
|
} else if (!targetIsPasswordBox && (isPasswordBox || force)) {
|
||||||
ipcRenderer.send(TOGGLE_SECURE_INPUT, false);
|
ipcRenderer.send(TOGGLE_SECURE_INPUT, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
isPasswordBox = targetIsPasswordBox;
|
isPasswordBox = targetIsPasswordBox;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.addEventListener('focusin', (event) => {
|
||||||
|
shouldSecureInput(event.target);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('focus', () => {
|
||||||
|
shouldSecureInput(document.activeElement, true);
|
||||||
});
|
});
|
||||||
|
@@ -27,6 +27,7 @@ import {
|
|||||||
MAIN_WINDOW_RESIZED,
|
MAIN_WINDOW_RESIZED,
|
||||||
MAIN_WINDOW_FOCUSED,
|
MAIN_WINDOW_FOCUSED,
|
||||||
VIEW_FINISHED_RESIZING,
|
VIEW_FINISHED_RESIZING,
|
||||||
|
TOGGLE_SECURE_INPUT,
|
||||||
} from 'common/communication';
|
} from 'common/communication';
|
||||||
import Config from 'common/config';
|
import Config from 'common/config';
|
||||||
import {Logger} from 'common/log';
|
import {Logger} from 'common/log';
|
||||||
@@ -314,6 +315,7 @@ export class MainWindow extends EventEmitter {
|
|||||||
globalShortcut.unregisterAll();
|
globalShortcut.unregisterAll();
|
||||||
|
|
||||||
this.emit(MAIN_WINDOW_RESIZED, this.getBounds());
|
this.emit(MAIN_WINDOW_RESIZED, this.getBounds());
|
||||||
|
ipcMain.emit(TOGGLE_SECURE_INPUT, null, false);
|
||||||
|
|
||||||
// App should save bounds when a window is closed.
|
// App should save bounds when a window is closed.
|
||||||
// However, 'close' is not fired in some situations(shutdown, ctrl+c)
|
// However, 'close' is not fired in some situations(shutdown, ctrl+c)
|
||||||
|
Reference in New Issue
Block a user