tarantula 0.2.0 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +3 -4
- data/Rakefile +9 -5
- data/VERSION.yml +2 -2
- data/examples/example_helper.rb +10 -1
- data/examples/relevance/tarantula/attack_handler_example.rb +1 -1
- data/examples/relevance/tarantula/basic_attack_example.rb +12 -0
- data/examples/relevance/tarantula/crawler_example.rb +66 -77
- data/examples/relevance/tarantula/form_example.rb +3 -3
- data/examples/relevance/tarantula/form_submission_example.rb +157 -57
- data/examples/relevance/tarantula/link_example.rb +24 -7
- data/examples/relevance/tarantula/rails_integration_proxy_example.rb +1 -1
- data/lib/relevance/tarantula/attack.rb +3 -0
- data/lib/relevance/tarantula/attack_handler.rb +1 -1
- data/lib/relevance/tarantula/basic_attack.rb +40 -0
- data/lib/relevance/tarantula/crawler.rb +36 -46
- data/lib/relevance/tarantula/detail.html.erb +11 -11
- data/lib/relevance/tarantula/form.rb +4 -2
- data/lib/relevance/tarantula/form_submission.rb +47 -29
- data/lib/relevance/tarantula/link.rb +24 -4
- data/lib/relevance/tarantula/rails_integration_proxy.rb +1 -1
- data/lib/relevance/tarantula/result.rb +14 -3
- data/lib/relevance/tarantula.rb +1 -1
- metadata +6 -6
- data/examples/relevance/tarantula/attack_form_submission_example.rb +0 -79
- data/lib/relevance/tarantula/attack_form_submission.rb +0 -75
data/README.rdoc
CHANGED
@@ -107,26 +107,25 @@ for URLs matching a given regex:
|
|
107
107
|
t = tarantula_crawler(self)
|
108
108
|
t.allow_404_for %r{/users/\d+/}
|
109
109
|
|
110
|
-
==
|
110
|
+
== Testing for Common Attacks
|
111
111
|
|
112
112
|
You can specify the attack strings that Tarantula throws at your application.
|
113
113
|
|
114
114
|
def test_tarantula
|
115
115
|
t = tarantula_crawler(self)
|
116
116
|
|
117
|
-
Relevance::Tarantula::
|
117
|
+
Relevance::Tarantula::FormSubmission.attacks << {
|
118
118
|
:name => :xss,
|
119
119
|
:input => "<script>gotcha!</script>",
|
120
120
|
:output => "<script>gotcha!</script>",
|
121
121
|
}
|
122
122
|
|
123
|
-
Relevance::Tarantula::
|
123
|
+
Relevance::Tarantula::FormSubmission.attacks << {
|
124
124
|
:name => :sql_injection,
|
125
125
|
:input => "a'; DROP TABLE posts;",
|
126
126
|
}
|
127
127
|
|
128
128
|
t.handlers << Relevance::Tarantula::AttackHandler.new
|
129
|
-
t.fuzzers << Relevance::Tarantula::AttackFormSubmission
|
130
129
|
t.times_to_crawl = 2
|
131
130
|
t.crawl "/posts"
|
132
131
|
end
|
data/Rakefile
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
3
|
require 'rake/rdoctask'
|
4
|
-
gem "spicycode-micronaut", ">= 0.2.4"
|
5
4
|
require 'micronaut'
|
6
5
|
require 'micronaut/rake_task'
|
7
6
|
|
@@ -46,12 +45,17 @@ namespace :examples do
|
|
46
45
|
Micronaut::RakeTask.new :coverage do |t|
|
47
46
|
t.pattern = "examples/**/*_example.rb"
|
48
47
|
t.rcov = true
|
49
|
-
t.rcov_opts = %[--exclude "gems/*,/Library/Ruby/*,config/*" --text-summary --sort coverage
|
48
|
+
t.rcov_opts = %[--exclude "gems/*,/Library/Ruby/*,config/*" --text-summary --sort coverage]
|
50
49
|
end
|
51
50
|
|
52
|
-
RAILS_VERSIONS = %w[2.
|
51
|
+
RAILS_VERSIONS = %w[2.3.2 2.3.4]
|
53
52
|
|
54
|
-
|
53
|
+
unless RUBY_VERSION =~ /^1\.9\./
|
54
|
+
RAILS_VERSIONS.unshift(*%w[2.0.2 2.1.0 2.1.1 2.2.2 2.3.3])
|
55
|
+
RAILS_VERSIONS.sort!
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "Run examples with multiple versions of rails"
|
55
59
|
task :multi_rails do
|
56
60
|
RAILS_VERSIONS.each do |rails_version|
|
57
61
|
puts
|
@@ -65,4 +69,4 @@ if ENV["RUN_CODE_RUN"]
|
|
65
69
|
task :default => "examples:multi_rails"
|
66
70
|
else
|
67
71
|
task :default => "examples"
|
68
|
-
end
|
72
|
+
end
|
data/VERSION.yml
CHANGED
data/examples/example_helper.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require 'rubygems'
|
1
2
|
lib_path = File.expand_path(File.dirname(__FILE__) + "/../lib")
|
2
3
|
$LOAD_PATH.unshift lib_path unless $LOAD_PATH.include?(lib_path)
|
3
|
-
|
4
|
+
require 'rubygems'
|
4
5
|
gem "spicycode-micronaut", ">= 0.2.4"
|
5
6
|
gem "log_buddy"
|
6
7
|
gem "mocha"
|
@@ -35,6 +36,14 @@ def stub_puts_and_print(obj)
|
|
35
36
|
obj.stubs(:print)
|
36
37
|
end
|
37
38
|
|
39
|
+
def make_link(link, crawler=Relevance::Tarantula::Crawler.new, referrer=nil)
|
40
|
+
Relevance::Tarantula::Link.new(link, crawler, referrer)
|
41
|
+
end
|
42
|
+
|
43
|
+
def make_form(form, crawler=Relevance::Tarantula::Crawler.new, referrer=nil)
|
44
|
+
Relevance::Tarantula::Form.new(form, crawler, referrer)
|
45
|
+
end
|
46
|
+
|
38
47
|
def not_in_editor?
|
39
48
|
['TM_MODE', 'EMACS', 'VIM'].all? { |k| !ENV.has_key?(k) }
|
40
49
|
end
|
@@ -22,7 +22,7 @@ describe "Attacks without an output specified" do
|
|
22
22
|
it "never matches anything" do
|
23
23
|
handler = Relevance::Tarantula::AttackHandler.new
|
24
24
|
attack = Relevance::Tarantula::Attack.new({:name => 'foo_name', :input => 'foo_code'})
|
25
|
-
Relevance::Tarantula::
|
25
|
+
Relevance::Tarantula::FormSubmission.stubs(:attacks).returns([attack])
|
26
26
|
result = handler.handle(Relevance::Tarantula::Result.new(:response => stub(:html? => true, :body => '<a href="/foo">good</a>')))
|
27
27
|
result.should == nil
|
28
28
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + "/../../example_helper.rb"
|
2
|
+
|
3
|
+
describe Relevance::Tarantula::BasicAttack do
|
4
|
+
before do
|
5
|
+
@attack = Relevance::Tarantula::BasicAttack.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "can generate a random whole number" do
|
9
|
+
@attack.random_whole_number.should >= 0
|
10
|
+
Fixnum.should === @attack.random_whole_number
|
11
|
+
end
|
12
|
+
end
|
@@ -88,97 +88,68 @@ describe Relevance::Tarantula::Crawler do
|
|
88
88
|
|
89
89
|
it 'queues and remembers links' do
|
90
90
|
crawler = Relevance::Tarantula::Crawler.new
|
91
|
-
crawler.expects(:transform_url).with("/url").returns("/transformed")
|
91
|
+
crawler.expects(:transform_url).with("/url").returns("/transformed").at_least_once
|
92
92
|
crawler.queue_link("/url")
|
93
|
-
|
94
|
-
crawler.
|
93
|
+
# TODO not sure this is the best way to test this anymore; relying on result of transform in both actual and expected
|
94
|
+
crawler.crawl_queue.should == [make_link("/url", crawler)]
|
95
|
+
crawler.links_queued.should == Set.new([make_link("/url", crawler)])
|
95
96
|
end
|
96
97
|
|
97
98
|
it 'queues and remembers forms' do
|
98
99
|
crawler = Relevance::Tarantula::Crawler.new
|
99
100
|
form = Hpricot('<form action="/action" method="post"/>').at('form')
|
100
|
-
signature = Relevance::Tarantula::FormSubmission.new(
|
101
|
+
signature = Relevance::Tarantula::FormSubmission.new(make_form(form)).signature
|
101
102
|
crawler.queue_form(form)
|
102
|
-
crawler.
|
103
|
+
crawler.crawl_queue.size.should == 1
|
103
104
|
crawler.form_signatures_queued.should == Set.new([signature])
|
104
105
|
end
|
105
106
|
|
106
|
-
it
|
107
|
+
it "passes link, self, and referrer when creating Link objects" do
|
107
108
|
crawler = Relevance::Tarantula::Crawler.new
|
108
|
-
|
109
|
-
crawler.
|
109
|
+
Relevance::Tarantula::Link.expects(:new).with('/url', crawler, '/some-referrer')
|
110
|
+
crawler.stubs(:should_skip_link?)
|
111
|
+
crawler.queue_link('/url', '/some-referrer')
|
110
112
|
end
|
111
113
|
|
112
114
|
end
|
113
115
|
|
114
116
|
describe "crawling" do
|
115
|
-
|
116
|
-
|
117
|
-
(proxy = stub_everything).expects(:send).raises(ActiveRecord::RecordNotFound)
|
118
|
-
crawler = Relevance::Tarantula::Crawler.new
|
119
|
-
crawler.proxy = proxy
|
120
|
-
response = crawler.crawl_form stub_everything(:method => nil)
|
121
|
-
response.code.should == "404"
|
122
|
-
response.content_type.should == "text/plain"
|
123
|
-
response.body.should == "ActiveRecord::RecordNotFound"
|
117
|
+
before do
|
118
|
+
@form = Hpricot('<form action="/action" method="post"/>').at('form')
|
124
119
|
end
|
125
|
-
|
126
|
-
it "does
|
120
|
+
|
121
|
+
it "does two things with each link: crawl and blip" do
|
127
122
|
crawler = Relevance::Tarantula::Crawler.new
|
128
123
|
crawler.proxy = stub
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
crawler.expects(:log).times(2)
|
133
|
-
crawler.expects(:handle_link_results).times(2)
|
124
|
+
crawler.crawl_queue = links = [make_link("/foo1", crawler), make_link("/foo2", crawler)]
|
125
|
+
|
126
|
+
links.each{|link| link.expects(:crawl)}
|
134
127
|
crawler.expects(:blip).times(2)
|
135
|
-
|
136
|
-
crawler.
|
128
|
+
|
129
|
+
crawler.crawl_the_queue
|
130
|
+
crawler.crawl_queue.should == []
|
137
131
|
end
|
138
132
|
|
139
133
|
it "invokes queued forms, logs responses, and calls handlers" do
|
140
134
|
crawler = Relevance::Tarantula::Crawler.new
|
141
|
-
crawler.
|
142
|
-
|
143
|
-
:data => "some data",
|
144
|
-
:to_s => "stub")
|
145
|
-
crawler.proxy = stub_everything(:send => stub(:code => "200" ))
|
146
|
-
crawler.expects(:log).with("Response 200 for stub")
|
135
|
+
crawler.crawl_queue << Relevance::Tarantula::FormSubmission.new(make_form(@form, crawler))
|
136
|
+
crawler.expects(:submit).returns(stub(:code => "200"))
|
147
137
|
crawler.expects(:blip)
|
148
|
-
crawler.
|
138
|
+
crawler.crawl_the_queue
|
149
139
|
end
|
150
140
|
|
151
|
-
|
152
|
-
|
153
|
-
stub_puts_and_print(crawler)
|
154
|
-
crawler.proxy = stub
|
155
|
-
response = stub(:code => "200")
|
156
|
-
crawler.links_to_crawl = [stub(:href => "/foo", :method => :get)]
|
157
|
-
crawler.proxy.expects(:get).returns(response).times(4)
|
158
|
-
crawler.forms_to_crawl << stub_everything(:method => "post",
|
159
|
-
:action => "/foo",
|
160
|
-
:data => "some data",
|
161
|
-
:to_s => "stub")
|
162
|
-
crawler.proxy.expects(:post).returns(response).times(2)
|
163
|
-
crawler.expects(:links_completed_count).returns(0,1,2,3,4,5).times(6)
|
164
|
-
crawler.times_to_crawl = 2
|
165
|
-
crawler.crawl
|
166
|
-
|
167
|
-
end
|
141
|
+
# TODO this is the same as "resets to the initial links/forms ..." and doesn't appear to test anything related to a timeout.
|
142
|
+
it "breaks out early if a timeout is set"
|
168
143
|
|
169
144
|
it "resets to the initial links/forms on subsequent crawls when times_to_crawl > 1" do
|
170
145
|
crawler = Relevance::Tarantula::Crawler.new
|
171
146
|
stub_puts_and_print(crawler)
|
172
|
-
crawler.proxy = stub
|
173
147
|
response = stub(:code => "200")
|
174
|
-
crawler.
|
175
|
-
crawler.
|
176
|
-
crawler.
|
177
|
-
|
178
|
-
|
179
|
-
:to_s => "stub")
|
180
|
-
crawler.proxy.expects(:post).returns(response).times(2)
|
181
|
-
crawler.expects(:links_completed_count).returns(0,1,2,3,4,5).times(6)
|
148
|
+
crawler.queue_link('/foo')
|
149
|
+
crawler.expects(:follow).returns(response).times(4) # (stub and "/") * 2
|
150
|
+
crawler.queue_form(@form)
|
151
|
+
crawler.expects(:submit).returns(response).times(2)
|
152
|
+
crawler.expects(:blip).times(6)
|
182
153
|
crawler.times_to_crawl = 2
|
183
154
|
crawler.crawl
|
184
155
|
end
|
@@ -186,9 +157,17 @@ describe Relevance::Tarantula::Crawler do
|
|
186
157
|
end
|
187
158
|
|
188
159
|
describe "report_results" do
|
189
|
-
|
160
|
+
it "prints a final summary line" do
|
161
|
+
crawler = Relevance::Tarantula::Crawler.new
|
162
|
+
crawler.stubs(:generate_reports)
|
163
|
+
crawler.expects(:total_links_count).returns(42)
|
164
|
+
crawler.expects(:puts).with("Crawled 42 links and forms.")
|
165
|
+
crawler.report_results
|
166
|
+
end
|
167
|
+
|
190
168
|
it "delegates to generate_reports" do
|
191
169
|
crawler = Relevance::Tarantula::Crawler.new
|
170
|
+
crawler.stubs(:puts)
|
192
171
|
crawler.expects(:generate_reports)
|
193
172
|
crawler.report_results
|
194
173
|
end
|
@@ -198,6 +177,7 @@ describe Relevance::Tarantula::Crawler do
|
|
198
177
|
describe "blip" do
|
199
178
|
|
200
179
|
it "blips the current progress if !verbose" do
|
180
|
+
$stdout.stubs(:tty?).returns(true)
|
201
181
|
crawler = Relevance::Tarantula::Crawler.new
|
202
182
|
crawler.stubs(:verbose).returns false
|
203
183
|
crawler.stubs(:timeout_if_too_long)
|
@@ -205,7 +185,17 @@ describe Relevance::Tarantula::Crawler do
|
|
205
185
|
crawler.blip
|
206
186
|
end
|
207
187
|
|
188
|
+
it "suppresses the blip message if not writing to a tty" do
|
189
|
+
$stdout.stubs(:tty?).returns(false)
|
190
|
+
crawler = Relevance::Tarantula::Crawler.new
|
191
|
+
crawler.stubs(:verbose).returns false
|
192
|
+
crawler.stubs(:timeout_if_too_long)
|
193
|
+
crawler.expects(:print).never
|
194
|
+
crawler.blip
|
195
|
+
end
|
196
|
+
|
208
197
|
it "blips nothing if verbose" do
|
198
|
+
$stdout.stubs(:tty?).returns(true)
|
209
199
|
crawler = Relevance::Tarantula::Crawler.new
|
210
200
|
crawler.stubs(:verbose).returns true
|
211
201
|
crawler.expects(:print).never
|
@@ -223,13 +213,13 @@ describe Relevance::Tarantula::Crawler do
|
|
223
213
|
|
224
214
|
it "isn't finished when links remain" do
|
225
215
|
crawler = Relevance::Tarantula::Crawler.new
|
226
|
-
crawler.
|
216
|
+
crawler.crawl_queue = [:stub_link]
|
227
217
|
crawler.finished?.should == false
|
228
218
|
end
|
229
219
|
|
230
|
-
it "isn't finished when
|
220
|
+
it "isn't finished when forms remain" do
|
231
221
|
crawler = Relevance::Tarantula::Crawler.new
|
232
|
-
crawler.
|
222
|
+
crawler.crawl_queue = [:stub_form]
|
233
223
|
crawler.finished?.should == false
|
234
224
|
end
|
235
225
|
|
@@ -238,8 +228,7 @@ describe Relevance::Tarantula::Crawler do
|
|
238
228
|
it "crawls links and forms again and again until finished?==true" do
|
239
229
|
crawler = Relevance::Tarantula::Crawler.new
|
240
230
|
crawler.expects(:finished?).times(3).returns(false, false, true)
|
241
|
-
crawler.expects(:
|
242
|
-
crawler.expects(:crawl_queued_forms).times(2)
|
231
|
+
crawler.expects(:crawl_the_queue).times(2)
|
243
232
|
crawler.do_crawl(1)
|
244
233
|
end
|
245
234
|
|
@@ -262,9 +251,9 @@ describe Relevance::Tarantula::Crawler do
|
|
262
251
|
|
263
252
|
it "skips links that are already queued" do
|
264
253
|
crawler = Relevance::Tarantula::Crawler.new
|
265
|
-
crawler.should_skip_link?(
|
266
|
-
crawler.queue_link("/foo").should ==
|
267
|
-
crawler.should_skip_link?(
|
254
|
+
crawler.should_skip_link?(make_link("/foo")).should == false
|
255
|
+
crawler.queue_link("/foo").should == make_link("/foo")
|
256
|
+
crawler.should_skip_link?(make_link("/foo")).should == true
|
268
257
|
end
|
269
258
|
|
270
259
|
describe "link skipping" do
|
@@ -272,38 +261,38 @@ describe Relevance::Tarantula::Crawler do
|
|
272
261
|
before { @crawler = Relevance::Tarantula::Crawler.new }
|
273
262
|
|
274
263
|
it "skips links that are too long" do
|
275
|
-
@crawler.should_skip_link?(
|
264
|
+
@crawler.should_skip_link?(make_link("/foo")).should == false
|
276
265
|
@crawler.max_url_length = 2
|
277
266
|
@crawler.expects(:log).with("Skipping long url /foo")
|
278
|
-
@crawler.should_skip_link?(
|
267
|
+
@crawler.should_skip_link?(make_link("/foo")).should == true
|
279
268
|
end
|
280
269
|
|
281
270
|
it "skips outbound links (those that begin with http)" do
|
282
271
|
@crawler.expects(:log).with("Skipping http-anything")
|
283
|
-
@crawler.should_skip_link?(
|
272
|
+
@crawler.should_skip_link?(make_link("http-anything")).should == true
|
284
273
|
end
|
285
274
|
|
286
275
|
it "skips javascript links (those that begin with javascript)" do
|
287
276
|
@crawler.expects(:log).with("Skipping javascript-anything")
|
288
|
-
@crawler.should_skip_link?(
|
277
|
+
@crawler.should_skip_link?(make_link("javascript-anything")).should == true
|
289
278
|
end
|
290
279
|
|
291
280
|
it "skips mailto links (those that begin with http)" do
|
292
281
|
@crawler.expects(:log).with("Skipping mailto-anything")
|
293
|
-
@crawler.should_skip_link?(
|
282
|
+
@crawler.should_skip_link?(make_link("mailto-anything")).should == true
|
294
283
|
end
|
295
284
|
|
296
285
|
it 'skips blank links' do
|
297
286
|
@crawler.queue_link(nil)
|
298
|
-
@crawler.
|
287
|
+
@crawler.crawl_queue.should == []
|
299
288
|
@crawler.queue_link("")
|
300
|
-
@crawler.
|
289
|
+
@crawler.crawl_queue.should == []
|
301
290
|
end
|
302
291
|
|
303
292
|
it "logs and skips links that match a pattern" do
|
304
293
|
@crawler.expects(:log).with("Skipping /the-red-button")
|
305
294
|
@crawler.skip_uri_patterns << /red-button/
|
306
|
-
@crawler.queue_link("/blue-button").should ==
|
295
|
+
@crawler.queue_link("/blue-button").should == make_link("/blue-button")
|
307
296
|
@crawler.queue_link("/the-red-button").should == nil
|
308
297
|
end
|
309
298
|
|
@@ -371,7 +360,7 @@ describe Relevance::Tarantula::Crawler do
|
|
371
360
|
crawler = Relevance::Tarantula::Crawler.new
|
372
361
|
crawler.crawl_timeout = 5.minutes
|
373
362
|
|
374
|
-
crawler.
|
363
|
+
crawler.crawl_queue = [stub(:href => "/foo1", :method => :get), stub(:href => "/foo2", :method => :get)]
|
375
364
|
crawler.proxy = stub
|
376
365
|
crawler.proxy.stubs(:get).returns(response = stub(:code => "200"))
|
377
366
|
|
@@ -11,7 +11,7 @@ describe "Relevance::Tarantula::Form large example" do
|
|
11
11
|
<input name="commit" type="submit" value="Log in" />
|
12
12
|
</form>
|
13
13
|
END
|
14
|
-
@form =
|
14
|
+
@form = make_form(@tag.at('form'))
|
15
15
|
end
|
16
16
|
|
17
17
|
it "has an action" do
|
@@ -27,7 +27,7 @@ end
|
|
27
27
|
describe "A Relevance::Tarantula::Form" do
|
28
28
|
it "defaults method to 'get'" do
|
29
29
|
@tag = Hpricot("<form/>")
|
30
|
-
@form =
|
30
|
+
@form = make_form(@tag.at('form'))
|
31
31
|
@form.method.should == 'get'
|
32
32
|
end
|
33
33
|
end
|
@@ -40,7 +40,7 @@ describe "A Relevance::Tarantula::Form with a hacked _method" do
|
|
40
40
|
<input id="_method" name="_method" size="30" type="text" value="PUT"/>
|
41
41
|
</form>
|
42
42
|
END
|
43
|
-
@form =
|
43
|
+
@form = make_form(@tag.at('form'))
|
44
44
|
end
|
45
45
|
|
46
46
|
it "has a method" do
|
@@ -1,71 +1,171 @@
|
|
1
1
|
require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "example_helper.rb"))
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe Relevance::Tarantula::FormSubmission do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
</
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
5
|
+
describe "with a good form" do
|
6
|
+
# TODO: add more from field types to this example form as needed
|
7
|
+
before do
|
8
|
+
@tag = Hpricot(%q{
|
9
|
+
<form action="/session" method="post">
|
10
|
+
<input id="email" name="email" size="30" type="text" />
|
11
|
+
<textarea id="comment" name="comment"value="1" />
|
12
|
+
<input name="commit" type="submit" value="Postit" />
|
13
|
+
<input name="secret" type="hidden" value="secret" />
|
14
|
+
<select id="foo_opened_on_1i" name="foo[opened_on(1i)]">
|
15
|
+
<option value="2003">2003</option>
|
16
|
+
<option value="2004">2004</option>
|
17
|
+
</select>
|
18
|
+
</form>
|
19
|
+
})
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "crawl" do
|
23
|
+
|
24
|
+
it "converts ActiveRecord::RecordNotFound into a 404" do
|
25
|
+
(crawler = stub_everything).expects(:submit).raises(ActiveRecord::RecordNotFound)
|
26
|
+
form = Relevance::Tarantula::FormSubmission.new(make_form(@tag.at('form'), crawler))
|
27
|
+
response = form.crawl
|
28
|
+
response.code.should == "404"
|
29
|
+
response.content_type.should == "text/plain"
|
30
|
+
response.body.should == "ActiveRecord::RecordNotFound"
|
31
|
+
end
|
32
|
+
|
33
|
+
it "submits the form and logs response" do
|
34
|
+
doc = Hpricot('<form action="/action" method="post"/>')
|
35
|
+
form = make_form(doc.at('form'))
|
36
|
+
fs = Relevance::Tarantula::FormSubmission.new(form)
|
37
|
+
form.crawler.expects(:submit).returns(stub(:code => "200"))
|
38
|
+
fs.expects(:log).with("Response 200 for #{fs}")
|
39
|
+
fs.crawl
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
describe "with default attack" do
|
45
|
+
before do
|
46
|
+
@form = make_form(@tag.at('form'))
|
47
|
+
@fs = Relevance::Tarantula::FormSubmission.new(@form)
|
48
|
+
end
|
22
49
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
50
|
+
it "can mutate text areas" do
|
51
|
+
@fs.attack.stubs(:random_int).returns("42")
|
52
|
+
@fs.mutate_text_areas(@form).should == {"comment" => "42"}
|
53
|
+
end
|
27
54
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
55
|
+
it "can mutate selects" do
|
56
|
+
Hpricot::Elements.any_instance.stubs(:rand).returns(stub(:[] => "2006-stub"))
|
57
|
+
@fs.mutate_selects(@form).should == {"foo[opened_on(1i)]" => "2006-stub"}
|
58
|
+
end
|
32
59
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
60
|
+
it "can mutate inputs" do
|
61
|
+
@fs.attack.stubs(:random_int).returns("43")
|
62
|
+
@fs.mutate_inputs(@form).should == {"commit"=>"43", "secret"=>"43", "email"=>"43"}
|
63
|
+
end
|
37
64
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
65
|
+
it "has a signature based on action and fields" do
|
66
|
+
@fs.signature.should == ['/session', [
|
67
|
+
"comment",
|
68
|
+
"commit",
|
69
|
+
"email",
|
70
|
+
"foo[opened_on(1i)]",
|
71
|
+
"secret"],
|
72
|
+
@fs.attack.name]
|
73
|
+
end
|
46
74
|
|
47
|
-
|
48
|
-
|
75
|
+
it "has a friendly to_s" do
|
76
|
+
@fs.to_s.should =~ %r{^/session post}
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe "with a custom attack" do
|
81
|
+
before do
|
82
|
+
@form = make_form(@tag.at('form'))
|
83
|
+
@attack = Relevance::Tarantula::Attack.new(:name => 'foo_name',
|
84
|
+
:input => 'foo_code',
|
85
|
+
:output => 'foo_code')
|
86
|
+
@fs = Relevance::Tarantula::FormSubmission.new(@form, @attack)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "can mutate text areas" do
|
90
|
+
@fs.mutate_text_areas(@form).should == {"comment" => "foo_code"}
|
91
|
+
end
|
92
|
+
|
93
|
+
it "can mutate selects" do
|
94
|
+
Hpricot::Elements.any_instance.stubs(:rand).returns(stub(:[] => "2006-stub"))
|
95
|
+
@fs.mutate_selects(@form).should == {"foo[opened_on(1i)]" => "2006-stub"}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "can mutate inputs" do
|
99
|
+
@fs.mutate_inputs(@form).should == {"commit"=>"foo_code", "secret"=>"foo_code", "email"=>"foo_code"}
|
100
|
+
end
|
101
|
+
|
102
|
+
it "has a signature based on action, fields, and attack name" do
|
103
|
+
@fs.signature.should == ['/session', [
|
104
|
+
"comment",
|
105
|
+
"commit",
|
106
|
+
"email",
|
107
|
+
"foo[opened_on(1i)]",
|
108
|
+
"secret"],
|
109
|
+
"foo_name"
|
110
|
+
]
|
111
|
+
end
|
112
|
+
|
113
|
+
it "has a friendly to_s" do
|
114
|
+
@fs.to_s.should =~ %r{^/session post}
|
115
|
+
end
|
116
|
+
|
117
|
+
it "processes all its attacks" do
|
118
|
+
Relevance::Tarantula::FormSubmission.stubs(:attacks).returns([
|
119
|
+
Relevance::Tarantula::Attack.new({:name => 'foo_name1', :input => 'foo_input', :output => 'foo_output'}),
|
120
|
+
Relevance::Tarantula::Attack.new({:name => 'foo_name2', :input => 'foo_input', :output => 'foo_output'}),
|
121
|
+
])
|
122
|
+
Relevance::Tarantula::FormSubmission.mutate(@form).size.should == 2
|
123
|
+
end
|
124
|
+
|
125
|
+
it "maps hash attacks to Attack instances" do
|
126
|
+
saved_attacks = Relevance::Tarantula::FormSubmission.instance_variable_get("@attacks")
|
127
|
+
begin
|
128
|
+
Relevance::Tarantula::FormSubmission.instance_variable_set("@attacks", [{ :name => "attack name"}])
|
129
|
+
Relevance::Tarantula::FormSubmission.attacks.should == [Relevance::Tarantula::Attack.new({:name => "attack name"})]
|
130
|
+
ensure
|
131
|
+
# isolate this test properly
|
132
|
+
Relevance::Tarantula::FormSubmission.instance_variable_set("@attacks", saved_attacks)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
49
136
|
end
|
50
137
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
138
|
+
describe "with a crummy form" do
|
139
|
+
before do
|
140
|
+
@tag = Hpricot(%q{
|
141
|
+
<form action="/session" method="post">
|
142
|
+
<input value="no_name" />
|
143
|
+
</form>
|
144
|
+
})
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "with default attack" do
|
148
|
+
before do
|
149
|
+
@form = make_form(@tag.at('form'))
|
150
|
+
@fs = Relevance::Tarantula::FormSubmission.new(@form)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "ignores unnamed inputs" do
|
154
|
+
@fs.mutate_inputs(@form).should == {}
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "with a custom attack" do
|
159
|
+
before do
|
160
|
+
@form = make_form(@tag.at('form'))
|
161
|
+
@fs = Relevance::Tarantula::FormSubmission.new(@form, {:name => 'foo_name', :input => 'foo_code', :output => 'foo_code'})
|
162
|
+
end
|
163
|
+
|
164
|
+
it "ignores unnamed inputs" do
|
165
|
+
@fs.mutate_inputs(@form).should == {}
|
166
|
+
end
|
167
|
+
end
|
56
168
|
|
57
|
-
describe "Relevance::Tarantula::FormSubmission for a crummy form" do
|
58
|
-
before do
|
59
|
-
@tag = Hpricot(<<END)
|
60
|
-
<form action="/session" method="post">
|
61
|
-
<input value="no_name" />
|
62
|
-
</form>
|
63
|
-
END
|
64
|
-
@form = Relevance::Tarantula::Form.new(@tag.at('form'))
|
65
|
-
@fs = Relevance::Tarantula::FormSubmission.new(@form)
|
66
169
|
end
|
67
170
|
|
68
|
-
it "ignores unnamed inputs" do
|
69
|
-
@fs.mutate_inputs(@form).should == {}
|
70
|
-
end
|
71
171
|
end
|