first commit

This commit is contained in:
JohnsonRan
2025-08-12 21:50:58 +08:00
commit 8b9be4bb19
121 changed files with 36497 additions and 0 deletions

View File

@@ -0,0 +1,129 @@
/* eslint-disable no-console,@typescript-eslint/no-explicit-any */
import { NextRequest, NextResponse } from 'next/server';
import { getConfig } from '@/lib/config';
import { db } from '@/lib/db';
export const runtime = 'edge';
// 读取存储类型环境变量,默认 localstorage
const STORAGE_TYPE =
(process.env.NEXT_PUBLIC_STORAGE_TYPE as
| 'localstorage'
| 'redis'
| 'upstash'
| undefined) || 'localstorage';
// 生成签名
async function generateSignature(
data: string,
secret: string
): Promise<string> {
const encoder = new TextEncoder();
const keyData = encoder.encode(secret);
const messageData = encoder.encode(data);
// 导入密钥
const key = await crypto.subtle.importKey(
'raw',
keyData,
{ name: 'HMAC', hash: 'SHA-256' },
false,
['sign']
);
// 生成签名
const signature = await crypto.subtle.sign('HMAC', key, messageData);
// 转换为十六进制字符串
return Array.from(new Uint8Array(signature))
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
}
// 生成认证Cookie带签名
async function generateAuthCookie(username: string): Promise<string> {
const authData: any = {
role: 'user',
username,
timestamp: Date.now(),
};
// 使用process.env.PASSWORD作为签名密钥而不是用户密码
const signingKey = process.env.PASSWORD || '';
const signature = await generateSignature(username, signingKey);
authData.signature = signature;
return encodeURIComponent(JSON.stringify(authData));
}
export async function POST(req: NextRequest) {
try {
// localstorage 模式下不支持注册
if (STORAGE_TYPE === 'localstorage') {
return NextResponse.json(
{ error: '当前模式不支持注册' },
{ status: 400 }
);
}
const config = await getConfig();
// 校验是否开放注册
if (!config.UserConfig.AllowRegister) {
return NextResponse.json({ error: '当前未开放注册' }, { status: 400 });
}
const { username, password } = await req.json();
if (!username || typeof username !== 'string') {
return NextResponse.json({ error: '用户名不能为空' }, { status: 400 });
}
if (!password || typeof password !== 'string') {
return NextResponse.json({ error: '密码不能为空' }, { status: 400 });
}
// 检查是否和管理员重复
if (username === process.env.USERNAME) {
return NextResponse.json({ error: '用户已存在' }, { status: 400 });
}
try {
// 检查用户是否已存在
const exist = await db.checkUserExist(username);
if (exist) {
return NextResponse.json({ error: '用户已存在' }, { status: 400 });
}
await db.registerUser(username, password);
// 添加到配置中并保存
config.UserConfig.Users.push({
username,
role: 'user',
});
await db.saveAdminConfig(config);
// 注册成功设置认证cookie
const response = NextResponse.json({ ok: true });
const cookieValue = await generateAuthCookie(username);
const expires = new Date();
expires.setDate(expires.getDate() + 7); // 7天过期
response.cookies.set('auth', cookieValue, {
path: '/',
expires,
sameSite: 'lax', // 改为 lax 以支持 PWA
httpOnly: false, // PWA 需要客户端可访问
secure: false, // 根据协议自动设置
});
return response;
} catch (err) {
console.error('数据库注册失败', err);
return NextResponse.json({ error: '数据库错误' }, { status: 500 });
}
} catch (error) {
console.error('注册接口异常', error);
return NextResponse.json({ error: '服务器错误' }, { status: 500 });
}
}