//! This module contains code dedicated to check validity of attribute's value. //! //! # Examples //! ``` //! use sanitize_html::rules::pattern::Pattern; //! use regex::Regex; //! //! let href = Pattern::regex(Regex::new("^(ftp:|http:|https:|mailto:)").unwrap()) | //! !Pattern::regex(Regex::new("^[^/]+[[:space:]]*:").unwrap()); //! //! assert!(href.matches("filename.xls")); //! assert!(href.matches("http://foo.com/")); //! assert!(href.matches(" filename with spaces .zip ")); //! assert!(!href.matches(" javascript : window.location = '//example.com/'")); // Attempt to make XSS //! ``` use regex::Regex; /// Value pattern pub struct Pattern(pub Box bool + Sync + Send>); impl Pattern { /// Creates pattern which accepts any value. /// /// # Example /// ``` /// use sanitize_html::rules::pattern::Pattern; /// use regex::Regex; /// /// let pattern = Pattern::any(); /// assert!(pattern.matches("")); /// assert!(pattern.matches("pants")); /// ``` pub fn any() -> Self { Pattern(Box::new(move |_value| true)) } /// Creates pattern which uses regular expression to check a value. Panics /// /// # Example /// ``` /// use sanitize_html::rules::pattern::Pattern; /// use regex::Regex; /// /// let pattern = Pattern::regex(Regex::new("ant").unwrap()); /// assert!(!pattern.matches("")); /// assert!(pattern.matches("pants")); /// ``` pub fn regex(re: Regex) -> Self { Pattern(Box::new(move |value| re.is_match(value))) } /// Checks if a value matches to a pattern. pub fn matches(&self, value: &str) -> bool { (self.0)(value) } } impl ::std::ops::Not for Pattern { type Output = Pattern; /// Negates pattern /// /// # Example /// ``` /// use sanitize_html::rules::pattern::Pattern; /// use regex::Regex; /// /// let pattern = !Pattern::any(); /// assert!(!pattern.matches("")); /// assert!(!pattern.matches("pants")); /// ``` fn not(self) -> Self::Output { let cb = self.0; Pattern(Box::new(move |value| !cb(value))) } } impl ::std::ops::BitAnd for Pattern { type Output = Pattern; /// Combines two patterns into a pattern which matches a string iff both patterns match that string. /// /// # Example /// ``` /// use sanitize_html::rules::pattern::Pattern; /// use regex::Regex; /// /// let pan = Pattern::regex(Regex::new("pan").unwrap()); /// let ant = Pattern::regex(Regex::new("ant").unwrap()); /// let pattern = pan & ant; /// /// assert!(!pattern.matches("pan")); /// assert!(!pattern.matches("ant")); /// assert!(pattern.matches("pants")); /// ``` fn bitand(self, rhs: Pattern) -> Self::Output { let cb1 = self.0; let cb2 = rhs.0; Pattern(Box::new(move |value| cb1(value) && cb2(value))) } } impl ::std::ops::BitOr for Pattern { type Output = Pattern; /// Combines two patterns into a pattern which matches a string if one of patterns matches that string. /// /// # Example /// ``` /// use sanitize_html::rules::pattern::Pattern; /// use regex::Regex; /// /// let pan = Pattern::regex(Regex::new("pan").unwrap()); /// let pot = Pattern::regex(Regex::new("pot").unwrap()); /// let pattern = pan | pot; /// /// assert!(pattern.matches("pants")); /// assert!(pattern.matches("pot")); /// assert!(!pattern.matches("jar")); /// ``` fn bitor(self, rhs: Pattern) -> Self::Output { let cb1 = self.0; let cb2 = rhs.0; Pattern(Box::new(move |value| cb1(value) || cb2(value))) } }