Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouwe Maan <douwe@gitlab.com>2017-06-22 18:33:17 +0300
committerMike Greiling <mike@pixelcog.com>2017-07-20 06:28:41 +0300
commitba60d4f6e4f3a6d3cb56c9320f475bee8f0b38da (patch)
tree51245b9a3f7df6df3e396f3335f88d79f5d2f328 /lib/gitlab/untrusted_regexp.rb
parentceda6bd5a6d5e7b24f0ec003ce2e7b446d0917c0 (diff)
Merge branch '24570-use-re2-for-user-supplied-regexp-9-3' into 'security-9-3'
24570 use re2 for user supplied regexp 9 3 See merge request !2129
Diffstat (limited to 'lib/gitlab/untrusted_regexp.rb')
-rw-r--r--lib/gitlab/untrusted_regexp.rb53
1 files changed, 53 insertions, 0 deletions
diff --git a/lib/gitlab/untrusted_regexp.rb b/lib/gitlab/untrusted_regexp.rb
new file mode 100644
index 00000000000..8b43f0053d6
--- /dev/null
+++ b/lib/gitlab/untrusted_regexp.rb
@@ -0,0 +1,53 @@
+module Gitlab
+ # 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 https://github.com/google/re2/wiki/Syntax for more details.
+ class UntrustedRegexp
+ delegate :===, to: :regexp
+
+ def initialize(pattern)
+ @regexp = RE2::Regexp.new(pattern, log_errors: false)
+
+ raise RegexpError.new(regexp.error) unless regexp.ok?
+ end
+
+ def replace_all(text, rewrite)
+ RE2.GlobalReplace(text, regexp, rewrite)
+ end
+
+ def scan(text)
+ scan_regexp.scan(text).map do |match|
+ if regexp.number_of_capturing_groups == 0
+ match.first
+ else
+ match
+ end
+ end
+ end
+
+ def replace(text, rewrite)
+ RE2.Replace(text, regexp, rewrite)
+ end
+
+ private
+
+ attr_reader :regexp
+
+ # RE2 scan operates differently to Ruby scan when there are no capture
+ # groups, so work around it
+ def scan_regexp
+ @scan_regexp ||=
+ if regexp.number_of_capturing_groups == 0
+ RE2::Regexp.new('(' + regexp.source + ')')
+ else
+ regexp
+ end
+ end
+ end
+end