tarantula 0.3.3 → 0.4.0

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.
Files changed (74) hide show
  1. data/.autotest +14 -0
  2. data/.gitignore +9 -0
  3. data/.rvmrc +1 -0
  4. data/DSL_EXAMPLES.md +120 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +108 -0
  7. data/{MIT-LICENSE → LICENSE} +0 -0
  8. data/README.rdoc +3 -28
  9. data/Rakefile +27 -59
  10. data/lib/relevance/core_extensions/ellipsize.rb +23 -19
  11. data/lib/relevance/core_extensions/file.rb +10 -4
  12. data/lib/relevance/core_extensions/response.rb +9 -6
  13. data/lib/relevance/core_extensions/test_case.rb +14 -12
  14. data/lib/relevance/tarantula.rb +24 -25
  15. data/lib/relevance/tarantula/attack.rb +19 -15
  16. data/lib/relevance/tarantula/attack_handler.rb +32 -26
  17. data/lib/relevance/tarantula/basic_attack.rb +36 -32
  18. data/lib/relevance/tarantula/crawler.rb +222 -216
  19. data/lib/relevance/tarantula/form.rb +27 -21
  20. data/lib/relevance/tarantula/form_submission.rb +79 -73
  21. data/lib/relevance/tarantula/html_document_handler.rb +37 -31
  22. data/lib/relevance/tarantula/html_report_helper.rb +36 -29
  23. data/lib/relevance/tarantula/html_reporter.rb +105 -99
  24. data/lib/relevance/tarantula/invalid_html_handler.rb +21 -15
  25. data/lib/relevance/tarantula/io_reporter.rb +37 -31
  26. data/lib/relevance/tarantula/link.rb +97 -73
  27. data/lib/relevance/tarantula/log_grabber.rb +20 -14
  28. data/lib/relevance/tarantula/rails_integration_proxy.rb +64 -58
  29. data/lib/relevance/tarantula/response.rb +16 -10
  30. data/lib/relevance/tarantula/result.rb +69 -63
  31. data/lib/relevance/tarantula/tidy_handler.rb +22 -17
  32. data/lib/relevance/tarantula/transform.rb +18 -14
  33. data/lib/relevance/tarantula/version.rb +5 -0
  34. data/{tasks → lib/relevance/tasks}/tarantula_tasks.rake +1 -1
  35. data/lib/tarantula-rails3.rb +9 -0
  36. data/{examples/relevance/core_extensions/ellipsize_example.rb → spec/relevance/core_extensions/ellipsize_spec.rb} +2 -2
  37. data/{examples/relevance/core_extensions/file_example.rb → spec/relevance/core_extensions/file_spec.rb} +2 -2
  38. data/{examples/relevance/core_extensions/response_example.rb → spec/relevance/core_extensions/response_spec.rb} +2 -2
  39. data/{examples/relevance/core_extensions/test_case_example.rb → spec/relevance/core_extensions/test_case_spec.rb} +1 -1
  40. data/{examples/relevance/tarantula/attack_handler_example.rb → spec/relevance/tarantula/attack_handler_spec.rb} +1 -1
  41. data/{examples/relevance/tarantula/basic_attack_example.rb → spec/relevance/tarantula/basic_attack_spec.rb} +2 -2
  42. data/{examples/relevance/tarantula/crawler_example.rb → spec/relevance/tarantula/crawler_spec.rb} +2 -2
  43. data/{examples/relevance/tarantula/form_example.rb → spec/relevance/tarantula/form_spec.rb} +2 -2
  44. data/{examples/relevance/tarantula/form_submission_example.rb → spec/relevance/tarantula/form_submission_spec.rb} +3 -3
  45. data/{examples/relevance/tarantula/html_document_handler_example.rb → spec/relevance/tarantula/html_document_handler_spec.rb} +1 -1
  46. data/{examples/relevance/tarantula/html_report_helper_example.rb → spec/relevance/tarantula/html_report_helper_spec.rb} +1 -1
  47. data/{examples/relevance/tarantula/html_reporter_example.rb → spec/relevance/tarantula/html_reporter_spec.rb} +1 -1
  48. data/{examples/relevance/tarantula/invalid_html_handler_example.rb → spec/relevance/tarantula/invalid_html_handler_spec.rb} +1 -1
  49. data/{examples/relevance/tarantula/io_reporter_example.rb → spec/relevance/tarantula/io_reporter_spec.rb} +1 -1
  50. data/{examples/relevance/tarantula/link_example.rb → spec/relevance/tarantula/link_spec.rb} +5 -5
  51. data/{examples/relevance/tarantula/log_grabber_example.rb → spec/relevance/tarantula/log_grabber_spec.rb} +1 -1
  52. data/{examples/relevance/tarantula/rails_integration_proxy_example.rb → spec/relevance/tarantula/rails_integration_proxy_spec.rb} +1 -1
  53. data/{examples/relevance/tarantula/result_example.rb → spec/relevance/tarantula/result_spec.rb} +1 -1
  54. data/{examples/relevance/tarantula/tidy_handler_example.rb → spec/relevance/tarantula/tidy_handler_spec.rb} +1 -1
  55. data/{examples/relevance/tarantula/transform_example.rb → spec/relevance/tarantula/transform_spec.rb} +2 -2
  56. data/{examples/relevance/tarantula_example.rb → spec/relevance/tarantula_spec.rb} +1 -1
  57. data/{examples/example_helper.rb → spec/spec_helper.rb} +6 -14
  58. data/tarantula.gemspec +31 -0
  59. data/template/tarantula_test.rb +1 -1
  60. data/vendor/xss-shield/MIT-LICENSE +20 -0
  61. data/vendor/xss-shield/README +76 -0
  62. data/vendor/xss-shield/init.rb +16 -0
  63. data/vendor/xss-shield/lib/xss_shield.rb +6 -0
  64. data/vendor/xss-shield/lib/xss_shield/erb_hacks.rb +111 -0
  65. data/vendor/xss-shield/lib/xss_shield/haml_hacks.rb +42 -0
  66. data/vendor/xss-shield/lib/xss_shield/safe_string.rb +47 -0
  67. data/vendor/xss-shield/lib/xss_shield/secure_helpers.rb +40 -0
  68. data/vendor/xss-shield/test/test_actionview_integration.rb +40 -0
  69. data/vendor/xss-shield/test/test_erb.rb +44 -0
  70. data/vendor/xss-shield/test/test_haml.rb +43 -0
  71. data/vendor/xss-shield/test/test_helpers.rb +25 -0
  72. data/vendor/xss-shield/test/test_safe_string.rb +55 -0
  73. metadata +170 -99
  74. data/VERSION.yml +0 -4
