Files
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

120 lines
5.5 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.
{% extends "base.html" %}
{% block title %}ACL 规则表 - Squid Manager{% endblock %}
{% block content %}
<div class="page-header">
<h1>🚦 ACL 规则表</h1>
<div class="page-actions">
<button onclick="document.getElementById('add-form').style.display='block'; this.scrollIntoView()" class="btn btn-primary btn-small"> 添加 ACL</button>
</div>
</div>
<div class="card" id="add-form" style="display:none;">
<h3 class="card-title">添加新 ACL</h3>
<form method="post" class="inline-form">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<input type="hidden" name="action" value="add">
<div class="filter-grid">
<div class="form-group">
<label>名称 <span class="hint">*</span></label>
<input type="text" name="name" class="form-input" required placeholder="my_network">
</div>
<div class="form-group">
<label>类型 <span class="hint">*</span></label>
<select name="type" class="form-input" required>
{% for code, desc in acl_types %}
<option value="{{ code }}">{{ code }} - {{ desc }}</option>
{% endfor %}
</select>
</div>
<div class="form-group" style="grid-column: span 2;">
<label><span class="hint">(空格分隔多个值)</span></label>
<input type="text" name="values" class="form-input" required placeholder="192.168.1.0/24">
</div>
<div class="form-group" style="grid-column: span 2;">
<label>备注</label>
<input type="text" name="comment" class="form-input" placeholder="可选">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">添加</button>
<button type="button" onclick="document.getElementById('add-form').style.display='none'" class="btn btn-secondary">取消</button>
</div>
</form>
</div>
<div class="card">
<form method="post">
<input type="hidden" name="_csrf" value="{{ csrf_token() }}">
<input type="hidden" name="action" value="save">
<p class="card-desc">共 {{ acls | length }} 条 ACL。修改后点击底部"保存"按钮。</p>
<div class="table-scroll">
<table class="data-table acl-table">
<thead>
<tr>
<th style="width:60px;">#</th>
<th>名称</th>
<th>类型</th>
<th></th>
<th>备注</th>
<th style="width:80px;">删除</th>
</tr>
</thead>
<tbody>
{% for acl in acls %}
<tr>
<td>{{ loop.index }}
<input type="hidden" name="id[]" value="{{ loop.index }}">
</td>
<td><input type="text" name="name[]" value="{{ acl.name }}" class="form-input"></td>
<td>
<select name="type[]" class="form-input">
{% for code, desc in acl_types %}
<option value="{{ code }}" {% if acl.type == code %}selected{% endif %}>{{ code }}</option>
{% endfor %}
</select>
</td>
<td><input type="text" name="values[]" value="{{ acl.values | join(' ') }}" class="form-input"></td>
<td><input type="text" name="comment[]" value="{{ acl.comment }}" class="form-input"></td>
<td>
<button type="button" class="btn btn-danger btn-tiny" onclick="this.closest('tr').remove()">删除</button>
</td>
</tr>
{% endfor %}
{% if not acls %}
<tr><td colspan="6" class="empty-row">暂无 ACL。点击上方"添加 ACL"按钮开始。</td></tr>
{% endif %}
</tbody>
</table>
</div>
{% if acls %}
<div class="form-actions">
<button type="submit" class="btn btn-primary">💾 保存所有 ACL</button>
</div>
{% endif %}
</form>
</div>
<div class="card">
<h3 class="card-title">📖 ACL 类型参考</h3>
<div class="table-scroll">
<table class="data-table">
<thead><tr><th>类型</th><th>说明</th><th>示例</th></tr></thead>
<tbody>
<tr><td><code>src</code></td><td>源 IP / CIDR</td><td>192.168.1.0/24</td></tr>
<tr><td><code>dst</code></td><td>目的 IP / CIDR</td><td>10.0.0.0/8</td></tr>
<tr><td><code>dstdomain</code></td><td>目的域名 (含子域)</td><td>.example.com</td></tr>
<tr><td><code>dstdom_regex</code></td><td>目的域名正则</td><td>^www\.</td></tr>
<tr><td><code>port</code></td><td>目的端口</td><td>80 443</td></tr>
<tr><td><code>method</code></td><td>HTTP 方法</td><td>GET POST</td></tr>
<tr><td><code>proto</code></td><td>协议</td><td>http https ftp</td></tr>
<tr><td><code>time</code></td><td>时间段 (周/时:分)</td><td>MTWHF 09:00-18:00</td></tr>
<tr><td><code>url_regex</code></td><td>URL 正则</td><td>\.mp3$</td></tr>
<tr><td><code>proxy_auth</code></td><td>认证用户</td><td>REQUIRED 或 user1 user2</td></tr>
<tr><td><code>maxconn</code></td><td>每客户端最大连接</td><td>16</td></tr>
<tr><td><code>browser</code></td><td>User-Agent 正则</td><td>Mozilla</td></tr>
</tbody>
</table>
</div>
</div>
{% endblock %}