import { neon } from "@neondatabase/serverless";
function generateToken(): string {
const bytes = crypto.getRandomValues(new Uint8Array(32));
return (
"glc_" +
Array.from(bytes)
.map((b) => b.toString(16).padStart(2, "0"))
.join("")
);
}
async function hashToken(token: string): Promise<string> {
const data = new TextEncoder().encode(token);
const hash = await crypto.subtle.digest("SHA-256", data);
return Array.from(new Uint8Array(hash))
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
async function main() {
const url = process.env.DATABASE_URL;
if (!url) {
console.error("DATABASE_URL is not set.");
process.exit(1);
}
const sql = neon(url);
const requestedUser = process.env.EMERGENCY_PAT_USER?.trim();
let userRow: { id: string; username: string } | undefined;
if (requestedUser) {
const rows = (await sql`
SELECT id, username FROM users WHERE LOWER(username) = LOWER(${requestedUser}) LIMIT 1
`) as Array<{ id: string; username: string }>;
userRow = rows[0];
} else {
const rows = (await sql`
SELECT id, username FROM users WHERE is_admin = true ORDER BY created_at ASC LIMIT 1
`) as Array<{ id: string; username: string }>;
userRow = rows[0];
}
if (!userRow) {
const all = (await sql`
SELECT username, email, is_admin, created_at
FROM users ORDER BY created_at ASC LIMIT 30
`) as Array<{
username: string; email: string; is_admin: boolean; created_at: Date;
}>;
console.error("");
console.error(
requestedUser
? `No user matched "${requestedUser}". Users in this DB:`
: "No admin user. All users in this DB:"
);
console.error("");
for (const u of all) {
console.error(
` ${u.username.padEnd(24)} ${u.email.padEnd(40)} admin=${u.is_admin}`
);
}
console.error("");
console.error(
"Re-run with EMERGENCY_PAT_USER=<exact-username-from-above>"
);
process.exit(1);
}
const token = generateToken();
const tokenHash = await hashToken(token);
const tokenPrefix = token.slice(0, 12);
await sql`
INSERT INTO api_tokens (user_id, name, token_hash, token_prefix, scopes)
VALUES (${userRow.id}, 'emergency-deploy-fix', ${tokenHash}, ${tokenPrefix}, 'admin')
`;
console.log("");
console.log(`User: ${userRow.username}`);
console.log(`Token: ${token}`);
console.log("");
console.log("Copy the token NOW (only shown once). Then run these two:");
console.log("");
console.log(` git remote set-url gluecron "https://${userRow.username}:${token}@gluecron.com/ccantynz/Gluecron.com.git"`);
console.log(" git push gluecron main");
process.exit(0);
}
main().catch((err) => {
console.error("Failed:", err);
process.exit(1);
});
|