@@ -1,18 +1,24 @@
1
- class Relevance::Tarantula::InvalidHtmlHandler
2
- include Relevance::Tarantula
3
- def handle(result)
4
- response = result.response
5
- return unless response.html?
6
- begin
7
- body = HTML::Document.new(response.body, true)
8
- rescue Exception => e
9
- error_result = result.dup
10
- error_result.success = false
11
- error_result.description = "Bad HTML (Scanner)"
12
- error_result.data = e.message
13
- error_result
14
- else
15
- nil
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class InvalidHtmlHandler
5
+ include Relevance::Tarantula
6
+ def handle(result)
7
+ response = result.response
8
+ return unless response.html?
9
+ begin
10
+ body = HTML::Document.new(response.body, true)
11
+ rescue Exception => e
12
+ error_result = result.dup
13
+ error_result.success = false
14
+ error_result.description = "Bad HTML (Scanner)"
15
+ error_result.data = e.message
16
+ error_result
17
+ else
18
+ nil
19
+ end
20
+ end
16
21
  end
22
+
17
23
  end
18
24
  end
@@ -1,34 +1,40 @@
1
- class Relevance::Tarantula::IOReporter
2
-
3
- include Relevance::Tarantula
4
- attr_accessor :io, :results
5
- delegate :successes, :failures, :to => :results
6
-
7
- IOResultOverview = Struct.new(:code, :url)
8
-
9
- def initialize(io)
10
- @io = io
11
- @results = Struct.new(:successes, :failures).new([], [])
12
- end
13
-
14
- def report(result)
15
- return if result.nil?
16
-
17
- unless result.success # collection = result.success ? results.successes : results.failures
18
- results.failures << IOResultOverview.new(
19
- result.code, result.url
20
- )
21
- end
22
- end
23
-
24
- def finish_report(test_name)
25
- unless (failures).empty?
26
- io.puts "****** FAILURES"
27
- failures.each do |failure|
28
- io.puts "#{failure.code}: #{failure.url}"
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class IOReporter
5
+
6
+ include Relevance::Tarantula
7
+ attr_accessor :io, :results
8
+ delegate :successes, :failures, :to => :results
9
+
10
+ IOResultOverview = Struct.new(:code, :url)
11
+
12
+ def initialize(io)
13
+ @io = io
14
+ @results = Struct.new(:successes, :failures).new([], [])
15
+ end
16
+
17
+ def report(result)
18
+ return if result.nil?
19
+
20
+ unless result.success # collection = result.success ? results.successes : results.failures
21
+ results.failures << IOResultOverview.new(
22
+ result.code, result.url
23
+ )
24
+ end
25
+ end
26
+
27
+ def finish_report(test_name)
28
+ unless (failures).empty?
29
+ io.puts "****** FAILURES"
30
+ failures.each do |failure|
31
+ io.puts "#{failure.code}: #{failure.url}"
32
+ end
33
+ raise "#{failures.size} failures"
34
+ end
29
35
  end
