relevance-tarantula 0.2.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,47 +4,64 @@ describe "Relevance::Tarantula::Link" do
4
4
  include ActionView::Helpers::UrlHelper
5
5
 
6
6
  it "does not raise an error when initializing without href attribtue" do
7
- link = Relevance::Tarantula::Link.new(Hpricot('<a="/foo">foo</a>').at('a'))
7
+ link = make_link(Hpricot('<a="/foo">foo</a>').at('a'))
8
8
  link.href.should == nil
9
9
  link.method.should == :get
10
10
  end
11
11
 
12
12
  it "parses anchor tags" do
13
- link = Relevance::Tarantula::Link.new(Hpricot('<a href="/foo">foo</a>').at('a'))
13
+ link = make_link(Hpricot('<a href="/foo">foo</a>').at('a'))
14
14
  link.href.should == '/foo'
15
15
  link.method.should == :get
16
16
  end
17
17
 
18
18
  it "parses anchor tags with POST 'method'" do
19
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:post)}">foo</a>}).at('a'))
19
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:post)}">foo</a>}).at('a'))
20
20
  link.href.should == '/foo'
21
21
  link.method.should == :post
22
22
  end
23
23
 
24
24
  it "parses anchor tags with PUT 'method'" do
25
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:put)}">foo</a>}).at('a'))
25
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:put)}">foo</a>}).at('a'))
26
26
  link.href.should == '/foo'
27
27
  link.method.should == :put
28
28
  end
29
29
 
30
30
  it "parses anchor tags with DELETE 'method'" do
31
- link = Relevance::Tarantula::Link.new(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:delete)}">foo</a>}).at('a'))
31
+ link = make_link(Hpricot(%Q{<a href="/foo" onclick="#{method_javascript_function(:delete)}">foo</a>}).at('a'))
32
32
  link.href.should == '/foo'
33
33
  link.method.should == :delete
34
34
  end
35
35
 
36
36
  it "parses link tags with text" do
37
- link = Relevance::Tarantula::Link.new(Hpricot('<link href="/bar">bar</a>').at('link'))
37
+ link = make_link(Hpricot('<link href="/bar">bar</a>').at('link'))
38
38
  link.href.should == '/bar'
39
39
  link.method.should == :get
40
40
  end
41
41
 
42
42
  it "parses link tags without text" do
43
- link = Relevance::Tarantula::Link.new(Hpricot('<link href="/bar" />').at('link'))
43
+ link = make_link(Hpricot('<link href="/bar" />').at('link'))
44
44
  link.href.should == '/bar'
45
45
  link.method.should == :get
46
46
  end
47
47
 
48
+ it 'remembers link referrer if there is one' do
49
+ link = make_link('/url', stub_everything, '/some-referrer')
50
+ link.referrer.should == '/some-referrer'
51
+ end
52
+
53
+ it "does two things when crawled: follow, log, and handle" do
54
+ crawler = Relevance::Tarantula::Crawler.new
55
+ link = make_link('/foo', crawler)
56
+
57
+ response = stub(:code => "200")
58
+ crawler.expects(:follow).returns(response)
59
+ link.expects(:log)
60
+ crawler.expects(:handle_link_results)
61
+
62
+ link.crawl
63
+ end
64
+
48
65
  # method_javascript_function needs this method
49
66
  def protect_against_forgery?
50
67
  false
@@ -10,6 +10,9 @@ class Relevance::Tarantula::Attack
10
10
  def ==(other)
11
11
  Relevance::Tarantula::Attack === other && HASHABLE_ATTRS.all? { |attr| send(attr) == other.send(attr)}
12
12
  end
13
+ def input(input_field=nil)
14
+ @input
15
+ end
13
16
  end
14
17
 
15
18
 
@@ -4,7 +4,7 @@ class Relevance::Tarantula::AttackHandler
4
4
  include ERB::Util
5
5
 
6
6
  def attacks
7
- Relevance::Tarantula::AttackFormSubmission.attacks.select(&:output)
7
+ Relevance::Tarantula::FormSubmission.attacks.select(&:output)
8
8
  end
9
9
 
10
10
  def handle(result)
