Skip to main content

source_map_tauri/
security.rs

1use once_cell::sync::Lazy;
2use regex::Regex;
3
4use crate::model::ArtifactDoc;
5
6pub struct RiskAssessment {
7    pub level: String,
8    pub reasons: Vec<String>,
9    pub contains_phi: bool,
10}
11
12static BEARER_RE: Lazy<Regex> =
13    Lazy::new(|| Regex::new(r"Bearer\s+[A-Za-z0-9._\-]+").expect("valid regex"));
14static URL_AUTH_RE: Lazy<Regex> =
15    Lazy::new(|| Regex::new(r"https?://[^/\s:@]+:[^/\s:@]+@").expect("valid regex"));
16
17pub fn redact_text(input: &str) -> String {
18    let step = BEARER_RE.replace_all(input, "Bearer [REDACTED_SECRET]");
19    URL_AUTH_RE
20        .replace_all(&step, "https://[REDACTED_SECRET]@")
21        .into_owned()
22}
23
24pub fn assess_risk(values: &[String]) -> RiskAssessment {
25    let joined = values.join(" ").to_lowercase();
26    let mut reasons = Vec::new();
27
28    for keyword in [
29        "patient",
30        "phi",
31        "mrn",
32        "consent",
33        "medication",
34        "lab",
35        "diagnosis",
36        "billing",
37        "insurance",
38        "discharge",
39        "audit",
40        "upload",
41        "export",
42    ] {
43        if joined.contains(keyword) {
44            reasons.push(format!("{keyword} keyword"));
45        }
46    }
47
48    let level = if joined.contains("database")
49        || joined.contains("filesystem_export")
50        || joined.contains("external_integration")
51    {
52        "critical"
53    } else if !reasons.is_empty() {
54        "high"
55    } else {
56        "low"
57    };
58
59    RiskAssessment {
60        level: level.to_owned(),
61        reasons,
62        contains_phi: false,
63    }
64}
65
66pub fn apply_artifact_security(doc: &mut ArtifactDoc) {
67    doc.comments = doc.comments.iter().map(|item| redact_text(item)).collect();
68    doc.tags = doc.tags.iter().map(|item| redact_text(item)).collect();
69    let mut samples = Vec::new();
70    if let Some(name) = &doc.name {
71        samples.push(name.clone());
72    }
73    if let Some(path) = &doc.source_path {
74        samples.push(path.clone());
75    }
76    samples.extend(doc.tags.clone());
77    samples.extend(doc.comments.clone());
78    let assessment = assess_risk(&samples);
79    if doc.risk_level == "low" || doc.risk_level.is_empty() {
80        doc.risk_level = assessment.level;
81    }
82    if doc.risk_reasons.is_empty() {
83        doc.risk_reasons = assessment.reasons;
84    }
85    doc.contains_phi = assessment.contains_phi;
86}