30
- raise "#{failures.size} failures"
36
+
31
37
  end
38
+
32
39
  end
33
-
34
- end
40
+ end
@@ -1,76 +1,100 @@
1
- class Relevance::Tarantula::Link
2
- include Relevance::Tarantula
3
-
4
- class << self
5
- include ActionView::Helpers::UrlHelper
6
- # method_javascript_function needs this method
7
- def protect_against_forgery?
8
- false
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class Link
5
+ include Relevance::Tarantula
6
+
7
+ class << self
8
+ include ActionView::Helpers::UrlHelper
9
+ # method_javascript_function needs this method
10
+ def protect_against_forgery?
11
+ false
12
+ end
13
+ #fast fix for rails3
14
+ def method_javascript_function(method, url = '', href = nil)
15
+ action = (href && url.size > 0) ? "'#{url}'" : 'this.href'
16
+ submit_function =
17
+ "var f = document.createElement('form'); f.style.display = 'none'; " +
18
+ "this.parentNode.appendChild(f); f.method = 'POST'; f.action = #{action};"
19
+
20
+ unless method == :post
21
+ submit_function << "var m = document.createElement('input'); m.setAttribute('type', 'hidden'); "
22
+ submit_function << "m.setAttribute('name', '_method'); m.setAttribute('value', '#{method}'); f.appendChild(m);"
23
+ end
24
+
25
+ if protect_against_forgery?
26
+ submit_function << "var s = document.createElement('input'); s.setAttribute('type', 'hidden'); "
27
+ submit_function << "s.setAttribute('name', '#{request_forgery_protection_token}'); s.setAttribute('value', '#{escape_javascript form_authenticity_token}'); f.appendChild(s);"
28
+ end
29
+ submit_function << "f.submit();"
30
+ end
31
+ end
32
+
33
+ METHOD_REGEXPS = {}
34
+ [:put, :delete, :post].each do |m|
35
+ # remove submit from the end so we'll match with or without forgery protection
36
+ s = method_javascript_function(m).gsub( /f.submit();/, "" )
37
+ # don't just match this.href in case a different url was passed originally
38
+ s = Regexp.escape(s).gsub( /this.href/, ".*" )
39
+ METHOD_REGEXPS[m] = /#{s}/
40
+ end
41
+
42
+ attr_accessor :href, :crawler, :referrer
43
+
44
+ def initialize(link, crawler, referrer)
45
+ @crawler, @referrer = crawler, referrer
46
+
47
+ if String === link || link.nil?
48
+ @href = transform_url(link)
49
+ @method = :get
50
+ else # should be a tag
51
+ @href = link['href'] ? transform_url(link['href'].downcase) : nil
52
+ @tag = link
53
+ end
54
+ end
55
+
56
+ def crawl
57
+ response = crawler.follow(method, href)
58
+ log "Response #{response.code} for #{self}"
59
+ crawler.handle_link_results(self, make_result(response))
60
+ end
61
+
62
+ def make_result(response)
63
+ crawler.make_result(:method => method,
64
+ :url => href,
65
+ :response => response,
66
+ :referrer => referrer)
67
+ end
68
+
69
+ def method
70
+ @method ||= begin
71
+ (@tag &&
72
+ [:put, :delete, :post].detect do |m| # post should be last since it's least specific
73
+ @tag['onclick'] =~ METHOD_REGEXPS[m]
74
+ end) ||
75
+ :get
76
+ end
77
+ end
78
+
79
+ def transform_url(link)
80
+ crawler.transform_url(link)
81
+ end
82
+
83
+ def ==(obj)
84
+ obj.respond_to?(:href) && obj.respond_to?(:method) &&
85
+ self.href.to_s == obj.href.to_s && self.method.to_s == obj.method.to_s
86
+ end
87
+ alias :eql? :==
88
+
89
+ def hash
90
+ to_s.hash
91
+ end
92
+
93
+ def to_s
94
+ "<Relevance::Tarantula::Link href=#{href}, method=#{method}>"
95
+ end
96
+
9
97
  end