@@ -0,0 +1,40 @@
1
+ class Relevance::Tarantula::BasicAttack
2
+ ATTRS = [:name, :output, :description]
3
+
4
+ attr_reader *ATTRS
5
+
6
+ def initialize
7
+ @name = "Tarantula Basic Fuzzer"
8
+ @output = nil
9
+ @description = "Supplies purely random but simplistically generated form input."
10
+ end
11
+
12
+ def ==(other)
13
+ Relevance::Tarantula::BasicAttack === other && ATTRS.all? { |attr| send(attr) == other.send(attr)}
14
+ end
15
+
16
+ def input(input_field)
17
+ case input_field['name']
18
+ when /amount/ then random_int
19
+ when /_id$/ then random_whole_number
20
+ when /uploaded_data/ then nil
21
+ when nil then input['value']
22
+ else
23
+ random_int
24
+ end
25
+ end
26
+
27
+ def big_number
28
+ 10000 # arbitrary
29
+ end
30
+
31
+ def random_int
32
+ rand(big_number) - (big_number/2)
33
+ end
34
+
35
+ def random_whole_number
36
+ rand(big_number)
37
+ end
38
+ end
39
+
40
+
@@ -10,7 +10,7 @@ class Relevance::Tarantula::Crawler
10
10
  class CrawlTimeout < RuntimeError; end
11
11
 
12
12
  attr_accessor :proxy, :handlers, :skip_uri_patterns, :log_grabber,
13
- :reporters, :links_to_crawl, :links_queued, :forms_to_crawl,
13
+ :reporters, :crawl_queue, :links_queued,
14
14
  :form_signatures_queued, :max_url_length, :response_code_handler,
15
15
  :times_to_crawl, :fuzzers, :test_name, :crawl_timeout
16
16
  attr_reader :transform_url_patterns, :referrers, :failures, :successes, :crawl_start_times, :crawl_end_times
@@ -22,8 +22,7 @@ class Relevance::Tarantula::Crawler
22
22
  @handlers = [@response_code_handler = Result]
23
23
  @links_queued = Set.new
24
24
  @form_signatures_queued = Set.new
25
- @links_to_crawl = []
26
- @forms_to_crawl = []
25
+ @crawl_queue = []
27
26
  @crawl_start_times, @crawl_end_times = [], []
28
27
  @crawl_timeout = 20.minutes
29
28
  @referrers = {}
@@ -55,8 +54,7 @@ class Relevance::Tarantula::Crawler
55
54
  def crawl(url = "/")
56
55
  orig_links_queued = @links_queued.dup
57
56
  orig_form_signatures_queued = @form_signatures_queued.dup
58
- orig_links_to_crawl = @links_to_crawl.dup
59
- orig_forms_to_crawl = @forms_to_crawl.dup
57
+ orig_crawl_queue = @crawl_queue.dup
60
58
  @times_to_crawl.times do |num|
61
59
  queue_link url
62
60
 
@@ -71,8 +69,7 @@ class Relevance::Tarantula::Crawler
71
69
  if num + 1 < @times_to_crawl
72
70
  @links_queued = orig_links_queued
73
71
  @form_signatures_queued = orig_form_signatures_queued
74
- @links_to_crawl = orig_links_to_crawl
75
- @forms_to_crawl = orig_forms_to_crawl
72
+ @crawl_queue = orig_crawl_queue
76
73
  @referrers = {}
77
74
  end
78
75
  end
@@ -83,23 +80,20 @@ class Relevance::Tarantula::Crawler
83
80
  end
84
81
 
85
82
  def finished?
86
- @links_to_crawl.empty? && @forms_to_crawl.empty?
83
+ @crawl_queue.empty?
87
84
  end
88
85
 
89
86
  def do_crawl(number)
90
87
  while (!finished?)
91
88
  @crawl_start_times << Time.now
92
- crawl_queued_links(number)
93
- crawl_queued_forms(number)
89
+ crawl_the_queue(number)
94
90
  @crawl_end_times << Time.now
95
91
  end
96
92
  end
97
93
 
98
- def crawl_queued_links(number = 0)
99
- while (link = @links_to_crawl.pop)
100
- response = proxy.send(link.method, link.href)
101
- log "Response #{response.code} for #{link}"
102
- handle_link_results(link, response)
94
+ def crawl_the_queue(number = 0)
95
+ while (request = @crawl_queue.pop)
96
+ request.crawl
103
97
  blip(number)
104
98
  end
105
99
  end
@@ -110,15 +104,10 @@ class Relevance::Tarantula::Crawler
110
104
  end
111
105
  end
112
106
 
113
- def handle_link_results(link, response)
107
+ def handle_link_results(link, result)
114
108
  handlers.each do |h|
115
109
  begin
