mirror of
https://github.com/dqzboy/Docker-Proxy.git
synced 2026-07-05 23:36:30 +08:00
176 lines
4.9 KiB
JavaScript
176 lines
4.9 KiB
JavaScript
/**
|
|
* 用户服务模块
|
|
*/
|
|
const fs = require('fs').promises;
|
|
const path = require('path');
|
|
const bcrypt = require('bcrypt');
|
|
const logger = require('../logger');
|
|
|
|
const USERS_FILE = path.join(__dirname, '..', 'users.json');
|
|
|
|
// 获取所有用户
|
|
async function getUsers() {
|
|
try {
|
|
const data = await fs.readFile(USERS_FILE, 'utf8');
|
|
return JSON.parse(data);
|
|
} catch (error) {
|
|
if (error.code === 'ENOENT') {
|
|
logger.warn('Users file does not exist, creating default user');
|
|
const defaultUser = {
|
|
username: 'root',
|
|
password: bcrypt.hashSync('admin', 10),
|
|
createdAt: new Date().toISOString(),
|
|
loginCount: 0,
|
|
lastLogin: null
|
|
};
|
|
await saveUsers([defaultUser]);
|
|
return { users: [defaultUser] };
|
|
}
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 保存用户
|
|
async function saveUsers(users) {
|
|
await fs.writeFile(USERS_FILE, JSON.stringify({ users }, null, 2), 'utf8');
|
|
}
|
|
|
|
// 更新用户登录信息
|
|
async function updateUserLoginInfo(username) {
|
|
try {
|
|
const { users } = await getUsers();
|
|
const user = users.find(u => u.username === username);
|
|
|
|
if (user) {
|
|
user.loginCount = (user.loginCount || 0) + 1;
|
|
user.lastLogin = new Date().toISOString();
|
|
await saveUsers(users);
|
|
}
|
|
} catch (error) {
|
|
logger.error('更新用户登录信息失败:', error);
|
|
}
|
|
}
|
|
|
|
// 获取用户统计信息
|
|
async function getUserStats(username) {
|
|
try {
|
|
const { users } = await getUsers();
|
|
const user = users.find(u => u.username === username);
|
|
|
|
if (!user) {
|
|
return { loginCount: '0', lastLogin: '未知', accountAge: '0' };
|
|
}
|
|
|
|
// 计算账户年龄(如果有创建日期)
|
|
let accountAge = '0';
|
|
if (user.createdAt) {
|
|
const createdDate = new Date(user.createdAt);
|
|
const currentDate = new Date();
|
|
const diffTime = Math.abs(currentDate - createdDate);
|
|
const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
|
|
accountAge = diffDays.toString();
|
|
}
|
|
|
|
// 格式化最后登录时间
|
|
let lastLogin = '未知';
|
|
if (user.lastLogin) {
|
|
const lastLoginDate = new Date(user.lastLogin);
|
|
const now = new Date();
|
|
const isToday = lastLoginDate.toDateString() === now.toDateString();
|
|
|
|
if (isToday) {
|
|
lastLogin = '今天 ' + lastLoginDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
} else {
|
|
lastLogin = lastLoginDate.toLocaleDateString() + ' ' + lastLoginDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
|
|
}
|
|
}
|
|
|
|
return {
|
|
username: user.username,
|
|
loginCount: (user.loginCount || 0).toString(),
|
|
lastLogin,
|
|
accountAge
|
|
};
|
|
} catch (error) {
|
|
logger.error('获取用户统计信息失败:', error);
|
|
return { loginCount: '0', lastLogin: '未知', accountAge: '0' };
|
|
}
|
|
}
|
|
|
|
// 创建新用户
|
|
async function createUser(username, password) {
|
|
try {
|
|
const { users } = await getUsers();
|
|
|
|
// 检查用户是否已存在
|
|
if (users.some(u => u.username === username)) {
|
|
throw new Error('用户名已存在');
|
|
}
|
|
|
|
const hashedPassword = bcrypt.hashSync(password, 10);
|
|
const newUser = {
|
|
username,
|
|
password: hashedPassword,
|
|
createdAt: new Date().toISOString(),
|
|
loginCount: 0,
|
|
lastLogin: null
|
|
};
|
|
|
|
users.push(newUser);
|
|
await saveUsers(users);
|
|
|
|
return { success: true, username };
|
|
} catch (error) {
|
|
logger.error('创建用户失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 修改用户密码
|
|
async function changePassword(username, currentPassword, newPassword) {
|
|
try {
|
|
const { users } = await getUsers();
|
|
const user = users.find(u => u.username === username);
|
|
|
|
if (!user) {
|
|
throw new Error('用户不存在');
|
|
}
|
|
|
|
// 验证当前密码
|
|
const isMatch = await bcrypt.compare(currentPassword, user.password);
|
|
if (!isMatch) {
|
|
throw new Error('当前密码不正确');
|
|
}
|
|
|
|
// 验证新密码复杂度(虽然前端做了,后端再做一层保险)
|
|
if (!isPasswordComplex(newPassword)) {
|
|
throw new Error('新密码不符合复杂度要求');
|
|
}
|
|
|
|
// 更新密码
|
|
user.password = await bcrypt.hash(newPassword, 10);
|
|
await saveUsers(users);
|
|
|
|
logger.info(`用户 ${username} 密码已成功修改`);
|
|
} catch (error) {
|
|
logger.error('修改密码失败:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
// 验证密码复杂度 (从 userCenter.js 复制过来并调整)
|
|
function isPasswordComplex(password) {
|
|
// 至少包含1个字母、1个数字和1个特殊字符,长度在8-16位之间
|
|
const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[.,\-_+=()[\]{}|\\;:'"<>?/@$!%*#?&])[A-Za-z\d.,\-_+=()[\]{}|\\;:'"<>?/@$!%*#?&]{8,16}$/;
|
|
return passwordRegex.test(password);
|
|
}
|
|
|
|
module.exports = {
|
|
getUsers,
|
|
saveUsers,
|
|
updateUserLoginInfo,
|
|
getUserStats,
|
|
createUser,
|
|
changePassword
|
|
};
|