cms_scanner 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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,55 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Finders::InterestingFile::SearchReplaceDB2 do
|
|
4
|
+
|
|
5
|
+
subject(:finder) { described_class.new(target) }
|
|
6
|
+
let(:target) { CMSScanner::Target.new(url) }
|
|
7
|
+
let(:url) { 'http://example.com/' }
|
|
8
|
+
let(:file) { url + 'searchreplacedb2.php' }
|
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'search_replace_db_2') }
|
|
10
|
+
|
|
11
|
+
describe '#url' do
|
|
12
|
+
its(:url) { should eq file }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '#aggressive' do
|
|
16
|
+
after do
|
|
17
|
+
stub_request(:get, file).to_return(status: status, body: body)
|
|
18
|
+
|
|
19
|
+
expect(finder.aggressive).to eql @expected
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
let(:body) { '' }
|
|
23
|
+
|
|
24
|
+
context 'when 404' do
|
|
25
|
+
let(:status) { 404 }
|
|
26
|
+
|
|
27
|
+
it 'returns nil' do
|
|
28
|
+
@expected = nil
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context 'when 200' do
|
|
33
|
+
let(:status) { 200 }
|
|
34
|
+
|
|
35
|
+
context 'when the body is empty' do
|
|
36
|
+
it 'returns nil' do
|
|
37
|
+
@expected = nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
context 'when the body matches' do
|
|
42
|
+
let(:body) { File.new(File.join(fixtures, 'searchreplacedb2.php')).read }
|
|
43
|
+
|
|
44
|
+
it 'returns the InterestingFile result' do
|
|
45
|
+
@expected = CMSScanner::InterestingFile.new(
|
|
46
|
+
file,
|
|
47
|
+
confidence: 100,
|
|
48
|
+
found_by: 'SearchReplaceDB2 (aggressive detection)'
|
|
49
|
+
)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Finders::InterestingFile::XMLRPC do
|
|
4
|
+
|
|
5
|
+
subject(:finder) { described_class.new(target) }
|
|
6
|
+
let(:target) { CMSScanner::Target.new(url) }
|
|
7
|
+
let(:url) { 'http://ex.lo/' }
|
|
8
|
+
let(:xml_rpc_url) { url + 'xmlrpc.php' }
|
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'xml_rpc') }
|
|
10
|
+
|
|
11
|
+
describe '#potential_urls' do
|
|
12
|
+
its(:potential_urls) { should be_empty }
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe '#passive' do
|
|
16
|
+
before do
|
|
17
|
+
expect(finder).to receive(:passive_headers).and_return(headers_stub)
|
|
18
|
+
expect(finder).to receive(:passive_body).and_return(body_stub)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
context 'when both passives return nil' do
|
|
22
|
+
let(:headers_stub) { nil }
|
|
23
|
+
let(:body_stub) { nil }
|
|
24
|
+
|
|
25
|
+
its(:passive) { should be_empty }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'when one passive is not nil' do
|
|
29
|
+
let(:headers_stub) { nil }
|
|
30
|
+
let(:body_stub) { 'test' }
|
|
31
|
+
|
|
32
|
+
its(:passive) { should eq %w(test) }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#passive_headers' do
|
|
37
|
+
before { stub_request(:get, url).to_return(headers: headers) }
|
|
38
|
+
|
|
39
|
+
let(:headers) { {} }
|
|
40
|
+
|
|
41
|
+
context 'when no headers' do
|
|
42
|
+
its(:passive_headers) { should be_nil }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
context 'when headers' do
|
|
46
|
+
context 'when URL is out of scope' do
|
|
47
|
+
let(:headers) { { 'X-Pingback' => 'http://ex.org/yolo' } }
|
|
48
|
+
|
|
49
|
+
its(:passive_headers) { should be_nil }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context 'when URL is in scope' do
|
|
53
|
+
let(:headers) { { 'X-Pingback' => xml_rpc_url } }
|
|
54
|
+
|
|
55
|
+
it 'adds the url to #potential_urls and returns the XMLRPC' do
|
|
56
|
+
result = finder.passive_headers
|
|
57
|
+
|
|
58
|
+
expect(finder.potential_urls).to eq [xml_rpc_url]
|
|
59
|
+
|
|
60
|
+
expect(result).to be_a CMSScanner::XMLRPC
|
|
61
|
+
expect(result).to eql CMSScanner::XMLRPC.new(
|
|
62
|
+
xml_rpc_url,
|
|
63
|
+
confidence: 30,
|
|
64
|
+
found_by: 'Headers (passive detection)'
|
|
65
|
+
)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe '#passive_body' do
|
|
72
|
+
before { stub_request(:get, url).to_return(body: body) }
|
|
73
|
+
|
|
74
|
+
context 'when no link rel="pingback" tag' do
|
|
75
|
+
let(:body) { '' }
|
|
76
|
+
|
|
77
|
+
its(:passive_body) { should be_nil }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
context 'when the tag is present' do
|
|
81
|
+
context 'when the URL is out of scope' do
|
|
82
|
+
let(:body) { File.new(File.join(fixtures, 'homepage_out_of_scope_pingback.html')).read }
|
|
83
|
+
|
|
84
|
+
its(:passive_body) { should be_nil }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'when URL is in scope' do
|
|
88
|
+
let(:body) { File.new(File.join(fixtures, 'homepage_in_scope_pingback.html')).read }
|
|
89
|
+
let(:expected_url) { 'http://ex.lo/wp/xmlrpc.php' }
|
|
90
|
+
|
|
91
|
+
it 'adds the URL to the #potential_urls and returns the XMLRPC' do
|
|
92
|
+
result = finder.passive_body
|
|
93
|
+
|
|
94
|
+
expect(finder.potential_urls).to eq [expected_url]
|
|
95
|
+
|
|
96
|
+
expect(result).to be_a CMSScanner::XMLRPC
|
|
97
|
+
expect(result).to eql CMSScanner::XMLRPC.new(
|
|
98
|
+
expected_url,
|
|
99
|
+
confidence: 30,
|
|
100
|
+
found_by: 'Link Tag (passive detection)'
|
|
101
|
+
)
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#aggressive' do
|
|
108
|
+
# Adds an out of scope URL which should be ignored
|
|
109
|
+
before { finder.potential_urls << 'htpp://ex.org' }
|
|
110
|
+
|
|
111
|
+
after do
|
|
112
|
+
stub_request(:get, xml_rpc_url).to_return(body: body)
|
|
113
|
+
|
|
114
|
+
expect(finder.aggressive).to eql @expected
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
context 'when the body does not match' do
|
|
118
|
+
let(:body) { '' }
|
|
119
|
+
|
|
120
|
+
it 'returns nil' do
|
|
121
|
+
@expected = nil
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
context 'when the body matches' do
|
|
126
|
+
let(:body) { File.new(File.join(fixtures, 'xmlrpc.php')).read }
|
|
127
|
+
|
|
128
|
+
it 'returns the InterestingFile result' do
|
|
129
|
+
@expected = CMSScanner::XMLRPC.new(
|
|
130
|
+
xml_rpc_url,
|
|
131
|
+
confidence: 100,
|
|
132
|
+
found_by: described_class::DIRECT_FILE_ACCESS
|
|
133
|
+
)
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Finders::InterestingFiles do
|
|
4
|
+
|
|
5
|
+
it_behaves_like CMSScanner::Finders::IndependentFinder do
|
|
6
|
+
let(:expected_finders) { %w(Headers RobotsTxt FantasticoFileslist SearchReplaceDB2 XMLRPC) }
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:files) { described_class.new(target) }
|
|
10
|
+
let(:target) { CMSScanner::Target.new(url) }
|
|
11
|
+
let(:url) { 'http://example.com/' }
|
|
12
|
+
|
|
13
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Formatter::CliNoColour do
|
|
4
|
+
|
|
5
|
+
subject(:formatter) { described_class.new }
|
|
6
|
+
|
|
7
|
+
describe '#format' do
|
|
8
|
+
its(:format) { should eq 'cli' }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#colorize' do
|
|
12
|
+
it 'returns the text w/o any colour' do
|
|
13
|
+
expect(formatter.red('Text')).to eq 'Text'
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Formatter::Cli do
|
|
4
|
+
|
|
5
|
+
subject(:formatter) { described_class.new }
|
|
6
|
+
|
|
7
|
+
describe '#format' do
|
|
8
|
+
its(:format) { should eq 'cli' }
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#green, #red, #colorize' do
|
|
12
|
+
it 'returns the correct red string' do
|
|
13
|
+
expect(formatter.red('Text')).to eq "\e[31mText\e[0m"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it 'returns the correct green string' do
|
|
17
|
+
expect(formatter.green('Another Text')).to eq "\e[32mAnother Text\e[0m"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Formatter::Json do
|
|
4
|
+
|
|
5
|
+
it_behaves_like CMSScanner::Formatter::Buffer
|
|
6
|
+
|
|
7
|
+
subject(:formatter) { described_class.new }
|
|
8
|
+
let(:output_file) { File.join(FIXTURES, 'output.txt') }
|
|
9
|
+
|
|
10
|
+
before { formatter.views_directories << FIXTURES_VIEWS }
|
|
11
|
+
|
|
12
|
+
describe '#format' do
|
|
13
|
+
its(:format) { should eq 'json' }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe '#output' do
|
|
17
|
+
it 'puts the rendered text in the buffer' do
|
|
18
|
+
2.times { formatter.output('@render_me', test: 'Working') }
|
|
19
|
+
|
|
20
|
+
expect(formatter.buffer).to eq "\"test\": \"Working\",\n" * 2
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe '#beautify' do
|
|
25
|
+
it 'writes the buffer in the file' do
|
|
26
|
+
2.times { formatter.output('@render_me', test: 'yolo') }
|
|
27
|
+
|
|
28
|
+
expect($stdout).to receive(:puts).with(JSON.pretty_generate(JSON.parse('{"test": "yolo"}')))
|
|
29
|
+
formatter.beautify
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::FantasticoFileslist do
|
|
4
|
+
|
|
5
|
+
subject(:file) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://example.com/robots.txt' }
|
|
7
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'fantastico_fileslist') }
|
|
8
|
+
|
|
9
|
+
describe '#interesting_entries' do
|
|
10
|
+
let(:headers) { { 'Content-Type' => 'text/plain; charset=utf-8' } }
|
|
11
|
+
|
|
12
|
+
after do
|
|
13
|
+
body = File.new(File.join(fixtures, fixture)).read
|
|
14
|
+
|
|
15
|
+
stub_request(:get, file.url).to_return(headers: headers, body: body)
|
|
16
|
+
|
|
17
|
+
expect(file.interesting_entries).to eq @expected
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'when empty or / entries' do
|
|
21
|
+
let(:fixture) { 'fantastico_fileslist.txt' }
|
|
22
|
+
|
|
23
|
+
it 'ignores them and only returns the others' do
|
|
24
|
+
@expected = %w(data.sql admin.txt)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe '#references' do
|
|
30
|
+
its(:references) { should_not be_nil }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Headers do
|
|
4
|
+
|
|
5
|
+
subject(:file) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://example.com/' }
|
|
7
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'headers') }
|
|
8
|
+
let(:fixture) { File.join(fixtures, 'interesting.txt') }
|
|
9
|
+
let(:headers) { {} }
|
|
10
|
+
|
|
11
|
+
before { stub_request(:get, file.url).to_return(headers: headers) }
|
|
12
|
+
|
|
13
|
+
describe '#known_headers' do
|
|
14
|
+
it 'does not contains dupliactes' do
|
|
15
|
+
expect(file.known_headers).to eql file.known_headers.uniq
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
describe '#entries' do
|
|
20
|
+
after { expect(file.entries).to eq @expected if @expected }
|
|
21
|
+
|
|
22
|
+
context 'when no headers' do
|
|
23
|
+
its(:entries) { should eq({}) }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context 'when headers' do
|
|
27
|
+
let(:headers) { parse_headers_file(fixture) }
|
|
28
|
+
|
|
29
|
+
it 'returns the headers' do
|
|
30
|
+
@expected = headers
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
describe '#interesting_entries' do
|
|
36
|
+
after { expect(file.interesting_entries).to eq @expected if @expected }
|
|
37
|
+
|
|
38
|
+
context 'when interesting headers' do
|
|
39
|
+
let(:headers) { parse_headers_file(fixture) }
|
|
40
|
+
|
|
41
|
+
it 'returns an array with the headers' do
|
|
42
|
+
@expected = ['Server: nginx/1.1.19', 'X-Article-Id: 12']
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
context 'when no interesting headers' do
|
|
47
|
+
let(:headers) { parse_headers_file(File.join(fixtures, 'no_interesting.txt')) }
|
|
48
|
+
|
|
49
|
+
its(:interesting_entries) { should eq [] }
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::InterestingFile do
|
|
4
|
+
|
|
5
|
+
it_behaves_like CMSScanner::Finders::Finding
|
|
6
|
+
|
|
7
|
+
subject(:file) { described_class.new(url, opts) }
|
|
8
|
+
let(:opts) { {} }
|
|
9
|
+
let(:url) { 'http://example.com/' }
|
|
10
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files') }
|
|
11
|
+
|
|
12
|
+
describe '#entries' do
|
|
13
|
+
after do
|
|
14
|
+
stub_request(:get, file.url).to_return(headers: headers, body: @body)
|
|
15
|
+
|
|
16
|
+
expect(file.entries).to eq @expected
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'when content-type matches text/plain' do
|
|
20
|
+
let(:headers) { { 'Content-Type' => 'text/plain; charset=utf-8' } }
|
|
21
|
+
|
|
22
|
+
it 'returns the file content as an array w/o empty strings' do
|
|
23
|
+
@body = File.new(File.join(fixtures, 'file.txt')).read
|
|
24
|
+
@expected = ['This is', 'a test file', 'with some content']
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
context 'when other content-type' do
|
|
29
|
+
let(:headers) { { 'Content-Type' => 'text.html; charset=utf-8' } }
|
|
30
|
+
|
|
31
|
+
it 'returns an empty array' do
|
|
32
|
+
@expected = []
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#==' do
|
|
38
|
+
context 'when same URL' do
|
|
39
|
+
it 'returns true' do
|
|
40
|
+
expect(file == described_class.new(url)).to be true
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when not the same URL' do
|
|
45
|
+
it 'returns false' do
|
|
46
|
+
expect(file == described_class.new('http://ex.lo')).to be false
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::RobotsTxt do
|
|
4
|
+
|
|
5
|
+
subject(:file) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://example.com/robots.txt' }
|
|
7
|
+
let(:fixtures) { File.join(FIXTURES, 'interesting_files', 'robots_txt') }
|
|
8
|
+
|
|
9
|
+
describe '#interesting_entries' do
|
|
10
|
+
let(:headers) { { 'Content-Type' => 'text/plain; charset=utf-8' } }
|
|
11
|
+
|
|
12
|
+
after do
|
|
13
|
+
body = File.new(File.join(fixtures, fixture)).read
|
|
14
|
+
|
|
15
|
+
stub_request(:get, file.url).to_return(headers: headers, body: body)
|
|
16
|
+
|
|
17
|
+
expect(file.interesting_entries).to eq @expected
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'when empty or / entries' do
|
|
21
|
+
let(:fixture) { 'robots.txt' }
|
|
22
|
+
|
|
23
|
+
it 'ignores them and only returns the others' do
|
|
24
|
+
@expected = %w(/admin /public/home)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|