116
- save_result h.handle(Result.new(:method => link.method,
117
- :url => link.href,
118
- :response => response,
119
- :log => grab_log!,
120
- :referrer => referrers[link],
121
- :test_name => test_name).freeze)
110
+ save_result h.handle(result)
122
111
  rescue Exception => e
123
112
  log "error handling #{link} #{e.message}"
124
113
  # TODO: pass to results
@@ -126,23 +115,14 @@ class Relevance::Tarantula::Crawler
126
115
  end
127
116
  end
128
117
 
129
- def crawl_form(form)
130
- response = proxy.send(form.method, form.action, form.data)
131
- log "Response #{response.code} for #{form}"
132
- response
133
- rescue ActiveRecord::RecordNotFound => e
134
- log "Skipping #{form.action}, presumed ok that record is missing"
135
- Relevance::Tarantula::Response.new(:code => "404", :body => e.message, :content_type => "text/plain")
136
- end
137
-
138
- def crawl_queued_forms(number = 0)
139
- while (form = @forms_to_crawl.pop)
140
- response = crawl_form(form)
141
- handle_form_results(form, response)
142
- blip(number)
143
- end
118
+ def follow(method, url, data=nil)
119
+ proxy.send(method, url, data)
144
120
  end
145
121
 
122
+ def submit(method, action, data)
123
+ proxy.send(method, action, data)
124
+ end
125
+
146
126
  def elasped_time_for_pass(num)
147
127
  Time.now - crawl_start_times[num]
148
128
  end
@@ -150,6 +130,14 @@ class Relevance::Tarantula::Crawler
150
130
  def grab_log!
151
131
  @log_grabber && @log_grabber.grab!
152
132
  end
133
+
134
+ def make_result(options)
135
+ defaults = {
136
+ :log => grab_log!,
137
+ :test_name => test_name
138
+ }
139
+ Result.new(defaults.merge(options)).freeze
140
+ end
153
141
 
154
142
  def handle_form_results(form, response)
155
143
  handlers.each do |h|
@@ -193,23 +181,21 @@ class Relevance::Tarantula::Crawler
193
181
  end
194
182
 
195
183
  def queue_link(dest, referrer = nil)
196
- dest = Link.new(dest)
197
- dest.href = transform_url(dest.href)
184
+ dest = Link.new(dest, self, referrer)
198
185
  return if should_skip_link?(dest)
199
- @referrers[dest] = referrer if referrer
200
- @links_to_crawl << dest
186
+ @crawl_queue << dest
201
187
  @links_queued << dest
202
188
  dest
203
189
  end
204
190
 
205
191
  def queue_form(form, referrer = nil)
206
192
  fuzzers.each do |fuzzer|
207
- fuzzer.mutate(Form.new(form)).each do |fs|
208
- # fs = fuzzer.new(Form.new(form))
193
+ fuzzer.mutate(Form.new(form, self, referrer)).each do |fs|
194
+ # fs = fuzzer.new(Form.new(form, self, referrer))
209
195
  fs.action = transform_url(fs.action)
210
196
  return if should_skip_form_submission?(fs)
211
197
  @referrers[fs.action] = referrer if referrer
212
- @forms_to_crawl << fs
198
+ @crawl_queue << fs
213
199
  @form_signatures_queued << fs.signature
214
200
  end
215
201
  end
@@ -234,6 +220,7 @@ class Relevance::Tarantula::Crawler
234
220
  end
235
221
 
236
222
  def report_results
223
+ puts "Crawled #{total_links_count} links and forms."
237
224
  generate_reports
238
225
  end
239
226
 
@@ -242,7 +229,7 @@ class Relevance::Tarantula::Crawler
242
229
  end
243
230
 
244
231
  def links_remaining_count
245
- @links_to_crawl.size + @forms_to_crawl.size
232
+ @crawl_queue.size
246
233
  end
247
234
 
248
235
  def links_completed_count
@@ -251,7 +238,7 @@ class Relevance::Tarantula::Crawler
251
238
 
252
239
  def blip(number = 0)
253
240
  unless verbose
254
- print "\r #{links_completed_count} of #{total_links_count} links completed "
241
+ print "\r #{links_completed_count} of #{total_links_count} links completed " if $stdout.tty?
255
242
  timeout_if_too_long(number)
256
243
  end
257
244
  end
@@ -2,8 +2,10 @@ class Relevance::Tarantula::Form
2
2
  extend Forwardable
3
3
  def_delegators("@tag", :search)
4
4
 
