Files
yuyx efaa2308eb 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>
2026-01-20 10:45:51 +08:00

289 lines
7.2 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>邮箱验证 - 玩玩云</title>
<link rel="stylesheet" href="libs/fontawesome/css/all.min.css">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
/* 暗色主题(默认) */
:root {
--bg-primary: #0a0a0f;
--bg-secondary: #12121a;
--bg-card: rgba(255, 255, 255, 0.03);
--glass-border: rgba(255, 255, 255, 0.08);
--text-primary: #ffffff;
--text-secondary: rgba(255, 255, 255, 0.6);
--accent-1: #667eea;
--accent-2: #764ba2;
--glow: rgba(102, 126, 234, 0.4);
}
/* 亮色主题 */
.light-theme {
--bg-primary: #f0f4f8;
--bg-secondary: #ffffff;
--bg-card: rgba(255, 255, 255, 0.8);
--glass-border: rgba(102, 126, 234, 0.15);
--text-primary: #1a1a2e;
--text-secondary: rgba(26, 26, 46, 0.7);
--accent-1: #5a67d8;
--accent-2: #6b46c1;
--glow: rgba(90, 103, 216, 0.3);
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: var(--bg-primary);
color: var(--text-primary);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 20px;
}
/* 动态背景 */
body::before {
content: '';
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: -1;
background:
radial-gradient(ellipse at top right, rgba(102, 126, 234, 0.15) 0%, transparent 50%),
radial-gradient(ellipse at bottom left, rgba(118, 75, 162, 0.15) 0%, transparent 50%),
var(--bg-primary);
}
body.light-theme::before {
background:
radial-gradient(ellipse at top right, rgba(102, 126, 234, 0.12) 0%, transparent 50%),
radial-gradient(ellipse at bottom left, rgba(118, 75, 162, 0.12) 0%, transparent 50%),
linear-gradient(135deg, #e0e7ff 0%, #f0f4f8 50%, #fdf2f8 100%);
}
.container {
max-width: 450px;
width: 100%;
}
.card {
background: var(--bg-card);
backdrop-filter: blur(20px);
border: 1px solid var(--glass-border);
border-radius: 20px;
padding: 40px;
text-align: center;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
}
body.light-theme .card {
background: rgba(255, 255, 255, 0.8);
box-shadow: 0 8px 32px rgba(102, 126, 234, 0.1);
}
.logo {
font-size: 48px;
margin-bottom: 20px;
background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.title {
font-size: 24px;
font-weight: 700;
margin-bottom: 10px;
color: var(--text-primary);
}
.subtitle {
color: var(--text-secondary);
margin-bottom: 30px;
font-size: 14px;
}
.status-icon {
font-size: 64px;
margin-bottom: 20px;
}
.status-icon.loading {
color: var(--accent-1);
animation: spin 1s linear infinite;
}
.status-icon.success {
color: #10b981;
}
.status-icon.error {
color: #ef4444;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.message {
font-size: 16px;
margin-bottom: 30px;
line-height: 1.6;
}
.btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 14px 32px;
border-radius: 12px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s;
text-decoration: none;
border: none;
}
.btn-primary {
background: linear-gradient(135deg, var(--accent-1), var(--accent-2));
color: white;
box-shadow: 0 4px 15px var(--glow);
}
.btn-primary:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px var(--glow);
}
.footer {
margin-top: 20px;
color: var(--text-secondary);
font-size: 13px;
}
.footer a {
color: var(--accent-1);
text-decoration: none;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<div class="card">
<div class="logo">
<i class="fas fa-cloud"></i>
</div>
<h1 class="title">邮箱验证</h1>
<p class="subtitle">玩玩云账号激活</p>
<div id="content">
<div class="status-icon loading">
<i class="fas fa-spinner"></i>
</div>
<p class="message">正在验证您的邮箱...</p>
</div>
</div>
<div class="footer">
<a href="index.html"><i class="fas fa-arrow-left"></i> 返回首页</a>
</div>
</div>
<script>
// 加载全局主题
async function loadTheme() {
try {
const res = await fetch('/api/public/theme');
const data = await res.json();
if (data.success && data.theme === 'light') {
document.body.classList.add('light-theme');
}
} catch (e) {
console.warn('[主题加载] 失败,使用默认主题:', e.message);
}
}
// 获取URL参数
function getParam(name) {
const url = new URL(window.location.href);
return url.searchParams.get(name);
}
// HTML 转义函数(防御 XSS
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
// 显示结果
function showResult(success, message, showButton = true) {
const content = document.getElementById('content');
const iconClass = success ? 'success' : 'error';
const iconName = success ? 'fa-check-circle' : 'fa-times-circle';
// 转义用户消息(但允许安全的 HTML 标签如 <br>
const safeMessage = message.replace(/</g, '&lt;').replace(/>/g, '&gt;')
.replace(/&lt;br&gt;/g, '<br>'); // 允许 <br> 标签
let html = `
<div class="status-icon ${iconClass}">
<i class="fas ${iconName}"></i>
</div>
<p class="message">${safeMessage}</p>
`;
if (showButton) {
html += `
<a href="app.html" class="btn btn-primary">
<i class="fas fa-right-to-bracket"></i> 前往登录
</a>
`;
}
content.innerHTML = html;
}
// 验证邮箱
async function verifyEmail() {
const token = getParam('verifyToken') || getParam('token');
if (!token) {
showResult(false, '无效的验证链接,缺少验证令牌');
return;
}
try {
const res = await fetch(`/api/verify-email?token=${encodeURIComponent(token)}`);
const data = await res.json();
if (data.success) {
showResult(true, '邮箱验证成功!<br>您的账号已激活,现在可以登录了。');
} else {
showResult(false, data.message || '验证失败,请重试或联系管理员');
}
} catch (error) {
showResult(false, '网络错误,请检查网络连接后重试');
}
}
// 初始化
loadTheme();
verifyEmail();
</script>
</body>
</html>