- 会话 cookie 增加 Secure 标志;新增 [web].cookie_secure 配置 (默认 true,仅本地 HTTP 调试关闭;缺失字段按安全默认处理) - SMTP/IMAP/POP3 认证接入封禁体系(store.RecordAuthFailure 与 Web 共用 ban_entries):失败计数达 ban.max_fail_attempts 即封禁 IP, 已封禁 IP 拒绝认证,堵住协议层暴力破解 - 附件存储路径遍历防护重写:FullPath 白名单校验(UUID 文件名格式) + baseDir 前缀兜底,非法路径返回错误;Save 扩展名白名单化 - 初始管理员不再使用 admin/admin:密码取 MAILGO_ADMIN_PASSWORD 或 随机生成并打印一次;新增 MustChangePassword 首登强制改密 (管理员重置密码同样触发) - 外发中继默认验证 TLS 证书(保护 AUTH 凭据,防 MITM),直投 MX 保持机会式 TLS;新增 outbound.relay_tls_insecure 开关(默认 false) - 新增安全响应头中间件:HSTS、X-Frame-Options DENY、nosniff、 Referrer-Policy、基础 CSP(frame-ancestors 'none' 防点击劫持, connect-src/form-action 'self' 防数据外泄) - LDAP/OAuth 登录错误统一为通用文案,原始错误只写日志, 不再回显邮箱/内部细节(防用户枚举与信息泄露) - 新增 25 个回归测试:cookie 标志、封禁阈值、路径遍历用例、 中继 TLS 验证(自签证书 STARTTLS 集成)、安全头、OAuth 文案 部署注意:升级后所有会话失效需重新登录;若直接以 HTTP 提供 服务需显式配置 cookie_secure = false。
84 lines
5.1 KiB
HTML
84 lines
5.1 KiB
HTML
{{define "settings"}}
|
|
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
<title>设置 - MailGo</title>
|
|
{{template "styles" .}}
|
|
</head>
|
|
<body class="page-settings">
|
|
{{template "navbar" .}}
|
|
<div class="app-body">
|
|
{{template "sidebar" .}}
|
|
<main class="mail-main settings-main">
|
|
{{if .error}}<div class="alert alert-error">{{.error}}</div>{{end}}
|
|
{{if .success}}<div class="alert alert-success">{{.success}}</div>{{end}}
|
|
{{if .mustChange}}<div class="alert" style="border:1px solid #ffa940;background:#fff7e6;color:#d46b08;border-radius:8px;padding:12px 16px;margin-bottom:16px;font-size:13.5px;">
|
|
⚠️ 首次登录/密码已被重置,请立即修改密码后再继续使用邮箱功能。
|
|
</div>{{end}}
|
|
|
|
<div class="card" style="max-width:720px;">
|
|
<h2 style="font-size:17px;margin-bottom:18px;display:flex;align-items:center;gap:10px;">
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#1677ff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
|
账号信息
|
|
</h2>
|
|
<div style="display:flex;align-items:center;gap:14px;margin-bottom:20px;">
|
|
<span class="avatar" style="width:52px;height:52px;font-size:22px;{{avatarStyle .currentUser.Username}}">{{initial .currentUser.Username}}</span>
|
|
<div>
|
|
<div style="font-size:16px;font-weight:600;">{{.currentUser.Username}}@{{.currentUser.Domain.Name}}</div>
|
|
<div style="color:var(--text-3);font-size:12.5px;margin-top:3px;">
|
|
已用 {{formatBytes .currentUser.UsedBytes}} / 配额 {{formatBytes .currentUser.QuotaBytes}}
|
|
{{if .currentUser.IsAdmin}} · 管理员{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="quota-bar" style="width:100%;" data-used="{{.currentUser.UsedBytes}}" data-quota="{{.currentUser.QuotaBytes}}"><i></i></div>
|
|
</div>
|
|
|
|
<div class="card" style="max-width:720px;">
|
|
<h2 style="font-size:17px;margin-bottom:18px;">修改密码</h2>
|
|
<form method="POST" action="/settings" style="max-width:420px;">
|
|
<div class="form-group">
|
|
<label>当前密码</label>
|
|
<input type="password" name="old_password" required placeholder="请输入当前密码" autocomplete="current-password">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>新密码</label>
|
|
<input type="password" name="new_password" required placeholder="请输入新密码" autocomplete="new-password">
|
|
</div>
|
|
<div class="form-group">
|
|
<label>确认新密码</label>
|
|
<input type="password" name="confirm_password" required placeholder="请再次输入新密码" autocomplete="new-password">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">修改密码</button>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="card" style="max-width:720px;">
|
|
<h2 style="font-size:17px;margin-bottom:10px;">帮助</h2>
|
|
<p style="color:var(--text-2);font-size:13.5px;line-height:1.9;">
|
|
客户端收发信(IMAP / SMTP)配置:<br>
|
|
IMAP 服务器:{{.currentUser.Domain.Name}} 端口 143 / SSL 993<br>
|
|
SMTP 服务器:{{.currentUser.Domain.Name}} 端口 587(提交)/ SSL 465
|
|
</p>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
<script>
|
|
(function () {
|
|
var bar = document.querySelector('.quota-bar[data-quota]');
|
|
if (bar) {
|
|
var used = parseInt(bar.dataset.used, 10) || 0;
|
|
var quota = parseInt(bar.dataset.quota, 10) || 1;
|
|
var pct = Math.min(100, Math.round(used / quota * 100));
|
|
bar.querySelector('i').style.width = pct + '%';
|
|
if (pct >= 90) bar.classList.add('warn');
|
|
if (pct >= 100) bar.classList.add('over');
|
|
}
|
|
})();
|
|
</script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|