mike-backend / backend /scripts /resetLocalAuthPassword.mjs
bardd's picture
Deploy Mike backend-only Space
06671aa verified
Raw History Blame Contribute Delete
2.09 kB
#!/usr/bin/env node
import crypto from "crypto";
import pg from "pg";
const { Pool } = pg;
const SCRYPT_PARAMS = { N: 16384, r: 8, p: 1, maxmem: 64 * 1024 * 1024 };
const SCRYPT_KEYLEN = 32;
const PASSWORD_PREFIX = "scrypt:v1:";
function hashPassword(password) {
const salt = crypto.randomBytes(16);
return new Promise((resolve, reject) => {
crypto.scrypt(password, salt, SCRYPT_KEYLEN, SCRYPT_PARAMS, (err, derived) => {
if (err) {
reject(err);
return;
}
resolve(
`${PASSWORD_PREFIX}${salt.toString("base64url")}:${derived.toString("base64url")}`,
);
});
});
}
async function main() {
const email = process.env.LOCAL_AUTH_EMAIL?.trim().toLowerCase();
const password = process.env.LOCAL_AUTH_PASSWORD;
const revokeSessions = process.env.LOCAL_AUTH_REVOKE_SESSIONS !== "0";
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error("DATABASE_URL is required");
}
if (!email) {
throw new Error("LOCAL_AUTH_EMAIL is required");
}
if (!password || password.length < 8) {
throw new Error("LOCAL_AUTH_PASSWORD must be at least 8 characters");
}
const pool = new Pool({ connectionString: databaseUrl });
const client = await pool.connect();
try {
const passwordHash = await hashPassword(password);
const updateResult = await client.query(
`UPDATE auth.users
SET password_hash = $1, updated_at = now()
WHERE lower(email) = lower($2)
RETURNING id, email`,
[passwordHash, email],
);
if (updateResult.rowCount === 0) {
throw new Error(`No user found for ${email}`);
}
const userId = updateResult.rows[0].id;
if (revokeSessions) {
await client.query(`DELETE FROM auth.sessions WHERE user_id = $1`, [userId]);
}
console.log(`Reset password for ${email}`);
if (revokeSessions) {
console.log("Revoked existing sessions");
}
} finally {
client.release();
await pool.end();
}
}
main().catch((err) => {
console.error(err.message || err);
process.exit(1);
});