Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wpscanteam
GitHub Repository: wpscanteam/wpscan
Path: blob/master/spec/app/controllers/core_spec.rb
486 views
1
# frozen_string_literal: true
2
3
describe WPScan::Controller::Core do
4
subject(:core) { described_class.new }
5
let(:target_url) { 'http://ex.lo/' }
6
let(:cli_args) { "--url #{target_url}" }
7
8
before do
9
described_class.reset
10
WPScan::ParsedCli.options = rspec_parsed_options(cli_args)
11
end
12
13
describe '#cli_options' do
14
its(:cli_options) { should_not be_empty }
15
its(:cli_options) { should be_a Array }
16
17
it 'contains to correct options' do
18
cli_options = core.cli_options
19
expect(cli_options.map(&:to_sym)).to include(:url, :server, :force, :update)
20
21
# Ensures the :url is the first one and is correctly setup
22
expect(cli_options.first.to_sym).to eql :url
23
expect(cli_options.first.required_unless).to match_array %i[update help hh version]
24
end
25
end
26
27
describe '#load_server_module' do
28
after do
29
expect(core.target).to receive(:server).and_return(@stubbed_server)
30
expect(core.load_server_module).to eql @expected
31
32
[core.target, WPScan::Model::WpItem.new(target_url, core.target)].each do |instance|
33
expect(instance).to respond_to(:directory_listing?)
34
expect(instance).to respond_to(:directory_listing_entries)
35
36
# The below doesn't work, the module would have to be removed from the class
37
# TODO: find a way to test this
38
# expect(instance.server).to eql @expected if instance.is_a? WPScan::Model::WpItem
39
end
40
end
41
42
context 'when no --server supplied' do
43
%i[Apache IIS Nginx].each do |server|
44
it "loads the #{server} module and returns :#{server}" do
45
@stubbed_server = server
46
@expected = server
47
end
48
end
49
end
50
51
context 'when --server' do
52
%i[apache iis nginx].each do |server|
53
context "when #{server}" do
54
let(:cli_args) { "#{super()} --server #{server}" }
55
let(:servers) { [:Apache, nil, :IIS, :Nginx] }
56
57
it "loads the #{server.capitalize} module and returns :#{server}" do
58
@stubbed_server = servers.sample
59
@expected = server == :iis ? :IIS : server.to_s.camelize.to_sym
60
end
61
end
62
end
63
end
64
end
65
66
describe '#update_db_required?' do
67
context 'when missing files' do
68
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(true) }
69
70
context 'when --no-update' do
71
let(:cli_args) { "#{super()} --no-update" }
72
73
it 'raises an error' do
74
expect { core.update_db_required? }.to raise_error(WPScan::Error::MissingDatabaseFile)
75
end
76
end
77
78
context 'otherwise' do
79
its(:update_db_required?) { should eql true }
80
end
81
end
82
83
context 'when not missing files' do
84
before { expect(core.local_db).to receive(:missing_files?).ordered.and_return(false) }
85
86
context 'when --update' do
87
let(:cli_args) { "#{super()} --update" }
88
89
its(:update_db_required?) { should eql true }
90
end
91
92
context 'when --no-update' do
93
let(:cli_args) { "#{super()} --no-update" }
94
95
its(:update_db_required?) { should eql false }
96
end
97
98
context 'when user_interation (i.e cli output)' do
99
let(:cli_args) { "#{super()} --format cli" }
100
101
context 'when the db is up-to-date' do
102
before { expect(core.local_db).to receive(:outdated?).and_return(false) }
103
104
its(:update_db_required?) { should eql false }
105
end
106
107
context 'when the db is outdated' do
108
before do
109
allow(core).to receive(:user_interaction?).and_return(true)
110
expect(core.local_db).to receive(:outdated?).ordered.and_return(true)
111
expect(core.formatter).to receive(:output).with('@notice', hash_including(:msg), 'core').ordered
112
expect($stdout).to receive(:write).ordered # for the print()
113
end
114
115
context 'when a positive answer' do
116
before do
117
allow($stdin).to receive(:gets).and_return("Yes\n")
118
end
119
120
its(:update_db_required?) { should eql true }
121
end
122
123
context 'when a negative answer' do
124
before do
125
allow($stdin).to receive(:gets).and_return("No\n")
126
end
127
128
its(:update_db_required?) { should eql false }
129
end
130
end
131
end
132
133
context 'when no user_interation' do
134
let(:cli_args) { "#{super()} --format json" }
135
136
its(:update_db_required?) { should eql false }
137
end
138
end
139
end
140
141
describe '#before_scan' do
142
before do
143
stub_request(:get, target_url)
144
145
expect(core.formatter).to receive(:output).with('banner', hash_including(verbose: nil), 'core')
146
147
expect(core).to receive(:update_db_required?).and_return(false) unless WPScan::ParsedCli.update
148
end
149
150
context 'when --update' do
151
before do
152
expect(core.formatter).to receive(:output)
153
.with('db_update_started', hash_including(verbose: nil), 'core').ordered
154
155
expect_any_instance_of(WPScan::DB::Updater).to receive(:update)
156
157
expect(core.formatter).to receive(:output)
158
.with('db_update_finished', hash_including(verbose: nil), 'core').ordered
159
end
160
161
context 'when the --url is not supplied' do
162
let(:cli_args) { '--update' }
163
164
it 'calls the formatter when started and finished to update the db and exit' do
165
expect { core.before_scan }.to raise_error(SystemExit)
166
end
167
end
168
169
context 'when --url is supplied' do
170
let(:cli_args) { "#{super()} --update" }
171
172
before do
173
expect(core).to receive(:load_server_module)
174
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
175
expect(core.target).to receive(:wordpress_hosted?).and_return(false)
176
end
177
178
it 'calls the formatter when started and finished to update the db' do
179
expect { core.before_scan }.to_not raise_error
180
end
181
end
182
end
183
184
context 'when hosted on wordpress.com' do
185
let(:target_url) { 'http://ex.wordpress.com' }
186
187
before { expect(core).to receive(:load_server_module) }
188
189
it 'raises an error' do
190
expect { core.before_scan }.to raise_error(WPScan::Error::WordPressHosted)
191
end
192
end
193
194
context 'when not hosted on wordpress.com' do
195
before { allow(core.target).to receive(:wordpress_hosted?).and_return(false) }
196
197
context 'when a redirect occurs' do
198
before do
199
stub_request(:any, target_url)
200
201
expect(core.target).to receive(:homepage_res)
202
.at_least(1)
203
.and_return(Typhoeus::Response.new(effective_url: redirection, body: ''))
204
end
205
206
context 'to the wp-admin/install.php' do
207
let(:redirection) { "#{target_url}wp-admin/install.php" }
208
209
it 'calls the formatter with the correct parameters and exit' do
210
expect(core.formatter).to receive(:output)
211
.with('not_fully_configured', hash_including(url: redirection), 'core').ordered
212
213
# TODO: Would be cool to be able to test the exit code
214
expect { core.before_scan }.to raise_error(SystemExit)
215
end
216
end
217
218
context 'to something else' do
219
let(:redirection) { 'http://g.com/' }
220
221
it 'raises an error' do
222
expect { core.before_scan }.to raise_error(CMSScanner::Error::HTTPRedirect)
223
end
224
end
225
226
context 'to another path with the wp-admin/install.php in the query' do
227
let(:redirection) { "#{target_url}index.php?a=/wp-admin/install.php" }
228
229
context 'when wordpress' do
230
it 'does not raise an error' do
231
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
232
233
expect { core.before_scan }.to_not raise_error
234
end
235
end
236
237
context 'when not wordpress' do
238
it 'raises an error' do
239
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
240
241
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
242
end
243
end
244
end
245
end
246
247
context 'when wordpress' do
248
before do
249
expect(core).to receive(:load_server_module)
250
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
251
end
252
253
it 'does not raise any error' do
254
expect { core.before_scan }.to_not raise_error
255
end
256
end
257
258
context 'when not wordpress' do
259
before do
260
expect(core).to receive(:load_server_module)
261
end
262
263
context 'when no --force' do
264
before { expect(core.target).to receive(:maybe_add_cookies) }
265
266
context 'when no cookies added or still not wordpress after being added' do
267
it 'raises an error' do
268
expect(core.target).to receive(:wordpress?).twice.with(:mixed).and_return(false)
269
270
expect { core.before_scan }.to raise_error(WPScan::Error::NotWordPress)
271
end
272
end
273
274
context 'when the added cookies solved it' do
275
it 'does not raise an error' do
276
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false).ordered
277
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true).ordered
278
279
expect { core.before_scan }.to_not raise_error
280
end
281
end
282
end
283
284
context 'when --force' do
285
let(:cli_args) { "#{super()} --force" }
286
287
it 'does not raise any error' do
288
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
289
290
expect { core.before_scan }.to_not raise_error
291
end
292
end
293
end
294
end
295
end
296
end
297
298