178 lines
6.4 KiB
JavaScript
178 lines
6.4 KiB
JavaScript
const { publicUser, findUserByToken } = require("./auth.cjs");
|
|
const { loadDb, saveDb, getSubscription, addUserLog, addGenerationLog } = require("./db.cjs");
|
|
const { sendJson } = require("./http-utils.cjs");
|
|
const { nowIso, createToken, checkPassword, passwordHash, daysRemaining } = require("./security.cjs");
|
|
|
|
function findLoginUser(db, account) {
|
|
const value = String(account || "").trim();
|
|
return db.users.find(user => user.email === value || user.username === value);
|
|
}
|
|
|
|
async function handleAppApi(req, res, pathname, body) {
|
|
const db = loadDb();
|
|
|
|
if (req.method === "GET" && pathname === "/api/system/config/public") {
|
|
sendJson(res, 200, { success: true, config: db.systemConfigs });
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/register") {
|
|
const username = String(body.username || "").trim();
|
|
const email = String(body.email || "").trim();
|
|
const password = String(body.password || "");
|
|
|
|
if (!username || !email || !password) {
|
|
sendJson(res, 200, { success: false, message: "用户名、手机号和密码不能为空" });
|
|
return true;
|
|
}
|
|
|
|
if (db.users.some(user => user.email === email || user.username === username)) {
|
|
sendJson(res, 200, { success: false, message: "用户名或手机号已存在" });
|
|
return true;
|
|
}
|
|
|
|
const isFirstUser = db.users.length === 0;
|
|
const user = {
|
|
id: db.nextUserId++,
|
|
username,
|
|
email,
|
|
password: passwordHash(password),
|
|
role: isFirstUser ? "admin" : "user",
|
|
status: "active",
|
|
points: isFirstUser ? 999999 : 1000,
|
|
is_super_admin: isFirstUser ? 1 : 0,
|
|
owner_admin_id: null,
|
|
invite_code: body.invite_code || null,
|
|
max_devices: 99,
|
|
device_fingerprint: body.device_fingerprint || "",
|
|
created_at: nowIso(),
|
|
updated_at: nowIso(),
|
|
last_login_at: nowIso(),
|
|
last_login_device: body.device_fingerprint || null,
|
|
current_token: "",
|
|
cloud_digital_human_disabled: 0,
|
|
};
|
|
const token = createToken(user.id);
|
|
user.current_token = token;
|
|
db.users.push(user);
|
|
const subscription = getSubscription(db, user.id);
|
|
addUserLog(db, user.id, "register", "本地注册成功", { device_fingerprint: body.device_fingerprint });
|
|
saveDb(db);
|
|
|
|
sendJson(res, 200, {
|
|
success: true,
|
|
token,
|
|
userId: user.id,
|
|
user: publicUser(user),
|
|
subscription,
|
|
message: "本地注册成功",
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/login") {
|
|
const account = body.email || body.username || body.phone;
|
|
const password = String(body.password || "");
|
|
const user = findLoginUser(db, account);
|
|
|
|
if (!user || !checkPassword(password, user.password)) {
|
|
sendJson(res, 200, { success: false, message: "账号或密码错误" });
|
|
return true;
|
|
}
|
|
|
|
if (user.status !== "active") {
|
|
sendJson(res, 200, { success: false, message: "账户已被禁用" });
|
|
return true;
|
|
}
|
|
|
|
const token = createToken(user.id);
|
|
user.current_token = token;
|
|
user.last_login_at = nowIso();
|
|
user.last_login_device = body.device_fingerprint || null;
|
|
const subscription = getSubscription(db, user.id);
|
|
addUserLog(db, user.id, "login", "本地登录成功", { device_fingerprint: body.device_fingerprint });
|
|
saveDb(db);
|
|
|
|
sendJson(res, 200, {
|
|
success: true,
|
|
token,
|
|
user: publicUser(user),
|
|
subscription,
|
|
message: "本地登录成功",
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/verify") {
|
|
const user = findUserByToken(db, body.token);
|
|
if (!user || user.status !== "active") {
|
|
sendJson(res, 200, { valid: false, success: false, message: "Token 无效" });
|
|
return true;
|
|
}
|
|
|
|
const subscription = getSubscription(db, user.id);
|
|
saveDb(db);
|
|
sendJson(res, 200, {
|
|
valid: true,
|
|
success: true,
|
|
payload: { userId: user.id, role: user.role },
|
|
user: publicUser(user),
|
|
subscription,
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/subscription/check") {
|
|
const userId = Number(body.user_id || body.userId);
|
|
const subscription = getSubscription(db, userId);
|
|
const remainingDays = daysRemaining(subscription.expires_at);
|
|
saveDb(db);
|
|
sendJson(res, 200, {
|
|
success: true,
|
|
hasAccess: remainingDays > 0,
|
|
expiresAt: subscription.expires_at,
|
|
remainingDays,
|
|
isExpired: remainingDays <= 0,
|
|
subscription,
|
|
});
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/device/checkin") {
|
|
const userId = Number(body.user_id || body.userId || 0);
|
|
if (userId) {
|
|
const user = db.users.find(item => Number(item.id) === userId);
|
|
if (user) {
|
|
user.device_fingerprint = body.device_fingerprint || user.device_fingerprint || "";
|
|
user.last_login_device = body.device_fingerprint || user.last_login_device || null;
|
|
user.updated_at = nowIso();
|
|
}
|
|
if (body.device_fingerprint && !db.devices.some(item => item.user_id === userId && item.device_fingerprint === body.device_fingerprint)) {
|
|
db.devices.push({ user_id: userId, device_fingerprint: body.device_fingerprint, created_at: nowIso() });
|
|
}
|
|
saveDb(db);
|
|
}
|
|
sendJson(res, 200, { success: true, message: "本地设备校验通过" });
|
|
return true;
|
|
}
|
|
|
|
if (req.method === "POST" && pathname === "/api/user/generation-log") {
|
|
addGenerationLog(
|
|
db,
|
|
body.user_id || body.userId,
|
|
body.type,
|
|
body.detail || body.message || body,
|
|
{ device_fingerprint: body.device_fingerprint },
|
|
);
|
|
saveDb(db);
|
|
sendJson(res, 200, { success: true });
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
module.exports = {
|
|
handleAppApi,
|
|
};
|