tarantula 0.2.0 → 0.3.3
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.
- 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
|