use matchy::database::Database;
use matchy::misp_importer::MispImporter;
use matchy::DataValue;
use matchy::MatchMode;
use std::env;
use std::fs;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
eprintln!("Usage: {} <misp-json-file> [additional-files...]", args[0]);
eprintln!("\nExample:");
eprintln!(" {} misp-example.json", args[0]);
eprintln!(" {} threats1.json threats2.json", args[0]);
std::process::exit(1);
}
let json_files = &args[1..];
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ MISP Threat Intelligence Database Builder ║");
println!("╚════════════════════════════════════════════════════════════════╝\n");
println!("📁 Loading MISP JSON files:");
for file in json_files {
println!(" • {file}");
}
println!();
let importer = MispImporter::from_files(json_files)?;
let stats = importer.stats();
println!("📊 Import Statistics:");
println!(" Events imported: {}", stats.total_events);
println!(" Total attributes: {}", stats.total_attributes);
println!(" Objects processed: {}", stats.total_objects);
println!();
println!("🔨 Building threat intelligence database...");
let builder = importer.build_database(MatchMode::CaseSensitive)?;
let builder_stats = builder.stats();
println!(" ✓ Total indicators: {}", builder_stats.total_entries);
println!(" ✓ IP entries: {}", builder_stats.ip_entries);
println!(" ✓ Literal entries: {}", builder_stats.literal_entries);
println!(" ✓ Glob entries: {}", builder_stats.glob_entries);
println!();
println!("💾 Serializing database...");
let database_bytes = builder.build()?;
println!(
" ✓ Database size: {} bytes ({:.2} MB)",
database_bytes.len(),
database_bytes.len() as f64 / (1024.0 * 1024.0)
);
println!();
let output_file = "misp_threat_intel.mmdb";
fs::write(output_file, &database_bytes)?;
println!("✅ Database saved to: {output_file}\n");
println!("🔍 Testing database queries...\n");
let db_result = Database::from_bytes(database_bytes);
if let Err(e) = &db_result {
println!(" ℹ️ Note: Pattern-only databases require direct Paraglob loading");
println!(" (This is normal when there are no IP addresses in the data)");
println!(" Error: {e:?}\n");
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ Database built successfully! ║");
println!("║ ║");
println!(
"║ The database contains {} threat indicators. ║",
builder_stats.literal_entries + builder_stats.glob_entries
);
println!("║ Load it using Paraglob API for pattern matching. ║");
println!("╚════════════════════════════════════════════════════════════════╝");
return Ok(());
}
let db = db_result?;
let test_queries = vec![
("7789611e7c2a7e78d0bded05924ede23", "MD5 hash from sample"),
("192.168.1.100", "IP address check"),
("evil.com", "Domain check"),
];
for (query, description) in test_queries {
print!(" Query: {query} ({description})");
match db.lookup(query)? {
Some(result) => match result {
matchy::database::QueryResult::Ip { data, .. } => {
println!(" ✓ MATCH FOUND (IP)");
if let DataValue::Map(map) = &data {
println!(" Type: {:?}", map.get("type"));
println!(" Event: {:?}", map.get("event_info"));
if let Some(tags) = map.get("tags") {
println!(" Tags: {tags:?}");
}
if let Some(threat) = map.get("threat_level") {
println!(" Threat Level: {threat:?}");
}
}
}
matchy::database::QueryResult::Pattern { data, .. } => {
println!(" ✓ MATCH FOUND (Pattern)");
if let Some(Some(DataValue::Map(map))) = data.first() {
println!(" Type: {:?}", map.get("type"));
println!(" Event: {:?}", map.get("event_info"));
if let Some(tags) = map.get("tags") {
println!(" Tags: {tags:?}");
}
if let Some(threat) = map.get("threat_level") {
println!(" Threat Level: {threat:?}");
}
}
}
matchy::database::QueryResult::NotFound => {
println!(" ✗ No match");
}
},
None => {
println!(" ✗ No match");
}
}
println!();
}
println!("╔════════════════════════════════════════════════════════════════╗");
println!("║ Database ready for use! ║");
println!("║ ║");
println!("║ You can now: ║");
println!("║ • Load it in your application with Database::from_file() ║");
println!("║ • Query IPs, hashes, domains, and more ║");
println!("║ • Access all metadata (tags, threat levels, etc.) ║");
println!("╚════════════════════════════════════════════════════════════════╝");
Ok(())
}