use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldStatusNotification {
pub jsonrpc: String,
pub method: String,
pub params: ShieldStatusParams,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldStatusParams {
pub active: bool,
pub enhanced: bool,
pub threats: u64,
pub threat_rate: f64,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_threat: Option<LastThreatInfo>,
pub performance: PerformanceMetrics,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct LastThreatInfo {
#[serde(rename = "type")]
pub threat_type: String,
pub severity: ThreatSeverity,
pub timestamp: u64,
pub description: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ThreatSeverity {
Low,
Medium,
High,
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PerformanceMetrics {
pub scan_time_us: u64,
pub queue_depth: usize,
pub memory_mb: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldControlRequest {
pub action: ShieldControlAction,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<u64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum ShieldControlAction {
Pause,
Resume,
Reset,
Enhance,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldControlResponse {
pub success: bool,
pub state: ShieldState,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldState {
pub active: bool,
pub paused: bool,
pub enhanced: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub pause_until: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldInfoParams {
#[serde(default)]
pub detailed: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldInfoResponse {
pub version: String,
pub state: ShieldState,
pub stats: ShieldStatistics,
#[serde(skip_serializing_if = "Option::is_none")]
pub config: Option<ShieldConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub patterns: Option<Vec<ThreatPattern>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldStatistics {
pub threats_blocked: u64,
pub threats_by_type: std::collections::HashMap<String, u64>,
pub total_scans: u64,
pub avg_scan_time_us: u64,
pub uptime_seconds: u64,
pub memory_usage_mb: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ShieldConfig {
pub sensitivity: String,
pub enabled_detectors: Vec<String>,
pub rate_limiting: bool,
pub max_threat_rate: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ThreatPattern {
pub name: String,
#[serde(rename = "type")]
pub pattern_type: String,
pub enabled: bool,
pub detections: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ClaudeCodeError {
pub code: ClaudeCodeErrorCode,
pub message: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub details: Option<Value>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ClaudeCodeErrorCode {
ShieldUnavailable = -40001,
InvalidAction = -40002,
OperationTimeout = -40003,
EnhancedModeUnavailable = -40004,
RateLimitExceeded = -40005,
}
#[cfg(feature = "enhanced")]
#[repr(C, packed)]
pub struct BinaryMessageHeader {
pub magic: u32,
pub version: u16,
pub msg_type: u16,
pub payload_len: u32,
pub timestamp: u64,
pub sequence: u32,
pub checksum: u32,
}
#[cfg(feature = "enhanced")]
impl BinaryMessageHeader {
pub const MAGIC: u32 = 0x4B475344; pub const VERSION: u16 = 1;
pub const MSG_TYPE_STATUS: u16 = 1;
pub const MSG_TYPE_THREAT: u16 = 2;
pub const MSG_TYPE_CONTROL: u16 = 3;
pub const MSG_TYPE_PERF: u16 = 4;
}
pub fn create_status_notification(params: ShieldStatusParams) -> ShieldStatusNotification {
ShieldStatusNotification {
jsonrpc: "2.0".to_string(),
method: "shield/status".to_string(),
params,
}
}
pub fn threat_to_severity(threat: &crate::scanner::Threat) -> ThreatSeverity {
match &threat.threat_type {
crate::scanner::ThreatType::UnicodeInvisible => ThreatSeverity::Medium,
crate::scanner::ThreatType::UnicodeBiDi => ThreatSeverity::High,
crate::scanner::ThreatType::UnicodeHomograph => ThreatSeverity::Medium,
crate::scanner::ThreatType::UnicodeControl => ThreatSeverity::Medium,
crate::scanner::ThreatType::PromptInjection => ThreatSeverity::High,
crate::scanner::ThreatType::CommandInjection => ThreatSeverity::Critical,
crate::scanner::ThreatType::PathTraversal => ThreatSeverity::High,
crate::scanner::ThreatType::SqlInjection => ThreatSeverity::Critical,
crate::scanner::ThreatType::CrossSiteScripting => ThreatSeverity::High,
crate::scanner::ThreatType::LdapInjection => ThreatSeverity::High,
crate::scanner::ThreatType::XmlInjection => ThreatSeverity::High,
crate::scanner::ThreatType::NoSqlInjection => ThreatSeverity::High,
crate::scanner::ThreatType::SessionIdExposure => ThreatSeverity::Critical,
crate::scanner::ThreatType::ToolPoisoning => ThreatSeverity::Critical,
crate::scanner::ThreatType::TokenTheft => ThreatSeverity::Critical,
crate::scanner::ThreatType::DosPotential => ThreatSeverity::High,
crate::scanner::ThreatType::Custom(_) => ThreatSeverity::Medium,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_status_notification_serialization() {
let notification = create_status_notification(ShieldStatusParams {
active: true,
enhanced: false,
threats: 42,
threat_rate: 2.5,
last_threat: Some(LastThreatInfo {
threat_type: "unicode_bidi".to_string(),
severity: ThreatSeverity::High,
timestamp: 1234567890,
description: "Right-to-left override detected".to_string(),
}),
performance: PerformanceMetrics {
scan_time_us: 123,
queue_depth: 5,
memory_mb: 45.6,
},
});
let json = serde_json::to_string_pretty(¬ification).unwrap();
assert!(json.contains("\"method\": \"shield/status\""));
assert!(json.contains("\"threats\": 42"));
assert!(json.contains("\"severity\": \"high\""));
}
#[test]
fn test_control_request_deserialization() {
let json = r#"{
"action": "pause",
"duration": 5000
}"#;
let request: ShieldControlRequest = serde_json::from_str(json).unwrap();
assert_eq!(request.action, ShieldControlAction::Pause);
assert_eq!(request.duration, Some(5000));
}
#[cfg(feature = "enhanced")]
#[test]
fn test_binary_header() {
use std::mem;
assert_eq!(mem::size_of::<BinaryMessageHeader>(), 28);
assert_eq!(BinaryMessageHeader::MAGIC, 0x4B475344);
}
}