File size: 2,035 Bytes
06671aa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#!/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 isOperator = process.env.LOCAL_AUTH_OPERATOR === "1";
  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 userId = crypto.randomUUID();

    const existing = await client.query(
      `SELECT id FROM auth.users WHERE lower(email) = lower($1) LIMIT 1`,
      [email],
    );

    if (existing.rows.length > 0) {
      throw new Error(`User already exists for ${email}`);
    }

    await client.query(
      `INSERT INTO auth.users (id, email, password_hash, is_operator)
       VALUES ($1, $2, $3, $4)`,
      [userId, email, passwordHash, isOperator],
    );

    console.log(
      `Created local auth user ${email} (operator=${isOperator ? "yes" : "no"})`,
    );
  } finally {
    client.release();
    await pool.end();
  }
}

main().catch((err) => {
  console.error(err.message || err);
  process.exit(1);
});