98
+
10
99
  end
11
-
12
- METHOD_REGEXPS = {}
13
- [:put, :delete, :post].each do |m|
14
- # remove submit from the end so we'll match with or without forgery protection
15
- s = method_javascript_function(m).gsub( /f.submit();/, "" )
16
- # don't just match this.href in case a different url was passed originally
17
- s = Regexp.escape(s).gsub( /this.href/, ".*" )
18
- METHOD_REGEXPS[m] = /#{s}/
19
- end
20
-
21
- attr_accessor :href, :crawler, :referrer
22
-
23
- def initialize(link, crawler, referrer)
24
- @crawler, @referrer = crawler, referrer
25
-
26
- if String === link || link.nil?
27
- @href = transform_url(link)
28
- @method = :get
29
- else # should be a tag
30
- @href = link['href'] ? transform_url(link['href'].downcase) : nil
31
- @tag = link
32
- end
33
- end
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
-
48
- def method
49
- @method ||= begin
50
- (@tag &&
51
- [:put, :delete, :post].detect do |m| # post should be last since it's least specific
52
- @tag['onclick'] =~ METHOD_REGEXPS[m]
53
- end) ||
54
- :get
55
- end
56
- end
57
-
58
- def transform_url(link)
59
- crawler.transform_url(link)
60
- end
61
-
62
- def ==(obj)
63
- obj.respond_to?(:href) && obj.respond_to?(:method) &&
64
- self.href.to_s == obj.href.to_s && self.method.to_s == obj.method.to_s
65
- end
66
- alias :eql? :==
67
-
68
- def hash
69
- to_s.hash
70
- end
71
-
72
- def to_s
73
- "<Relevance::Tarantula::Link href=#{href}, method=#{method}>"
74
- end
75
-
76
100
  end
@@ -1,16 +1,22 @@
1
- class Relevance::Tarantula::LogGrabber
2
- attr_accessor :path
3
- def initialize(path)
4
- @path = path
5
- end
6
-
7
- def clear!
8
- File.open(@path, "w")
9
- end
10
-
11
- def grab!
12
- File.read(@path)
13
- ensure
14
- clear!
1
+ module Relevance
2
+ module Tarantula
3
+
4
+ class LogGrabber
5
+ attr_accessor :path
6
+ def initialize(path)
7
+ @path = path
8
+ end
9
+
10
+ def clear!
11
+ File.open(@path, "w")
12
+ end
13
+
14
+ def grab!
15
+ File.read(@path)
16
+ ensure
17
+ clear!
18
+ end
19
+ end
20
+
15
21
  end
16
22
  end
@@ -1,68 +1,74 @@
1
1
  require 'test/unit'
2
2
 
3
- class Relevance::Tarantula::RailsIntegrationProxy
4
- include Relevance::Tarantula
5
- extend Relevance::Tarantula
6
- extend Forwardable
7
- attr_accessor :integration_test
3
+ module Relevance
4
+ module Tarantula
8
5
 
