summaryrefslogtreecommitdiff
path: root/lib/gitlab/untrusted_regexp/ruby_syntax.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/untrusted_regexp/ruby_syntax.rb')
-rw-r--r--lib/gitlab/untrusted_regexp/ruby_syntax.rb43
1 files changed, 43 insertions, 0 deletions
diff --git a/lib/gitlab/untrusted_regexp/ruby_syntax.rb b/lib/gitlab/untrusted_regexp/ruby_syntax.rb
new file mode 100644
index 00000000000..91f300f97d0
--- /dev/null
+++ b/lib/gitlab/untrusted_regexp/ruby_syntax.rb
@@ -0,0 +1,43 @@
+# frozen_string_literal: true
+
+module Gitlab
+ class UntrustedRegexp
+ # This class implements support for Ruby syntax of regexps
+ # and converts that to RE2 representation:
+ # /<regexp>/<flags>
+ class RubySyntax
+ PATTERN = %r{^/(?<regexp>.+)/(?<flags>[ismU]*)$}.freeze
+
+ # Checks if pattern matches a regexp pattern
+ # but does not enforce it's validity
+ def self.matches_syntax?(pattern)
+ pattern.is_a?(String) && pattern.match(PATTERN).present?
+ end
+
+ # The regexp can match the pattern `/.../`, but may not be fabricatable:
+ # it can be invalid or incomplete: `/match ( string/`
+ def self.valid?(pattern)
+ !!self.fabricate(pattern)
+ end
+
+ def self.fabricate(pattern)
+ self.fabricate!(pattern)
+ rescue RegexpError
+ nil
+ end
+
+ def self.fabricate!(pattern)
+ raise RegexpError, 'Pattern is not string!' unless pattern.is_a?(String)
+
+ matches = pattern.match(PATTERN)
+ raise RegexpError, 'Invalid regular expression!' if matches.nil?
+
+ expression = matches[:regexp]
+ flags = matches[:flags]
+ expression.prepend("(?#{flags})") if flags.present?
+
+ UntrustedRegexp.new(expression, multiline: false)
+ end
+ end
+ end
+end