1use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use crate::constants::*;
7
8#[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 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 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#[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 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 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 value.parse::<std::net::IpAddr>().is_ok()
110 }
111
112 fn validate_domain(&self, value: &str) -> bool {
113 !value.is_empty() && !value.contains(' ') && value.len() <= MAX_DOMAIN_LENGTH
115 }
116
117 fn validate_url(&self, value: &str) -> bool {
118 value.starts_with("http://") || value.starts_with("https://")
120 }
121
122 fn validate_email(&self, value: &str) -> bool {
123 value.contains('@') && value.len() <= MAX_EMAIL_LENGTH
125 }
126
127 fn validate_hash(&self, value: &str) -> bool {
128 value.len() == 32 || value.len() == 40 || value.len() == 64 }
131}
132
133#[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#[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 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 pub fn requires_immediate_action(&self) -> bool {
182 matches!(self, RiskLevel::Critical | RiskLevel::High)
183 }
184}
185
186#[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#[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 pub fn new() -> Self {
208 Self::default()
209 }
210
211 pub fn add_vulnerability(&mut self, vuln: Vulnerability) {
213 self.vulnerabilities.push(vuln);
214 }
215
216 pub fn add_ioc(&mut self, ioc: IOC) {
218 self.iocs.push(ioc);
219 }
220
221 pub fn add_threat_actor(&mut self, actor: ThreatActor) {
223 self.threat_actors.push(actor);
224 }
225
226 pub fn total_count(&self) -> usize {
228 self.vulnerabilities.len() + self.iocs.len() + self.threat_actors.len()
229 }
230
231 pub fn is_empty(&self) -> bool {
233 self.vulnerabilities.is_empty() && self.iocs.is_empty() && self.threat_actors.is_empty()
234 }
235}