(async () => { const fs = require('fs'); const os = require('os'); const path = require('path'); const pkg = require('./package.json'); const chalk = (await import('chalk')).default; const YAML = require('yaml'); const uuid = require('uuid'); const cp = require('child_process'); let p; function verbose(message) { console.log(chalk.cyan("[snowjail] " + message)); } function info(message) { console.log(chalk.green("[snowjail] " + message)); } function warning(message) { console.log(chalk.yellow("[snowjail] " + message)); } function fatal(message) { console.log(chalk.red("[snowjail] " + message)); process.exit(1); } verbose("Starting Snowjail v" + pkg.version + "..."); warning("Moving to Podman (instead of Docker) is planned before v1.0.0, made sure you have both installed to keep running your applications smoothly"); if (process.argv[2] !== undefined && fs.existsSync(process.argv[2]) && fs.lstatSync(process.argv[2]).isDirectory()) { global.root = path.resolve(process.argv[2]); verbose("Loading from " + root + "..."); } else if (process.argv[2] !== undefined) { if (fs.existsSync(process.argv[2])) { fatal(process.argv[2] + ": not a directory"); } else { fatal(process.argv[2] + ": not found"); } } else { fatal("missing operand"); } if (!fs.existsSync(root + "/snowjail.yml") || (fs.existsSync(root + "/snowjail.yml") && !fs.lstatSync(root + "/snowjail.yml").isFile())) { warning("Config not found, creating a default config file"); try { fs.writeFileSync(root + "/snowjail.yml", fs.readFileSync(__dirname + "/default.yml").toString().replace("$VERSION$", pkg.version)); } catch (e) { fatal("unable to create config: " + e.message); } } try { global.config = YAML.parse(fs.readFileSync(root + "/snowjail.yml").toString()); } catch (e) { fatal("unable to load config: " + e.message); } verbose("Loaded config") verbose("Checking config...") // TODO: Check config for completeness verbose("Locking config file...") if (os.platform() === "darwin") { cp.spawnSync("chflags", ["uchg", root]); } else { cp.spawnSync("chattr", ["+i", root]); } verbose("Creating jail...") let jid = uuid.v4(); let hid = jid.replaceAll("-", ""); let args = ["create", "-h", "snowjail-" + hid, "-v", root + ":/snowjail/" + hid, "--name", "sj-" + jid, "-i", "-t"]; if (config.cpu > 0) { args.push(...["-c", config.cpu]); } if (config.ram > 0) { if (config.enforce_ram) { args.push(...["-m", config.ram * 1048576]); } else { args.push(...["--memory-reservation", config.ram * 1048576]); } } if (config.hardware) { args.push("--privileged"); } for (let port of config.ports) { if (port.match(/^[0-9]{1,5}:[0-9]{1,5}$/g) !== null) { args.push(...["-p", port]); } } args.push(config.image); p = cp.spawnSync("docker", args, { stdio: "inherit" }); if (p.exitCode !== 0 && p.exitCode !== undefined) { fatal("unable to create jail: subprocess finished with non-zero exit code: " + p.exitCode); } verbose("Starting jail...") p = cp.spawnSync("docker", ["start", "sj-" + jid], { stdio: "inherit" }); if (p.exitCode !== 0 && p.exitCode !== undefined) { fatal("unable to start jail: subprocess finished with non-zero exit code: " + p.exitCode); } let index = 1; for (let command of config.commands) { info("Running command " + index + "/" + config.commands.length + ": " + command.join(" ")); p = cp.spawnSync("docker", ["exec", "-i", "-t", "sj-" + jid, ...command], { stdio: "inherit" }); if (p.exitCode !== 0 && p.exitCode !== undefined) { fatal("unable to execute command: subprocess finished with non-zero exit code: " + p.exitCode); } index++; } verbose("Deleting jail...") p = cp.spawnSync("docker", ["stop", "sj-" + jid], { stdio: "inherit" }); if (p.exitCode !== 0 && p.exitCode !== undefined) { fatal("unable to delete jail: subprocess finished with non-zero exit code: " + p.exitCode); } p = cp.spawnSync("docker", ["rm", "sj-" + jid], { stdio: "inherit" }); if (p.exitCode !== 0 && p.exitCode !== undefined) { fatal("unable to delete jail: subprocess finished with non-zero exit code: " + p.exitCode); } verbose("Unlocking config file...") if (os.platform() === "darwin") { cp.spawnSync("chflags", ["nouchg", root]); } else { cp.spawnSync("chattr", ["-i", root]); } })()