feat: send-code before register, dup game_name check, skin hides uid

This commit is contained in:
2026-07-17 00:42:19 +08:00
parent 511d5ab36f
commit 926bcb626b
2 changed files with 80 additions and 39 deletions

View File

@@ -14,15 +14,43 @@ async function getSiteUrl() {
return row?.v || 'http://localhost:3100';
}
router.post('/send-verify-code', async (req, res) => {
try {
const { email } = req.body;
if (!email) return res.status(400).json({ error: '请输入邮箱' });
const code = String(Math.floor(100000 + Math.random() * 900000));
const codeId = uuid();
await query("DELETE FROM captchas WHERE created_at < NOW() - INTERVAL 5 MINUTE");
await query('INSERT INTO captchas(id, question, answer) VALUES (?,?,?)', [codeId, email, code]);
const sent = await sendEmail(email, 'verify_email', {
username: email.split('@')[0], game_name: '', game_uid: '',
verify_link: code,
});
if (!sent) {
await query('DELETE FROM captchas WHERE id = ?', [codeId]);
return res.status(200).json({ code_id: codeId, code, dev: true });
}
res.json({ code_id: codeId, message: '验证码已发送' });
} catch (err) { console.error(err); res.status(500).json({ error: '服务器内部错误' }); }
});
router.post('/register', validateLengths({
username: 20, password: 100, email: 100, game_name: 50, game_uid: 50,
}), async (req, res) => {
try {
const { username, password, email, game_name, game_uid, captcha_id, captcha_answer, source } = req.body;
const { username, password, email, game_name, game_uid, captcha_id, captcha_answer, source, code_id, code } = req.body;
if (!username || !password || !email || !game_name || !game_uid) {
if (!username || !password || !email || !game_name) {
return res.status(400).json({ error: '所有字段均为必填' });
}
if (source === 'netease' && !game_uid) return res.status(400).json({ error: '网易端必须填写UID' });
if (!code_id || !code) return res.status(400).json({ error: '请先完成邮箱验证' });
const codeRow = await getRow("SELECT * FROM captchas WHERE id = ? AND created_at > NOW() - INTERVAL 10 MINUTE", [code_id]);
if (!codeRow || codeRow.answer !== code) return res.status(400).json({ error: '验证码无效或已过期' });
await query('DELETE FROM captchas WHERE id = ?', [code_id]);
if (username.length < 2 || username.length > 20) {
return res.status(400).json({ error: '用户名需2-20个字符' });
}
@@ -45,27 +73,17 @@ router.post('/register', validateLengths({
if (existingUser || existingEmail) {
return res.status(400).json({ error: '用户名或邮箱已被使用' });
}
const hashed = await bcrypt.hash(password, 10);
const verifyCode = String(Math.floor(100000 + Math.random() * 900000));
const verifyExpires = new Date(Date.now() + 30 * 60000).toISOString().replace('T', ' ').slice(0, 19);
await query(
'INSERT INTO users(username, password, email, game_name, game_uid, active, email_verified, verify_token, verify_expires, source) VALUES (?,?,?,?,?,?,?,?,?,?)',
[username, hashed, email, game_name, game_uid, 0, 0, verifyCode, verifyExpires, source || 'netease']
);
const sent = await sendEmail(email, 'verify_email', {
username, game_name, game_uid,
verify_link: verifyCode,
});
if (!sent) {
await query('UPDATE users SET email_verified = 1, active = 1, verify_token = NULL, verify_expires = NULL WHERE username = ?', [username]);
return res.status(201).json({ message: '注册成功SMTP未配置账号已自动激活请直接登录' });
if (game_name && (source || 'netease') === 'netease') {
const dup = await getRow('SELECT id FROM users WHERE game_name = ? AND source = ?', [game_name, source || 'netease']);
if (dup) return res.status(400).json({ error: '该游戏名在此来源下已注册' });
}
res.status(201).json({ message: '注册成功,请查收验证邮件' });
const hashed = await bcrypt.hash(password, 10);
await query(
'INSERT INTO users(username, password, email, game_name, game_uid, active, email_verified, source) VALUES (?,?,?,?,?,?,?,?)',
[username, hashed, email, game_name, game_uid||'', 1, 1, source || 'netease']
);
res.status(201).json({ message: '注册成功,请登录' });
} catch (err) {
console.error('[auth]', err);
res.status(500).json({ error: '服务器内部错误' });