| 1 | /** |
| 2 | * 初始化脚本 - 创建默认用户并生成自动登录 token |
| 3 | * 通过 docker-compose aitoearn-init 服务运行 |
| 4 | */ |
| 5 | |
| 6 | import { MongoClient } from 'mongodb' |
| 7 | import jwt from 'jsonwebtoken' |
| 8 | import { writeFileSync, mkdirSync } from 'fs' |
| 9 | import { dirname } from 'path' |
| 10 | import crypto from 'crypto' |
| 11 | |
| 12 | const MONGO_URI = process.env.MONGO_URI || 'mongodb://admin:password@mongodb:27017' |
| 13 | const JWT_SECRET = process.env.JWT_SECRET || 'change-this-jwt-secret' |
| 14 | const DB_NAME = process.env.DB_NAME || 'aitoearn' |
| 15 | const TOKEN_PATH = process.env.AUTO_LOGIN_TOKEN_PATH || '/data/init/token.txt' |
| 16 | const DEFAULT_EMAIL = 'admin@aitoearn.local' |
| 17 | |
| 18 | async function main() { |
| 19 | const client = new MongoClient(MONGO_URI) |
| 20 | await client.connect() |
| 21 | console.log('Connected to MongoDB') |
| 22 | |
| 23 | const db = client.db(DB_NAME) |
| 24 | const users = db.collection('user') |
| 25 | |
| 26 | let user = await users.findOne({ mail: DEFAULT_EMAIL, isDelete: { $ne: true } }) |
| 27 | |
| 28 | if (!user) { |
| 29 | const now = new Date() |
| 30 | const result = await users.insertOne({ |
| 31 | name: 'Admin', |
| 32 | mail: DEFAULT_EMAIL, |
| 33 | status: 1, |
| 34 | userType: 'CREATOR', |
| 35 | isDelete: false, |
| 36 | score: 0, |
| 37 | usedStorage: 0, |
| 38 | storage: { total: 524288000 }, |
| 39 | locale: 'en-US', |
| 40 | createdAt: now, |
| 41 | updatedAt: now, |
| 42 | }) |
| 43 | user = { _id: result.insertedId, mail: DEFAULT_EMAIL, name: 'Admin' } |
| 44 | |
| 45 | // 生成 popularizeCode(复用后端算法) |
| 46 | const identifier = DEFAULT_EMAIL |
| 47 | const phoneHash = crypto |
| 48 | .createHash('sha256') |
| 49 | .update(identifier) |
| 50 | .digest('hex') |
| 51 | .substring(0, 16) |
| 52 | const combinedSalt = `aitoearn${phoneHash}` |
| 53 | const hash = crypto |
| 54 | .createHash('sha256') |
| 55 | .update(user._id.toString()) |
| 56 | .update(combinedSalt) |
| 57 | .digest('hex') |
| 58 | const numericValue = parseInt(hash.substring(0, 6), 16) |
| 59 | const code = numericValue |
| 60 | .toString(36) |
| 61 | .slice(-5) |
| 62 | .toUpperCase() |
| 63 | .padStart(5, '0') |
| 64 | |
| 65 | await users.updateOne({ _id: user._id }, { $set: { popularizeCode: code } }) |
| 66 | console.log(`Created default user: ${DEFAULT_EMAIL}`) |
| 67 | } else { |
| 68 | console.log(`Found existing user: ${DEFAULT_EMAIL}`) |
| 69 | } |
| 70 | |
| 71 | const token = jwt.sign( |
| 72 | { id: user._id.toString(), mail: user.mail, name: user.name }, |
| 73 | JWT_SECRET, |
| 74 | { expiresIn: '100y' }, |
| 75 | ) |
| 76 | |
| 77 | mkdirSync(dirname(TOKEN_PATH), { recursive: true }) |
| 78 | writeFileSync(TOKEN_PATH, token) |
| 79 | console.log(`Token written to ${TOKEN_PATH}`) |
| 80 | |
| 81 | await client.close() |
| 82 | } |
| 83 | |
| 84 | main().catch((e) => { |
| 85 | console.error(e) |
| 86 | process.exit(1) |
| 87 | }) |
| 88 |