5
- def initialize(tag)
6
- @tag = tag
5
+ attr_accessor :crawler, :referrer
6
+
7
+ def initialize(tag, crawler, referrer)
8
+ @tag, @crawler, @referrer = tag, crawler, referrer
7
9
  end
8
10
 
9
11
  def action
@@ -1,25 +1,58 @@
1
1
  class Relevance::Tarantula::FormSubmission
2
- attr_accessor :method, :action, :data
3
- def initialize(form)
2
+ include Relevance::Tarantula
3
+ attr_accessor :method, :action, :data, :attack, :form
4
+
5
+ class << self
6
+ def attacks
7
+ # normalize from hash input to Attack
8
+ @attacks = @attacks.map do |val|
9
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
10
+ end
11
+ @attacks
12
+ end
13
+ def attacks=(atts)
14
+ # normalize from hash input to Attack
15
+ @attacks = atts.map do |val|
16
+ Hash === val ? Relevance::Tarantula::Attack.new(val) : val
17
+ end
18
+ end
19
+ end
20
+ @attacks = [Relevance::Tarantula::BasicAttack.new]
21
+
22
+ def initialize(form, attack = Relevance::Tarantula::BasicAttack.new)
23
+ @form = form
4
24
  @method = form.method
5
25
  @action = form.action
26
+ @attack = attack
6
27
  @data = mutate_selects(form).merge(mutate_text_areas(form)).merge(mutate_inputs(form))
7
28
  end
8
29
 
30
+ def crawl
31
+ begin
32
+ response = form.crawler.submit(method, action, data)
33
+ log "Response #{response.code} for #{self}"
34
+ rescue ActiveRecord::RecordNotFound => e
35
+ log "Skipping #{action}, presumed ok that record is missing"
36
+ response = Relevance::Tarantula::Response.new(:code => "404", :body => e.message, :content_type => "text/plain")
37
+ end
38
+ form.crawler.handle_form_results(self, response)
39
+ response
40
+ end
41
+
9
42
  def self.mutate(form)
10
- [self.new(form)]
43
+ attacks.map{|attack| new(form, attack)} if attacks
11
44
  end
12
-
45
+
13
46
  def to_s
14
- "#{action} #{method} #{data.inspect}"
47
+ "#{action} #{method} #{data.inspect} #{attack.inspect}"
15
48
  end
16
-
49
+
17
50
  # a form's signature is what makes it unique (e.g. action + fields)
18
51
  # used to keep track of which forms we have submitted already
19
52
  def signature
20
- [action, data.keys.sort]
53
+ [action, data.keys.sort, attack.name]
21
54
  end
22
-
55
+
23
56
  def create_random_data_for(form, tag_selector)
24
57
  form.search(tag_selector).inject({}) do |form_args, input|
25
58
  # TODO: test
@@ -35,37 +68,21 @@ class Relevance::Tarantula::FormSubmission
35
68
  def mutate_text_areas(form)
36
69
  create_random_data_for(form, 'textarea')
37
70
  end
38
-
71
+
39
72
  def mutate_selects(form)
40
73
  form.search('select').inject({}) do |form_args, select|
41
74
  options = select.search('option')
42
75
  option = options.rand
43
- form_args[select['name']] = option['value']
76
+ form_args[select['name']] = option['value']
44
77
  form_args
45
78
  end
46
79
  end
47
-
80
+
48
81
  def random_data(input)
49
82
  case input['name']
50
- when /amount/ then random_int
51
- when /_id$/ then random_whole_number
52
- when /uploaded_data/ then nil
53
- when /^_method$/ then input['value']
54
- when nil then input['value']
55
- else
56
- random_int
83
+ when /^_method$/ then input['value']
84
+ else
85
+ attack.input(input)
57
86
  end
58
87
  end
59
-
60
- def big_number
61
- 10000 # arbitrary
62
- end
63
-
64
- def random_int
65
- rand(big_number) - (big_number/2)
66
- end
67
-
68
- def random_whole_number
69
- rand(big_number)
70
- end
71
88
  end
@@ -1,4 +1,5 @@
1
1
  class Relevance::Tarantula::Link
2
+ include Relevance::Tarantula
2
3
 
3
4
  class << self
4
5
  include ActionView::Helpers::UrlHelper
@@ -17,18 +18,33 @@ class Relevance::Tarantula::Link
17
18
  METHOD_REGEXPS[m] = /#{s}/
18
19
  end
19
20
 
20
- attr_accessor :href
21
+ attr_accessor :href, :crawler, :referrer
21
22
 
