Client: - Commit: batch `p4 reopen` so huge changelists (63k+) no longer blow the Windows command-line limit; live "N / total" progress + spinner during commit. - Submit dialog: white arrow, "N of total" + % bar, running file log, Cancel button (aborts pre-commit; changelist stays pending). - Disk scan: streaming reconcile with a live "found N files" counter + Cancel. - Thumbnails: only decode browser-renderable image formats; glyph fallback (+ onError) instead of a broken-image icon for bmp/tga/dds/etc. Landing + waitlist: - waitlist-server: Express + SQLite email collector (dedup) with a secure admin panel (scrypt auth, rate-limited login, signed cookies) and CSV export. - landing form now POSTs signups to the waitlist API. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
38 lines
1.1 KiB
JavaScript
38 lines
1.1 KiB
JavaScript
// Generate an ADMIN_PASS_HASH for .env from a password.
|
|
//
|
|
// node scripts/set-password.js "my super secret"
|
|
// node scripts/set-password.js # prompts (hidden input)
|
|
//
|
|
// Paste the printed line into .env — the plaintext password is never stored.
|
|
|
|
import readline from "node:readline";
|
|
import { hashPassword } from "../lib/auth.js";
|
|
|
|
function ask(question) {
|
|
return new Promise((resolve) => {
|
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
// hide typed characters
|
|
const orig = rl._writeToOutput.bind(rl);
|
|
rl._writeToOutput = (str) => {
|
|
if (str.includes(question)) orig(str);
|
|
else orig("*");
|
|
};
|
|
rl.question(question, (answer) => {
|
|
rl.close();
|
|
process.stdout.write("\n");
|
|
resolve(answer);
|
|
});
|
|
});
|
|
}
|
|
|
|
const argPw = process.argv.slice(2).join(" ").trim();
|
|
const pw = argPw || (await ask("New admin password: "));
|
|
|
|
if (!pw || pw.length < 8) {
|
|
console.error("Password must be at least 8 characters.");
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log("\nAdd this line to your .env:\n");
|
|
console.log(`ADMIN_PASS_HASH=${hashPassword(pw)}\n`);
|