Add extended /regexp/ scheme support to untrusted regexp

This commit is contained in:
Grzegorz Bizon 2018-05-17 12:29:47 +02:00
parent f52de2f73c
commit 0ce63efe96
2 changed files with 71 additions and 1 deletions

View file

@ -9,6 +9,8 @@ module Gitlab
# 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
require_dependency 're2'
delegate :===, :source, to: :regexp
def initialize(pattern, multiline: false)
@ -52,6 +54,27 @@ module Gitlab
Regexp.new(pattern)
end
def self.valid?(pattern)
self.fabricate(pattern)
rescue RegexpError
false
end
def self.fabricate(pattern)
matches = pattern.match(%r{^/(?<regexp>.+)/(?<flags>[ismU]*)$})
if matches
expression = matches[:regexp]
flags = matches[:flags]
expression.prepend("(?#{flags})") if flags.present?
self.new(expression, multiline: false)
else
self.new(pattern, multiline: false)
end
end
private
attr_reader :regexp

View file

@ -1,6 +1,53 @@
require 'spec_helper'
require 'fast_spec_helper'
require 'support/shared_examples/malicious_regexp_shared_examples'
describe Gitlab::UntrustedRegexp do
describe '.valid?' do
it 'returns true if regexp is valid' do
end
it 'returns true if regexp is invalid' do
end
end
describe '.fabricate' do
context 'when regexp is using /regexp/ scheme with flags' do
it 'fabricates regexp with a single flag' do
regexp = described_class.fabricate('/something/i')
expect(regexp).to eq described_class.new('(?i)something')
expect(regexp.scan('SOMETHING')).to be_one
end
it 'fabricates regexp with multiple flags' do
regexp = described_class.fabricate('/something/im')
expect(regexp).to eq described_class.new('(?im)something')
end
it 'fabricates regexp without flags' do
regexp = described_class.fabricate('/something/')
expect(regexp).to eq described_class.new('something')
end
end
context 'when regexp is not plain pattern' do
it 'fabricates regexp without flags' do
regexp = described_class.fabricate('something')
expect(regexp).to eq described_class.new('something')
end
end
context 'when regexp is invalid' do
it 'raises an error' do
expect { described_class.fabricate('/some ( thing/') }
.to raise_error(RegexpError)
end
end
end
describe '#initialize' do
subject { described_class.new(pattern) }