22
- def initialize(link)
23
+ def initialize(link, crawler, referrer)
24
+ @crawler, @referrer = crawler, referrer
25
+
23
26
  if String === link || link.nil?
24
- @href = link
27
+ @href = transform_url(link)
25
28
  @method = :get
26
29
  else # should be a tag
27
- @href = link['href'] ? link['href'].downcase : nil
30
+ @href = link['href'] ? transform_url(link['href'].downcase) : nil
28
31
  @tag = link
29
32
  end
30
33
  end
31
34
 
35
+ def crawl
36
+ response = crawler.follow(method, href)
37
+ log "Response #{response.code} for #{self}"
38
+ crawler.handle_link_results(self, make_result(response))
39
+ end
40
+
41
+ def make_result(response)
42
+ crawler.make_result(:method => method,
43
+ :url => href,
44
+ :response => response,
45
+ :referrer => referrer)
46
+ end
47
+
32
48
  def method
33
49
  @method ||= begin
34
50
  (@tag &&
@@ -39,6 +55,10 @@ class Relevance::Tarantula::Link
39
55
  end
40
56
  end
41
57
 
58
+ def transform_url(link)
59
+ crawler.transform_url(link)
60
+ end
61
+
42
62
  def ==(obj)
43
63
  obj.respond_to?(:href) && obj.respond_to?(:method) &&
44
64
  self.href.to_s == obj.href.to_s && self.method.to_s == obj.method.to_s
@@ -41,7 +41,7 @@ class Relevance::Tarantula::RailsIntegrationProxy
41
41
  if response.code == '404'
42
42
  if File.exist?(static_content_path(url))
43
43
  case ext = File.extension(url)
44
- when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf/
44
+ when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf|ico/
45
45
  response.body = static_content_file(url)
46
46
  response.headers["type"] = "text/#{ext}" # readable as response.content_type
47
47
  response.meta.attr_accessor :code
@@ -49,10 +49,10 @@ require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "log_gra
49
49
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "invalid_html_handler"))
50
50
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "transform"))
51
51
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "crawler"))
52
+ require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "basic_attack"))
52
53
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "form"))
53
54
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "form_submission"))
54
55
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack"))
55
- require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack_form_submission"))
56
56
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "attack_handler"))
57
57
  require File.expand_path(File.join(File.dirname(__FILE__), "tarantula", "link"))
58
58
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: relevance-tarantula
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Relevance, Inc.
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-21 00:00:00 -07:00
12
+ date: 2009-09-24 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -51,8 +51,8 @@ files:
51
51
  - examples/relevance/core_extensions/file_example.rb
52
52
  - examples/relevance/core_extensions/response_example.rb
53
53
  - examples/relevance/core_extensions/test_case_example.rb
54
- - examples/relevance/tarantula/attack_form_submission_example.rb
55
54
  - examples/relevance/tarantula/attack_handler_example.rb
55
+ - examples/relevance/tarantula/basic_attack_example.rb
56
56
  - examples/relevance/tarantula/crawler_example.rb
57
57
  - examples/relevance/tarantula/form_example.rb
58
58
  - examples/relevance/tarantula/form_submission_example.rb
@@ -84,8 +84,8 @@ files:
84
84
  - lib/relevance/core_extensions/test_case.rb
85
85
  - lib/relevance/tarantula.rb
86
86
  - lib/relevance/tarantula/attack.rb
87
- - lib/relevance/tarantula/attack_form_submission.rb
88
87
  - lib/relevance/tarantula/attack_handler.rb
88
+ - lib/relevance/tarantula/basic_attack.rb
89
89
  - lib/relevance/tarantula/crawler.rb
90
90
  - lib/relevance/tarantula/detail.html.erb
91
91
  - lib/relevance/tarantula/form.rb
@@ -107,7 +107,7 @@ files:
107
107
  - lib/relevance/tarantula/transform.rb
108
108
  - tasks/tarantula_tasks.rake
109
109
  - template/tarantula_test.rb
110
- has_rdoc: true
110
+ has_rdoc: false
111
111
  homepage: http://github.com/relevance/tarantula
112
112
  licenses:
113
113
  post_install_message:
@@ -132,7 +132,7 @@ requirements: []
132
132
  rubyforge_project: thinkrelevance
133
133
  rubygems_version: 1.3.5
134
134
  signing_key:
135
- specification_version: 2
135
+ specification_version: 3
136
136
  summary: A big hairy fuzzy spider that crawls your site, wreaking havoc
