feat: 添加新插件支持及多项功能改进

- 新增磁盘加密、打印审计和剪贴板管控插件支持
- 优化水印插件显示效果,支持中文及更多Unicode字符
- 改进硬件资产收集逻辑,更准确获取磁盘和显卡信息
- 增强API错误处理,添加详细日志记录
- 完善前端界面,新增插件管理页面
- 修复多个UI问题,优化页面过渡效果
- 添加环境变量覆盖配置功能
- 实现插件状态管理API
- 更新文档和变更日志
- 添加安装程序脚本支持
This commit is contained in:
iven
2026-04-10 22:21:05 +08:00
parent 3d39f0e426
commit b5333d8c93
101 changed files with 4487 additions and 661 deletions

172
CLAUDE.md Normal file
View File

@@ -0,0 +1,172 @@
# CSM — 企业终端安全管理系统
## 项目概览
CSM (Client Security Manager) 是一个医院设备终端安全管控平台,采用 C/S + Web 管理面板三层架构。
```
[Web 管理面板] --HTTP/WS--> [Server] --自定义 TCP 二进制协议--> [Client 代理]
Vue3+ElementPlus Axum+SQLite Windows 服务/控制台
端口 9997(dev) HTTP:9998 WS:/ws TCP:9999
```
### Workspace 结构
| Crate | 职责 | 关键技术 |
|-------|------|---------|
| `csm-protocol` | Frame 编解码、MessageType 枚举、payload 结构体 | serde, thiserror |
| `csm-server` | HTTP API、TCP 接入、数据库、WebSocket 推送 | axum, sqlx, JWT, rustls |
| `csm-client` | 设备监控、插件采集、Windows 服务 | tokio, sysinfo, windows-rs |
**依赖方向**: `server``protocol``client`。Server 和 Client 之间不直接依赖。
### 前端
Vue 3 + TypeScript + Vite + Element Plus + Pinia + ECharts。源码在 `web/src/`
---
## 编码规范
### Rust
- 错误处理: `anyhow::Result` 作为顶层返回类型,`thiserror` 定义库级错误枚举
- 日志: 使用 `tracing` (info!/warn!/error!/debug!),禁止 println!
- 序列化: 所有网络传输使用 JSON (`serde + serde_json`)
- 时间: `chrono::Utc::now().to_rfc3339()`,数据库统一用 `datetime('now')`
- Windows-only 代码使用 `#[cfg(target_os = "windows")]` 门控,非 Windows 提供 `Vec::new()` 空实现
- PowerShell 调用使用 `tokio::process::Command` (异步),参数 `-NoProfile -NonInteractive -Command`
### API 响应
统一 `ApiResponse<T>` 信封:`{ success, data, error }`。分页用 `Pagination` 结构体(默认 page=1, page_size=20, 上限 100)。
### 数据库
- 使用 `sqlx` 手写 SQL + 参数绑定 (`.bind()`),绝不拼接 SQL
- INSERT 使用 `ON CONFLICT ... DO UPDATE` 做 upsert
- 迁移只追加,永不修改已有文件
- 外键启用,时间列统一命名 `created_at` / `updated_at` / `reported_at`
### 命名
| 类型 | 约定 | 示例 |
|------|------|------|
| MessageType 枚举 | PascalCase | `WebFilterRuleUpdate` |
| 数据库表 | snake_case | `clipboard_violations` |
| API 路由 | kebab-case | `/api/plugins/web-filter/rules` |
| 环境变量 | CSM_ 前缀 UPPER_SNAKE | `CSM_SERVER`, `CSM_USE_TLS` |
| 客户端插件目录 | snake_case | `clipboard_control/mod.rs` |
---
## 二进制协议
```
MAGIC(4B) + VERSION(1B) + TYPE(1B) + LENGTH(4B) + PAYLOAD(变长)
"CSM\0" 0x01 0x01-0x95 big-endian u32 JSON bytes
```
最大 payload 4MB。MessageType 按插件分块: 0x1x=核心, 0x2x=上网, 0x3x=时长, 0x4x=软件, 0x5x=弹窗, 0x6x=U盘文件, 0x7x=水印/USB策略, 0x8x=插件控制, 0x9x=加密/打印/剪贴板。
---
## 插件开发
### 客户端插件模板
每个客户端插件遵循统一模式:
```rust
// crates/client/src/<plugin>/mod.rs
#[derive(Debug, Clone, Default)]
pub struct PluginConfig { pub enabled: bool, /* ... */ }
pub async fn start(
mut config_rx: watch::Receiver<PluginConfig>,
data_tx: mpsc::Sender<Frame>,
device_uid: String,
) {
let mut config = config_rx.borrow_and_update().clone();
let mut interval = tokio::time::interval(/* ... */);
interval.tick().await;
loop {
tokio::select! {
result = config_rx.changed() => { if result.is_err() { break; } /* 更新 config */ }
_ = interval.tick() => { if !config.enabled { continue; } /* 采集上报 */ }
}
}
}
```
### 新增插件必改文件清单
按顺序检查,每个都必须改:
1. `crates/protocol/src/message.rs` — 添加 MessageType 枚举值 + payload struct
2. `crates/protocol/src/lib.rs` — re-export 新类型
3. `crates/client/src/<plugin>/mod.rs` — 创建插件实现
4. `crates/client/src/main.rs``mod <plugin>`, watch channel, PluginChannels 字段, spawn 任务
5. `crates/client/src/network/mod.rs` — PluginChannels 字段, handle_server_message 分支, handle_plugin_control 分支
6. `crates/server/src/api/plugins/<plugin>.rs` — 创建 API handler
7. `crates/server/src/api/plugins/mod.rs` — mod 声明 + 路由注册
8. `crates/server/src/tcp.rs` — process_frame 新分支 + push_all_plugin_configs 初始推送
9. `crates/server/src/db.rs` — DeviceRepo 新增 DB 操作方法
10. `migrations/NNN_<name>.sql` — 新迁移文件
11. `crates/server/src/main.rs` — include_str! 新迁移
### 配置推送三级作用域
`push_to_targets()` 支持 `global` / `group` / `device`,优先级 device > group > global。
---
## 安全
- JWT access(30min) + refresh(7d) + token family 轮换防重放
- 密码: bcrypt cost=12
- 心跳 HMAC-SHA256 签名验证
- 登录限流: 5 分钟窗口 10 次
- API 路由三层权限: 公开 / 认证 / admin
- HTTP 安全头: CSP, X-Frame-Options, X-Content-Type-Options
- 敏感数据(如剪贴板)只上报元数据 `[N chars]`,不存原文
- 帧速率限制: 100 帧/5秒/连接
---
## 常见陷阱
- **不要忘记 verify_device_uid**: 每个 process_frame 分支必须在处理前验证发送者身份
- **不要在 API 响应中泄露内部错误**: 使用 `ApiResponse::internal_error()` 隐藏详情
- **不要忘记 upsert 中的 updated_at**: INSERT ON CONFLICT DO UPDATE 时必须更新 `updated_at = datetime('now')`
- **不要在新 API handler 中引用不存在的列**: SQL SELECT 的列必须与 migration DDL 完全匹配
- **不要在异步任务中执行阻塞 IO**: PowerShell 用 `tokio::process::Command`
- **断线后清空 stale 数据**: `try_recv` 循环 drain channel
- **新增 payload struct 必须同时在 lib.rs re-export**: 否则其他 crate 无法使用
- **print_audit 等轮询插件必须做去重**: 记录 last_seen_timestamp只上报新事件
---
## 构建与运行
```bash
# 全量构建
cargo build --workspace
cargo build --release --workspace # LTO + strip + size 优化
# 服务端
cargo run -p csm-server # 读取 config.toml
# 客户端 (控制台模式)
cargo run -p csm-client
# 环境变量: CSM_SERVER, CSM_REGISTRATION_TOKEN, CSM_USE_TLS
# 客户端 (Windows 服务)
cargo run -p csm-client -- --install
cargo run -p csm-client -- --uninstall
cargo run -p csm-client -- --service
# 前端
cd web && npm install && npm run dev # dev server :9997
cd web && npm run build # 产物 web/dist/
```