diff options
Diffstat (limited to 'spec')
8 files changed, 235 insertions, 236 deletions
diff --git a/spec/lib/gitlab/url_blocker_spec.rb b/spec/lib/gitlab/url_blocker_spec.rb index f8bfcc6c99a..08678de87c9 100644 --- a/spec/lib/gitlab/url_blocker_spec.rb +++ b/spec/lib/gitlab/url_blocker_spec.rb @@ -501,6 +501,18 @@ describe Gitlab::UrlBlocker, :stub_invalid_dns_only do it_behaves_like 'dns rebinding checks' end end + + context 'with ports' do + let(:whitelist) do + ["127.0.0.1:2000"] + end + + it 'allows domain with port when resolved ip has port whitelisted' do + stub_domain_resolv("www.resolve-domain.com", '127.0.0.1') do + expect(described_class).not_to be_blocked_url("http://www.resolve-domain.com:2000", url_blocker_attributes) + end + end + end end end diff --git a/spec/lib/gitlab/url_blockers/domain_whitelist_entry_spec.rb b/spec/lib/gitlab/url_blockers/domain_whitelist_entry_spec.rb new file mode 100644 index 00000000000..34ea6c328e6 --- /dev/null +++ b/spec/lib/gitlab/url_blockers/domain_whitelist_entry_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UrlBlockers::DomainWhitelistEntry do + let(:domain) { 'www.example.com' } + + describe '#initialize' do + it 'initializes without port' do + domain_whitelist_entry = described_class.new(domain) + + expect(domain_whitelist_entry.domain).to eq(domain) + expect(domain_whitelist_entry.port).to be(nil) + end + + it 'initializes with port' do + port = 8080 + domain_whitelist_entry = described_class.new(domain, port: port) + + expect(domain_whitelist_entry.domain).to eq(domain) + expect(domain_whitelist_entry.port).to eq(port) + end + end + + describe '#match?' do + it 'matches when domain and port are equal' do + port = 8080 + domain_whitelist_entry = described_class.new(domain, port: port) + + expect(domain_whitelist_entry).to be_match(domain, port) + end + + it 'matches any port when port is nil' do + domain_whitelist_entry = described_class.new(domain) + + expect(domain_whitelist_entry).to be_match(domain, 8080) + expect(domain_whitelist_entry).to be_match(domain, 9090) + end + + it 'does not match when port is present but requested_port is nil' do + domain_whitelist_entry = described_class.new(domain, port: 8080) + + expect(domain_whitelist_entry).not_to be_match(domain, nil) + end + + it 'matches when port and requested_port are nil' do + domain_whitelist_entry = described_class.new(domain) + + expect(domain_whitelist_entry).to be_match(domain) + end + + it 'does not match if domain is not equal' do + domain_whitelist_entry = described_class.new(domain) + + expect(domain_whitelist_entry).not_to be_match('www.gitlab.com', 8080) + end + end +end diff --git a/spec/lib/gitlab/url_blockers/ip_whitelist_entry_spec.rb b/spec/lib/gitlab/url_blockers/ip_whitelist_entry_spec.rb new file mode 100644 index 00000000000..042d135d265 --- /dev/null +++ b/spec/lib/gitlab/url_blockers/ip_whitelist_entry_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Gitlab::UrlBlockers::IpWhitelistEntry do + let(:ipv4) { IPAddr.new('192.168.1.1') } + + describe '#initialize' do + it 'initializes without port' do + ip_whitelist_entry = described_class.new(ipv4) + + expect(ip_whitelist_entry.ip).to eq(ipv4) + expect(ip_whitelist_entry.port).to be(nil) + end + + it 'initializes with port' do + port = 8080 + ip_whitelist_entry = described_class.new(ipv4, port: port) + + expect(ip_whitelist_entry.ip).to eq(ipv4) + expect(ip_whitelist_entry.port).to eq(port) + end + end + + describe '#match?' do + it 'matches with equivalent IP and port' do + port = 8080 + ip_whitelist_entry = described_class.new(ipv4, port: port) + + expect(ip_whitelist_entry).to be_match(ipv4.to_s, port) + end + + it 'matches any port when port is nil' do + ip_whitelist_entry = described_class.new(ipv4) + + expect(ip_whitelist_entry).to be_match(ipv4.to_s, 8080) + expect(ip_whitelist_entry).to be_match(ipv4.to_s, 9090) + end + + it 'does not match when port is present but requested_port is nil' do + ip_whitelist_entry = described_class.new(ipv4, port: 8080) + + expect(ip_whitelist_entry).not_to be_match(ipv4.to_s, nil) + end + + it 'matches when port and requested_port are nil' do + ip_whitelist_entry = described_class.new(ipv4) + + expect(ip_whitelist_entry).to be_match(ipv4.to_s) + end + + it 'works with ipv6' do + ipv6 = IPAddr.new('fe80::c800:eff:fe74:8') + ip_whitelist_entry = described_class.new(ipv6) + + expect(ip_whitelist_entry).to be_match(ipv6.to_s, 8080) + end + + it 'matches ipv4 within IPv4 range' do + ipv4_range = IPAddr.new('127.0.0.0/28') + ip_whitelist_entry = described_class.new(ipv4_range) + + expect(ip_whitelist_entry).to be_match(ipv4_range.to_range.last.to_s, 8080) + expect(ip_whitelist_entry).not_to be_match('127.0.1.1', 8080) + end + + it 'matches IPv6 within IPv6 range' do + ipv6_range = IPAddr.new('fd84:6d02:f6d8:c89e::/124') + ip_whitelist_entry = described_class.new(ipv6_range) + + expect(ip_whitelist_entry).to be_match(ipv6_range.to_range.last.to_s, 8080) + expect(ip_whitelist_entry).not_to be_match('fd84:6d02:f6d8:f::f', 8080) + end + end +end diff --git a/spec/lib/gitlab/url_blockers/url_whitelist_spec.rb b/spec/lib/gitlab/url_blockers/url_whitelist_spec.rb index 64d804e8541..e43cd819838 100644 --- a/spec/lib/gitlab/url_blockers/url_whitelist_spec.rb +++ b/spec/lib/gitlab/url_blockers/url_whitelist_spec.rb @@ -13,20 +13,17 @@ describe Gitlab::UrlBlockers::UrlWhitelist do end describe '#domain_whitelisted?' do - let(:whitelist) do - [ - 'www.example.com', - 'example.com' - ] - end + let(:whitelist) { ['www.example.com', 'example.com'] } it 'returns true if domains present in whitelist' do + not_whitelisted = ['subdomain.example.com', 'example.org'] + aggregate_failures do whitelist.each do |domain| expect(described_class).to be_domain_whitelisted(domain) end - ['subdomain.example.com', 'example.org'].each do |domain| + not_whitelisted.each do |domain| expect(described_class).not_to be_domain_whitelisted(domain) end end @@ -35,6 +32,28 @@ describe Gitlab::UrlBlockers::UrlWhitelist do it 'returns false when domain is blank' do expect(described_class).not_to be_domain_whitelisted(nil) end + + context 'with ports' do + let(:whitelist) { ['example.io:3000'] } + + it 'returns true if domain and ports present in whitelist' do + parsed_whitelist = [['example.io', { port: 3000 }]] + not_whitelisted = [ + 'example.io', + ['example.io', { port: 3001 }] + ] + + aggregate_failures do + parsed_whitelist.each do |domain_and_port| + expect(described_class).to be_domain_whitelisted(*domain_and_port) + end + + not_whitelisted.each do |domain_and_port| + expect(described_class).not_to be_domain_whitelisted(*domain_and_port) + end + end + end + end end describe '#ip_whitelisted?' do @@ -114,5 +133,32 @@ describe Gitlab::UrlBlockers::UrlWhitelist do expect(described_class).not_to be_ip_whitelisted("127.0.1.15") end end + + context 'with ports' do + let(:whitelist) { ['127.0.0.9:3000', '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443'] } + + it 'returns true if ip and ports present in whitelist' do + parsed_whitelist = [ + ['127.0.0.9', { port: 3000 }], + ['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 443 }] + ] + not_whitelisted = [ + '127.0.0.9', + ['127.0.0.9', { port: 3001 }], + '[2001:db8:85a3:8d3:1319:8a2e:370:7348]', + ['[2001:db8:85a3:8d3:1319:8a2e:370:7348]', { port: 3001 }] + ] + + aggregate_failures do + parsed_whitelist.each do |ip_and_port| + expect(described_class).to be_ip_whitelisted(*ip_and_port) + end + + not_whitelisted.each do |ip_and_port| + expect(described_class).not_to be_ip_whitelisted(*ip_and_port) + end + end + end + end end end diff --git a/spec/support/shared_contexts/upload_type_check_shared_context.rb b/spec/support/shared_contexts/upload_type_check_shared_context.rb index b0b569fe83f..f168cad961c 100644 --- a/spec/support/shared_contexts/upload_type_check_shared_context.rb +++ b/spec/support/shared_contexts/upload_type_check_shared_context.rb @@ -2,37 +2,6 @@ # Construct an `uploader` variable that is configured to `check_upload_type` # with `mime_types` and `extensions`. -RSpec.shared_context 'uploader with type check' do - let(:uploader_class) do - Class.new(GitlabUploader) do - include UploadTypeCheck::Concern - storage :file - end - end - - let(:mime_types) { nil } - let(:extensions) { nil } - let(:uploader) do - uploader_class.class_exec(mime_types, extensions) do |mime_types, extensions| - check_upload_type mime_types: mime_types, extensions: extensions - end - uploader_class.new(build_stubbed(:user)) - end -end - -# This works with the UploadTypeCheck::Concern -RSpec.shared_context 'stubbed MimeMagic mime type detection' do - let(:mime_type) { '' } - let(:magic_mime) { mime_type } - let(:ext_mime) { mime_type } - before do - magic_mime_obj = MimeMagic.new(magic_mime) - ext_mime_obj = MimeMagic.new(ext_mime) - allow(MimeMagic).to receive(:by_magic).with(anything).and_return(magic_mime_obj) - allow(MimeMagic).to receive(:by_path).with(anything).and_return(ext_mime_obj) - end -end - # @param uploader [CarrierWave::Uploader::Base] uploader with extension_whitelist method. RSpec.shared_context 'ignore extension whitelist check' do before do diff --git a/spec/support/shared_examples/models/application_setting_shared_examples.rb b/spec/support/shared_examples/models/application_setting_shared_examples.rb index a43d2a75082..aed85a6630a 100644 --- a/spec/support/shared_examples/models/application_setting_shared_examples.rb +++ b/spec/support/shared_examples/models/application_setting_shared_examples.rb @@ -68,12 +68,12 @@ RSpec.shared_examples 'application settings examples' do setting.outbound_local_requests_whitelist_raw = 'example.com' expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( - [], ['example.com'] + [], [an_object_having_attributes(domain: 'example.com')] ) setting.outbound_local_requests_whitelist_raw = 'gitlab.com' expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( - [], ['gitlab.com'] + [], [an_object_having_attributes(domain: 'gitlab.com')] ) end end @@ -81,15 +81,42 @@ RSpec.shared_examples 'application settings examples' do context 'outbound_local_requests_whitelist_arrays' do it 'separates the IPs and domains' do setting.outbound_local_requests_whitelist = [ - '192.168.1.1', '127.0.0.0/28', 'www.example.com', 'example.com', - '::ffff:a00:2', '1:0:0:0:0:0:0:0/124', 'subdomain.example.com' + '192.168.1.1', + '127.0.0.0/28', + '::ffff:a00:2', + '1:0:0:0:0:0:0:0/124', + 'example.com', + 'subdomain.example.com', + 'www.example.com', + '::', + '1::', + '::1', + '1:2:3:4:5::7:8', + '[1:2:3:4:5::7:8]', + '[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443', + 'www.example2.com:8080', + 'example.com:8080' ] ip_whitelist = [ - IPAddr.new('192.168.1.1'), IPAddr.new('127.0.0.0/8'), - IPAddr.new('::ffff:a00:2'), IPAddr.new('1:0:0:0:0:0:0:0/124') + an_object_having_attributes(ip: IPAddr.new('192.168.1.1')), + an_object_having_attributes(ip: IPAddr.new('127.0.0.0/8')), + an_object_having_attributes(ip: IPAddr.new('::ffff:a00:2')), + an_object_having_attributes(ip: IPAddr.new('1:0:0:0:0:0:0:0/124')), + an_object_having_attributes(ip: IPAddr.new('::')), + an_object_having_attributes(ip: IPAddr.new('1::')), + an_object_having_attributes(ip: IPAddr.new('::1')), + an_object_having_attributes(ip: IPAddr.new('1:2:3:4:5::7:8')), + an_object_having_attributes(ip: IPAddr.new('[1:2:3:4:5::7:8]')), + an_object_having_attributes(ip: IPAddr.new('[2001:db8:85a3:8d3:1319:8a2e:370:7348]'), port: 443) + ] + domain_whitelist = [ + an_object_having_attributes(domain: 'example.com'), + an_object_having_attributes(domain: 'subdomain.example.com'), + an_object_having_attributes(domain: 'www.example.com'), + an_object_having_attributes(domain: 'www.example2.com', port: 8080), + an_object_having_attributes(domain: 'example.com', port: 8080) ] - domain_whitelist = ['www.example.com', 'example.com', 'subdomain.example.com'] expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( ip_whitelist, domain_whitelist @@ -117,7 +144,7 @@ RSpec.shared_examples 'application settings examples' do expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( [], - ['example.com'] + [an_object_having_attributes(domain: 'example.com')] ) setting.add_to_outbound_local_requests_whitelist( @@ -126,7 +153,7 @@ RSpec.shared_examples 'application settings examples' do expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( [], - ['example.com', 'gitlab.com'] + [an_object_having_attributes(domain: 'example.com'), an_object_having_attributes(domain: 'gitlab.com')] ) end @@ -137,7 +164,7 @@ RSpec.shared_examples 'application settings examples' do expect(setting.outbound_local_requests_whitelist).to contain_exactly('gitlab.com') expect(setting.outbound_local_requests_whitelist_arrays).to contain_exactly( - [], ['gitlab.com'] + [], [an_object_having_attributes(domain: 'gitlab.com')] ) end diff --git a/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb b/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb index 99da2a14bb6..81ac6bd94db 100644 --- a/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb +++ b/spec/support/shared_examples/uploaders/upload_type_shared_examples.rb @@ -26,67 +26,3 @@ shared_examples 'accepted carrierwave upload' do expect { uploader.cache!(fixture_file) }.to change { uploader.file }.from(nil).to(kind_of(CarrierWave::SanitizedFile)) end end - -def check_content_matches_extension!(file = double(read: nil, path: '')) - magic_file = UploadTypeCheck::MagicFile.new(file) - uploader.check_content_matches_extension!(magic_file) -end - -RSpec.shared_examples 'upload passes content type check' do - it 'does not raise error' do - expect { check_content_matches_extension! }.not_to raise_error - end -end - -RSpec.shared_examples 'upload fails content type check' do - it 'raises error' do - expect { check_content_matches_extension! }.to raise_error(CarrierWave::IntegrityError) - end -end - -def upload_type_checked_filenames(filenames) - Array(filenames).each do |filename| - # Feed the uploader "some" content. - path = File.join('spec', 'fixtures', 'dk.png') - file = File.new(path, 'r') - # Rename the file with what we want. - allow(file).to receive(:path).and_return(filename) - - # Force the content type to match the extension type. - mime_type = MimeMagic.by_path(filename) - allow(MimeMagic).to receive(:by_magic).and_return(mime_type) - - uploaded_file = Rack::Test::UploadedFile.new(file, original_filename: filename) - uploader.cache!(uploaded_file) - end -end - -def upload_type_checked_fixtures(upload_fixtures) - upload_fixtures = Array(upload_fixtures) - upload_fixtures.each do |upload_fixture| - path = File.join('spec', 'fixtures', upload_fixture) - uploader.cache!(fixture_file_upload(path)) - end -end - -RSpec.shared_examples 'type checked uploads' do |upload_fixtures = nil, filenames: nil| - it 'check type' do - upload_fixtures = Array(upload_fixtures) - filenames = Array(filenames) - - times = upload_fixtures.length + filenames.length - expect(uploader).to receive(:check_content_matches_extension!).exactly(times).times - - upload_type_checked_fixtures(upload_fixtures) unless upload_fixtures.empty? - upload_type_checked_filenames(filenames) unless filenames.empty? - end -end - -RSpec.shared_examples 'skipped type checked uploads' do |upload_fixtures = nil, filenames: nil| - it 'skip type check' do - expect(uploader).not_to receive(:check_content_matches_extension!) - - upload_type_checked_fixtures(upload_fixtures) if upload_fixtures - upload_type_checked_filenames(filenames) if filenames - end -end diff --git a/spec/uploaders/upload_type_check_spec.rb b/spec/uploaders/upload_type_check_spec.rb deleted file mode 100644 index a4895f6a956..00000000000 --- a/spec/uploaders/upload_type_check_spec.rb +++ /dev/null @@ -1,124 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -describe UploadTypeCheck do - include_context 'uploader with type check' - - def upload_fixture(filename) - fixture_file_upload(File.join('spec', 'fixtures', filename)) - end - - describe '#check_content_matches_extension! callback using file upload' do - context 'when extension matches contents' do - it 'not raise error on upload' do - expect { uploader.cache!(upload_fixture('banana_sample.gif')) }.not_to raise_error - end - end - - context 'when extension does not match contents' do - it 'raise error' do - expect { uploader.cache!(upload_fixture('not_a_png.png')) }.to raise_error(CarrierWave::IntegrityError) - end - end - end - - describe '#check_content_matches_extension! callback using stubs' do - include_context 'stubbed MimeMagic mime type detection' - - context 'when no extension and with ambiguous/text content' do - let(:magic_mime) { '' } - let(:ext_mime) { '' } - - it_behaves_like 'upload passes content type check' - end - - context 'when no extension and with non-text content' do - let(:magic_mime) { 'image/gif' } - let(:ext_mime) { '' } - - it_behaves_like 'upload fails content type check' - end - - # Most text files will exhibit this behaviour. - context 'when ambiguous content with text extension' do - let(:magic_mime) { '' } - let(:ext_mime) { 'text/plain' } - - it_behaves_like 'upload passes content type check' - end - - context 'when text content with text extension' do - let(:magic_mime) { 'text/plain' } - let(:ext_mime) { 'text/plain' } - - it_behaves_like 'upload passes content type check' - end - - context 'when ambiguous content with non-text extension' do - let(:magic_mime) { '' } - let(:ext_mime) { 'application/zip' } - - it_behaves_like 'upload fails content type check' - end - - # These are the types when uploading a .dmg - context 'when content and extension do not match' do - let(:magic_mime) { 'application/x-bzip' } - let(:ext_mime) { 'application/x-apple-diskimage' } - - it_behaves_like 'upload fails content type check' - end - end - - describe '#check_content_matches_extension! mime_type filtering' do - context 'without mime types' do - let(:mime_types) { nil } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt rails_sample.jpg] - end - - context 'with mime types string' do - let(:mime_types) { 'text/plain' } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt] - it_behaves_like 'skipped type checked uploads', %w[dk.png] - end - - context 'with mime types regex' do - let(:mime_types) { [/image\/(gif|png)/] } - - it_behaves_like 'type checked uploads', %w[banana_sample.gif dk.png] - it_behaves_like 'skipped type checked uploads', %w[doc_sample.txt] - end - - context 'with mime types array' do - let(:mime_types) { ['text/plain', /image\/png/] } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png] - it_behaves_like 'skipped type checked uploads', %w[audio_sample.wav] - end - end - - describe '#check_content_matches_extension! extensions filtering' do - context 'without extensions' do - let(:extensions) { nil } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png] - end - - context 'with extensions string' do - let(:extensions) { 'txt' } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt] - it_behaves_like 'skipped type checked uploads', %w[rails_sample.jpg] - end - - context 'with extensions array of strings' do - let(:extensions) { %w[txt png] } - - it_behaves_like 'type checked uploads', %w[doc_sample.txt dk.png] - it_behaves_like 'skipped type checked uploads', %w[audio_sample.wav] - end - end -end |