|
1 | 1 | import { exec } from "./dependencies.ts"; |
2 | | -import dockerize from "./utils/container.ts"; |
| 2 | +import dockerize, { dockerignore } from "./utils/container.ts"; |
3 | 3 | import DfContentMap from "./types/maps_interface.ts"; |
4 | 4 |
|
5 | 5 | const MEMORY_LIMIT = Deno.env.get("MEMORY_LIMIT"); |
6 | 6 |
|
| 7 | +function shellEscape(input: string, label = "input"): string { |
| 8 | + if (!input) return ""; |
| 9 | + if (input.startsWith("-")) { |
| 10 | + throw new Error(`[scripts] Invalid ${label}: cannot start with a hyphen`); |
| 11 | + } |
| 12 | + const safeCharPattern = /^[a-zA-Z0-9.\-_:/~?=#]+$/; |
| 13 | + |
| 14 | + if (!safeCharPattern.test(input)) { |
| 15 | + throw new Error(`[scripts] Invalid characters in ${label}: ${input}`); |
| 16 | + } |
| 17 | + return input; |
| 18 | +} |
| 19 | + |
| 20 | +async function safeExec(command: string): Promise<void> { |
| 21 | + try { |
| 22 | + await exec(command); |
| 23 | + } catch (error) { |
| 24 | + console.error(`[scripts] exec failed: ${command}`); |
| 25 | + console.error(error); |
| 26 | + throw error; |
| 27 | + } |
| 28 | +} |
| 29 | + |
7 | 30 | async function addScript( |
8 | 31 | document: DfContentMap, |
9 | 32 | env_content: string, |
10 | 33 | static_content: string, |
11 | | - dockerfile_present:string, |
| 34 | + dockerfile_present: string, |
12 | 35 | stack: string, |
13 | 36 | port: string, |
14 | 37 | build_cmds: string, |
15 | 38 | ) { |
| 39 | + const subdomain = shellEscape(document.subdomain, "subdomain"); |
| 40 | + const resource = shellEscape(document.resource, "resource"); |
| 41 | + const safePort = shellEscape(port, "port"); |
| 42 | + const memLimit = shellEscape(MEMORY_LIMIT || "512m", "MEMORY_LIMIT"); |
| 43 | + |
16 | 44 | if (document.resource_type === "URL") { |
17 | | - await exec( |
18 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/automate.sh -u ${document.resource} ${document.subdomain}' > /hostpipe/pipe"`, |
| 45 | + await safeExec( |
| 46 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/automate.sh -u ${resource} ${subdomain}' > /hostpipe/pipe"`, |
19 | 47 | ); |
20 | 48 | } else if (document.resource_type === "PORT") { |
21 | | - await exec( |
22 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/automate.sh -p ${document.resource} ${document.subdomain}' > /hostpipe/pipe"`, |
| 49 | + await safeExec( |
| 50 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/automate.sh -p ${resource} ${subdomain}' > /hostpipe/pipe"`, |
23 | 51 | ); |
24 | 52 | } else if (document.resource_type === "GITHUB" && static_content == "Yes") { |
25 | | - Deno.writeTextFile(`/hostpipe/.env`, env_content); |
26 | | - await exec( |
27 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -s ${document.subdomain} ${document.resource} 80 ${MEMORY_LIMIT}' > /hostpipe/pipe"`, |
| 53 | + await Deno.writeTextFile(`/hostpipe/.env`, env_content); |
| 54 | + await safeExec( |
| 55 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -s ${subdomain} ${resource} 80 ${memLimit}' > /hostpipe/pipe"`, |
28 | 56 | ); |
29 | 57 | } else if (document.resource_type === "GITHUB" && static_content == "No") { |
30 | | - if(dockerfile_present === 'No'){ |
31 | | - const dockerfile = dockerize(stack, port, build_cmds); |
32 | | - Deno.writeTextFile(`/hostpipe/Dockerfile`, dockerfile); |
33 | | - Deno.writeTextFile(`/hostpipe/.env`, env_content); |
34 | | - await exec( |
35 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -g ${document.subdomain} ${document.resource} ${port} ${MEMORY_LIMIT}' > /hostpipe/pipe"`, |
36 | | - ); |
37 | | - }else if(dockerfile_present === 'Yes'){ |
38 | | - |
39 | | - await exec( |
40 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -d ${document.subdomain} ${document.resource} ${port} ${MEMORY_LIMIT}' > /hostpipe/pipe"`, |
| 58 | + if (dockerfile_present === 'No') { |
| 59 | + await Deno.writeTextFile(`/hostpipe/Dockerfile`, dockerize(stack, safePort, build_cmds)); |
| 60 | + await Deno.writeTextFile(`/hostpipe/.dockerignore`, dockerignore(stack)); |
| 61 | + await Deno.writeTextFile(`/hostpipe/.env`, env_content); |
| 62 | + await safeExec( |
| 63 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -g ${subdomain} ${resource} ${safePort} ${memLimit}' > /hostpipe/pipe"`, |
| 64 | + ); |
| 65 | + } else if (dockerfile_present === 'Yes') { |
| 66 | + await safeExec( |
| 67 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/container.sh -d ${subdomain} ${resource} ${safePort} ${memLimit}' > /hostpipe/pipe"`, |
41 | 68 | ); |
42 | 69 | } |
43 | | - |
44 | 70 | } |
45 | 71 | } |
46 | 72 |
|
47 | 73 | async function deleteScript(document: DfContentMap) { |
48 | | - await exec( |
49 | | - `bash -c "echo 'bash ../../src/backend/shell_scripts/delete.sh ${document.subdomain}' > /hostpipe/pipe"`, |
| 74 | + const subdomain = shellEscape(document.subdomain, "subdomain"); |
| 75 | + await safeExec( |
| 76 | + `bash -c "echo 'bash ../../src/backend/shell_scripts/delete.sh ${subdomain}' > /hostpipe/pipe"`, |
50 | 77 | ); |
51 | 78 | } |
52 | 79 |
|
|
0 commit comments