Some checks failed
Deploy to Cloudflare Workers / deploy (push) Has been cancelled
98 lines
2.6 KiB
JavaScript
98 lines
2.6 KiB
JavaScript
/**
|
|
* Dev/admin: set a user's password without sending email (bypasses 429 rate limits).
|
|
*
|
|
* Requires in .env.local:
|
|
* NEXT_PUBLIC_SUPABASE_URL
|
|
* SUPABASE_SERVICE_ROLE_KEY (Dashboard → Project Settings → API → service_role)
|
|
*
|
|
* Usage:
|
|
* npm run auth:reset-password -- you@example.com YourNewPassword
|
|
*/
|
|
import { createClient } from "@supabase/supabase-js";
|
|
import { readFileSync, existsSync } from "fs";
|
|
import { dirname, join } from "path";
|
|
import { fileURLToPath } from "url";
|
|
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
|
|
function loadEnvLocal() {
|
|
const path = join(root, ".env.local");
|
|
if (!existsSync(path)) return {};
|
|
const env = {};
|
|
for (const line of readFileSync(path, "utf8").split(/\r?\n/)) {
|
|
const trimmed = line.trim();
|
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
const eq = trimmed.indexOf("=");
|
|
if (eq === -1) continue;
|
|
const key = trimmed.slice(0, eq).trim();
|
|
let val = trimmed.slice(eq + 1).trim();
|
|
if (
|
|
(val.startsWith('"') && val.endsWith('"')) ||
|
|
(val.startsWith("'") && val.endsWith("'"))
|
|
) {
|
|
val = val.slice(1, -1);
|
|
}
|
|
env[key] = val;
|
|
}
|
|
return env;
|
|
}
|
|
|
|
const [, , emailArg, passwordArg] = process.argv;
|
|
const email = emailArg?.trim().toLowerCase();
|
|
const password = passwordArg;
|
|
|
|
if (!email || !password) {
|
|
console.error(
|
|
"Usage: npm run auth:reset-password -- <email> <new-password>\n"
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
console.error("Password must be at least 6 characters.");
|
|
process.exit(1);
|
|
}
|
|
|
|
const env = loadEnvLocal();
|
|
const url = env.NEXT_PUBLIC_SUPABASE_URL;
|
|
const serviceKey = env.SUPABASE_SERVICE_ROLE_KEY;
|
|
|
|
if (!url || !serviceKey) {
|
|
console.error(
|
|
"Missing NEXT_PUBLIC_SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY in .env.local"
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
const admin = createClient(url, serviceKey, {
|
|
auth: { autoRefreshToken: false, persistSession: false },
|
|
});
|
|
|
|
const { data: list, error: listError } = await admin.auth.admin.listUsers({
|
|
page: 1,
|
|
perPage: 1000,
|
|
});
|
|
|
|
if (listError) {
|
|
console.error("listUsers failed:", listError.message);
|
|
process.exit(1);
|
|
}
|
|
|
|
const user = list.users.find((u) => u.email?.toLowerCase() === email);
|
|
if (!user) {
|
|
console.error(`No user found with email: ${email}`);
|
|
process.exit(1);
|
|
}
|
|
|
|
const { error: updateError } = await admin.auth.admin.updateUserById(user.id, {
|
|
password,
|
|
});
|
|
|
|
if (updateError) {
|
|
console.error("updateUserById failed:", updateError.message);
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(`Password updated for ${email} (${user.id})`);
|
|
console.log("Sign in at /login/manager or /login/master with the new password.");
|