Files
squid-manager/templates/change_password.html
T
Hermes Agent 4a1d949e41 feat: 完整 Squid Web Manager 平台 - P0-P3 全功能
完整 Web 管理平台,涵盖:

P0 生产加固:
- 会话超时(空闲+绝对) + CSRF 防护 + 登录失败限流
- HTTPS/TLS 证书管理(自签生成/上传/删除/过期提醒)
- SSL Bump (HTTPS 透明代理) 可视化配置
- 配置文件 diff 预览 + 二次确认才写入
- 服务控制二次确认 + 操作期间按钮锁定

P1 运维能力:
- 日志轮转管理(logrotate) + 日志状态监控
- 告警规则(5xx/命中率/磁盘/客户端流量)
- 多 Squid 实例管理 + 一键切换
- squidclient mgr 实时性能指标
- 流量异常检测(突增/大文件/高频小包/新客户端)

P2 日志分析增强:
- 日志持久化到 SQLite + 历史时间范围查询
- 导出 CSV/JSON(日志/KPI/异常/审计)
- GeoIP 地图(Leaflet + ip-api.com 离线可选 GeoLite2)
- 每客户端 24h 趋势图
- 自定义 Squid logformat 解析器

P3 体验锦上添花:
- 暗/亮主题切换(cookie 持久化)
- WebSSH 终端(xterm.js + paramiko)
- 完整审计日志 + 用户管理

技术栈: Flask 3.0 + SQLAlchemy 2.0 + SQLite + Chart.js + Leaflet
总代码量: ~16500 行 (15 Python 模块 + 34 模板 + CSS)
路由数: 73
2026-07-15 10:19:21 +08:00

98 lines
4.0 KiB
HTML

{% extends "base.html" %}
{% block title %}修改密码 - Squid Manager{% endblock %}
{% block content %}
<div class="page-header">
<h1>🔒 修改密码</h1>
</div>
<div class="card">
<form method="post" class="form-narrow" id="change-pw-form">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<div class="form-group">
<label>旧密码</label>
<input type="password" name="old_password" required class="form-input"
autocomplete="current-password">
</div>
<div class="form-group">
<label>新密码 <span class="hint">至少 8 位,含大小写+数字</span></label>
<input type="password" name="new_password" id="new_password" required
class="form-input" autocomplete="new-password" minlength="8">
<div class="pw-strength" id="pw-strength">
<div class="pw-strength-bar"><div class="pw-strength-fill" id="pw-fill"></div></div>
<span class="pw-strength-label" id="pw-label"></span>
<span class="pw-strength-hint" id="pw-hint"></span>
</div>
</div>
<div class="form-group">
<label>确认新密码</label>
<input type="password" name="confirm_password" id="confirm_password" required
class="form-input" autocomplete="new-password">
<div class="pw-match" id="pw-match"></div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">💾 修改</button>
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">取消</a>
</div>
</form>
</div>
{% endblock %}
{% block scripts %}
<script>
const newPw = document.getElementById('new_password');
const confirmPw = document.getElementById('confirm_password');
const fill = document.getElementById('pw-fill');
const label = document.getElementById('pw-label');
const hint = document.getElementById('pw-hint');
const matchEl = document.getElementById('pw-match');
const COLORS = ['#ef4444', '#f59e0b', '#eab308', '#10b981', '#059669'];
const LABELS = ['极弱', '弱', '中', '强', '很强'];
function score(pw) {
if (!pw) return 0;
let s = 0;
if (pw.length >= 8) s++;
if (pw.length >= 12) s++;
if (/[A-Z]/.test(pw) && /[a-z]/.test(pw)) s++;
if (/\d/.test(pw)) s++;
if (/[^A-Za-z0-9]/.test(pw)) s++;
if (pw.toLowerCase() === 'admin' || pw.toLowerCase() === 'password' ||
pw.toLowerCase() === '123456' || pw.toLowerCase() === 'squid' ||
pw.toLowerCase() === 'changeme') s = Math.max(0, s - 2);
return Math.min(4, Math.max(0, s));
}
newPw.addEventListener('input', () => {
const s = score(newPw.value);
fill.style.width = ((s + 1) * 20) + '%';
fill.style.background = COLORS[s];
label.textContent = '强度: ' + LABELS[s];
label.style.color = COLORS[s];
if (s < 2) hint.textContent = '建议 8+ 字符,含大小写+数字+特殊字符';
else if (s < 3) hint.textContent = '可加入特殊字符进一步提升';
else hint.textContent = '密码强度良好';
if (newPw.value && confirmPw.value) checkMatch();
});
confirmPw.addEventListener('input', checkMatch);
function checkMatch() {
if (!confirmPw.value) { matchEl.textContent = ''; return; }
if (newPw.value === confirmPw.value) {
matchEl.textContent = '✓ 两次输入一致';
matchEl.style.color = '#10b981';
} else {
matchEl.textContent = '✗ 两次输入不一致';
matchEl.style.color = '#ef4444';
}
}
</script>
<style>
.pw-strength { margin-top: 8px; font-size: 12px; }
.pw-strength-bar { height: 4px; background: var(--border); border-radius: 2px; overflow: hidden; margin-bottom: 4px; }
.pw-strength-fill { height: 100%; width: 0; background: #ef4444; transition: width 0.2s, background 0.2s; }
.pw-strength-label { font-weight: 600; }
.pw-strength-hint { color: var(--text-muted); margin-left: 8px; }
.pw-match { font-size: 12px; margin-top: 4px; min-height: 16px; }
</style>
{% endblock %}