Skip to main content

perl_regex/validator/
mod.rs

1mod code_execution;
2mod complexity;
3mod config;
4mod group;
5mod nested_quantifier;
6
7pub use config::RegexValidationConfig;
8
9use crate::error::RegexError;
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct RegexFinding {
13    pub offset: usize,
14    pub message: &'static str,
15}
16
17pub struct RegexValidator {
18    config: RegexValidationConfig,
19}
20
21impl Default for RegexValidator {
22    fn default() -> Self {
23        Self::new()
24    }
25}
26
27impl RegexValidator {
28    pub fn new() -> Self {
29        Self { config: RegexValidationConfig::default() }
30    }
31
32    pub fn with_config(config: RegexValidationConfig) -> Self {
33        Self { config }
34    }
35
36    pub fn config(&self) -> &RegexValidationConfig {
37        &self.config
38    }
39
40    pub fn validate(&self, pattern: &str, start_pos: usize) -> Result<(), RegexError> {
41        if let Some(finding) = self.find_code_execution(pattern, start_pos) {
42            return Err(RegexError::syntax(finding.message, finding.offset));
43        }
44        if let Some(finding) = self.find_nested_quantifier(pattern, start_pos) {
45            return Err(RegexError::syntax(finding.message, finding.offset));
46        }
47        complexity::check_complexity(pattern, start_pos, &self.config)
48    }
49
50    pub fn detects_code_execution(&self, pattern: &str) -> bool {
51        code_execution::detects_code_execution(pattern)
52    }
53
54    pub fn detect_nested_quantifiers(&self, pattern: &str) -> bool {
55        nested_quantifier::detect_nested_quantifiers(pattern)
56    }
57
58    pub fn find_code_execution(&self, pattern: &str, start_pos: usize) -> Option<RegexFinding> {
59        code_execution::find_code_execution(pattern, start_pos).map(|finding| {
60            let message = match finding.kind {
61                code_execution::EmbeddedCodeKind::Immediate => {
62                    "Embedded code execution is not allowed in regex patterns"
63                }
64                code_execution::EmbeddedCodeKind::Deferred => {
65                    "Deferred embedded code execution is not allowed in regex patterns"
66                }
67            };
68            RegexFinding { offset: finding.offset, message }
69        })
70    }
71
72    pub fn find_nested_quantifier(&self, pattern: &str, start_pos: usize) -> Option<RegexFinding> {
73        nested_quantifier::find_nested_quantifier(pattern, start_pos).map(|offset| RegexFinding {
74            offset,
75            message: "Nested quantifiers may cause catastrophic backtracking",
76        })
77    }
78}