perl_regex/validator/
mod.rs1mod 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}