use crate::core::behavior_bio::{AnalysisResult as BehaviorResult, BehaviorEngine, BehaviorInput};
use crate::core::device_fp::{AdaptiveFingerprint, AdaptiveFingerprintEngine};
use crate::core::geo_resolver::{GeoLocation, GeoResolver};
use crate::core::network_analyzer::NetworkAnalyzer;
use crate::core::sensors_analyzer::SensorsAnalyzerEngine;
use crate::security::secret::SecureBytes;
use crate::security::signing::sign_hmac_sha512;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::sync::Arc;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CrossValidationError {
#[error("GeoResolver failed: {0}")]
GeoResolutionFailed(String),
#[error("Device Fingerprinting failed: {0}")]
FingerprintFailed(String),
#[error("Behavior Analysis failed: {0}")]
BehaviorAnalysisFailed(String),
#[error("Signature generation failed: {0}")]
SignatureError(String),
#[error("Invalid secret key for signing")]
InvalidKey,
}
#[derive(Clone)]
pub struct CrossValidationInput<'a> {
pub ip_address: Option<std::net::IpAddr>,
pub gps_data: Option<(f64, f64, u8, f64)>,
pub os_info: &'a str,
pub device_details: &'a str,
pub environment_context: &'a str,
pub behavior_input: BehaviorInput,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ValidationResult {
pub final_trust_score: f32, pub is_trusted: bool,
pub geo_location: GeoLocation,
pub device_fingerprint: AdaptiveFingerprint,
pub behavior_analysis: BehaviorResult,
pub signature: String,
pub timestamp: i64,
}
#[async_trait]
pub trait ScoringStrategy: Send + Sync {
async fn calculate_score(
&self,
geo_result: &GeoLocation,
fp_result: &AdaptiveFingerprint,
behavior_result: &BehaviorResult,
) -> f32;
}
pub struct CrossValidationEngine {
pub geo_resolver: Arc<GeoResolver>,
pub fp_engine: Arc<AdaptiveFingerprintEngine>,
pub behavior_engine: Arc<BehaviorEngine>,
pub sensors_engine: Arc<SensorsAnalyzerEngine>,
pub network_engine: Arc<NetworkAnalyzer>,
pub scoring_strategy: Arc<dyn ScoringStrategy>,
pub signing_key: SecureBytes,
}
impl CrossValidationEngine {
pub fn new(
geo_resolver: Arc<GeoResolver>,
fp_engine: Arc<AdaptiveFingerprintEngine>,
behavior_engine: Arc<BehaviorEngine>,
sensors_engine: Arc<SensorsAnalyzerEngine>,
network_engine: Arc<NetworkAnalyzer>,
scoring_strategy: Arc<dyn ScoringStrategy>,
signing_key: SecureBytes,
) -> Self {
Self {
geo_resolver,
fp_engine,
behavior_engine,
sensors_engine,
network_engine,
scoring_strategy,
signing_key,
}
}
pub async fn validate(
&self,
input: CrossValidationInput<'_>,
) -> Result<ValidationResult, CrossValidationError> {
let geo_handle = self
.geo_resolver
.resolve(crate::core::geo_resolver::ResolveParams {
ip: input.ip_address,
gps: input.gps_data,
sim_location: None,
satellite_location: None,
indoor_data: None,
ar_data: None,
mfa_token: None,
});
let fp_handle = self.fp_engine.generate_fingerprint(
input.os_info,
input.device_details,
input.environment_context,
);
let behavior_handle = self.behavior_engine.process(input.behavior_input);
let (geo_res, fp_res, behavior_res) = tokio::join!(geo_handle, fp_handle, behavior_handle);
let geo_location =
geo_res.map_err(|e| CrossValidationError::GeoResolutionFailed(e.to_string()))?;
let device_fingerprint =
fp_res.map_err(|e| CrossValidationError::FingerprintFailed(e.to_string()))?;
let behavior_analysis = behavior_res
.map_err(|e| CrossValidationError::BehaviorAnalysisFailed(e.to_string()))?;
let final_trust_score = self
.scoring_strategy
.calculate_score(&geo_location, &device_fingerprint, &behavior_analysis)
.await;
let mut result = ValidationResult {
final_trust_score,
is_trusted: final_trust_score >= 0.7, geo_location,
device_fingerprint,
behavior_analysis,
signature: String::new(), timestamp: chrono::Utc::now().timestamp(),
};
let signature = self.sign_verdict(&result)?;
result.signature = signature;
Ok(result)
}
fn sign_verdict(&self, result: &ValidationResult) -> Result<String, CrossValidationError> {
let mut result_to_sign = result.clone();
result_to_sign.signature = String::new();
let serialized = serde_json::to_vec(&result_to_sign)
.map_err(|e| CrossValidationError::SignatureError(e.to_string()))?;
let sig = sign_hmac_sha512(&serialized, &self.signing_key)
.map_err(|_| CrossValidationError::InvalidKey)?;
Ok(hex::encode(sig))
}
}
pub struct DefaultScoringStrategy {
pub location_weight: f32,
pub fingerprint_weight: f32,
pub behavior_weight: f32,
}
#[async_trait]
impl ScoringStrategy for DefaultScoringStrategy {
async fn calculate_score(
&self,
geo_result: &GeoLocation,
fp_result: &AdaptiveFingerprint,
behavior_result: &BehaviorResult,
) -> f32 {
let location_score = f32::from(geo_result.confidence) / 100.0;
let fp_score = f32::from(fp_result.security_level) / 10.0;
let behavior_score = 1.0 - behavior_result.risk_score;
let final_score = crate::utils::precision::weighted_sum_f32(&[
(location_score, self.location_weight),
(fp_score, self.fingerprint_weight),
(behavior_score, self.behavior_weight),
]);
final_score.clamp(0.0, 1.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::behavior_bio::{DefaultAnomalyDetector, DefaultBehavioralModel};
use crate::core::device_fp::{
DefaultAiProcessor as DefaultFpAi, DefaultQuantumEngine, DefaultSecurityMonitor,
};
use crate::core::geo_resolver::GeoReaderEnum;
use crate::core::geo_resolver::{DefaultAiModel, DefaultBlockchain};
use hmac::Hmac;
use hmac::Mac;
use maxminddb::Reader;
use sha2::Sha512;
use std::collections::HashMap;
use std::fs;
use tokio::sync::RwLock;
fn setup_full_engine() -> CrossValidationEngine {
let geo_reader = fs::read("GeoLite2-City-Test.mmdb").map_or_else(
|_| {
let geo_db_bytes = hex::decode(
"89ABCDEF0123456789ABCDEF0123456789ABCDEF14042A00000000000600000002000000100000000200000004000000020000000C000000636F756E747279070000000700000049534F5F636F646502000000070000000400000055530000"
).unwrap();
Arc::new(GeoReaderEnum::Real(
Reader::from_source(geo_db_bytes).unwrap(),
))
},
|bytes| Arc::new(GeoReaderEnum::Real(
Reader::from_source(bytes).expect("Failed to read mmdb file"),
)),
);
let geo_resolver = Arc::new(GeoResolver::new(
crate::security::secret::SecureBytes::new(vec![1; 32]),
Arc::new(DefaultAiModel),
Arc::new(DefaultBlockchain),
true,
false,
geo_reader,
));
let fp_engine = Arc::new(AdaptiveFingerprintEngine::new(
Arc::new(DefaultSecurityMonitor::new()),
Arc::new(DefaultQuantumEngine::new().unwrap()),
Arc::new(DefaultFpAi),
Arc::new(RwLock::new(HashMap::new())),
));
let behavior_engine = Arc::new(BehaviorEngine::new(
Arc::new(DefaultBehavioralModel),
Arc::new(DefaultAnomalyDetector {
max_speed_kmh: 1200.0,
}),
10,
));
let sensors_engine = Arc::new(SensorsAnalyzerEngine::new(
crate::security::secret::SecureBytes::new(vec![42; 48]),
Arc::new(crate::core::sensors_analyzer::DefaultSensorAnomalyDetector::default()),
));
let proxy_db = Arc::new(RwLock::new(
crate::core::network_analyzer::ProxyDatabase::default(),
));
let geo_reader = fs::read("GeoLite2-City-Test.mmdb").map_or_else(
|_| {
let geo_db_bytes = hex::decode(
"89ABCDEF0123456789ABCDEF0123456789ABCDEF14042A00000000000600000002000000100000000200000004000000020000000C000000636F756E747279070000000700000049534F5F636F646502000000070000000400000055530000"
).unwrap();
Arc::new(GeoReaderEnum::Real(
Reader::from_source(geo_db_bytes).unwrap(),
))
},
|bytes| Arc::new(GeoReaderEnum::Real(
Reader::from_source(bytes).expect("Failed to read mmdb file"),
)),
);
let network_engine = Arc::new(NetworkAnalyzer::new(
crate::security::secret::SecureBytes::new(vec![42; 32]),
proxy_db,
geo_reader,
Arc::new(crate::core::network_analyzer::DefaultAiNetworkAnalyzer),
));
let scoring_strategy = Arc::new(DefaultScoringStrategy {
location_weight: 0.4,
fingerprint_weight: 0.3,
behavior_weight: 0.3,
});
CrossValidationEngine::new(
geo_resolver,
fp_engine,
behavior_engine,
sensors_engine,
network_engine,
scoring_strategy,
crate::security::secret::SecureBytes::new(b"final_verdict_signing_key".to_vec()),
)
}
#[tokio::test]
async fn test_successful_validation_scenario() {
type HmacSha512 = Hmac<Sha512>;
let engine = setup_full_engine();
let input = CrossValidationInput {
ip_address: Some("8.8.8.8".parse().unwrap()),
gps_data: Some((34.05, -118.24, 95, 5.0)),
os_info: "Windows 11",
device_details: "Dell XPS",
environment_context: "desktop",
behavior_input: BehaviorInput {
entity_id: "test_user".to_string(),
timestamp: chrono::Utc::now(),
location: (34.05, -118.24),
network_info: crate::core::behavior_bio::NetworkInfo {
ip_address: "8.8.8.8".to_string(),
is_vpn: false,
connection_type: "WiFi".to_string(),
},
device_fingerprint: "initial_fp".to_string(),
},
};
let Ok(result) = engine.validate(input).await else {
return;
};
assert!(result.is_trusted);
assert!(result.final_trust_score > 0.7);
assert!(!result.signature.is_empty());
let signature_bytes = hex::decode(&result.signature).unwrap();
let mut mac = HmacSha512::new_from_slice(b"final_verdict_signing_key").unwrap();
let mut signed_result = result;
signed_result.signature = String::new();
let serialized = serde_json::to_vec(&signed_result).unwrap();
mac.update(&serialized);
assert!(mac.verify_slice(&signature_bytes).is_ok());
}
}