Files
squid-manager/templates/config_tls.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

162 lines
6.8 KiB
HTML
Raw 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.
{% extends "base.html" %}
{% block title %}TLS 证书 - Squid Manager{% endblock %}
{% block content %}
<div class="page-header">
<h1>🔐 TLS 证书管理</h1>
<div class="page-actions">
<span class="meta-text">共 {{ certs | length }} 个证书 · 目录 <code>{{ cert_dir }}</code></span>
</div>
</div>
<div class="card">
<p class="card-desc">
HTTPS 反代需要 TLS 证书。这里可以一键生成<strong>自签名证书</strong>用于快速测试,
也可以上传由 Let's Encrypt / 商业 CA 签发的正式证书(<code>.pem</code> / <code>.crt</code> + <code>.key</code>)。
<br>
<strong>⚠️ 生产环境强烈建议</strong>: 使用 <code>nginx</code> + <code>Let's Encrypt</code> 反向代理并强制 HTTPS,
而不是把本 Web 平台直接暴露在公网。
</p>
</div>
<div class="card">
<h3 class="card-title">🪄 生成自签名证书</h3>
<p class="card-desc">立即可用的测试证书,有效期可选 (1 ~ 3650 天)。建议仅用于内网 / 临时调试。</p>
<form method="post" action="{{ url_for('config_tls_generate') }}">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<div class="filter-grid">
<div class="form-group">
<label>Common Name (CN) <span class="hint">主机名 / 域名, 例如 proxy.example.com</span></label>
<input type="text" name="common_name" required minlength="1" maxlength="253"
placeholder="proxy.example.com" class="form-input">
</div>
<div class="form-group">
<label>有效期 (天) <span class="hint">默认 365, 最大 3650</span></label>
<input type="number" name="days" value="365" min="1" max="3650" class="form-input">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">🔧 生成自签名证书</button>
</div>
</form>
</div>
<div class="card">
<h3 class="card-title">⬆ 上传证书</h3>
<p class="card-desc">
支持 <code>.pem</code> / <code>.crt</code> / <code>.key</code>。单个文件上限 <strong>1 MB</strong>
上传后请在表中核对<strong>主题 (CN)</strong><strong>到期时间</strong>
</p>
<form method="post" action="{{ url_for('config_tls_upload') }}"
enctype="multipart/form-data">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<div class="form-group">
<label>证书 / 私钥文件 (.pem / .crt / .key)</label>
<input type="file" name="certfile" required accept=".pem,.crt,.key" class="form-input">
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">📤 上传</button>
</div>
</form>
</div>
<div class="card">
<h3 class="card-title">📜 已有证书</h3>
{% if certs %}
<table class="data-table">
<thead>
<tr>
<th>文件名</th>
<th>类型</th>
<th>主题 (CN)</th>
<th>到期</th>
<th>状态</th>
<th>SHA-256 指纹</th>
<th>大小</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{% for c in certs %}
<tr>
<td><code>{{ c.name }}</code></td>
<td>
{% if c.is_key %}
<span class="badge badge-blue">KEY</span>
{% elif c.ext == '.pem' %}
<span class="badge badge-purple">PEM</span>
{% else %}
<span class="badge badge-cyan">CRT</span>
{% endif %}
</td>
<td>
{% if c.parsed_ok and c.cn %}
{{ c.cn }}
{% elif c.parsed_ok %}
<span class="meta-text"></span>
{% else %}
<span class="badge badge-gray">{{ c.parse_error[:30] }}</span>
{% endif %}
</td>
<td>
{% if c.parsed_ok and c.not_after %}
<span title="{{ c.expires_iso }}">{{ c.not_after }}</span>
{% else %}
<span class="meta-text"></span>
{% endif %}
</td>
<td>
{% if c.parsed_ok %}
{% if c.status == 'valid' %}
<span class="badge badge-green">有效 ({{ c.days_remaining }} 天)</span>
{% elif c.status == 'expiring' %}
<span class="badge badge-yellow">即将过期 ({{ c.days_remaining }} 天)</span>
{% elif c.status == 'expired' %}
<span class="badge badge-red">已过期</span>
{% else %}
<span class="badge badge-gray">未知</span>
{% endif %}
{% else %}
<span class="badge badge-gray">未识别</span>
{% endif %}
</td>
<td>
{% if c.sha256 %}
<code class="meta-text" title="{{ c.sha256 }}">{{ c.sha256[:16] }}…</code>
{% else %}
<span class="meta-text"></span>
{% endif %}
</td>
<td>{{ c.size }} B</td>
<td>
<form method="post" action="{{ url_for('config_tls_delete') }}"
style="display:inline;"
onsubmit="return confirm('确认删除证书 {{ c.name }}? 此操作不可恢复。');">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<input type="hidden" name="name" value="{{ c.name }}">
<button type="submit" class="btn btn-small btn-warning">🗑 删除</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<div class="card-empty">
<div class="empty-icon">🔐</div>
<p>暂无证书。先点击上方「生成自签名证书」或上传一个 .pem / .crt 文件。</p>
</div>
{% endif %}
</div>
<div class="card">
<h3 class="card-title">️ 使用提示</h3>
<ul>
<li>所有证书都存储在 <code>{{ cert_dir }}/</code>,文件权限建议 <code>600</code></li>
<li>自签名证书浏览器会提示<strong>不受信任</strong>,仅适合内网 / 临时测试</li>
<li>推荐的正式方案见 README 中的 <strong>TLS / HTTPS 部署指南</strong></li>
<li>删除私钥 (<code>.key</code>) 后,对应的证书将无法继续用于 HTTPS</li>
<li>上传的 .pem 同时包含证书和私钥时,<strong>请确保只有 root 才能访问本目录</strong></li>
</ul>
</div>
{% endblock %}