1use serde::{Deserialize, Serialize};
20use serde_json::Value;
21
22#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(rename_all = "camelCase")]
25pub struct ShieldStatusNotification {
26 pub jsonrpc: String,
28 pub method: String,
30 pub params: ShieldStatusParams,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36#[serde(rename_all = "camelCase")]
37pub struct ShieldStatusParams {
38 pub active: bool,
40 pub enhanced: bool,
42 pub threats: u64,
44 pub threat_rate: f64,
46 #[serde(skip_serializing_if = "Option::is_none")]
48 pub last_threat: Option<LastThreatInfo>,
49 pub performance: PerformanceMetrics,
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(rename_all = "camelCase")]
56pub struct LastThreatInfo {
57 #[serde(rename = "type")]
59 pub threat_type: String,
60 pub severity: ThreatSeverity,
62 pub timestamp: u64,
64 pub description: String,
66}
67
68#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(rename_all = "lowercase")]
71pub enum ThreatSeverity {
72 Low,
73 Medium,
74 High,
75 Critical,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
80#[serde(rename_all = "camelCase")]
81pub struct PerformanceMetrics {
82 pub scan_time_us: u64,
84 pub queue_depth: usize,
86 pub memory_mb: f64,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "camelCase")]
93pub struct ShieldControlRequest {
94 pub action: ShieldControlAction,
96 #[serde(skip_serializing_if = "Option::is_none")]
98 pub duration: Option<u64>,
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
103#[serde(rename_all = "lowercase")]
104pub enum ShieldControlAction {
105 Pause,
107 Resume,
109 Reset,
111 Enhance,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117#[serde(rename_all = "camelCase")]
118pub struct ShieldControlResponse {
119 pub success: bool,
121 pub state: ShieldState,
123 #[serde(skip_serializing_if = "Option::is_none")]
125 pub message: Option<String>,
126}
127
128#[derive(Debug, Clone, Serialize, Deserialize)]
130#[serde(rename_all = "camelCase")]
131pub struct ShieldState {
132 pub active: bool,
134 pub paused: bool,
136 pub enhanced: bool,
138 #[serde(skip_serializing_if = "Option::is_none")]
140 pub pause_until: Option<u64>,
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145#[serde(rename_all = "camelCase")]
146pub struct ShieldInfoParams {
147 #[serde(default)]
149 pub detailed: bool,
150}
151
152#[derive(Debug, Clone, Serialize, Deserialize)]
154#[serde(rename_all = "camelCase")]
155pub struct ShieldInfoResponse {
156 pub version: String,
158 pub state: ShieldState,
160 pub stats: ShieldStatistics,
162 #[serde(skip_serializing_if = "Option::is_none")]
164 pub config: Option<ShieldConfig>,
165 #[serde(skip_serializing_if = "Option::is_none")]
167 pub patterns: Option<Vec<ThreatPattern>>,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct ShieldStatistics {
174 pub threats_blocked: u64,
176 pub threats_by_type: std::collections::HashMap<String, u64>,
178 pub total_scans: u64,
180 pub avg_scan_time_us: u64,
182 pub uptime_seconds: u64,
184 pub memory_usage_mb: f64,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
190#[serde(rename_all = "camelCase")]
191pub struct ShieldConfig {
192 pub sensitivity: String,
194 pub enabled_detectors: Vec<String>,
196 pub rate_limiting: bool,
198 pub max_threat_rate: u64,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
204#[serde(rename_all = "camelCase")]
205pub struct ThreatPattern {
206 pub name: String,
208 #[serde(rename = "type")]
210 pub pattern_type: String,
211 pub enabled: bool,
213 pub detections: u64,
215}
216
217#[derive(Debug, Clone, Serialize, Deserialize)]
219#[serde(rename_all = "camelCase")]
220pub struct ClaudeCodeError {
221 pub code: ClaudeCodeErrorCode,
223 pub message: String,
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub details: Option<Value>,
228}
229
230#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
232pub enum ClaudeCodeErrorCode {
233 ShieldUnavailable = -40001,
235 InvalidAction = -40002,
237 OperationTimeout = -40003,
239 EnhancedModeUnavailable = -40004,
241 RateLimitExceeded = -40005,
243}
244
245#[cfg(feature = "enhanced")]
247#[repr(C, packed)]
248pub struct BinaryMessageHeader {
249 pub magic: u32,
251 pub version: u16,
253 pub msg_type: u16,
255 pub payload_len: u32,
257 pub timestamp: u64,
259 pub sequence: u32,
261 pub checksum: u32,
263}
264
265#[cfg(feature = "enhanced")]
266impl BinaryMessageHeader {
267 pub const MAGIC: u32 = 0x4B475344; pub const VERSION: u16 = 1;
269
270 pub const MSG_TYPE_STATUS: u16 = 1;
271 pub const MSG_TYPE_THREAT: u16 = 2;
272 pub const MSG_TYPE_CONTROL: u16 = 3;
273 pub const MSG_TYPE_PERF: u16 = 4;
274}
275
276pub fn create_status_notification(params: ShieldStatusParams) -> ShieldStatusNotification {
278 ShieldStatusNotification {
279 jsonrpc: "2.0".to_string(),
280 method: "shield/status".to_string(),
281 params,
282 }
283}
284
285pub fn threat_to_severity(threat: &crate::scanner::Threat) -> ThreatSeverity {
287 match &threat.threat_type {
288 crate::scanner::ThreatType::UnicodeInvisible => ThreatSeverity::Medium,
289 crate::scanner::ThreatType::UnicodeBiDi => ThreatSeverity::High,
290 crate::scanner::ThreatType::UnicodeHomograph => ThreatSeverity::Medium,
291 crate::scanner::ThreatType::UnicodeControl => ThreatSeverity::Medium,
292 crate::scanner::ThreatType::PromptInjection => ThreatSeverity::High,
293 crate::scanner::ThreatType::CommandInjection => ThreatSeverity::Critical,
294 crate::scanner::ThreatType::PathTraversal => ThreatSeverity::High,
295 crate::scanner::ThreatType::SqlInjection => ThreatSeverity::Critical,
296 crate::scanner::ThreatType::CrossSiteScripting => ThreatSeverity::High,
297 crate::scanner::ThreatType::LdapInjection => ThreatSeverity::High,
298 crate::scanner::ThreatType::XmlInjection => ThreatSeverity::High,
299 crate::scanner::ThreatType::NoSqlInjection => ThreatSeverity::High,
300 crate::scanner::ThreatType::SessionIdExposure => ThreatSeverity::Critical,
301 crate::scanner::ThreatType::ToolPoisoning => ThreatSeverity::Critical,
302 crate::scanner::ThreatType::TokenTheft => ThreatSeverity::Critical,
303 crate::scanner::ThreatType::DosPotential => ThreatSeverity::High,
304 crate::scanner::ThreatType::Custom(_) => ThreatSeverity::Medium,
305 }
306}
307
308#[cfg(test)]
309mod tests {
310 use super::*;
311
312 #[test]
313 fn test_status_notification_serialization() {
314 let notification = create_status_notification(ShieldStatusParams {
315 active: true,
316 enhanced: false,
317 threats: 42,
318 threat_rate: 2.5,
319 last_threat: Some(LastThreatInfo {
320 threat_type: "unicode_bidi".to_string(),
321 severity: ThreatSeverity::High,
322 timestamp: 1234567890,
323 description: "Right-to-left override detected".to_string(),
324 }),
325 performance: PerformanceMetrics {
326 scan_time_us: 123,
327 queue_depth: 5,
328 memory_mb: 45.6,
329 },
330 });
331
332 let json = serde_json::to_string_pretty(¬ification).unwrap();
333 assert!(json.contains("\"method\": \"shield/status\""));
334 assert!(json.contains("\"threats\": 42"));
335 assert!(json.contains("\"severity\": \"high\""));
336 }
337
338 #[test]
339 fn test_control_request_deserialization() {
340 let json = r#"{
341 "action": "pause",
342 "duration": 5000
343 }"#;
344
345 let request: ShieldControlRequest = serde_json::from_str(json).unwrap();
346 assert_eq!(request.action, ShieldControlAction::Pause);
347 assert_eq!(request.duration, Some(5000));
348 }
349
350 #[cfg(feature = "enhanced")]
351 #[test]
352 fn test_binary_header() {
353 use std::mem;
354
355 assert_eq!(mem::size_of::<BinaryMessageHeader>(), 28);
356 assert_eq!(BinaryMessageHeader::MAGIC, 0x4B475344);
357 }
358}