threat_intel/
types.rs

1//! Type definitions for threat intelligence
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::constants::*;
7
8/// Vulnerability information
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct Vulnerability {
11    pub id: String,
12    pub cve_id: Option<String>,
13    pub title: String,
14    pub description: String,
15    pub severity: Severity,
16    pub cvss_score: Option<f32>,
17    pub affected_products: Vec<AffectedProduct>,
18    pub published_date: DateTime<Utc>,
19    pub last_modified: DateTime<Utc>,
20    pub references: Vec<String>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
24pub enum Severity {
25    Critical,
26    High,
27    Medium,
28    Low,
29    Info,
30}
31
32impl Severity {
33    /// Get the numeric weight for risk scoring
34    pub fn weight(&self) -> u32 {
35        match self {
36            Severity::Critical => CRITICAL_WEIGHT,
37            Severity::High => HIGH_WEIGHT,
38            Severity::Medium => MEDIUM_WEIGHT,
39            Severity::Low => LOW_WEIGHT,
40            Severity::Info => 0,
41        }
42    }
43
44    /// Check if this severity is critical or high
45    pub fn is_high_severity(&self) -> bool {
46        matches!(self, Severity::Critical | Severity::High)
47    }
48}
49
50#[derive(Debug, Clone, Serialize, Deserialize)]
51pub struct AffectedProduct {
52    pub vendor: String,
53    pub product: String,
54    pub version: String,
55    pub platform: Option<String>,
56}
57
58/// Indicator of Compromise
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct IOC {
61    pub id: String,
62    pub ioc_type: IOCType,
63    pub value: String,
64    pub description: Option<String>,
65    pub confidence: f32,
66    pub first_seen: DateTime<Utc>,
67    pub last_seen: DateTime<Utc>,
68    pub tags: Vec<String>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
72pub enum IOCType {
73    IpAddress,
74    Domain,
75    Url,
76    FileHash,
77    Email,
78    Other(String),
79}
80
81impl IOCType {
82    /// Get the maximum allowed length for this IOC type
83    pub fn max_length(&self) -> usize {
84        match self {
85            IOCType::Domain => MAX_DOMAIN_LENGTH,
86            IOCType::Email => MAX_EMAIL_LENGTH,
87            _ => MAX_IOC_VALUE_LENGTH,
88        }
89    }
90
91    /// Validate the IOC value
92    pub fn validate(&self, value: &str) -> bool {
93        if value.len() > self.max_length() {
94            return false;
95        }
96
97        match self {
98            IOCType::IpAddress => self.validate_ip(value),
99            IOCType::Domain => self.validate_domain(value),
100            IOCType::Url => self.validate_url(value),
101            IOCType::Email => self.validate_email(value),
102            IOCType::FileHash => self.validate_hash(value),
103            IOCType::Other(_) => true,
104        }
105    }
106
107    fn validate_ip(&self, value: &str) -> bool {
108        // Basic IP validation (IPv4 and IPv6)
109        value.parse::<std::net::IpAddr>().is_ok()
110    }
111
112    fn validate_domain(&self, value: &str) -> bool {
113        // Basic domain validation
114        !value.is_empty() && !value.contains(' ') && value.len() <= MAX_DOMAIN_LENGTH
115    }
116
117    fn validate_url(&self, value: &str) -> bool {
118        // Basic URL validation
119        value.starts_with("http://") || value.starts_with("https://")
120    }
121
122    fn validate_email(&self, value: &str) -> bool {
123        // Basic email validation
124        value.contains('@') && value.len() <= MAX_EMAIL_LENGTH
125    }
126
127    fn validate_hash(&self, value: &str) -> bool {
128        // Basic hash validation (hex string)
129        value.len() == 32 || value.len() == 40 || value.len() == 64 // MD5, SHA1, SHA256
130    }
131}
132
133/// Threat Actor information
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct ThreatActor {
136    pub id: String,
137    pub name: String,
138    pub aliases: Vec<String>,
139    pub description: String,
140    pub tactics: Vec<String>,
141    pub techniques: Vec<String>,
142    pub first_seen: Option<DateTime<Utc>>,
143    pub country: Option<String>,
144    pub motivation: Option<String>,
145}
146
147/// Risk assessment result
148#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct RiskAssessment {
150    pub level: RiskLevel,
151    pub score: f32,
152    pub critical_count: usize,
153    pub high_count: usize,
154    pub medium_count: usize,
155    pub low_count: usize,
156    pub recommendations: Vec<String>,
157}
158
159#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq)]
160pub enum RiskLevel {
161    Critical,
162    High,
163    Medium,
164    Low,
165    Info,
166}
167
168impl RiskLevel {
169    /// Get the priority order for this risk level
170    pub fn priority(&self) -> u8 {
171        match self {
172            RiskLevel::Critical => 5,
173            RiskLevel::High => 4,
174            RiskLevel::Medium => 3,
175            RiskLevel::Low => 2,
176            RiskLevel::Info => 1,
177        }
178    }
179
180    /// Check if this risk level requires immediate action
181    pub fn requires_immediate_action(&self) -> bool {
182        matches!(self, RiskLevel::Critical | RiskLevel::High)
183    }
184}
185
186/// Statistics about the threat intelligence cache
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct ThreatIntelStats {
189    pub sources_count: usize,
190    pub total_vulnerabilities: usize,
191    pub total_iocs: usize,
192    pub total_threat_actors: usize,
193    pub last_sync: Option<DateTime<Utc>>,
194}
195
196/// Data returned from a threat intelligence source
197#[derive(Debug, Clone, Default)]
198pub struct ThreatData {
199    pub vulnerabilities: Vec<Vulnerability>,
200    pub iocs: Vec<IOC>,
201    pub threat_actors: Vec<ThreatActor>,
202    pub raw_data: Option<serde_json::Value>,
203}
204
205impl ThreatData {
206    /// Create a new empty threat data instance
207    pub fn new() -> Self {
208        Self::default()
209    }
210
211    /// Add a vulnerability to the data
212    pub fn add_vulnerability(&mut self, vuln: Vulnerability) {
213        self.vulnerabilities.push(vuln);
214    }
215
216    /// Add an IOC to the data
217    pub fn add_ioc(&mut self, ioc: IOC) {
218        self.iocs.push(ioc);
219    }
220
221    /// Add a threat actor to the data
222    pub fn add_threat_actor(&mut self, actor: ThreatActor) {
223        self.threat_actors.push(actor);
224    }
225
226    /// Get the total count of all data types
227    pub fn total_count(&self) -> usize {
228        self.vulnerabilities.len() + self.iocs.len() + self.threat_actors.len()
229    }
230
231    /// Check if the data is empty
232    pub fn is_empty(&self) -> bool {
233        self.vulnerabilities.is_empty() && self.iocs.is_empty() && self.threat_actors.is_empty()
234    }
235}