Files

42 lines
2.6 KiB
JavaScript

import { config } from 'dotenv'
import { PrismaClient } from '@prisma/client'
import { randomBytes, scryptSync } from 'node:crypto'
import { readFileSync } from 'node:fs'
import { fileURLToPath } from 'node:url'
config({ path: fileURLToPath(new URL('../.env', import.meta.url)), quiet: true })
const prisma = new PrismaClient()
try {
const username = (process.env.SUPPLIED_ADMIN_USERNAME || 'admin').trim()
const password = process.env.SUPPLIED_ADMIN_PASSWORD || `Sp!${randomBytes(12).toString('base64url')}9a`
if (!username || username.length > 64 || password.length < 12 || password.length > 128) {
throw new Error('账号长度需为 1-64,密码长度需为 12-128')
}
const tables = await prisma.$queryRaw`SELECT TABLE_NAME AS name FROM information_schema.TABLES
WHERE TABLE_SCHEMA = DATABASE() AND LOWER(TABLE_NAME) IN ('user', 'cartitem', 'supplied_cart_item')`
const legacyUser = tables.find(row => row.name.toLowerCase() === 'user')
const legacyCart = tables.find(row => row.name.toLowerCase() === 'cartitem')
if (legacyUser) {
const rows = await prisma.$queryRawUnsafe('SELECT COUNT(*) AS count FROM `' + legacyUser.name.replace(/`/g, '``') + '`')
if (Number(rows[0].count) > 0) throw new Error('旧 user 表存在数据,未删除,请先处理原有数据')
}
if (legacyCart) {
if (tables.some(row => row.name.toLowerCase() === 'supplied_cart_item')) throw new Error('新旧购物车表同时存在,未覆盖数据')
await prisma.$executeRawUnsafe('RENAME TABLE `' + legacyCart.name.replace(/`/g, '``') + '` TO `supplied_cart_item`')
}
if (legacyUser) await prisma.$executeRawUnsafe('DROP TABLE `' + legacyUser.name.replace(/`/g, '``') + '`')
await prisma.$executeRawUnsafe(readFileSync(new URL('./sql/supplied-user.sql', import.meta.url), 'utf8').trim().replace(/;$/, ''))
const existing = await prisma.$queryRaw`SELECT id FROM supplied_user WHERE username = ${username} LIMIT 1`
if (existing.length) throw new Error('账号已存在,未覆盖原有密码')
const salt = randomBytes(16).toString('hex')
const hash = scryptSync(password, salt, 64, { N: 32768, r: 8, p: 1, maxmem: 64 * 1024 * 1024 }).toString('hex')
const passwordHash = `scrypt$${salt}$${hash}`
await prisma.$executeRaw`INSERT INTO supplied_user (username, passwordHash, nickname) VALUES (${username}, ${passwordHash}, ${'管理员'})`
console.log(JSON.stringify({ username, password, table: 'supplied_user' }))
} catch (error) {
console.error(error instanceof Error ? error.message : '初始化账号失败')
process.exitCode = 1
} finally {
await prisma.$disconnect()
}