use wasm_bindgen::prelude::*;
use crate::{
security_analyzer::SecurityAnalyzer,
alert_analyzer::AlertAnalyzer,
time_series_analyzer::{TimeSeriesAnalyzer, TimeSeriesConfig},
Config,
Error,
};
use serde::{Serialize, Deserialize};
use chrono::{DateTime, Utc, Duration};
use web_sys::console;
#[wasm_bindgen]
pub struct WasmSecurityAnalyzer {
analyzer: SecurityAnalyzer,
alert_analyzer: AlertAnalyzer,
time_series_analyzer: TimeSeriesAnalyzer,
}
#[derive(Serialize, Deserialize)]
pub struct AnalysisOptions {
pub enable_pattern_detection: bool,
pub enable_time_series: bool,
pub min_confidence: f64,
pub time_window: i64, }
#[wasm_bindgen]
impl WasmSecurityAnalyzer {
#[wasm_bindgen(constructor)]
pub fn new() -> Self {
console_error_panic_hook::set_once();
let config = Config::default();
let time_series_config = TimeSeriesConfig {
min_data_points: 10,
forecast_horizon: Duration::hours(24),
seasonality_threshold: 0.3,
trend_threshold: 0.1,
};
Self {
analyzer: SecurityAnalyzer::new(config),
alert_analyzer: AlertAnalyzer::new(),
time_series_analyzer: TimeSeriesAnalyzer::new(time_series_config),
}
}
#[wasm_bindgen]
pub fn analyze(&self, data: &str, options_str: &str) -> Result<JsValue, JsError> {
console::log_1(&"Starting analysis...".into());
let options: AnalysisOptions = serde_json::from_str(options_str)
.map_err(|e| JsError::new(&format!("Failed to parse options: {}", e)))?;
let audit_entries: Vec<AuditLogEntry> = serde_json::from_str(data)
.map_err(|e| JsError::new(&format!("Failed to parse audit entries: {}", e)))?;
let start_time = Utc::now();
let mut result = json!({
"timestamp": start_time,
"options": options,
});
let security_report = self.analyzer.analyze_sync(&audit_entries)
.map_err(|e| JsError::new(&format!("Security analysis failed: {}", e)))?;
result["security_analysis"] = json!({
"risk_level": security_report.risk_level,
"findings": security_report.findings,
"recommendations": security_report.recommendations,
});
if options.enable_pattern_detection {
let patterns = self.alert_analyzer.analyze_patterns(&security_report.alerts)
.map_err(|e| JsError::new(&format!("Pattern analysis failed: {}", e)))?;
let filtered_patterns = patterns.into_iter()
.filter(|p| p.confidence >= options.min_confidence)
.collect::<Vec<_>>();
result["pattern_analysis"] = json!({
"patterns": filtered_patterns,
"total_patterns": filtered_patterns.len(),
});
}
if options.enable_time_series {
let time_window = Duration::hours(options.time_window);
let recent_alerts: Vec<_> = security_report.alerts.iter()
.filter(|a| a.created_at + time_window > Utc::now())
.cloned()
.collect();
if let Some(analysis) = self.time_series_analyzer.analyze(&recent_alerts) {
result["time_series_analysis"] = json!({
"trend": analysis.trend,
"seasonality": analysis.seasonality,
"forecasts": analysis.forecasts,
});
}
}
result["performance"] = json!({
"analysis_duration": (Utc::now() - start_time).num_milliseconds(),
"total_events": audit_entries.len(),
"memory_usage": get_memory_usage(),
});
console::log_1(&"Analysis completed successfully".into());
Ok(serde_wasm_bindgen::to_value(&result)?)
}
#[wasm_bindgen]
pub fn get_version() -> String {
env!("CARGO_PKG_VERSION").to_string()
}
#[wasm_bindgen]
pub fn validate_data(data: &str) -> Result<bool, JsError> {
match serde_json::from_str::<Vec<AuditLogEntry>>(data) {
Ok(_) => Ok(true),
Err(e) => Err(JsError::new(&format!("Invalid data format: {}", e))),
}
}
}
fn get_memory_usage() -> usize {
#[cfg(target_arch = "wasm32")]
{
web_sys::window()
.and_then(|w| w.performance())
.map(|p| p.timing().dom_interactive() as usize)
.unwrap_or(0)
}
#[cfg(not(target_arch = "wasm32"))]
{
0
}
}