Skip to content

Commit bc4b498

Browse files
committed
Add sudo desktop API
1 parent 8db0fd4 commit bc4b498

File tree

4 files changed

+49
-2
lines changed

4 files changed

+49
-2
lines changed

package-lock.json

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
"publish": null
130130
},
131131
"dependencies": {
132+
"@expo/sudo-prompt": "^9.3.2",
132133
"@httptoolkit/util": "^0.1.8",
133134
"@sentry/electron": "^4.0.0",
134135
"@sentry/integrations": "^7.8.1",

src/index.ts

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ const rmRF = (p: string) => fs.rm(p, { recursive: true, force: true });
1919
import windowStateKeeper from 'electron-window-state';
2020
import { getSystemProxy } from 'os-proxy-config';
2121
import registerContextMenu = require('electron-context-menu');
22-
import { getDeferred, delay } from '@httptoolkit/util';
22+
import * as sudoPrompt from '@expo/sudo-prompt';
23+
import { getDeferred, delay, ErrorLike } from '@httptoolkit/util';
2324

2425
import { getMenu, shouldAutoHideMenu } from './menu';
2526
import { ContextMenuDefinition, openContextMenu } from './context-menu';
@@ -659,3 +660,33 @@ ipcMain.handle('restart-app', ipcHandler(() => {
659660
app.relaunch();
660661
app.quit();
661662
}));
663+
664+
// Prompt the user to authorize a command to run as root, for system setup we can't do
665+
// without elevated permissions. We try to avoid this, but for system config changes
666+
// it's required, and much better to do per-command than running the whole app as root.
667+
ipcMain.handle('sudo', ipcHandler(async (options: {
668+
command: string
669+
}) => {
670+
if (typeof options?.command !== 'string') {
671+
throw new Error("Invalid command for sudo");
672+
}
673+
674+
const result = getDeferred<{ success: boolean, error?: ErrorLike, stdout: string, stderr: string }>();
675+
676+
sudoPrompt.exec(options.command, {
677+
name: 'HTTP Toolkit'
678+
}, (error: unknown | null, stdout: string, stderr: string) => {
679+
// Types suggest this could be a buffer, but we want to
680+
// enforce simpler string output:
681+
stdout = stdout?.toString() ?? '';
682+
stderr = stderr?.toString() ?? '';
683+
684+
if (error) {
685+
result.resolve({ success: false, error, stdout, stderr });
686+
} else {
687+
result.resolve({ success: true, stdout, stderr });
688+
}
689+
});
690+
691+
return result.promise;
692+
}));

src/preload.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,8 @@ contextBridge.exposeInMainWorld('desktopApi', {
4646
ipcRenderer.invoke('open-context-menu', options),
4747

4848
restartApp: () =>
49-
ipcRenderer.invoke('restart-app')
49+
ipcRenderer.invoke('restart-app'),
50+
51+
sudo: (options: any) =>
52+
ipcRenderer.invoke('sudo', options)
5053
});

0 commit comments

Comments
 (0)