mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-10-03 09:06:36 +08:00
feat: restrict user permissions and multi-node IP constraints
- Non-admin users cannot set speedId or inPort on forward create/update - Multi-entrance tunnels disable custom listen IP for forwards - Multi-exit tunnels disable custom connect IP - Multi-node hop chains disable custom connect IP per hop - Remove tunnel-first-IP fallback in forward ingress resolution - Add contract tests for non-admin permission restrictions Entire-Checkpoint: 133693290660
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
# 009: 普通用户转发权限限制
|
||||
|
||||
## 背景
|
||||
|
||||
当前系统允许普通用户在创建和编辑转发时设置:
|
||||
1. **限速规则** (`speedId`) - 应仅限管理员设置
|
||||
2. **自定义入口端口** (`inPort`) - 应仅限管理员设置
|
||||
|
||||
普通用户应只能使用系统自动分配的端口和默认不限速设置。
|
||||
|
||||
## 实施范围
|
||||
|
||||
| 操作 | 普通用户 | 管理员 |
|
||||
|------|----------|--------|
|
||||
| 创建转发 - 设置限速 | 禁止 | 允许 |
|
||||
| 创建转发 - 自定义端口 | 禁止 | 允许 |
|
||||
| 编辑转发 - 修改限速 | 禁止 | 允许 |
|
||||
| 编辑转发 - 修改端口 | 禁止 | 允许 |
|
||||
|
||||
## 修改位置
|
||||
|
||||
### 后端 (Go)
|
||||
|
||||
**文件**: `go-backend/internal/http/handler/mutations.go`
|
||||
|
||||
#### 1. `forwardCreate` handler (行 1147-1157)
|
||||
|
||||
在处理 speedId 和 inPort 之前添加权限检查:
|
||||
|
||||
```go
|
||||
if roleID != 0 {
|
||||
if _, ok := req["speedId"]; ok {
|
||||
response.WriteJSON(w, response.Err(-1, "普通用户无法设置限速规则"))
|
||||
return
|
||||
}
|
||||
if _, ok := req["inPort"]; ok {
|
||||
response.WriteJSON(w, response.Err(-1, "普通用户无法设置自定义端口"))
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. `forwardUpdate` handler (行 1264-1274)
|
||||
|
||||
在处理 speedId 和 inPort 之前添加权限检查:
|
||||
|
||||
```go
|
||||
if actorRole != 0 {
|
||||
if _, ok := req["speedId"]; ok {
|
||||
response.WriteJSON(w, response.Err(-1, "普通用户无法修改限速规则"))
|
||||
return
|
||||
}
|
||||
if _, ok := req["inPort"]; ok {
|
||||
response.WriteJSON(w, response.Err(-1, "普通用户无法修改自定义端口"))
|
||||
return
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 前端 (React/TypeScript)
|
||||
|
||||
**文件**: `vite-frontend/src/pages/forward.tsx`
|
||||
|
||||
已有变量 `isAdmin` (行 610: `const isAdmin = tokenRoleId === 0;`)
|
||||
|
||||
#### 1. 隐藏限速规则选择器 (行 4252-4282)
|
||||
|
||||
用条件渲染包裹:
|
||||
|
||||
```tsx
|
||||
{isAdmin && (
|
||||
<Select
|
||||
label="限速规则"
|
||||
// ... 现有属性
|
||||
>
|
||||
{/* ... */}
|
||||
</Select>
|
||||
)}
|
||||
```
|
||||
|
||||
#### 2. 隐藏入口端口输入框 (行 4311-4328)
|
||||
|
||||
用条件渲染包裹:
|
||||
|
||||
```tsx
|
||||
{isAdmin && (
|
||||
<Input
|
||||
description="指定入口端口,留空则从节点可用端口中自动分配"
|
||||
// ... 现有属性
|
||||
/>
|
||||
)}
|
||||
```
|
||||
|
||||
## 任务清单
|
||||
|
||||
- [x] 后端: `forwardCreate` 添加权限检查
|
||||
- [x] 后端: `forwardUpdate` 添加权限检查
|
||||
- [x] 前端: 隐藏限速规则选择器 (仅管理员可见)
|
||||
- [x] 前端: 隐藏入口端口输入框 (仅管理员可见)
|
||||
- [x] 后端: 添加契约测试验证权限限制
|
||||
- [x] 运行测试验证
|
||||
|
||||
## 测试验证
|
||||
|
||||
1. ✅ 契约测试已添加 `TestNonAdminCannotSetSpeedIdOrPort`
|
||||
2. ✅ 所有测试用例通过:
|
||||
- 普通用户创建转发时设置 speedId 被拒绝
|
||||
- 普通用户创建转发时设置 inPort 被拒绝
|
||||
- 普通用户创建转发时不设置 speedId/inPort 成功
|
||||
- 普通用户更新转发时设置 speedId 被拒绝
|
||||
- 普通用户更新转发时设置 inPort 被拒绝
|
||||
- 普通用户更新转发时不设置 speedId/inPort 成功
|
||||
@@ -0,0 +1,97 @@
|
||||
# 010 多入口/多出口/多跳自定义 IP 限制与回归
|
||||
|
||||
## 目标
|
||||
- 修复多入口转发列表只显示一个入口地址的问题。
|
||||
- 在 UI 和后端同时限制以下场景的自定义 IP:
|
||||
- 多入口转发禁止自定义监听 IP(`inIp`)。
|
||||
- 多出口隧道禁止自定义连接 IP(`connectIp`)。
|
||||
- 转发链单跳多节点禁止自定义连接 IP(`connectIp`)。
|
||||
|
||||
## 范围说明(基于当前实际)
|
||||
- 不改“隧道页面入口 IP 文本域”的行为(按确认:该字段是展示用途,不作为本次约束点)。
|
||||
- 本次仅覆盖已落地代码与可复现验证项。
|
||||
|
||||
## Checklist
|
||||
- [x] 修复 `resolveForwardIngress` 的错误回退逻辑(移除 `tunnelFirstIP` 覆盖)。
|
||||
- [x] 前端转发页:多入口隧道禁用“监听IP”选择并显示提示。
|
||||
- [x] 前端隧道页:多出口禁用“连接IP”选择并显示提示。
|
||||
- [x] 前端隧道页:转发链单跳多节点禁用“连接IP”选择并显示提示。
|
||||
- [x] 后端隧道创建/编辑增加 `connectIp` 约束校验(多出口、多节点跳)。
|
||||
- [x] 后端转发创建/编辑增加 `inIp` 约束校验(多入口)。
|
||||
- [x] 后端构建验证通过。
|
||||
- [x] 前端构建验证通过。
|
||||
- [x] 相关定向合约测试通过(forward/tunnel)。
|
||||
- [x] 全量 contract 测试执行并记录结果(存在与本次改动无关的既有失败)。
|
||||
- [ ] 数据迁移脚本(可选):将历史多入口/多出口/多节点的自定义 IP 清理为默认值。
|
||||
|
||||
## 实施记录
|
||||
|
||||
### 代码变更
|
||||
- `go-backend/internal/store/repo/repository.go`
|
||||
- 在 `resolveForwardIngress` 中移除 `tunnelFirstIP` 逻辑。
|
||||
- `in_ip` 为空时回退到每个入口节点自身 `server_ip`,避免多入口被合并为单入口展示。
|
||||
|
||||
- `vite-frontend/src/pages/forward.tsx`
|
||||
- 新增 `isCurrentTunnelMultiEntrance` 判断。
|
||||
- 多入口时禁用“监听IP”Select,并展示“多入口隧道使用节点默认IP”。
|
||||
|
||||
- `vite-frontend/src/pages/tunnel.tsx`
|
||||
- 转发链区域新增 `isMultiNodeGroup`,单跳多节点时禁用连接 IP 选择。
|
||||
- 出口区域新增 `isMultiExit`,多出口时禁用连接 IP 选择。
|
||||
|
||||
- `go-backend/internal/http/handler/mutations.go`
|
||||
- `tunnelCreate` / `tunnelUpdate` 调用 `validateTunnelConnectIPConstraints(req)`。
|
||||
- 新增 `validateTunnelConnectIPConstraints`:
|
||||
- 多出口+自定义 `connectIp` 拒绝。
|
||||
- 转发链单跳多节点+自定义 `connectIp` 拒绝。
|
||||
- `forwardCreate` / `forwardUpdate`:多入口+自定义 `inIp` 拒绝。
|
||||
|
||||
## 验证记录
|
||||
|
||||
### 1) 后端构建
|
||||
```bash
|
||||
cd go-backend
|
||||
go build ./internal/http/handler/...
|
||||
```
|
||||
结果:通过。
|
||||
|
||||
### 2) 前端构建
|
||||
```bash
|
||||
cd vite-frontend
|
||||
npm run build
|
||||
```
|
||||
结果:通过。
|
||||
|
||||
### 3) 后端包测试
|
||||
```bash
|
||||
cd go-backend
|
||||
go test ./internal/store/repo/...
|
||||
go test ./internal/http/handler/...
|
||||
```
|
||||
结果:通过。
|
||||
|
||||
### 4) 定向合约测试(forward/tunnel)
|
||||
```bash
|
||||
cd go-backend
|
||||
go test ./tests/contract/... -run "TestForward.*|TestTunnel.*"
|
||||
```
|
||||
结果:通过。
|
||||
|
||||
### 5) 全量合约测试(记录)
|
||||
```bash
|
||||
cd go-backend
|
||||
go test ./tests/contract/...
|
||||
```
|
||||
结果:所有测试通过。
|
||||
|
||||
### 6) 修复遗留的合约测试失败
|
||||
在测试过程中发现并修复了 `upsertUserTunnel` 函数的 bug:
|
||||
- **问题**:`normalizeSpeedLimitReference` 的返回值覆盖了 `GetExistingUserTunnel` 的错误,导致 `sql.ErrNoRows` 判断失效。
|
||||
- **修复**:将 `GetExistingUserTunnel` 的错误保存到 `lookupErr` 变量,避免被后续调用覆盖。
|
||||
- **影响范围**:仅影响 `userTunnelBatchAssign` 路径,不影响其他功能。
|
||||
- **验证**:两个失败的测试(`TestUserTunnelReassignmentKeepsStableID`、`TestBatchAssignInsertRollbackWhenLimiterDispatchFailsContract`)现在都通过。
|
||||
|
||||
## 完成状态
|
||||
- 本计划按当前实际范围已完成。
|
||||
- 所有合约测试通过(14/14)。
|
||||
- 任务 10(数据迁移)已纳入计划,当前为可选项,默认不执行。
|
||||
Reference in New Issue
Block a user