spb/chat-spboucher Public
Private universal chat interface over the OpenRouter ecosystem — 400+ models, branching, streaming, usage tracking. Next.js 16 + SQLite, PWA, deployed on m4m64a at chat.spboucher.ai
TypeScript 78.8%
CSS 15.1%
JavaScript 4.9%
Shell 1.2%
1// Author: Simon-Pierre Boucher2// Contact: contact@spboucher.ai3// Project: chat.spboucher.ai45// Creates or updates the single user. Usage:6// node scripts/set-password.mjs <username> [password]7// If no password is given, a strong one is generated and printed once.89import crypto from "node:crypto";10import path from "node:path";11import fs from "node:fs";12import { createRequire } from "node:module";1314const require = createRequire(import.meta.url);15const Database = require("better-sqlite3");16const { hashSync } = require("@node-rs/argon2");1718const username = process.argv[2];19const password = process.argv[3] ?? crypto.randomBytes(18).toString("base64url");20if (!username) {21 console.error("Usage: node scripts/set-password.mjs <username> [password]");22 process.exit(1);23}2425const dataDir = path.resolve(process.env.CHAT_DATA_DIR || "./data");26fs.mkdirSync(dataDir, { recursive: true });27const db = new Database(path.join(dataDir, "chat.db"));28db.pragma("journal_mode = WAL");2930// Make sure the users table exists even before the app has booted once.31db.exec(`CREATE TABLE IF NOT EXISTS users (32 id TEXT PRIMARY KEY,33 username TEXT NOT NULL UNIQUE,34 password_hash TEXT NOT NULL,35 totp_secret TEXT,36 created_at INTEGER NOT NULL,37 updated_at INTEGER NOT NULL38)`);3940const hash = hashSync(password, { memoryCost: 65536, timeCost: 3, parallelism: 2 });41const now = Date.now();42const existing = db.prepare("SELECT id FROM users WHERE username = ?").get(username);43if (existing) {44 db.prepare("UPDATE users SET password_hash = ?, updated_at = ? WHERE username = ?").run(hash, now, username);45 db.prepare("DELETE FROM sessions WHERE user_id = ?").run(existing.id);46 console.log(`Password updated for "${username}" (all sessions revoked).`);47} else {48 db.prepare(49 "INSERT INTO users (id, username, password_hash, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"50 ).run(crypto.randomUUID(), username, hash, now, now);51 console.log(`User "${username}" created.`);52}53if (!process.argv[3]) {54 console.log(`Generated password (store it now, it is not shown again):\n${password}`);55}56