9
- def self.rails_integration_test(integration_test, options = {})
10
- t = Crawler.new
11
- t.max_url_length = options[:max_url_length] if options[:max_url_length]
12
- t.proxy = RailsIntegrationProxy.new(integration_test)
13
- t.handlers << HtmlDocumentHandler.new(t)
14
- t.handlers << InvalidHtmlHandler.new
15
- t.log_grabber = Relevance::Tarantula::LogGrabber.new(File.join(rails_root, "log/test.log"))
16
- t.skip_uri_patterns << /logout$/
17
- t.transform_url_patterns += [
18
- [/\?\d+$/, ''], # strip trailing numbers for assets
19
- [/^http:\/\/#{integration_test.host}/, ''] # strip full path down to relative
20
- ]
21
- t.test_name = t.proxy.integration_test.method_name
22
- t.reporters << Relevance::Tarantula::HtmlReporter.new(t.report_dir)
23
- t
24
- end
6
+ class RailsIntegrationProxy
7
+ include Relevance::Tarantula
8
+ extend Relevance::Tarantula
9
+ extend Forwardable
10
+ attr_accessor :integration_test
25
11
 
26
- def initialize(integration_test)
27
- @integration_test = integration_test
28
- @integration_test.meta.attr_accessor :response
29
- end
30
-
31
- [:get, :post, :put, :delete].each do |verb|
32
- define_method(verb) do |url, *args|
33
- integration_test.send(verb, url, *args)
34
- response = integration_test.response
35
- patch_response(url, response)
36
- response
37
- end
38
- end
12
+ def self.rails_integration_test(integration_test, options = {})
13
+ t = Crawler.new
14
+ t.max_url_length = options[:max_url_length] if options[:max_url_length]
15
+ t.proxy = RailsIntegrationProxy.new(integration_test)
16
+ t.handlers << HtmlDocumentHandler.new(t)
17
+ t.handlers << InvalidHtmlHandler.new
18
+ t.log_grabber = Relevance::Tarantula::LogGrabber.new(File.join(rails_root, "log/test.log"))
19
+ t.skip_uri_patterns << /logout$/
20
+ t.transform_url_patterns += [
21
+ [/\?\d+$/, ''], # strip trailing numbers for assets
22
+ [/^http:\/\/#{integration_test.host}/, ''] # strip full path down to relative
23
+ ]
24
+ t.test_name = t.proxy.integration_test.method_name
25
+ t.reporters << Relevance::Tarantula::HtmlReporter.new(t.report_dir)
26
+ t
27
+ end
39
28
 
40
- def patch_response(url, response)
41
- if response.code == '404'
42
- if File.exist?(static_content_path(url))
43
- case ext = File.extension(url)
44
- when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf|ico/
45
- response.body = static_content_file(url)
46
- response.headers["type"] = "text/#{ext}" # readable as response.content_type
47
- response.meta.attr_accessor :code
48
- response.code = "200"
49
- else
50
- log "Skipping unknown type #{url}"
29
+ def initialize(integration_test)
30
+ @integration_test = integration_test
31
+ @integration_test.meta.attr_accessor :response
32
+ end
33
+
34
+ [:get, :post, :put, :delete].each do |verb|
35
+ define_method(verb) do |url, *args|
36
+ integration_test.send(verb, url, *args)
37
+ response = integration_test.response
38
+ patch_response(url, response)
39
+ response
51
40
  end
52
41
  end
42
+
43
+ def patch_response(url, response)
44
+ if response.code == '404'
45
+ if File.exist?(static_content_path(url))
46
+ case ext = File.extension(url)
47
+ when /html|te?xt|css|js|jpe?g|gif|psd|png|eps|pdf|ico/
48
+ response.body = static_content_file(url)
49
+ response.headers["type"] = "text/#{ext}" # readable as response.content_type
50
+ response.meta.attr_accessor :code
51
+ response.code = "200"
52
+ else
53
+ log "Skipping unknown type #{url}"
54
+ end
55
+ end
56
+ end
57
+ # don't count on metaclass taking block, e.g.
58
+ # http://relevancellc.com/2008/2/12/how-should-metaclass-work
59
+ response.metaclass.class_eval do
60
+ include Relevance::CoreExtensions::Response
61
+ end
62
+ end
63
+
64
+ def static_content_file(url)
65
+ File.read(static_content_path(url))
66
+ end
67
+
68
+ def static_content_path(url)
69
+ File.expand_path(File.join(rails_root, "public", url))
70
+ end
53
71
  end
54
- # don't count on metaclass taking block, e.g.
55
- # http://relevancellc.com/2008/2/12/how-should-metaclass-work
56
- response.metaclass.class_eval do
57
- include Relevance::CoreExtensions::Response
58
- end
59
- end
60
-
61
- def static_content_file(url)
62
- File.read(static_content_path(url))
63
- end
64
-
65
- def static_content_path(url)
66
- File.expand_path(File.join(rails_root, "public", url))
72
+
67
73
  end
68
74
  end