From 50b1fe512405791c7d1c5dc7780c253711abfd2f Mon Sep 17 00:00:00 2001 From: "Lin, Hung-Shin" Date: Thu, 26 Oct 2023 14:57:58 +0800 Subject: [PATCH] feat: execute files check via docker cli WARNING: possible command injection vunerability. --- packages/container/print.js | 6 ---- server/src/containers/cli.js | 16 +++++++++++ server/src/containers/docker.js | 46 ------------------------------- server/src/game/commandHandler.js | 2 +- 4 files changed, 17 insertions(+), 53 deletions(-) create mode 100644 server/src/containers/cli.js diff --git a/packages/container/print.js b/packages/container/print.js index 7a98bc4..3ad7b29 100644 --- a/packages/container/print.js +++ b/packages/container/print.js @@ -36,12 +36,6 @@ function waitForEnter() { }) } -function waitTime(time) { - return new Promise((resolve) => { - setTimeout(resolve, time) - }) -} - function printLine(content, delay, color) { const printContent = `${colorize(content, color)}${RETURN_SYMBOL}` return new Promise((resolve) => { diff --git a/server/src/containers/cli.js b/server/src/containers/cli.js new file mode 100644 index 0000000..392e949 --- /dev/null +++ b/server/src/containers/cli.js @@ -0,0 +1,16 @@ +import { exec } from 'child_process' + +import { buildFileCheckCmd } from '@linux-odyssey/utils' + +// eslint-disable-next-line import/prefer-default-export +export function checkFiles(id, files) { + return new Promise((resolve) => { + const cmd = buildFileCheckCmd(files) + // WARNING: This is not secure! + exec(`docker exec ${id} ${cmd}`, (error, stdout, stderr) => { + console.log('stdout', stdout) + console.log('stderr', stderr) + resolve(!error) + }) + }) +} diff --git a/server/src/containers/docker.js b/server/src/containers/docker.js index 12b81cd..be652f5 100644 --- a/server/src/containers/docker.js +++ b/server/src/containers/docker.js @@ -1,6 +1,4 @@ -import { PassThrough } from 'stream' import Docker from 'dockerode' -import { buildFileCheckCmd } from '@linux-odyssey/utils' import config from '../config.js' const engine = new Docker() @@ -79,47 +77,3 @@ export async function deleteContainer(id) { } await container.remove() } - -// Utility function to convert a stream to a string -function streamToString(stream) { - const chunks = [] - return new Promise((resolve, reject) => { - stream.on('data', (chunk) => chunks.push(chunk)) - stream.on('error', reject) - stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf8'))) - setTimeout(() => resolve(Buffer.concat(chunks).toString('utf8')), 100) - }) -} - -export async function checkFiles(id, files) { - const container = engine.getContainer(id) - if (!container) { - throw new Error('Container not found') - } - - const cmd = buildFileCheckCmd(files) - console.log(cmd) - const exec = await container.exec({ - AttachStdout: true, - AttachStderr: true, - Cmd: ['sh', '-c', cmd], - }) - const execStream = await exec.start() - const outStream = new PassThrough() - const errStream = new PassThrough() - - console.log('exec started') - - exec.modem.demuxStream(execStream, outStream, errStream) - const [output, errorOutput] = await Promise.all([ - streamToString(outStream), - streamToString(errStream), - ]) - - console.log('output', output, 'errorOutput', errorOutput) - - const execOutput = await exec.inspect() - console.log('exit code', execOutput.ExitCode) - console.log('exit code === 0', execOutput.ExitCode === 0) - return execOutput.ExitCode === 0 -} diff --git a/server/src/game/commandHandler.js b/server/src/game/commandHandler.js index 5fe13c5..4066323 100644 --- a/server/src/game/commandHandler.js +++ b/server/src/game/commandHandler.js @@ -3,7 +3,7 @@ import { FileGraph } from '@linux-odyssey/file-graph' import { Quest } from '@linux-odyssey/models' import { pushToSession } from '../api/socket.js' import SessionHandler from './sessionHandler.js' -import { checkFiles } from '../containers/docker.js' +import { checkFiles } from '../containers/cli.js' // 檢查 pattern 是否符合 input const checkMatch = (pattern, input) => {