use rswappalyzer_engine::{
CompiledPattern,
CompiledTechRule,
RuleLibraryRuntime,
Scope,
compiled::{LiteralId, LiteralInterner},
};
use rustc_hash::{FxHashMap, FxHashSet};
use crate::{
analyzer::{
common::handle_match_success,
Analyzer,
},
VersionExtractor,
};
use crate::analyzer::AnalyzerInput;
pub struct UrlAnalyzer;
impl<'a> Analyzer<[CompiledPattern], UrlEvidence<'a>> for UrlAnalyzer {
const TYPE_NAME: &'static str = "URL";
fn get_patterns(tech: &CompiledTechRule) -> Option<&[CompiledPattern]> {
tech.url_patterns.as_deref()
}
fn match_logic<'d>(
tech_name: &str,
patterns: &[CompiledPattern],
evidence: &UrlEvidence<'a>,
literal_interner: &'d LiteralInterner,
detected: &mut FxHashMap<String, (u8, Option<String>)>,
) {
let urls = evidence.urls;
if urls.is_empty() {
return;
}
let (literals_hit_ids, any_hit_ids, contains_hit_ids) = (
&evidence.literals_hit_ids,
&evidence.any_hit_ids,
&evidence.contains_hit_ids,
);
for url in urls {
for pattern in patterns {
let matcher = pattern.exec.get_matcher();
if pattern.matches_with_prune(
url,
literals_hit_ids,
any_hit_ids,
contains_hit_ids,
literal_interner,
) {
let version = matcher
.captures(url)
.and_then(|cap| VersionExtractor::extract(&pattern.exec.version_template, &cap));
handle_match_success(
Self::TYPE_NAME,
tech_name,
url,
url,
&version,
Some(pattern.exec.confidence),
&matcher.describe(literal_interner),
detected,
);
break; }
}
}
}
}
impl UrlAnalyzer {
#[inline(always)]
pub fn analyze(
runtime_lib: &RuleLibraryRuntime,
urls: &[&str],
detected: &mut FxHashMap<String, (u8, Option<String>)>,
) {
let url_evidence = UrlEvidence::new(urls);
<Self as Analyzer<[CompiledPattern], UrlEvidence>>::analyze(
runtime_lib,
&url_evidence,
Scope::Url,
detected,
);
}
}
#[derive(Debug)]
pub struct UrlEvidence<'a> {
pub urls: &'a [&'a str],
literals_hit_ids: FxHashSet<LiteralId>,
any_hit_ids: FxHashSet<LiteralId>,
contains_hit_ids: FxHashSet<LiteralId>,
empty_str_set: FxHashSet<LiteralId>,
}
impl<'a> UrlEvidence<'a> {
#[inline(always)]
pub fn new(urls: &'a [&'a str]) -> Self {
Self {
urls,
literals_hit_ids: FxHashSet::default(),
any_hit_ids: FxHashSet::default(),
contains_hit_ids: FxHashSet::default(),
empty_str_set: FxHashSet::default(), }
}
}
impl<'a> AnalyzerInput for UrlEvidence<'a> {
fn get_contains_hit_ids(&self) -> &FxHashSet<LiteralId> {
&self.empty_str_set
}
fn get_literal_hit_ids(&self) -> &FxHashSet<LiteralId> {
&self.empty_str_set
}
fn get_any_hit_ids(&self) -> &FxHashSet<LiteralId> {
&self.empty_str_set
}
}