Skip to content

Commit ca5ab81

Browse files
committed
fix: the bug when running command need sudo. 添加特权操作支持,封装sudo命令以简化权限管理
1 parent a90303f commit ca5ab81

File tree

7 files changed

+51
-54
lines changed

7 files changed

+51
-54
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,13 @@ npm run electron
450450
- `os-network-fallback.cjs` 会在 `uv_interface_addresses` 权限受限时返回回环接口,避免 node-ipc 崩溃。
451451
- 若仍需沙箱,只能在支持 setuid 的环境或 root 下运行。
452452

453+
#### 5)需要特权操作的说明
454+
455+
- 部分操作需要系统管理员权限(例如释放占用端口、修改系统网络设置、在 Windows 上启用 Loopback 等)。
456+
- 若权限不足,请手动以管理员权限运行相关命令或以管理员身份启动应用;在容器/受限环境中仅能执行当前用户可用的操作。
457+
- 开发者可在代码中统一通过 `DevSidecar.api.shell.sudo`(核心实现见 `packages/core/src/shell/sudo.js`)封装处理。
458+
459+
453460
### 8.2、开发调试模式启动
454461

455462
运行如下命令即可开发模式启动

packages/core/src/shell/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const setSystemEnv = require('./scripts/set-system-env')
88
const setSystemProxy = require('./scripts/set-system-proxy')
99
const setupCa = require('./scripts/setup-ca')
1010
const shell = require('./shell')
11+
const sudo = require('./sudo')
1112

1213
module.exports = {
1314
killByPort,
@@ -19,6 +20,7 @@ module.exports = {
1920
setSystemProxy,
2021
enableLoopback,
2122
extraPath,
23+
sudo,
2224
async exec (cmds, args) {
2325
return shell.getSystemShell().exec(cmds, args)
2426
},

packages/core/src/shell/scripts/enable-loopback.js

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,40 +2,20 @@
22
*/
33
const Shell = require('../shell')
44
const extraPath = require('./extra-path')
5-
const sudoPrompt = require('@vscode/sudo-prompt')
6-
const log = require('../../utils/util.log.core')
5+
const sudo = require('../sudo')
76
const execute = Shell.execute
87

98
const executor = {
10-
windows (exec) {
9+
windows(exec) {
1110
const loopbackPath = extraPath.getEnableLoopbackPath()
12-
const sudoCommand = [`"${loopbackPath}"`]
11+
const sudoCommand = `"${loopbackPath}"`
1312

14-
const options = {
15-
name: 'EnableLoopback',
16-
}
17-
return new Promise((resolve, reject) => {
18-
sudoPrompt.exec(
19-
sudoCommand.join(' '),
20-
options,
21-
(error, _, stderr) => {
22-
if (stderr) {
23-
log.error(`[sudo-prompt] 发生错误: ${stderr}`)
24-
}
25-
26-
if (error) {
27-
reject(error)
28-
} else {
29-
resolve(undefined)
30-
}
31-
},
32-
)
33-
})
13+
return sudo(sudoCommand, { name: 'EnableLoopback' })
3414
},
35-
async linux (exec, { port }) {
15+
async linux(exec, { port }) {
3616
throw new Error('不支持此操作')
3717
},
38-
async mac (exec, { port }) {
18+
async mac(exec, { port }) {
3919
throw new Error('不支持此操作')
4020
},
4121
}

packages/core/src/shell/scripts/setup-ca.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
const Shell = require('../shell')
2+
const sudo = require('../sudo')
23

34
const execute = Shell.execute
45

56
const executor = {
6-
async windows (exec, { certPath }) {
7+
async windows(exec, { certPath }) {
78
const cmds = [`start "" "${certPath}"`]
89
await exec(cmds, { type: 'cmd' })
910
return true
1011
},
11-
async linux (exec, { certPath }) {
12-
const cmds = [`sudo cp ${certPath} /usr/local/share/ca-certificates`, 'sudo update-ca-certificates ']
13-
await exec(cmds)
12+
async linux(exec, { certPath }) {
13+
await sudo(`cp ${certPath} /usr/local/share/ca-certificates && update-ca-certificates`, { name: 'DevSidecar CA Install' })
1414
return true
1515
},
16-
async mac (exec, { certPath }) {
16+
async mac(exec, { certPath }) {
1717
const cmds = [`open "${certPath}"`]
1818
await exec(cmds, { type: 'cmd' })
1919
return true

packages/core/src/shell/sudo.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
'use strict'
2+
3+
const os = require('node:os')
4+
const sudoPrompt = require('@vscode/sudo-prompt')
5+
const log = require('../utils/util.log.core')
6+
7+
function sudo (command, options = {}) {
8+
const { name = 'DevSidecar', onStdout, onStderr } = options
9+
10+
if (!['darwin', 'linux', 'win32'].includes(os.platform())) {
11+
return Promise.reject(new Error('Unsupported platform for privileged operations'))
12+
}
13+
14+
return new Promise((resolve, reject) => {
15+
sudoPrompt.exec(command, { name }, (error, stdout = '', stderr = '') => {
16+
if (stdout && onStdout) onStdout(stdout)
17+
if (stderr && onStderr) onStderr(stderr)
18+
if (error) {
19+
log.error('[sudo] command failed:', command, error)
20+
return reject(error)
21+
}
22+
resolve({ stdout, stderr })
23+
})
24+
})
25+
}
26+
27+
module.exports = sudo
Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,17 @@
11
/* global __static */
22
import DevSidecar from '@docmirror/dev-sidecar'
3-
import sudoPrompt from '@vscode/sudo-prompt'
43
import { join } from 'node:path'
5-
import log from '../../utils/util.log.gui'
64

75
export default {
8-
open () {
6+
open() {
97
const options = {
108
name: 'EnableLoopback',
119
icns: process.platform === 'darwin' ? join(__static, 'icon.icns') : undefined,
1210
env: { PARAM: 'VALUE' },
1311
}
1412
const exeFile = DevSidecar.api.shell.extraPath.getEnableLoopbackPath()
15-
const sudoCommand = [`"${exeFile}"`]
13+
const sudoCommand = `"${exeFile}"`
1614

17-
return new Promise((resolve, reject) => {
18-
sudoPrompt.exec(
19-
sudoCommand.join(' '),
20-
options,
21-
(error, _, stderr) => {
22-
if (stderr) {
23-
log.error(`[sudo-prompt] 发生错误: ${stderr}`)
24-
}
25-
26-
if (error) {
27-
reject(error)
28-
} else {
29-
resolve(undefined)
30-
}
31-
},
32-
)
33-
})
15+
return DevSidecar.api.shell.sudo(sudoCommand, options)
3416
},
3517
}

packages/gui/src/bridge/auto-start/backend.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ EOF
2020
`
2121
await DevSidecar.api.shell.exec(cmd)
2222
} else {
23-
const removeStart = 'sudo rm ~/.config/autostart/dev-sidecar.desktop -rf'
24-
await DevSidecar.api.shell.exec(removeStart)
23+
await DevSidecar.api.shell.sudo('rm ~/.config/autostart/dev-sidecar.desktop -rf', { name: 'Remove Autostart' })
2524
}
2625
}
2726
export default {

0 commit comments

Comments
 (0)