Class: Gitlab::UntrustedRegexp
- Inherits:
-
Object
- Object
- Gitlab::UntrustedRegexp
- Defined in:
- lib/gitlab/untrusted_regexp.rb,
lib/gitlab/untrusted_regexp/ruby_syntax.rb
Overview
An untrusted regular expression is any regexp containing patterns sourced from user input.
Ruby's built-in regular expression library allows patterns which complete in exponential time, permitting denial-of-service attacks.
Not all regular expression features are available in untrusted regexes, and there is a strict limit on total execution time. See the RE2 documentation at github.com/google/re2/wiki/Syntax for more details.
Defined Under Namespace
Classes: RubySyntax
Class Method Summary collapse
-
.with_fallback(pattern, multiline: false) ⇒ Object
Handles regular expressions with the preferred RE2 library where possible via UntustedRegex.
Instance Method Summary collapse
- #==(other) ⇒ Object
-
#initialize(pattern, multiline: false) ⇒ UntrustedRegexp
constructor
A new instance of UntrustedRegexp.
- #match(text) ⇒ Object
- #match?(text) ⇒ Boolean
- #replace(text, rewrite) ⇒ Object
- #replace_all(text, rewrite) ⇒ Object
- #scan(text) ⇒ Object
Constructor Details
#initialize(pattern, multiline: false) ⇒ UntrustedRegexp
Returns a new instance of UntrustedRegexp.
18 19 20 21 22 23 24 25 26 |
# File 'lib/gitlab/untrusted_regexp.rb', line 18 def initialize(pattern, multiline: false) if multiline pattern = "(?m)#{pattern}" end @regexp = RE2::Regexp.new(pattern, log_errors: false) raise RegexpError, regexp.error unless regexp.ok? end |
Class Method Details
.with_fallback(pattern, multiline: false) ⇒ Object
Handles regular expressions with the preferred RE2 library where possible via UntustedRegex. Falls back to Ruby's built-in regular expression library when the syntax would be invalid in RE2.
One difference between these is `(?m)` multi-line mode. Ruby regex enables this by default, but also handles `^` and `$` differently. See: www.regular-expressions.info/modifiers.html
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/gitlab/untrusted_regexp.rb', line 61 def self.with_fallback(pattern, multiline: false) UntrustedRegexp.new(pattern, multiline: multiline) rescue RegexpError raise if Feature.enabled?(:disable_unsafe_regexp) if Feature.enabled?(:ci_unsafe_regexp_logger, type: :ops) Gitlab::AppJsonLogger.info( class: self.name, regexp: pattern.to_s, fabricated: 'unsafe ruby regexp' ) end Regexp.new(pattern) end |
Instance Method Details
#==(other) ⇒ Object
50 51 52 |
# File 'lib/gitlab/untrusted_regexp.rb', line 50 def ==(other) self.source == other.source end |
#match(text) ⇒ Object
38 39 40 |
# File 'lib/gitlab/untrusted_regexp.rb', line 38 def match(text) scan_regexp.match(text) end |
#match?(text) ⇒ Boolean
42 43 44 |
# File 'lib/gitlab/untrusted_regexp.rb', line 42 def match?(text) text.present? && scan(text).present? end |
#replace(text, rewrite) ⇒ Object
46 47 48 |
# File 'lib/gitlab/untrusted_regexp.rb', line 46 def replace(text, rewrite) RE2.Replace(text, regexp, rewrite) end |
#replace_all(text, rewrite) ⇒ Object
28 29 30 |
# File 'lib/gitlab/untrusted_regexp.rb', line 28 def replace_all(text, rewrite) RE2.GlobalReplace(text, regexp, rewrite) end |
#scan(text) ⇒ Object
32 33 34 35 36 |
# File 'lib/gitlab/untrusted_regexp.rb', line 32 def scan(text) matches = scan_regexp.scan(text).to_a matches.map!(&:first) if regexp.number_of_capturing_groups == 0 matches end |