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

173 lines
6.2 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.

# 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/
```