cms_scanner 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +14 -0
- data/Gemfile +6 -0
- data/README.md +20 -0
- data/Rakefile +9 -0
- data/app/app.rb +4 -0
- data/app/controllers.rb +2 -0
- data/app/controllers/core.rb +46 -0
- data/app/controllers/core/cli_options.rb +68 -0
- data/app/controllers/interesting_files.rb +12 -0
- data/app/finders.rb +1 -0
- data/app/finders/interesting_files.rb +21 -0
- data/app/finders/interesting_files/fantastico_fileslist.rb +23 -0
- data/app/finders/interesting_files/headers.rb +15 -0
- data/app/finders/interesting_files/robots_txt.rb +22 -0
- data/app/finders/interesting_files/search_replace_db_2.rb +28 -0
- data/app/finders/interesting_files/xml_rpc.rb +62 -0
- data/app/formatters.rb +3 -0
- data/app/formatters/cli.rb +18 -0
- data/app/formatters/cli_no_colour.rb +15 -0
- data/app/formatters/json.rb +12 -0
- data/app/models.rb +5 -0
- data/app/models/fantastico_fileslist.rb +20 -0
- data/app/models/headers.rb +37 -0
- data/app/models/interesting_file.rb +30 -0
- data/app/models/robots_txt.rb +20 -0
- data/app/models/xml_rpc.rb +35 -0
- data/app/views/cli/core/finished.erb +4 -0
- data/app/views/cli/core/started.erb +3 -0
- data/app/views/cli/interesting_files/findings.erb +19 -0
- data/app/views/cli/scan_aborted.erb +4 -0
- data/app/views/json/core/finished.erb +3 -0
- data/app/views/json/core/started.erb +3 -0
- data/app/views/json/interesting_files/findings.erb +1 -0
- data/app/views/json/scan_aborted.erb +4 -0
- data/cms_scanner.gemspec +37 -0
- data/examples/views/cli/wp_custom/test.erb +1 -0
- data/examples/views/json/wp_custom/test.erb +1 -0
- data/examples/wpscan.rb +29 -0
- data/lib/cms_scanner.rb +71 -0
- data/lib/cms_scanner/browser.rb +68 -0
- data/lib/cms_scanner/browser/actions.rb +48 -0
- data/lib/cms_scanner/browser/options.rb +53 -0
- data/lib/cms_scanner/cache/file_store.rb +75 -0
- data/lib/cms_scanner/cache/typhoeus.rb +21 -0
- data/lib/cms_scanner/controller.rb +90 -0
- data/lib/cms_scanner/controllers.rb +34 -0
- data/lib/cms_scanner/errors/auth_errors.rb +15 -0
- data/lib/cms_scanner/finders.rb +5 -0
- data/lib/cms_scanner/finders/finder.rb +27 -0
- data/lib/cms_scanner/finders/finding.rb +32 -0
- data/lib/cms_scanner/finders/findings.rb +25 -0
- data/lib/cms_scanner/finders/independent_finder.rb +30 -0
- data/lib/cms_scanner/finders/independent_finders.rb +41 -0
- data/lib/cms_scanner/formatter.rb +118 -0
- data/lib/cms_scanner/formatter/buffer.rb +15 -0
- data/lib/cms_scanner/target.rb +33 -0
- data/lib/cms_scanner/target/platform.rb +2 -0
- data/lib/cms_scanner/target/platform/php.rb +39 -0
- data/lib/cms_scanner/target/platform/wordpress.rb +35 -0
- data/lib/cms_scanner/target/platform/wordpress/custom_directories.rb +62 -0
- data/lib/cms_scanner/target/server.rb +3 -0
- data/lib/cms_scanner/target/server/apache.rb +43 -0
- data/lib/cms_scanner/target/server/generic.rb +34 -0
- data/lib/cms_scanner/target/server/iis.rb +48 -0
- data/lib/cms_scanner/version.rb +4 -0
- data/lib/cms_scanner/web_site.rb +68 -0
- data/lib/helper.rb +24 -0
- data/spec/app/controllers/core_spec.rb +152 -0
- data/spec/app/controllers/interesting_files_spec.rb +50 -0
- data/spec/app/finders/interesting_files/fantastico_fileslist_spec.rb +68 -0
- data/spec/app/finders/interesting_files/headers_spec.rb +38 -0
- data/spec/app/finders/interesting_files/robots_txt_spec.rb +56 -0
- data/spec/app/finders/interesting_files/search_replace_db_2_spec.rb +55 -0
- data/spec/app/finders/interesting_files/xml_rpc_spec.rb +138 -0
- data/spec/app/finders/interesting_files_spec.rb +13 -0
- data/spec/app/formatters/cli_no_colour_spec.rb +17 -0
- data/spec/app/formatters/cli_spec.rb +21 -0
- data/spec/app/formatters/json_spec.rb +33 -0
- data/spec/app/models/fantastico_fileslist_spec.rb +32 -0
- data/spec/app/models/headers_spec.rb +52 -0
- data/spec/app/models/interesting_file_spec.rb +51 -0
- data/spec/app/models/robots_txt_spec.rb +28 -0
- data/spec/app/models/xml_rpc_spec.rb +47 -0
- data/spec/cache/.gitignore +4 -0
- data/spec/dummy_finders.rb +41 -0
- data/spec/fixtures/interesting_files/fantastico_fileslist/fantastico_fileslist.txt +12 -0
- data/spec/fixtures/interesting_files/file.txt +4 -0
- data/spec/fixtures/interesting_files/headers/interesting.txt +14 -0
- data/spec/fixtures/interesting_files/headers/no_interesting.txt +12 -0
- data/spec/fixtures/interesting_files/robots_txt/robots.txt +10 -0
- data/spec/fixtures/interesting_files/search_replace_db_2/searchreplacedb2.php +188 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_in_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_out_of_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/xmlrpc.php +1 -0
- data/spec/fixtures/output.txt +0 -0
- data/spec/fixtures/target/platform/php/debug_log/debug.log +2 -0
- data/spec/fixtures/target/platform/php/fpd/wp_rss_functions.php +2 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/custom_w_spaces.html +10 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/default.html +14 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/https.html +12 -0
- data/spec/fixtures/target/platform/wordpress/detection/default.html +4 -0
- data/spec/fixtures/target/platform/wordpress/detection/not_wp.html +8 -0
- data/spec/fixtures/target/platform/wordpress/detection/wp_includes.html +3 -0
- data/spec/fixtures/target/server/apache/directory_listing/2.2.16.html +15 -0
- data/spec/fixtures/target/server/generic/server/apache/basic.txt +5 -0
- data/spec/fixtures/target/server/generic/server/iis/basic.txt +6 -0
- data/spec/fixtures/target/server/generic/server/not_detected.txt +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/no_parent.html +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/with_parent.html +3 -0
- data/spec/fixtures/views/base/ctrl/local.erb +1 -0
- data/spec/fixtures/views/base/ctrl/test.erb +3 -0
- data/spec/fixtures/views/base/global.erb +1 -0
- data/spec/fixtures/views/base/test.erb +2 -0
- data/spec/fixtures/views/based_format/test.erb +1 -0
- data/spec/fixtures/views/json/render_me.erb +4 -0
- data/spec/lib/browser_spec.rb +141 -0
- data/spec/lib/cache/file_store_spec.rb +101 -0
- data/spec/lib/cache/typhoeus_spec.rb +30 -0
- data/spec/lib/cms_scanner_spec.rb +45 -0
- data/spec/lib/controller_spec.rb +23 -0
- data/spec/lib/controllers_spec.rb +52 -0
- data/spec/lib/finders/findings_spec.rb +49 -0
- data/spec/lib/finders/independent_finders_spec.rb +98 -0
- data/spec/lib/formatter_spec.rb +136 -0
- data/spec/lib/sub_scanner_spec.rb +27 -0
- data/spec/lib/target/platforms_spec.rb +13 -0
- data/spec/lib/target/servers_spec.rb +13 -0
- data/spec/lib/target_spec.rb +50 -0
- data/spec/lib/web_site_spec.rb +124 -0
- data/spec/shared_examples.rb +11 -0
- data/spec/shared_examples/browser_actions.rb +32 -0
- data/spec/shared_examples/finding.rb +20 -0
- data/spec/shared_examples/formatter_buffer.rb +8 -0
- data/spec/shared_examples/formatter_class_methods.rb +26 -0
- data/spec/shared_examples/independent_finder.rb +33 -0
- data/spec/shared_examples/target/platform/php.rb +58 -0
- data/spec/shared_examples/target/platform/wordpress.rb +41 -0
- data/spec/shared_examples/target/platform/wordpress/custom_directories.rb +50 -0
- data/spec/shared_examples/target/server/apache.rb +33 -0
- data/spec/shared_examples/target/server/generic.rb +34 -0
- data/spec/shared_examples/target/server/iis.rb +38 -0
- data/spec/spec_helper.rb +41 -0
- metadata +432 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dummy_finders'
|
3
|
+
|
4
|
+
describe CMSScanner::Finders::Findings do
|
5
|
+
|
6
|
+
subject(:findings) { described_class.new }
|
7
|
+
let(:dummy) { CMSScanner::DummyFinding }
|
8
|
+
|
9
|
+
describe '#<<' do
|
10
|
+
after { expect(findings).to eq @expected }
|
11
|
+
|
12
|
+
context 'when empty array' do
|
13
|
+
it 'adds it' do
|
14
|
+
findings << 'empty-test'
|
15
|
+
@expected = %w(empty-test)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when not empty' do
|
20
|
+
let(:confirmed) { dummy.new('confirmed') }
|
21
|
+
|
22
|
+
before { findings << dummy.new('test') << confirmed }
|
23
|
+
|
24
|
+
it 'adds a confirmed result correctly' do
|
25
|
+
confirmed_dup = confirmed.dup
|
26
|
+
confirmed_dup.confidence = 100
|
27
|
+
|
28
|
+
findings << dummy.new('test2')
|
29
|
+
findings << confirmed_dup
|
30
|
+
|
31
|
+
confirmed.confirmed_by = confirmed_dup
|
32
|
+
|
33
|
+
@expected = [] << dummy.new('test') << confirmed << dummy.new('test2')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#+' do
|
39
|
+
after { expect(findings).to eq @expected }
|
40
|
+
|
41
|
+
it 'adds it/them' do
|
42
|
+
# Dummy assignement to avoid the 'Operator used in void context'
|
43
|
+
_ = findings + %w(test1 test2)
|
44
|
+
|
45
|
+
@expected = %w(test1 test2)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'dummy_finders'
|
3
|
+
|
4
|
+
describe CMSScanner::Finders::IndependentFinders do
|
5
|
+
|
6
|
+
subject(:finders) { described_class.new }
|
7
|
+
|
8
|
+
describe '#run' do
|
9
|
+
let(:target) { 'target' }
|
10
|
+
let(:finding) { CMSScanner::DummyFinding }
|
11
|
+
let(:expected_aggressive) { finding.new('test', found_by: 'override', confidence: 100) }
|
12
|
+
let(:expected_passive) do
|
13
|
+
[
|
14
|
+
finding.new('test', found_by: 'DummyFinder (passive detection)'),
|
15
|
+
finding.new('spotted', found_by: 'NoAggressiveResult (passive detection)', confidence: 10)
|
16
|
+
]
|
17
|
+
end
|
18
|
+
|
19
|
+
before do
|
20
|
+
finders << CMSScanner::Finders::DummyFinder.new(target) <<
|
21
|
+
CMSScanner::Finders::NoAggressiveResult.new(target)
|
22
|
+
|
23
|
+
@found = finders.run(mode: mode)
|
24
|
+
|
25
|
+
expect(@found).to be_a(CMSScanner::Finders::Findings)
|
26
|
+
|
27
|
+
@found.each { |f| expect(f).to be_a finding }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when :passive mode' do
|
31
|
+
let(:mode) { :passive }
|
32
|
+
|
33
|
+
it 'returns 2 results' do
|
34
|
+
expect(@found.size).to eq 2
|
35
|
+
expect(@found.first).to eql expected_passive.first
|
36
|
+
expect(@found.last).to eql expected_passive.last
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'when :aggressive mode' do
|
41
|
+
let(:mode) { :aggressive }
|
42
|
+
|
43
|
+
it 'returns 1 result' do
|
44
|
+
expect(@found.size).to eq 1
|
45
|
+
expect(@found.first).to eql expected_aggressive
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when :mixed mode' do
|
50
|
+
let(:mode) { :mixed }
|
51
|
+
|
52
|
+
it 'returns 2 results' do
|
53
|
+
expect(@found.size).to eq 2
|
54
|
+
expect(@found.first).to eql expected_passive.first
|
55
|
+
expect(@found.first.confirmed_by).to eql [expected_aggressive]
|
56
|
+
expect(@found.last).to eql expected_passive.last
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when multiple results returned' do
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#symbols_from_mode' do
|
66
|
+
after { expect(finders.symbols_from_mode(@mode)).to eq @expected }
|
67
|
+
|
68
|
+
context 'when :mixed' do
|
69
|
+
it 'returns [:passive, :aggressive]' do
|
70
|
+
@mode = :mixed
|
71
|
+
@expected = [:passive, :aggressive]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when :passive or :aggresssive' do
|
76
|
+
[:passive, :aggressive].each do |symbol|
|
77
|
+
it 'returns it in an array' do
|
78
|
+
@mode = symbol
|
79
|
+
@expected = [*symbol]
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'otherwise' do
|
85
|
+
it 'returns []' do
|
86
|
+
@mode = :unallowed
|
87
|
+
@expected = []
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#findings' do
|
93
|
+
it 'returns a Findings object' do
|
94
|
+
expect(finders.findings).to be_a CMSScanner::Finders::Findings
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Test Module to check the correct inclusion of
|
4
|
+
# the class methods
|
5
|
+
module OtherFormatter
|
6
|
+
include CMSScanner::Formatter
|
7
|
+
end
|
8
|
+
|
9
|
+
[CMSScanner::Formatter, OtherFormatter].each do |f|
|
10
|
+
describe "#{f}" do
|
11
|
+
subject(:formatter) { f }
|
12
|
+
it_behaves_like CMSScanner::Formatter::ClassMethods
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module CMSScanner
|
17
|
+
module Formatter
|
18
|
+
module Spec
|
19
|
+
# Base Format Test Class
|
20
|
+
class BasedFormat < Base
|
21
|
+
def base_format
|
22
|
+
'base'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe CMSScanner::Formatter::Base do
|
30
|
+
|
31
|
+
subject(:formatter) { described_class.new }
|
32
|
+
|
33
|
+
describe '#format' do
|
34
|
+
its(:format) { should eq 'base' }
|
35
|
+
end
|
36
|
+
|
37
|
+
describe '#render, output' do
|
38
|
+
before { formatter.views_directories << FIXTURES_VIEWS }
|
39
|
+
|
40
|
+
it 'renders the global template and does not override the @views_directories' do
|
41
|
+
expect($stdout).to receive(:puts)
|
42
|
+
.with("It Works!\nViews Dirs: #{formatter.views_directories}")
|
43
|
+
|
44
|
+
formatter.output('@test', test: 'Works!', views_directories: 'owned')
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'when global and local rendering are used inside a template' do
|
48
|
+
it 'renders them correcly' do
|
49
|
+
rendered = formatter.render('test', { var: 'Works' }, 'ctrl')
|
50
|
+
|
51
|
+
expect(rendered).to eq "Test: Works\nLocal View\nGlobal View"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises an error if the controller_name is nil and tpl is not a global one' do
|
56
|
+
expect { formatter.output('test') }.to raise_error('The controller_name can not be nil')
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
describe '#view_path' do
|
61
|
+
before do
|
62
|
+
formatter.views_directories << FIXTURES_VIEWS
|
63
|
+
formatter.render('local', {}, 'ctrl') # Used to set the @controller_name
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the tpl format is invalid' do
|
67
|
+
let(:tpl) { '../try-this' }
|
68
|
+
|
69
|
+
it 'raises an error' do
|
70
|
+
expect { formatter.view_path(tpl) }.to raise_error("Wrong tpl format: 'ctrl/#{tpl}'")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when the tpl is not found' do
|
75
|
+
let(:tpl) { 'not_there' }
|
76
|
+
|
77
|
+
it 'raises an error' do
|
78
|
+
expect { formatter.view_path(tpl) }.to raise_error("View not found for base/ctrl/#{tpl}")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
context 'when the tpl is found' do
|
83
|
+
after { expect(formatter.view_path(@tpl)).to eq @expected }
|
84
|
+
|
85
|
+
context 'if it\'s a global tpl' do
|
86
|
+
it 'returns its path' do
|
87
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'test.erb')
|
88
|
+
@tpl = '@test'
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
context 'if it\s a local tpl' do
|
93
|
+
it 'retuns its path' do
|
94
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'ctrl', 'local.erb')
|
95
|
+
@tpl = 'local'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when base_format' do
|
101
|
+
subject(:formatter) { CMSScanner::Formatter::Spec::BasedFormat.new }
|
102
|
+
|
103
|
+
after { expect(formatter.view_path(@tpl)).to eq @expected }
|
104
|
+
|
105
|
+
context 'when the ovverided view exists' do
|
106
|
+
it 'returns it' do
|
107
|
+
@expected = File.join(FIXTURES_VIEWS, 'based_format', 'test.erb')
|
108
|
+
@tpl = '@test'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'returns the base views otherwise' do
|
113
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'ctrl', 'local.erb')
|
114
|
+
@tpl = 'local'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
describe '#views_directories' do
|
121
|
+
let(:default_directories) { [APP_VIEWS] }
|
122
|
+
|
123
|
+
context 'when default directories' do
|
124
|
+
its(:views_directories) { should eq(default_directories) }
|
125
|
+
end
|
126
|
+
|
127
|
+
context 'when adding directories' do
|
128
|
+
it 'adds them' do
|
129
|
+
formatter.views_directories << 'testing'
|
130
|
+
|
131
|
+
expect(formatter.views_directories).to eq(default_directories << 'testing')
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# Module included the CMSScanner to test its correct inclusion
|
4
|
+
module SubScanner
|
5
|
+
include CMSScanner
|
6
|
+
|
7
|
+
# This Target class should be called in the CMSScanner::Controller::Base
|
8
|
+
# instead of the CMSScanner::Target
|
9
|
+
class Target < CMSScanner::Target
|
10
|
+
def new_method
|
11
|
+
'working'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe SubScanner::Scan do
|
17
|
+
subject(:scanner) { described_class.new }
|
18
|
+
let(:controller) { SubScanner::Controller }
|
19
|
+
|
20
|
+
it 'loads the overrided Target class' do
|
21
|
+
target = scanner.controllers.first.target
|
22
|
+
|
23
|
+
expect(target).to be_a SubScanner::Target
|
24
|
+
expect(target.respond_to?(:new_method)).to eq true
|
25
|
+
expect(target.new_method).to eq 'working'
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
[:WordPress, :PHP].each do |platform|
|
4
|
+
describe CMSScanner::Target do
|
5
|
+
subject(:target) do
|
6
|
+
described_class.new(url).extend(described_class::Platform.const_get(platform))
|
7
|
+
end
|
8
|
+
let(:url) { 'http://ex.lo' }
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'target', 'platform', platform.to_s.downcase) }
|
10
|
+
|
11
|
+
it_behaves_like described_class::Platform.const_get(platform)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
[:Generic, :Apache, :IIS].each do |server|
|
4
|
+
describe CMSScanner::Target do
|
5
|
+
subject(:target) do
|
6
|
+
described_class.new(url).extend(described_class::Server.const_get(server))
|
7
|
+
end
|
8
|
+
let(:url) { 'http://ex.lo' }
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'target', 'server', server.to_s.downcase) }
|
10
|
+
|
11
|
+
it_behaves_like described_class::Server.const_get(server)
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CMSScanner::Target do
|
4
|
+
|
5
|
+
subject(:target) { described_class.new(url) }
|
6
|
+
let(:url) { 'http://ex.lo' }
|
7
|
+
|
8
|
+
describe '#in_scope?' do
|
9
|
+
after { expect(target.in_scope?(@url)).to eq @expected }
|
10
|
+
|
11
|
+
[nil, '', 'http://out-of-scope.com', '//jquery.com/j.js'].each do |url|
|
12
|
+
it "returns false for #{url}" do
|
13
|
+
@url = url
|
14
|
+
@expected = false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
%w(https://ex.lo/file.txt http://ex.lo/ /relative).each do |url|
|
19
|
+
it "returns true for #{url}" do
|
20
|
+
@url = url
|
21
|
+
@expected = true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#interesting_files' do
|
27
|
+
before do
|
28
|
+
expect(CMSScanner::Finders::InterestingFiles).to receive(:find).and_return(stubbed)
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'when no findings' do
|
32
|
+
let(:stubbed) { [] }
|
33
|
+
|
34
|
+
its(:interesting_files) { should eq stubbed }
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'when findings' do
|
38
|
+
let(:stubbed) { ['yolo'] }
|
39
|
+
|
40
|
+
it 'allows findings to be added with <<' do
|
41
|
+
expect(target.interesting_files).to eq stubbed
|
42
|
+
|
43
|
+
target.interesting_files << 'other-finding'
|
44
|
+
|
45
|
+
expect(target.interesting_files).to eq(stubbed << 'other-finding')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CMSScanner::WebSite do
|
4
|
+
|
5
|
+
subject(:web_site) { described_class.new(url) }
|
6
|
+
let(:url) { 'http://ex.lo' }
|
7
|
+
|
8
|
+
describe '#url=' do
|
9
|
+
context 'when the url is incorrect' do
|
10
|
+
|
11
|
+
after do
|
12
|
+
expect { web_site.url = @url }.to raise_error Addressable::URI::InvalidURIError
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'raises an error if empty' do
|
16
|
+
@url = ''
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'raises an error if wrong format' do
|
20
|
+
@url = 'jj'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'when valid' do
|
25
|
+
it 'creates an Addressable object and adds a traling slash' do
|
26
|
+
web_site.url = 'http://site.com'
|
27
|
+
|
28
|
+
expect(web_site.url).to eq('http://site.com/')
|
29
|
+
expect(web_site.uri).to be_a Addressable::URI
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#url' do
|
35
|
+
context 'when no path argument' do
|
36
|
+
its(:url) { should eql 'http://ex.lo/' }
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when a path argument' do
|
40
|
+
it 'appends the path' do
|
41
|
+
expect(web_site.url('file.txt')).to eql "#{url}/file.txt"
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'when relative path' do
|
45
|
+
let(:url) { 'http://ex.lo/dir/' }
|
46
|
+
|
47
|
+
it 'appends it from the host/domain' do
|
48
|
+
expect(web_site.url('/sub/file.txt')).to eql 'http://ex.lo/sub/file.txt'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#online?' do
|
55
|
+
context 'when online' do
|
56
|
+
before { stub_request(:get, url).to_return(status: 200) }
|
57
|
+
|
58
|
+
it { should be_online }
|
59
|
+
end
|
60
|
+
|
61
|
+
context 'when offline' do
|
62
|
+
before { stub_request(:get, url).to_return(status: 0) }
|
63
|
+
|
64
|
+
it { should_not be_online }
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe '#http_auth?' do
|
69
|
+
context 'when http auth' do
|
70
|
+
before { stub_request(:get, url).to_return(status: 401) }
|
71
|
+
|
72
|
+
it { should be_http_auth }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'when no http auth' do
|
76
|
+
before { stub_request(:get, url).to_return(status: 200) }
|
77
|
+
|
78
|
+
it { should_not be_http_auth }
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe '#proxy_auth?' do
|
83
|
+
# Handled in app/controllers/core_spec
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#redirection' do
|
87
|
+
it 'returns nil if no redirection detected' do
|
88
|
+
stub_request(:get, web_site.url).to_return(status: 200, body: '')
|
89
|
+
|
90
|
+
expect(web_site.redirection).to be_nil
|
91
|
+
end
|
92
|
+
|
93
|
+
[301, 302].each do |status_code|
|
94
|
+
it "returns http://new-location.com if the status code is #{status_code}" do
|
95
|
+
new_location = 'http://new-location.com'
|
96
|
+
|
97
|
+
stub_request(:get, web_site.url)
|
98
|
+
.to_return(status: status_code, headers: { location: new_location })
|
99
|
+
|
100
|
+
stub_request(:get, new_location).to_return(status: 200)
|
101
|
+
|
102
|
+
expect(web_site.redirection).to eq new_location
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'when multiple redirections' do
|
107
|
+
it 'returns the last redirection' do
|
108
|
+
first_redirection = 'www.redirection.com'
|
109
|
+
last_redirection = 'redirection.com'
|
110
|
+
|
111
|
+
stub_request(:get, web_site.url)
|
112
|
+
.to_return(status: 301, headers: { location: first_redirection })
|
113
|
+
|
114
|
+
stub_request(:get, first_redirection)
|
115
|
+
.to_return(status: 302, headers: { location: last_redirection })
|
116
|
+
|
117
|
+
stub_request(:get, last_redirection).to_return(status: 200)
|
118
|
+
|
119
|
+
expect(web_site.redirection).to eq last_redirection
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|