Files
Havline/docs/agent-server-form-review.md
T
mrlee 2a0740a60f
CI / verify (push) Canceled after 0s
Docker Release / build-and-push (amd64, linux/amd64) (push) Canceled after 0s
Docker Release / build-and-push (arm64, linux/arm64) (push) Canceled after 0s
GitHub Release / release (push) Canceled after 0s
Docker Release / create-manifest (push) Canceled after 0s
chore(release): 发布 v1.9.2
- 「公网服务端」新增 Nginx 启停控制(Agent 0.15.2,停止带二次确认)
- frps 启动失败不再误报成功,并增强启动诊断
- frps vhost 端口禁止 80/443,避免与 VPS 上 Nginx 冲突
- 旧服务端配置的 tcp_mux / login_fail_exit 默认值补齐
- 新增安全审查、页面布局方案与场景操作文档
2026-10-07 19:26:02 +08:00

171 lines
14 KiB
Markdown
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.
# 公网服务端「添加 / 编辑」弹窗表单合理性分析
> 分析对象:`F:\Fonu-main\havline\web\src\views\AgentView.vue` 中的服务端弹窗(`showServerModal`)
> 重点:**「远程管理」标签**(`serverFormTab === 'remote'`,模板 464–540 行)
> 性质:静态代码审查(未运行、未修改),用于后续评审与改进。
> 结论先行:整体结构清晰、密文回显与插件提示较完善,但**「远程管理」标签的帮助栏与标签页不匹配、表单缺少任何校验、`enabled` 字段无 UI 入口**,属于需要优先修复的合理性问题。
---
## 一、分析对象与背景
- 该弹窗同时用于「添加服务端」和「编辑服务端」(`openServerModal`,1407 行),标题随 `editingServer` 切换。
- 表单分为三个标签页(tabbar,404–406 行):
1. `basic` 基础配置(410 行起):名称/地址/端口/认证(含 OIDC)/描述。
2. `advanced` 高级配置(542 行起):frpc 日志级别、传输协议、TLS、连接调优。
3. `remote` 远程管理(464 行起):frps 服务端参数、管理接口、公网 Agent 接入。
- 三块面板通过 `v-show` 切换,共用一个 `<n-form>`(409 行)和底部单个「保存」按钮(`saveServer`,1603 行)。
- 本次重点分析的「远程管理」标签包含 4 个区块:
- `frps vhost 与域名反代`(466–491)
- `TCP/UDP 端口分配`(493–500)
- `frps 管理接口`(502–521)
- `公网 Agent 管理`(523–540)
---
## 二、表单整体结构观察
| 观察点 | 现状 | 合理性判断 |
| --- | --- | --- |
| 标签顺序 | tabbar 顺序为 基础 / 高级 / 远程;DOM 面板顺序为 basic / remote / advanced(`v-show` 不影响显示,但维护易错位) | 基本可用,但 DOM 与 tab 顺序不一致,改动时易踩坑 |
| 表单校验 | `<n-form label-placement="top" class="proxy-modal__pane" @submit.prevent="saveServer">`,**无 `:model`、无 `:rules`** | ⚠️ 偏弱:`required` 仅显示星号,不产生校验 |
| 提交按钮 | 三页共用底部「保存」,只写数据库 | ⚠️ 与"远端需下发/重启才生效"的语义割裂 |
| 密文字段 | Token / OIDC Secret / Dashboard 密码 / SSH 密码密钥 / Agent Token 统一用 `ConfiguredSecretField` | ✅ 较好,编辑留空保持不变 |
| 危险操作 | 「清除管理密码」「清除证书/密钥/CA」均有独立按钮 | ✅ 较好 |
---
## 三、「远程管理」标签逐区块分析
### 3.1 frps vhost 与域名反代(466–491 行)
字段:HTTP 回源端口 `vhost_http_port`、HTTPS 回源端口 `vhost_https_port`、子域名根 `sub_domain_host`、tcpmux 监听端口 `tcpmux_http_connect_port`、自定义 404 页面 `custom_404_page`、强制 TLS `tls_force`、frps 写文件日志 `frps_log_to_file`、日志保留天数 `frps_log_max_days`。
合理之处:
- 对 80/443 冲突有专门告警(469 行),并解释"应由 Nginx 占用"。
- 提示了"修改后需下发并重启、重新部署规则"的必要性。
问题:
1. **本质是 frps 服务端配置,却归入"远程管理"**:`vhostHTTPPort/vhostHTTPSPort/subDomainHost/tcpmux` 是 frps.toml 的服务端参数,与"是否远程管理"无关;`tls_force`、`frps_log_*` 同样是 frps 服务端行为。标签命名与内容职责不匹配。
2. **端口冲突无校验**:只对 `==80/443` 告警,未校验 `vhost_http_port` 与 `vhost_https_port`、`server_port`(默认 7000)、`dashboard_port`、`tcpmux_http_connect_port` 之间的重复。
3. **`tls_force` 与高级标签的 `tls_enabled` 无联动**:类型注释已写明"frpc 必须开 transport.tls.enable"(types.ts 405 行),但两字段分属不同标签、互不校验,配置成 `tls_force=true` + `tls_enabled=false` 时连接会失败。
4. **默认值呈现不一致**:placeholder 写"默认 8080/8443",但 `defaultServerOptions()`(1291 行)**不包含** `vhost_http_port/vhost_https_port/sub_domain_host/tcpmux_http_connect_port/custom_404_page/tls_force/frps_log_to_file/frps_log_max_days/allow_ports/max_ports_per_client`,新增服务端时这些字段为 `undefined`。
5. **`custom_404_page` 无格式/存在性校验**(VPS 本地路径只能靠后端报错)。
6. **`sub_domain_host` 的依赖关系未提示校验**(规则用 subdomain 时才生效,属跨模块依赖)。
### 3.2 TCP/UDP 端口分配(493–500 行)
字段:`allow_ports`(端口白名单)、`max_ports_per_client`。
- 说明文字较准确(区分 vhost 回源端口不在此限制、需云安全组与主机防火墙放行)。
- 问题:`allow_ports` 为纯文本,格式(`6000,6005-6010`)无前端校验,错误只会在后端/下发阶段暴露;`max_ports_per_client` 允许 0(不限)与 `n-input-number` 默认空值语义需要靠文案理解。
### 3.3 frps 管理接口(502–521 行)
字段:`dashboard_addr`、`dashboard_port`、`dashboard_user`、`dashboard_password`(密文)+「清除管理密码」。
- 说明清楚地区分了"仅用于 Havline 拉取流量,与连接认证无关"。
- 问题:
1. **成对字段无关联校验**:只填 `dashboard_port` 不填 `dashboard_addr`(或反之)时无提示,仅静默不采集。
2. 该区块与「远程管理」标签主题(Agent/远程)关联度弱,它其实是 frps 的可观测性配置。
### 3.4 公网 Agent 管理(523–540 行)
字段:`agent_url`、`agent_token`、`ssh_host`、`ssh_port`、`ssh_user`、`ssh_auth`(key/password)、`ssh_secret`、「启用 Agent 日常管理」`mgmt_enabled`;编辑且已配置时额外显示「测试连接 / 下发 frps 配置 / 查看服务端详情」。
合理之处:
- 明确"首次安装/升级需 SSH,日常走 Agent API";SSH 仅用于生命周期与隧道。
- 三个快捷操作按钮对编辑态友好。
问题:
1. **`agent_url` placeholder 与实际安全模型冲突**:示例 `http://vps.example.com:7700`(525 行)鼓励公网明文 HTTP,而页面自身文案强调"不会默认暴露公网 7700"(244 行),且默认推荐 SSH 隧道 / HTTPS 固定。示例具有误导性。
2. **SSH 字段无完整性校验**:填了 `ssh_host` 但缺 `ssh_user`/`ssh_secret`、或 `ssh_auth=key` 却粘贴密码时,无前端提示,失败延后到安装阶段。
3. **`ssh_secret` 文案不随 `ssh_auth` 切换**:始终为"SSH 密码/私钥",用户需自行判断格式。
4. **`mgmt_enabled=true` 但 `agent_url` 为空**的冲突组合无提示。
5. **弹窗内「下发 frps 配置」(539 行)用的是已保存数据**:`pushAgentConfig(editingServer)` 以服务端 id 触发,后端按已存库配置生成;若用户在同一弹窗内刚改了 vhost/端口(尚未保存),点它下发的是**旧配置**,与"修改后需下发"的预期相悖。
---
## 四、合理性问题清单(按优先级)
### P0(建议优先修复)
1. **「远程管理」帮助栏串台(明确缺陷)**
- `serverHelpItems`(1307 行)只对 `advanced` 分支;`remote` 落入默认分支,展示的是**基础配置**的说明(基本信息/认证方式/frps 管理接口/描述)。
- 帮助栏标题 `serverFormTab === 'basic' ? '配置说明' : '高级配置说明'`(601 行):`remote` 标签显示"高级配置说明"。
- `serverHelpTip`(1323 行)对 `remote` 返回通用兜底文案。
- 结果:用户在「远程管理」标签看到的右侧说明与其所在标签完全不符。
2. **表单无任何校验**(409、1603 行)
- 无 `:model`/`:rules`;`saveServer` 直接提交。缺:名称/主机地址必填、端口有效、**创建时 token 认证令牌为空**、dashboard 成对、SSH 完整性、端口冲突等。
3. **`enabled` 字段无 UI 入口**
- `serverForm.enabled` 在 reactive(1300 行)与 payload(1611 行)中存在,但**三个标签页均无绑定输入**,添加/编辑恒为 `true`。用户无法在表单中停用服务端。
### P1(影响体验/正确性)
4. 跨字段、跨标签冲突无校验(端口重复;`tls_force` ↔ `tls_enabled`;`sub_domain_host` 依赖)。
5. 保存与"下发/重启"语义混用;弹窗内「下发 frps 配置」可能下发未保存前的旧配置。
6. **过时文案**:多处提示"在「内网穿透」页服务端表单…填写"(244、310 行),但服务端表单已于 2026-09-24 迁入本页(AgentView),指引指向错误。
7. `agent_url` 示例鼓励公网明文 HTTP,与页面安全模型矛盾。
8. `dashboard_port`/`tcpmux` 的 0/空语义依赖文案,无强制。
### P2(可优化)
9. 「远程管理」混合了 frps 服务端参数、管理接口、Agent 接入三类关注点,标签命名与内容不符;建议拆分或重命名为"服务端与 Agent"。
10. `defaultServerOptions()` 未覆盖远程标签字段,新增时 `undefined`,`n-switch`(`tls_force`/`frps_log_to_file`)可能收到 `undefined`。
11. 高级标签用 collapse 收纳密集字段,远程标签 4 区块 ~18 字段平铺,密度管理不一致。
12. `frps_log_max_days`(远程)与 `log_max_days`(高级/frpc)命名相近、分属不同标签,易混。
13. `custom_404_page`、`allow_ports` 无格式校验。
---
## 五、「远程管理」字段级对照表
| 字段(绑定) | 标签 | 控件 | 主要问题 | 建议 |
| --- | --- | --- | --- | --- |
| `options.vhost_http_port` | HTTP 回源端口 | number | 端口冲突未校验;无默认值 | 与相关端口做唯一性校验;补充默认值 |
| `options.vhost_https_port` | HTTPS 回源端口 | number | 同上;`tls_force` 联动缺失 | 同上;联动 TLS 校验 |
| `options.sub_domain_host` | 子域名根 | text | 依赖关系未提示 | 增加格式校验与说明 |
| `options.tcpmux_http_connect_port` | tcpmux 监听端口 | number | "存在 tcpmux 规则时必填"无强制 | 按规则类型动态必填 |
| `options.custom_404_page` | 自定义 404 页面 | text | 无路径校验 | 格式提示/后端预校验 |
| `options.tls_force` | 强制 TLS | switch | 与 frpc `tls_enabled` 无联动 | 跨标签联动校验/提示 |
| `options.frps_log_to_file` | frps 写文件日志 | switch | 默认 undefined | 纳入 defaultServerOptions |
| `options.frps_log_max_days` | 日志保留天数 | number | 与 frpc `log_max_days` 易混 | 明确命名/分组 |
| `options.allow_ports` | 端口白名单 | text | 无格式校验 | 正则校验 `\d+(-\d+)?(,\d+(-\d+)?)*` |
| `options.max_ports_per_client` | 每客户端端口上限 | number | 0=不限需文案 | 保留,补 hint |
| `options.dashboard_addr` | 管理地址 | text | 与 port 不成对校验 | 成对校验 |
| `options.dashboard_port` | 管理端口 | number | 同上 | 成对校验 |
| `options.dashboard_user` | 管理用户 | text | — | — |
| `serverForm.dashboard_password` | 管理密码 | 密文 | — | — |
| `serverForm.agent_url` | Agent API 地址 | text | 示例误导;无格式校验 | 改为隧道/HTTPS 示例;URL 校验 |
| `serverForm.agent_token` | Agent Token | 密文 | — | — |
| `serverForm.ssh_host` | SSH 地址 | text | 无完整性依赖校验 | 完整性校验 |
| `serverForm.ssh_port` | SSH 端口 | number | — | — |
| `serverForm.ssh_user` | SSH 用户 | text | 同上 | 完整性校验 |
| `serverForm.ssh_auth` | SSH 认证 | select | 未联动 `ssh_secret` 文案 | 随选择切换文案/校验 |
| `serverForm.ssh_secret` | SSH 密码/私钥 | 密文 | 同上 | 按认证方式校验格式 |
| `serverForm.mgmt_enabled` | 启用 Agent 日常管理 | switch | 与 `agent_url` 空值冲突 | 联动提示 |
| `serverForm.enabled` | (无标签) | 无 | **无 UI 入口** | 暴露或移除 |
---
## 六、改进建议
1. **修正帮助栏(低成本、高收益)**:为 `remote` 增加独立说明项集合;帮助栏标题改为按标签映射(如 `basic→配置说明 / advanced→高级配置说明 / remote→远程管理说明`)。
2. **引入表单校验**:给 `<n-form>` 加 `:model` + `:rules`(或提交前手工校验),至少覆盖:名称/主机地址必填、端口范围、创建时 Token 认证必填、dashboard 成对、SSH 三件套完整、端口冲突、`allow_ports` 格式。
3. **处理 `enabled`**:在基础配置补充"启用服务端"开关,或从表单与 payload 中移除。
4. **跨字段联动**:`tls_force` ↔ `tls_enabled`、`ssh_auth` ↔ `ssh_secret`、`mgmt_enabled` ↔ `agent_url`、端口唯一性。
5. **明确保存/生效语义**:保存后如涉及 frps 参数变更,给出"需下发并重启"的显式提示;或将「下发 frps 配置」改为先保存再下发,避免下发旧配置。
6. **修正过时文案**:将"在「内网穿透」页服务端表单…"改为"本页表单…"(244、310 行)。
7. **重排/重命名远程标签**:按"frps 服务端参数 / 可观测性(管理接口) / Agent 接入"折叠分组;标签可命名为"服务端与 Agent"。补齐 `defaultServerOptions()` 的远程字段默认值。
8. **示例文案**:`agent_url` placeholder 改为 SSH 隧道本地地址或 HTTPS 固定示例,并注明不推荐公网明文。
---
## 七、附:类型定义对照
`FrpServerOptions`(`web/src/api/types.ts` 395–450 行)中与「远程管理」相关的字段均已定义,并有中文注释(如 `tls_force` 注明"frpc 必须开 transport.tls.enable"、`dashboard_*` 注明"仅用于拉取只读信息")。前端表单字段与类型基本一致,主要缺口在**校验、默认值、帮助文案与字段归置**,而非类型缺失。
> 本文档为静态分析结论,具体以 `AgentView.vue` 源码为准;建议评审确认后再实施改动。