diff --git a/electron/ipc-handler.ts b/electron/ipc-handler.ts index 6c8104be8..d840ec83c 100644 --- a/electron/ipc-handler.ts +++ b/electron/ipc-handler.ts @@ -2,6 +2,7 @@ // --------------- import { app, + dialog, globalShortcut, ipcMain, IpcMainEvent, @@ -19,6 +20,7 @@ import { log } from 'electron-log/main'; import { exec } from 'child_process'; import { getWin } from './main-window'; import { quitApp, showOrFocus } from './various-shared'; +import { loadSimpleStoreAll, saveSimpleStore } from './simple-store'; // HANDLER // ------- @@ -55,9 +57,6 @@ ipcMain.on(IPC.RELOAD_MAIN_WIN, () => getWin().reload()); ipcMain.on(IPC.OPEN_PATH, (ev, path: string) => shell.openPath(path)); ipcMain.on(IPC.OPEN_EXTERNAL, (ev, url: string) => shell.openExternal(url)); -// TODO check -ipcMain.on(IPC.EXEC, execWithFrontendErrorHandlerInform); - ipcMain.on(IPC.LOCK_SCREEN, () => { if ((app as any).isLocked) { return; @@ -109,6 +108,8 @@ ipcMain.on(IPC.SHOW_OR_FOCUS, () => { showOrFocus(mainWin); }); +ipcMain.on(IPC.EXEC, execWithFrontendErrorHandlerInform); + // eslint-disable-next-line prefer-arrow/prefer-arrow-functions function registerShowAppShortCuts(cfg: KeyboardConfig): void { // unregister all previous @@ -179,12 +180,49 @@ function registerShowAppShortCuts(cfg: KeyboardConfig): void { } } +const COMMAND_MAP_PROP = 'allowedCommands'; + // eslint-disable-next-line prefer-arrow/prefer-arrow-functions -function execWithFrontendErrorHandlerInform(ev: IpcMainEvent, command: string): void { - log('running command ' + command); - exec(command, (err) => { - if (err) { - errorHandlerWithFrontendInform(err); +async function execWithFrontendErrorHandlerInform( + ev: IpcMainEvent, + command: string, +): Promise { + log('trying to run command ' + command); + const existingData = await loadSimpleStoreAll(); + const allowedCommands: string[] = (existingData[COMMAND_MAP_PROP] as string[]) || []; + + if (!Array.isArray(allowedCommands)) { + throw new Error('allowedCommands is no array ???'); + } + if (allowedCommands.includes(command)) { + exec(command, (err) => { + if (err) { + errorHandlerWithFrontendInform(err); + } + }); + } else { + const res = await dialog.showMessageBox(null, { + type: 'question', + buttons: ['Cancel', 'Yes, execute!'], + defaultId: 2, + title: 'Super Productivity – Exec', + message: + 'Do you want to execute this command? ONLY confirm if you are sure you know what you are doing!!', + detail: command, + checkboxLabel: 'Remember my answer', + checkboxChecked: true, + }); + const { response, checkboxChecked } = res; + + if (response === 1) { + if (checkboxChecked) { + await saveSimpleStore(COMMAND_MAP_PROP, [...allowedCommands, command]); + } + exec(command, (err) => { + if (err) { + errorHandlerWithFrontendInform(err); + } + }); } - }); + } } diff --git a/electron/preload.ts b/electron/preload.ts index 90f9dc3ee..5c262867f 100644 --- a/electron/preload.ts +++ b/electron/preload.ts @@ -77,8 +77,7 @@ const ea: ElectronAPI = { updateCurrentTask: (task) => _send('CURRENT_TASK_UPDATED', task), - // TODO make secure - exec: () => _send('EXEC'), + exec: (command: string) => _send('EXEC', command), }; contextBridge.exposeInMainWorld('ea', ea); diff --git a/electron/simple-store.ts b/electron/simple-store.ts new file mode 100644 index 000000000..bc2461e13 --- /dev/null +++ b/electron/simple-store.ts @@ -0,0 +1,31 @@ +import { promises as fs } from 'fs'; +import { app } from 'electron'; +import * as path from 'path'; + +const DATA_PATH = path.join(app.getPath('userData'), 'simpleSettings'); + +type SimpleStoreData = { [key: string]: unknown }; + +export const saveSimpleStore = async ( + dataKey = 'main', + data: unknown, +): Promise => { + const prevData = await loadSimpleStoreAll(); + + return await fs.writeFile(DATA_PATH, JSON.stringify({ ...prevData, [dataKey]: data }), { + encoding: 'utf8', + }); +}; + +export const loadSimpleStoreAll = async (): Promise => { + try { + const data = await fs.readFile(DATA_PATH, { encoding: 'utf8' }); + console.log(data); + console.log(JSON.parse(data)); + + return JSON.parse(data); + } catch (e) { + console.error(e); + return {}; + } +};