Files
csm/CLAUDE.md
iven 60ee38a3c2 feat: 新增补丁管理和异常检测插件及相关功能
feat(protocol): 添加补丁管理和行为指标协议类型
feat(client): 实现补丁管理插件采集功能
feat(server): 添加补丁管理和异常检测API
feat(database): 新增补丁状态和异常检测相关表
feat(web): 添加补丁管理和异常检测前端页面
fix(security): 增强输入验证和防注入保护
refactor(auth): 重构认证检查逻辑
perf(service): 优化Windows服务恢复策略
style: 统一健康评分显示样式
docs: 更新知识库文档
2026-04-11 15:59:53 +08:00

175 lines
6.3 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 — 企业终端安全管理系统
> **知识库**: @wiki/index.md — 编译后的模块化知识,新会话加载即了解全貌。
## 项目概览
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/
```