@geekbeer/minion 2.57.0 → 2.58.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/routes/sudoers.js +70 -0
- package/linux/server.js +3 -0
- package/package.json +1 -1
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sudoers endpoint
|
|
3
|
+
*
|
|
4
|
+
* Endpoints:
|
|
5
|
+
* - GET /api/sudoers - List sudo permissions for the current user
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const { exec } = require('child_process')
|
|
9
|
+
const { promisify } = require('util')
|
|
10
|
+
const execAsync = promisify(exec)
|
|
11
|
+
|
|
12
|
+
const { verifyToken } = require('../lib/auth')
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Parse `sudo -l` output into structured permission entries
|
|
16
|
+
* @param {string} output - Raw output from `sudo -l`
|
|
17
|
+
* @returns {string[]} List of allowed commands
|
|
18
|
+
*/
|
|
19
|
+
function parseSudoList(output) {
|
|
20
|
+
const lines = output.split('\n')
|
|
21
|
+
const commands = []
|
|
22
|
+
|
|
23
|
+
for (const line of lines) {
|
|
24
|
+
const trimmed = line.trim()
|
|
25
|
+
// Lines starting with (root) contain permission entries
|
|
26
|
+
if (trimmed.startsWith('(root)') || trimmed.startsWith('(ALL)')) {
|
|
27
|
+
// Extract the command part after NOPASSWD: or the run-as spec
|
|
28
|
+
const match = trimmed.match(/(?:NOPASSWD:\s*)(.+)$/)
|
|
29
|
+
if (match) {
|
|
30
|
+
commands.push(match[1].trim())
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return commands
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Register sudoers routes as Fastify plugin
|
|
40
|
+
* @param {import('fastify').FastifyInstance} fastify
|
|
41
|
+
*/
|
|
42
|
+
async function sudoersRoutes(fastify) {
|
|
43
|
+
fastify.get('/api/sudoers', async (request, reply) => {
|
|
44
|
+
if (!verifyToken(request)) {
|
|
45
|
+
reply.code(401)
|
|
46
|
+
return { success: false, error: 'Unauthorized' }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
const { stdout } = await execAsync('sudo -n -l 2>/dev/null', { timeout: 5000 })
|
|
51
|
+
const commands = parseSudoList(stdout)
|
|
52
|
+
|
|
53
|
+
return {
|
|
54
|
+
success: true,
|
|
55
|
+
commands,
|
|
56
|
+
raw: stdout.trim(),
|
|
57
|
+
}
|
|
58
|
+
} catch (error) {
|
|
59
|
+
// sudo -l may fail if sudo is not configured at all
|
|
60
|
+
return {
|
|
61
|
+
success: true,
|
|
62
|
+
commands: [],
|
|
63
|
+
raw: '',
|
|
64
|
+
note: 'sudo is not configured or no permissions granted',
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { sudoersRoutes }
|
package/linux/server.js
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
* Secrets: GET /api/secrets, PUT/DELETE /api/secrets/:key
|
|
21
21
|
* Config: GET /api/config/backup, GET/PUT /api/config/env
|
|
22
22
|
* Executions: GET /api/executions, GET /api/executions/:id, etc.
|
|
23
|
+
* Sudoers: GET /api/sudoers
|
|
23
24
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
24
25
|
*/
|
|
25
26
|
|
|
@@ -65,6 +66,7 @@ const { authRoutes } = require('../core/routes/auth')
|
|
|
65
66
|
const { variableRoutes } = require('../core/routes/variables')
|
|
66
67
|
const { memoryRoutes } = require('../core/routes/memory')
|
|
67
68
|
const { dailyLogRoutes } = require('../core/routes/daily-logs')
|
|
69
|
+
const { sudoersRoutes } = require('../core/routes/sudoers')
|
|
68
70
|
|
|
69
71
|
// Linux-specific routes
|
|
70
72
|
const { commandRoutes, getProcessManager, getAllowedCommands } = require('./routes/commands')
|
|
@@ -265,6 +267,7 @@ async function registerAllRoutes(app) {
|
|
|
265
267
|
await app.register(variableRoutes)
|
|
266
268
|
await app.register(memoryRoutes)
|
|
267
269
|
await app.register(dailyLogRoutes)
|
|
270
|
+
await app.register(sudoersRoutes)
|
|
268
271
|
|
|
269
272
|
// Linux-specific routes
|
|
270
273
|
await app.register(commandRoutes)
|