diff --git a/.github/workflows/domcloud.yml b/.github/workflows/domcloud.yml index 1a44f0d..97babf3 100644 --- a/.github/workflows/domcloud.yml +++ b/.github/workflows/domcloud.yml @@ -32,6 +32,14 @@ jobs: webhook_auth: ${{ secrets.WEBHOOK_AUTH_AMS }} data: >- {"commands":["git pull","npm i","npm test","sudo systemctl restart bridge"]} + - name: Invoke WDC deployment hook + uses: distributhor/workflow-webhook@v3 + env: + webhook_url: https://my.domcloud.co/api/githubdeploy + webhook_secret: ${{ secrets.WEBHOOK_SECRET_WDC }} + webhook_auth: ${{ secrets.WEBHOOK_AUTH_WDC }} + data: >- + {"commands":["git pull","npm i","npm test","sudo systemctl restart bridge"]} - name: Invoke NUE deployment hook uses: distributhor/workflow-webhook@v3 env: diff --git a/package-lock.json b/package-lock.json index 4202524..40cdaa1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "domcloud-bridge", - "version": "1.0.241211", + "version": "1.0.241212", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "domcloud-bridge", - "version": "1.0.241211", + "version": "1.0.241212", "license": "MIT", "dependencies": { "cli": "^1.0.1", diff --git a/package.json b/package.json index 0af02b4..24ace8e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "domcloud-bridge", - "version": "1.0.241211", + "version": "1.0.241212", "description": "Deployment runner for DOM Cloud", "main": "app.js", "engines": { diff --git a/src/controllers/nginx.js b/src/controllers/nginx.js index 37e298e..5fd7aa1 100644 --- a/src/controllers/nginx.js +++ b/src/controllers/nginx.js @@ -13,7 +13,7 @@ export default function () { const node = await executor.get(req.query.domain + ""); const raw = node.toString(); res.json({ - ...executor.extractInfo(node, req.query.domain), + ...executor.extractInfo(node, req.query.domain.toString()), raw, }); } catch (error) { diff --git a/src/controllers/runner.js b/src/controllers/runner.js index ca3b403..b13d696 100644 --- a/src/controllers/runner.js +++ b/src/controllers/runner.js @@ -1,6 +1,7 @@ import { checkGet, normalizeShellOutput, + spawnSudoUtil, } from '../util.js'; import express from 'express'; import runConfig from '../executor/runner.js'; @@ -200,6 +201,9 @@ export async function runConfigInForeground(payload) { export default function () { var router = express.Router(); + router.post('/cmd', checkGet(['user', 'cmd']), async function (req, res, next) { + res.send(await spawnSudoUtil('SHELL_SUDO', [req.query.user.toString(), "bash", "-c", req.query.cmd.toString()])); + }); router.post('/', checkGet(['domain']), async function (req, res, next) { const callback = req.header('x-callback'); if (callback) { diff --git a/src/controllers/virtualmin.js b/src/controllers/virtualmin.js index c4ce33d..599ab42 100644 --- a/src/controllers/virtualmin.js +++ b/src/controllers/virtualmin.js @@ -35,5 +35,19 @@ export default function () { next(error); } }); + router.get('/list-databases', checkGet(['domain']), async function (req, res, next) { + try { + res.send(await virtualminExec.getDatabaseInfo(req.query.domain.toString())); + } catch (error) { + next(error); + } + }); + router.get('/list-users', checkGet(['domain']), async function (req, res, next) { + try { + res.send(await virtualminExec.getUserInfo(req.query.domain.toString())); + } catch (error) { + next(error); + } + }); return router; } \ No newline at end of file diff --git a/src/executor/runner.js b/src/executor/runner.js index 3432c43..c69371a 100644 --- a/src/executor/runner.js +++ b/src/executor/runner.js @@ -326,6 +326,23 @@ export default async function runConfig(config, domain, writer, sandbox = false) firewallStatusCache = false; } break; + case 'sshpass': + if (value === '' || value === 'on') { + await writeLog("$> Changing ssh password login to " + (value || 'on')); + await virtExec("modify-users", { + domain, + 'all-users': true, + 'enable': true, + }); + } else if (value === 'off') { + await writeLog("$> Changing ssh password login to " + value); + await virtExec("modify-users", { + domain, + 'all-users': true, + 'disable': true, + }); + } + break; default: await runConfigCodeFeatures(key, value, writeLog, domaindata, sshExec); break; diff --git a/src/executor/virtualmin.js b/src/executor/virtualmin.js index 01633f7..8027a25 100644 --- a/src/executor/virtualmin.js +++ b/src/executor/virtualmin.js @@ -98,6 +98,83 @@ class VirtualminExecutor { } return result; } + /** + * @param {string} domain + */ + async getDatabaseInfo(domain) { + let r = await virtualminExec.execFormatted("list-databases", { + domain, + multiline: true, + }); + if (process.env.NODE_ENV === 'development') + r = { + code: 0, + stdout: cat('./test/database'), + stderr: '', + } + if (r.code === 255) + throw r; + let data = r.stdout.split('\n'), + result = {}, + neskey = '', + nesval = {}; + for (let line of data) { + line = line.trimEnd(); + if (line.length >= 4 && line[0] === ' ') { + let pair = splitLimit(line.trimStart(), /:/g, 2); + if (pair.length === 2) { + nesval[pair[0]] = pair[1].trimStart(); + } + } else if (line.length >= 1 && !line.includes(' ')) { + if (neskey) { + result[neskey] = nesval; + nesval = {}; + } + neskey = line; + } + } + result[neskey] = nesval; + return result; + } + /** + * @param {string} domain + */ + async getUserInfo(domain) { + let r = await virtualminExec.execFormatted("list-users", { + domain, + multiline: true, + 'include-owner': true, + }); + if (process.env.NODE_ENV === 'development') + r = { + code: 0, + stdout: cat('./test/user'), + stderr: '', + } + if (r.code === 255) + throw r; + let data = r.stdout.split('\n'), + result = {}, + neskey = '', + nesval = {}; + for (let line of data) { + line = line.trimEnd(); + if (line.length >= 4 && line[0] === ' ') { + let pair = splitLimit(line.trimStart(), /:/g, 2); + if (pair.length === 2) { + nesval[pair[0]] = pair[1].trimStart(); + } + } else if (line.length >= 1 && !line.includes(' ')) { + if (neskey) { + result[neskey] = nesval; + nesval = {}; + } + neskey = line; + } + } + result[neskey] = nesval; + return result; + } /** * @param {string} program * @param {object[]} opts diff --git a/src/index.js b/src/index.js index 739b503..76f835a 100644 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,7 @@ dotenv.config(); initUtils(); const app = express(); - +app.set('trust proxy', 'loopback'); app.use(express.static('public')); app.use(express.json()); app.use('/status', status()); diff --git a/sudoutil.js b/sudoutil.js index abbd771..78ebd09 100755 --- a/sudoutil.js +++ b/sudoutil.js @@ -301,7 +301,7 @@ switch (cli.args.shift()) { // just in case if (!sudo.killed) sudo.kill(); - }, 1000 * 60 * 60).unref(); + }, 1000 * 60).unref(); break; case 'SHELL_INTERACTIVE': arg = cli.args.shift();