lonkero 3.6.2

Web scanner built for actual pentests. Fast, modular, Rust.
Documentation
// Copyright (c) 2026 Bountyy Oy. All rights reserved.
// This software is proprietary and confidential.

use crate::types::{ScanResults, Vulnerability};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ReportConfig {
    pub format: ReportFormat,
    pub include_executive_summary: bool,
    pub include_charts: bool,
    pub include_remediation: bool,
    pub include_compliance_mapping: bool,
    pub include_owasp_mapping: bool,
    pub deduplicate: bool,
    pub filter_false_positives: bool,
    pub min_severity: Option<String>,
    pub branding: Option<BrandingConfig>,
    pub template: Option<String>,
    pub compare_with: Option<String>,
}

impl Default for ReportConfig {
    fn default() -> Self {
        Self {
            format: ReportFormat::Json,
            include_executive_summary: true,
            include_charts: true,
            include_remediation: true,
            include_compliance_mapping: true,
            include_owasp_mapping: true,
            deduplicate: true,
            filter_false_positives: true,
            min_severity: None,
            branding: None,
            template: None,
            compare_with: None,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum ReportFormat {
    Pdf,
    Html,
    Json,
    Csv,
    Sarif,
    JunitXml,
    Xlsx,
    Markdown,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct BrandingConfig {
    pub company_name: String,
    pub logo_path: Option<String>,
    pub primary_color: String,
    pub secondary_color: String,
    pub report_title: Option<String>,
    pub footer_text: Option<String>,
}

impl Default for BrandingConfig {
    fn default() -> Self {
        Self {
            company_name: "Security Baseline Scanner".to_string(),
            logo_path: None,
            primary_color: "#2563eb".to_string(),
            secondary_color: "#1e40af".to_string(),
            report_title: None,
            footer_text: Some("Confidential - For Internal Use Only".to_string()),
        }
    }
}

#[derive(Debug, Clone)]
pub struct ReportOutput {
    pub format: ReportFormat,
    pub data: Vec<u8>,
    pub filename: String,
    pub mime_type: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct EnhancedReport {
    pub scan_results: ScanResults,
    pub executive_summary: ExecutiveSummary,
    pub vulnerability_breakdown: VulnerabilityBreakdown,
    pub owasp_mapping: HashMap<String, Vec<Vulnerability>>,
    pub cwe_mapping: HashMap<String, Vec<Vulnerability>>,
    pub compliance_mapping: ComplianceMapping,
    pub risk_assessment: RiskAssessment,
    pub trends: Option<TrendAnalysis>,
    pub generated_at: String,
    pub report_version: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ExecutiveSummary {
    pub target: String,
    pub scan_date: String,
    pub total_vulnerabilities: usize,
    pub critical_count: usize,
    pub high_count: usize,
    pub medium_count: usize,
    pub low_count: usize,
    pub info_count: usize,
    pub risk_score: f64,
    pub risk_level: String,
    pub key_findings: Vec<String>,
    pub recommendations: Vec<String>,
    pub duration_seconds: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VulnerabilityBreakdown {
    pub by_severity: HashMap<String, usize>,
    pub by_category: HashMap<String, usize>,
    pub by_confidence: HashMap<String, usize>,
    pub verified_count: usize,
    pub unverified_count: usize,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ComplianceMapping {
    pub pci_dss: HashMap<String, Vec<String>>,
    pub hipaa: HashMap<String, Vec<String>>,
    pub soc2: HashMap<String, Vec<String>>,
    pub iso27001: HashMap<String, Vec<String>>,
    pub gdpr: HashMap<String, Vec<String>>,
    pub nist_csf: HashMap<String, Vec<String>>,
    pub dora: HashMap<String, Vec<String>>,
    pub nis2: HashMap<String, Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RiskAssessment {
    pub overall_risk_score: f64,
    pub risk_level: String,
    pub risk_matrix: Vec<RiskMatrixEntry>,
    pub attack_surface_score: f64,
    pub exploitability_score: f64,
    pub business_impact_score: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct RiskMatrixEntry {
    pub vulnerability_id: String,
    pub vulnerability_type: String,
    pub likelihood: String,
    pub impact: String,
    pub risk_score: f64,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TrendAnalysis {
    pub previous_scan_id: String,
    pub previous_scan_date: String,
    pub new_vulnerabilities: usize,
    pub fixed_vulnerabilities: usize,
    pub recurring_vulnerabilities: usize,
    pub risk_score_change: f64,
    pub severity_changes: HashMap<String, i32>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SarifReport {
    pub version: String,
    #[serde(rename = "$schema")]
    pub schema: String,
    pub runs: Vec<SarifRun>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifRun {
    pub tool: SarifTool,
    pub results: Vec<SarifResult>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SarifTool {
    pub driver: SarifDriver,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifDriver {
    pub name: String,
    pub version: String,
    pub information_uri: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub rules: Option<Vec<SarifRule>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifRule {
    pub id: String,
    pub name: String,
    pub short_description: SarifMessage,
    pub full_description: SarifMessage,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub help: Option<SarifMessage>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub help_uri: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub properties: Option<SarifRuleProperties>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifRuleProperties {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub precision: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub security_severity: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub tags: Option<Vec<String>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifResult {
    pub rule_id: String,
    pub level: String,
    pub message: SarifMessage,
    pub locations: Vec<SarifLocation>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fingerprints: Option<std::collections::HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub partial_fingerprints: Option<std::collections::HashMap<String, String>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fixes: Option<Vec<SarifFix>>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifFix {
    pub description: SarifMessage,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SarifMessage {
    pub text: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifLocation {
    pub physical_location: SarifPhysicalLocation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct SarifPhysicalLocation {
    pub artifact_location: SarifArtifactLocation,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SarifArtifactLocation {
    pub uri: String,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunitTestSuites {
    pub name: String,
    pub tests: usize,
    pub failures: usize,
    pub time: f64,
    pub testsuites: Vec<JunitTestSuite>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunitTestSuite {
    pub name: String,
    pub tests: usize,
    pub failures: usize,
    pub time: f64,
    pub testcases: Vec<JunitTestCase>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunitTestCase {
    pub name: String,
    pub classname: String,
    pub time: f64,
    pub failure: Option<JunitFailure>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct JunitFailure {
    pub message: String,
    #[serde(rename = "type")]
    pub failure_type: String,
    pub text: String,
}