# 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` 信封:`{ 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//mod.rs #[derive(Debug, Clone, Default)] pub struct PluginConfig { pub enabled: bool, /* ... */ } pub async fn start( mut config_rx: watch::Receiver, data_tx: mpsc::Sender, 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//mod.rs` — 创建插件实现 4. `crates/client/src/main.rs` — `mod `, watch channel, PluginChannels 字段, spawn 任务 5. `crates/client/src/network/mod.rs` — PluginChannels 字段, handle_server_message 分支, handle_plugin_control 分支 6. `crates/server/src/api/plugins/.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_.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/ ```