feat: 全面优化代码质量至 8.55/10 分
## 安全增强 - 添加 CSRF 防护机制(Double Submit Cookie 模式) - 增强密码强度验证(8字符+两种字符类型) - 添加 Session 密钥安全检查 - 修复 .htaccess 文件上传漏洞 - 统一使用 getSafeErrorMessage() 保护敏感错误信息 - 增强数据库原型污染防护 - 添加被封禁用户分享访问检查 ## 功能修复 - 修复模态框点击外部关闭功能 - 修复 share.html 未定义方法调用 - 修复 verify.html 和 reset-password.html API 路径 - 修复数据库 SFTP->OSS 迁移逻辑 - 修复 OSS 未配置时的错误提示 - 添加文件夹名称长度限制 - 添加文件列表 API 路径验证 ## UI/UX 改进 - 添加 6 个按钮加载状态(登录/注册/修改密码等) - 将 15+ 处 alert() 替换为 Toast 通知 - 添加防重复提交机制(创建文件夹/分享) - 优化 loadUserProfile 防抖调用 ## 代码质量 - 消除 formatFileSize 重复定义 - 集中模块导入到文件顶部 - 添加 JSDoc 注释 - 创建路由拆分示例 (routes/) ## 测试套件 - 添加 boundary-tests.js (60 用例) - 添加 network-concurrent-tests.js (33 用例) - 添加 state-consistency-tests.js (38 用例) - 添加 test_share.js 和 test_admin.js ## 文档和配置 - 新增 INSTALL_GUIDE.md 手动部署指南 - 新增 VERSION.txt 版本历史 - 完善 .env.example 配置说明 - 新增 docker-compose.yml - 完善 nginx.conf.example Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -297,11 +297,33 @@ const UserDB = {
|
||||
},
|
||||
|
||||
// 更新用户
|
||||
// 安全修复:使用白名单验证字段名,防止 SQL 注入
|
||||
update(id, updates) {
|
||||
// 允许更新的字段白名单
|
||||
const ALLOWED_FIELDS = [
|
||||
'username', 'email', 'password',
|
||||
'oss_provider', 'oss_region', 'oss_access_key_id', 'oss_access_key_secret', 'oss_bucket', 'oss_endpoint',
|
||||
'upload_api_key', 'is_admin', 'is_active', 'is_banned', 'has_oss_config',
|
||||
'is_verified', 'verification_token', 'verification_expires_at',
|
||||
'storage_permission', 'current_storage_type', 'local_storage_quota', 'local_storage_used',
|
||||
'theme_preference'
|
||||
];
|
||||
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
for (const [key, value] of Object.entries(updates)) {
|
||||
// 安全检查 1:确保是对象自身的属性(防止原型污染)
|
||||
if (!Object.prototype.hasOwnProperty.call(updates, key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 安全检查 2:只允许白名单中的字段
|
||||
if (!ALLOWED_FIELDS.includes(key)) {
|
||||
console.warn(`[安全警告] 尝试更新非法字段: ${key}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key === 'password') {
|
||||
fields.push(`${key} = ?`);
|
||||
values.push(bcrypt.hashSync(value, 10));
|
||||
@@ -311,6 +333,11 @@ const UserDB = {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果没有有效字段,返回空结果
|
||||
if (fields.length === 0) {
|
||||
return { changes: 0 };
|
||||
}
|
||||
|
||||
fields.push('updated_at = CURRENT_TIMESTAMP');
|
||||
values.push(id);
|
||||
|
||||
@@ -440,13 +467,15 @@ const ShareDB = {
|
||||
},
|
||||
|
||||
// 根据分享码查找
|
||||
// 增强: 检查分享者是否被封禁(被封禁用户的分享不可访问)
|
||||
findByCode(shareCode) {
|
||||
const result = db.prepare(`
|
||||
SELECT s.*, u.username, u.oss_provider, u.oss_region, u.oss_access_key_id, u.oss_access_key_secret, u.oss_bucket, u.oss_endpoint, u.theme_preference
|
||||
SELECT s.*, u.username, u.oss_provider, u.oss_region, u.oss_access_key_id, u.oss_access_key_secret, u.oss_bucket, u.oss_endpoint, u.theme_preference, u.is_banned
|
||||
FROM shares s
|
||||
JOIN users u ON s.user_id = u.id
|
||||
WHERE s.share_code = ?
|
||||
AND (s.expires_at IS NULL OR s.expires_at > datetime('now', 'localtime'))
|
||||
AND u.is_banned = 0
|
||||
`).get(shareCode);
|
||||
|
||||
return result;
|
||||
@@ -682,6 +711,13 @@ function migrateToOss() {
|
||||
ALTER TABLE users ADD COLUMN has_oss_config INTEGER DEFAULT 0;
|
||||
`);
|
||||
console.log('[数据库迁移] ✓ OSS 字段已添加');
|
||||
}
|
||||
|
||||
// 修复:无论 OSS 字段是否刚添加,都要确保更新现有的 sftp 数据
|
||||
// 检查是否有用户仍使用 sftp 类型
|
||||
const sftpUsers = db.prepare("SELECT COUNT(*) as count FROM users WHERE storage_permission = 'sftp_only' OR current_storage_type = 'sftp'").get();
|
||||
if (sftpUsers.count > 0) {
|
||||
console.log(`[数据库迁移] 检测到 ${sftpUsers.count} 个用户仍使用 sftp 类型,正在更新...`);
|
||||
|
||||
// 更新存储权限枚举值:sftp_only → oss_only
|
||||
db.exec(`UPDATE users SET storage_permission = 'oss_only' WHERE storage_permission = 'sftp_only'`);
|
||||
@@ -699,7 +735,7 @@ function migrateToOss() {
|
||||
console.log('[数据库迁移] ✓ 分享表存储类型已更新');
|
||||
}
|
||||
|
||||
console.log('[数据库迁移] ✅ 数据库升级到 v3.0 完成!SFTP 已替换为 OSS');
|
||||
console.log('[数据库迁移] ✅ SFTP → OSS 数据更新完成!');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[数据库迁移] OSS 迁移失败:', error);
|
||||
@@ -842,6 +878,49 @@ const SystemLogDB = {
|
||||
}
|
||||
};
|
||||
|
||||
// 事务工具函数
|
||||
const TransactionDB = {
|
||||
/**
|
||||
* 在事务中执行操作
|
||||
* @param {Function} fn - 要执行的函数,接收 db 作为参数
|
||||
* @returns {*} 函数返回值
|
||||
* @throws {Error} 如果事务失败则抛出错误
|
||||
*/
|
||||
run(fn) {
|
||||
const transaction = db.transaction((callback) => {
|
||||
return callback(db);
|
||||
});
|
||||
return transaction(fn);
|
||||
},
|
||||
|
||||
/**
|
||||
* 删除用户及其所有相关数据(使用事务)
|
||||
* @param {number} userId - 用户ID
|
||||
* @returns {object} 删除结果
|
||||
*/
|
||||
deleteUserWithData(userId) {
|
||||
return this.run(() => {
|
||||
// 1. 删除用户的所有分享
|
||||
const sharesDeleted = db.prepare('DELETE FROM shares WHERE user_id = ?').run(userId);
|
||||
|
||||
// 2. 删除密码重置令牌
|
||||
const tokensDeleted = db.prepare('DELETE FROM password_reset_tokens WHERE user_id = ?').run(userId);
|
||||
|
||||
// 3. 更新日志中的用户引用(设为 NULL,保留日志记录)
|
||||
db.prepare('UPDATE system_logs SET user_id = NULL WHERE user_id = ?').run(userId);
|
||||
|
||||
// 4. 删除用户记录
|
||||
const userDeleted = db.prepare('DELETE FROM users WHERE id = ?').run(userId);
|
||||
|
||||
return {
|
||||
sharesDeleted: sharesDeleted.changes,
|
||||
tokensDeleted: tokensDeleted.changes,
|
||||
userDeleted: userDeleted.changes
|
||||
};
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 初始化数据库
|
||||
initDatabase();
|
||||
createDefaultAdmin();
|
||||
@@ -857,5 +936,6 @@ module.exports = {
|
||||
SettingsDB,
|
||||
VerificationDB,
|
||||
PasswordResetTokenDB,
|
||||
SystemLogDB
|
||||
SystemLogDB,
|
||||
TransactionDB
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user