137
137
  test_files:
138
138
  - examples/example_helper.rb
@@ -140,8 +140,8 @@ test_files:
140
140
  - examples/relevance/core_extensions/file_example.rb
141
141
  - examples/relevance/core_extensions/response_example.rb
142
142
  - examples/relevance/core_extensions/test_case_example.rb
143
- - examples/relevance/tarantula/attack_form_submission_example.rb
144
143
  - examples/relevance/tarantula/attack_handler_example.rb
144
+ - examples/relevance/tarantula/basic_attack_example.rb
145
145
  - examples/relevance/tarantula/crawler_example.rb
146
146
  - examples/relevance/tarantula/form_example.rb
147
147
  - examples/relevance/tarantula/form_submission_example.rb
@@ -1,79 +0,0 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "example_helper.rb"))
2
-
3
- describe "Relevance::Tarantula::AttackFormSubmission" do
4
-
5
- # TODO: add more from field types to this example form as needed
6
- before do
7
- @tag = Hpricot(<<END)
8
- <form action="/session" method="post">
9
- <input id="email" name="email" size="30" type="text" />
10
- <textarea id="comment" name="comment"value="1" />
11
- <input name="commit" type="submit" value="Postit" />
12
- <input name="secret" type="hidden" value="secret" />
13
- <select id="foo_opened_on_1i" name="foo[opened_on(1i)]">
14
- <option value="2003">2003</option>
15
- <option value="2004">2004</option>
16
- </select>
17
- </form>
18
- END
19
- @form = Relevance::Tarantula::Form.new(@tag.at('form'))
20
- @fs = Relevance::Tarantula::AttackFormSubmission.new(@form, Relevance::Tarantula::Attack.new({:name => 'foo_name', :input => 'foo_code', :output => 'foo_code'}))
21
- end
22
-
23
- it "can mutate text areas" do
24
- @fs.mutate_text_areas(@form).should == {"comment" => "foo_code"}
25
- end
26
-
27
- it "can mutate selects" do
28
- Hpricot::Elements.any_instance.stubs(:rand).returns(stub(:[] => "2006-stub"))
29
- @fs.mutate_selects(@form).should == {"foo[opened_on(1i)]" => "2006-stub"}
30
- end
31
-
32
- it "can mutate inputs" do
33
- @fs.mutate_inputs(@form).should == {"commit"=>"foo_code", "secret"=>"foo_code", "email"=>"foo_code"}
34
- end
35
-
36
- it "has a signature based on action, fields, and attack name" do
37
- @fs.signature.should == ['/session', [
38
- "comment",
39
- "commit",
40
- "email",
41
- "foo[opened_on(1i)]",
42
- "secret"],
43
- "foo_name"
44
- ]
45
- end
46
-
47
- it "has a friendly to_s" do
48
- @fs.to_s.should =~ %r{^/session post}
49
- end
50
-
51
- it "processes all its attacks" do
52
- Relevance::Tarantula::AttackFormSubmission.stubs(:attacks).returns([
53
- Relevance::Tarantula::Attack.new({:name => 'foo_name1', :input => 'foo_input', :output => 'foo_output'}),
54
- Relevance::Tarantula::Attack.new({:name => 'foo_name2', :input => 'foo_input', :output => 'foo_output'}),
55
- ])
56
- Relevance::Tarantula::AttackFormSubmission.mutate(@form).size.should == 2
57
- end
58
-
59
- it "maps hash attacks to Attack instances" do
60
- Relevance::Tarantula::AttackFormSubmission.instance_variable_set("@attacks", [{ :name => "attack name"}])
61
- Relevance::Tarantula::AttackFormSubmission.attacks.should == [Relevance::Tarantula::Attack.new({:name => "attack name"})]
62
- end
63
- end
64
-
65
- describe "Relevance::Tarantula::AttackFormSubmission for a crummy form" do
66
- before do
67
- @tag = Hpricot(<<END)
68
- <form action="/session" method="post">
69
- <input value="no_name" />
70
- </form>
71
- END
72
- @form = Relevance::Tarantula::Form.new(@tag.at('form'))
73
- @fs = Relevance::Tarantula::AttackFormSubmission.new(@form, {:name => 'foo_name', :input => 'foo_code', :output => 'foo_code'})
74
- end
75
-
76
- it "ignores unnamed inputs" do
77
- @fs.mutate_inputs(@form).should == {}
78
- end
79
- end