#!/usr/bin/env node // Prints a DOCKDECK_OPERATOR_PASSWORD_HASH value ("salt:hash", scrypt, // hex-encoded) for a password read from standard input. Run locally, set the // printed value as an env var, and never place the plaintext in process args. import { randomBytes, scryptSync } from "node:crypto"; if (process.argv.length > 2) { console.error( "Do not pass a password as an argument; provide it on standard input.", ); process.exit(1); } async function readPassword() { if (!process.stdin.isTTY) { let value = ""; for await (const chunk of process.stdin) value += chunk; return value.replace(/[\r\n]+$/, ""); } return new Promise((resolve, reject) => { let value = ""; const finish = (error) => { process.stdin.setRawMode(false); process.stdin.pause(); process.stdin.removeListener("data", onData); process.stderr.write("\n"); if (error) reject(error); else resolve(value); }; const onData = (chunk) => { for (const character of String(chunk)) { if (character === "\u0003") return finish(new Error("Cancelled")); if (character === "\r" || character === "\n") return finish(); if (character === "\u007f" || character === "\b") value = value.slice(0, -1); else value += character; } }; process.stderr.write("Operator password: "); process.stdin.setRawMode(true); process.stdin.setEncoding("utf8"); process.stdin.resume(); process.stdin.on("data", onData); }); } const password = await readPassword(); if (!password) { console.error("Usage: provide the password on standard input."); process.exit(1); } const salt = randomBytes(16).toString("hex"); const hash = scryptSync(password, salt, 32).toString("hex"); console.log(`${salt}:${hash}`);