codez-tarantula 0.5.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 (88) hide show
  1. data/.autotest +14 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG +64 -0
  5. data/DSL_EXAMPLES.md +120 -0
  6. data/Gemfile +2 -0
  7. data/LICENSE +20 -0
  8. data/README.rdoc +136 -0
  9. data/Rakefile +36 -0
  10. data/ci/rails2.gemfile +4 -0
  11. data/ci/rails3.gemfile +4 -0
  12. data/laf/images/header_bg.jpg +0 -0
  13. data/laf/images/logo.png +0 -0
  14. data/laf/images/tagline.png +0 -0
  15. data/laf/javascripts/jquery-1.2.3.js +3408 -0
  16. data/laf/javascripts/jquery-ui-tabs.js +890 -0
  17. data/laf/javascripts/jquery.tablesorter.js +861 -0
  18. data/laf/javascripts/tarantula.js +10 -0
  19. data/laf/stylesheets/tarantula.css +346 -0
  20. data/lib/relevance/core_extensions/ellipsize.rb +38 -0
  21. data/lib/relevance/core_extensions/file.rb +15 -0
  22. data/lib/relevance/core_extensions/metaclass.rb +78 -0
  23. data/lib/relevance/core_extensions/response.rb +14 -0
  24. data/lib/relevance/core_extensions/test_case.rb +21 -0
  25. data/lib/relevance/tarantula.rb +55 -0
  26. data/lib/relevance/tarantula/attack.rb +22 -0
  27. data/lib/relevance/tarantula/attack_handler.rb +43 -0
  28. data/lib/relevance/tarantula/basic_attack.rb +44 -0
  29. data/lib/relevance/tarantula/crawler.rb +271 -0
  30. data/lib/relevance/tarantula/detail.html.erb +81 -0
  31. data/lib/relevance/tarantula/form.rb +29 -0
  32. data/lib/relevance/tarantula/form_submission.rb +98 -0
  33. data/lib/relevance/tarantula/html_document_handler.rb +42 -0
  34. data/lib/relevance/tarantula/html_report_helper.rb +46 -0
  35. data/lib/relevance/tarantula/html_reporter.rb +111 -0
  36. data/lib/relevance/tarantula/index.html.erb +37 -0
  37. data/lib/relevance/tarantula/invalid_html_handler.rb +27 -0
  38. data/lib/relevance/tarantula/io_reporter.rb +40 -0
  39. data/lib/relevance/tarantula/link.rb +105 -0
  40. data/lib/relevance/tarantula/log_grabber.rb +22 -0
  41. data/lib/relevance/tarantula/rails_integration_proxy.rb +90 -0
  42. data/lib/relevance/tarantula/recording.rb +12 -0
  43. data/lib/relevance/tarantula/response.rb +19 -0
  44. data/lib/relevance/tarantula/result.rb +83 -0
  45. data/lib/relevance/tarantula/test_report.html.erb +32 -0
  46. data/lib/relevance/tarantula/tidy_handler.rb +35 -0
  47. data/lib/relevance/tarantula/transform.rb +21 -0
  48. data/lib/relevance/tarantula/version.rb +5 -0
  49. data/lib/relevance/tasks/tarantula_tasks.rake +42 -0
  50. data/lib/tarantula-rails3.rb +9 -0
  51. data/spec/relevance/core_extensions/ellipsize_spec.rb +19 -0
  52. data/spec/relevance/core_extensions/file_spec.rb +7 -0
  53. data/spec/relevance/core_extensions/response_spec.rb +48 -0
  54. data/spec/relevance/core_extensions/test_case_spec.rb +19 -0
  55. data/spec/relevance/tarantula/attack_handler_spec.rb +29 -0
  56. data/spec/relevance/tarantula/basic_attack_spec.rb +12 -0
  57. data/spec/relevance/tarantula/crawler_spec.rb +409 -0
  58. data/spec/relevance/tarantula/form_spec.rb +50 -0
  59. data/spec/relevance/tarantula/form_submission_spec.rb +171 -0
  60. data/spec/relevance/tarantula/html_document_handler_spec.rb +43 -0
  61. data/spec/relevance/tarantula/html_report_helper_spec.rb +46 -0
  62. data/spec/relevance/tarantula/html_reporter_spec.rb +82 -0
  63. data/spec/relevance/tarantula/invalid_html_handler_spec.rb +33 -0
  64. data/spec/relevance/tarantula/io_reporter_spec.rb +11 -0
  65. data/spec/relevance/tarantula/link_spec.rb +132 -0
  66. data/spec/relevance/tarantula/log_grabber_spec.rb +26 -0
  67. data/spec/relevance/tarantula/rails_integration_proxy_spec.rb +100 -0
  68. data/spec/relevance/tarantula/result_spec.rb +85 -0
  69. data/spec/relevance/tarantula/tidy_handler_spec.rb +58 -0
  70. data/spec/relevance/tarantula/transform_spec.rb +20 -0
  71. data/spec/relevance/tarantula_spec.rb +23 -0
  72. data/spec/spec_helper.rb +43 -0
  73. data/tarantula.gemspec +25 -0
  74. data/template/tarantula_test.rb +22 -0
  75. data/vendor/xss-shield/MIT-LICENSE +20 -0
  76. data/vendor/xss-shield/README +76 -0
  77. data/vendor/xss-shield/init.rb +16 -0
  78. data/vendor/xss-shield/lib/xss_shield.rb +6 -0
  79. data/vendor/xss-shield/lib/xss_shield/erb_hacks.rb +111 -0
  80. data/vendor/xss-shield/lib/xss_shield/haml_hacks.rb +42 -0
  81. data/vendor/xss-shield/lib/xss_shield/safe_string.rb +47 -0
  82. data/vendor/xss-shield/lib/xss_shield/secure_helpers.rb +40 -0
  83. data/vendor/xss-shield/test/test_actionview_integration.rb +40 -0
  84. data/vendor/xss-shield/test/test_erb.rb +44 -0
  85. data/vendor/xss-shield/test/test_haml.rb +43 -0
  86. data/vendor/xss-shield/test/test_helpers.rb +25 -0
  87. data/vendor/xss-shield/test/test_safe_string.rb +55 -0
  88. metadata +247 -0
@@ -0,0 +1,16 @@
1
+ unless ENV['DISABLE_XSS_SHIELD']
2
+ puts "Loading XSS Shield"
3
+ require 'xss_shield'
4
+ else
5
+ class ::String
6
+ def mark_as_xss_protected
7
+ self
8
+ end
9
+ end
10
+
11
+ class ::NilClass
12
+ def mark_as_xss_protected
13
+ self
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,6 @@
1
+ require 'xss_shield/safe_string'
2
+ # Tarantula doesn't use haml
3
+ # require 'xss_shield/haml_hacks'
4
+ # ERB hacks blow up Rails
5
+ # require 'xss_shield/erb_hacks'
6
+ require 'xss_shield/secure_helpers'
@@ -0,0 +1,111 @@
1
+ class XSSProtectedERB < ERB
2
+ class Compiler < ::ERB::Compiler
3
+ def compile(s)
4
+ out = Buffer.new(self)
5
+
6
+ content = ''
7
+ scanner = make_scanner(s)
8
+ scanner.scan do |token|
9
+ if scanner.stag.nil?
10
+ case token
11
+ when PercentLine
12
+ out.push("#{@put_cmd} #{content.dump}") if content.size > 0
13
+ content = ''
14
+ out.push(token.to_s)
15
+ out.cr
16
+ when :cr
17
+ out.cr
18
+ when '<%', '<%=', '<%#'
19
+ scanner.stag = token
20
+ out.push("#{@put_cmd} #{content.dump}") if content.size > 0
21
+ content = ''
22
+ when "\n"
23
+ content << "\n"
24
+ out.push("#{@put_cmd} #{content.dump}")
25
+ out.cr
26
+ content = ''
27
+ when '<%%'
28
+ content << '<%'
29
+ else
30
+ content << token
31
+ end
32
+ else
33
+ case token
34
+ when '%>'
35
+ case scanner.stag
36
+ when '<%'
37
+ if content[-1] == ?\n
38
+ content.chop!
39
+ out.push(content)
40
+ out.cr
41
+ else
42
+ out.push(content)
43
+ end
44
+ when '<%='
45
+ # NOTE: Changed lines
46
+ out.push("#{@insert_cmd}((#{content}).to_s_xss_protected)")
47
+ # NOTE: End changed lines
48
+ when '<%#'
49
+ # out.push("# #{content.dump}")
50
+ end
51
+ scanner.stag = nil
52
+ content = ''
53
+ when '%%>'
54
+ content << '%>'
55
+ else
56
+ content << token
57
+ end
58
+ end
59
+ end
60
+ out.push("#{@put_cmd} #{content.dump}") if content.size > 0
61
+ out.close
62
+ out.script
63
+ end
64
+ end
65
+
66
+ def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
67
+ @safe_level = safe_level
68
+ compiler = XSSProtectedERB::Compiler.new(trim_mode)
69
+ set_eoutvar(compiler, eoutvar)
70
+ @src = compiler.compile(str)
71
+ @filename = nil
72
+ end
73
+ end
74
+
75
+ module ActionView
76
+ class Base
77
+ private
78
+ def create_template_source(extension, template, render_symbol, locals)
79
+ if template_requires_setup?(extension)
80
+ body = case extension.to_sym
81
+ when :rxml, :builder
82
+ content_type_handler = (controller.respond_to?(:response) ? "controller.response" : "controller")
83
+ "#{content_type_handler}.content_type ||= Mime::XML\n" +
84
+ "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
85
+ template +
86
+ "\nxml.target!\n"
87
+ when :rjs
88
+ "controller.response.content_type ||= Mime::JS\n" +
89
+ "update_page do |page|\n#{template}\nend"
90
+ end
91
+ # NOTE: Changed lines
92
+ elsif extension.to_sym == :rhtml
93
+ body = XSSProtectedERB.new(template, nil, @@erb_trim_mode).src
94
+ # NOTE: End changed lines
95
+ else
96
+ body = ERB.new(template, nil, @@erb_trim_mode).src
97
+ end
98
+
99
+ @@template_args[render_symbol] ||= {}
100
+ locals_keys = @@template_args[render_symbol].keys | locals
101
+ @@template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
102
+
103
+ locals_code = ""
104
+ locals_keys.each do |key|
105
+ locals_code << "#{key} = local_assigns[:#{key}]\n"
106
+ end
107
+
108
+ "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,42 @@
1
+ raise "Haml not loaded" unless Haml::Engine.instance_method(:push_script)
2
+
3
+ module Haml
4
+ class Engine
5
+ def push_script(text, flattened)
6
+ unless options[:suppress_eval]
7
+ push_silent("haml_temp = #{text}", true)
8
+ push_silent("haml_temp = haml_temp.to_s_xss_protected", true)
9
+ out = "haml_temp = _hamlout.push_script(haml_temp, #{@output_tabs}, #{flattened})\n"
10
+ if @block_opened
11
+ push_and_tabulate([:loud, out])
12
+ else
13
+ @precompiled << out
14
+ end
15
+ end
16
+ end
17
+
18
+ def build_attributes(attributes = {})
19
+ # We ignore @options[:attr_wrapper] because ERB::Util.h does not espace ' to &apos;
20
+ # making ' as attribute quote not workable
21
+ result = attributes.map do |a,v|
22
+ v = v.to_s_xss_protected
23
+ unless v.blank?
24
+ " #{a}=\"#{v}\""
25
+ end
26
+ end
27
+ result.sort.join
28
+ end
29
+ end
30
+
31
+ class Buffer
32
+ def build_attributes(attributes = {})
33
+ result = attributes.map do |a,v|
34
+ v = v.to_s_xss_protected
35
+ unless v.blank?
36
+ " #{a}=\"#{v}\""
37
+ end
38
+ end
39
+ result.sort.join
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,47 @@
1
+ class SafeString < String
2
+ def to_s
3
+ self
4
+ end
5
+ def to_s_xss_protected
6
+ self
7
+ end
8
+ end
9
+
10
+ class String
11
+ def mark_as_xss_protected
12
+ SafeString.new(self)
13
+ end
14
+ end
15
+
16
+ class NilClass
17
+ def mark_as_xss_protected
18
+ self
19
+ end
20
+ end
21
+
22
+ # ERB::Util.h and (include ERB::Util; h) are different methods
23
+ module ERB::Util
24
+ class <<self
25
+ def h_with_xss_protection(*args)
26
+ h_without_xss_protection(*args).mark_as_xss_protected
27
+ end
28
+ alias_method_chain :h, :xss_protection
29
+ end
30
+
31
+ def h_with_xss_protection(*args)
32
+ h_without_xss_protection(*args).mark_as_xss_protected
33
+ end
34
+ alias_method_chain :h, :xss_protection
35
+ end
36
+
37
+ class Object
38
+ def to_s_xss_protected
39
+ ERB::Util.h(to_s).mark_as_xss_protected
40
+ end
41
+ end
42
+
43
+ class Array
44
+ def join_xss_protected(sep="")
45
+ map(&:to_s_xss_protected).join(sep.to_s_xss_protected).mark_as_xss_protected
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ class Module
2
+ def mark_helpers_as_xss_protected(*ms)
3
+ ms.each do |m|
4
+ begin
5
+ instance_method("#{m}_with_xss_protection")
6
+ rescue NameError
7
+ define_method :"#{m}_with_xss_protection" do |*args|
8
+ send(:"#{m}_without_xss_protection", *args).mark_as_xss_protected
9
+ end
10
+ alias_method_chain m, :xss_protection
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class ActionView::Base
17
+ mark_helpers_as_xss_protected :javascript_include_tag,
18
+ :stylesheet_link_tag,
19
+ :render,
20
+ :text_field_tag,
21
+ :submit_tag,
22
+ :radio_button,
23
+ :text_area,
24
+ :auto_discovery_link_tag,
25
+ :image_tag
26
+
27
+ def link_to_with_xss_protection(text, *args)
28
+ link_to_without_xss_protection(text.to_s_xss_protected, *args).mark_as_xss_protected
29
+ end
30
+ alias_method_chain :link_to, :xss_protection
31
+
32
+ def button_to_with_xss_protection(text, *args)
33
+ button_to_without_xss_protection(text.to_s_xss_protected, *args).mark_as_xss_protected
34
+ end
35
+ alias_method_chain :button_to, :xss_protection
36
+ end
37
+
38
+ module ActionView::Helpers::FormHelper
39
+ mark_helpers_as_xss_protected :text_field, :check_box
40
+ end
@@ -0,0 +1,40 @@
1
+ # Run from your Rails main directory
2
+ require 'test/test_helper'
3
+
4
+ class TestActionViewIntegration < Test::Unit::TestCase
5
+ def assert_renders(expected, input, extension)
6
+ base = ActionView::Base.new
7
+ actual = base.render_template(extension, input, "foo.#{extension}")
8
+ assert_equal expected, actual
9
+ end
10
+
11
+ def test_erb
12
+ assert_renders <<OUT, <<IN, :erb
13
+ A & B
14
+ A & B
15
+ OUT
16
+ <%= "A & B" %>
17
+ <%= "A & B".mark_as_xss_protected %>
18
+ IN
19
+ end
20
+
21
+ def test_rhtml
22
+ assert_renders <<OUT, <<IN, :rhtml
23
+ A &amp; B
24
+ A & B
25
+ OUT
26
+ <%= "A & B" %>
27
+ <%= "A & B".mark_as_xss_protected %>
28
+ IN
29
+ end
30
+
31
+ def test_haml
32
+ assert_renders <<OUT, <<IN, :haml
33
+ A &amp; B
34
+ A & B
35
+ OUT
36
+ = "A & B"
37
+ = "A & B".mark_as_xss_protected
38
+ IN
39
+ end
40
+ end
@@ -0,0 +1,44 @@
1
+ # Run from your Rails main directory
2
+ require 'test/test_helper'
3
+
4
+ class TestERB < Test::Unit::TestCase
5
+ def assert_renders_erb(expected, input, shield=true)
6
+ erb_class = shield ? XSSProtectedERB : ERB
7
+
8
+ actual = eval(erb_class.new(input).src)
9
+
10
+ assert_equal expected, actual
11
+ end
12
+
13
+ def test_erb_with_shield
14
+ assert_renders_erb <<OUT, <<IN, true
15
+ Foo &amp;amp; Bar
16
+ Foo &amp;amp; Bar
17
+ Foo &amp; Bar
18
+ Foo &amp; Bar
19
+ Foo &amp; Bar
20
+ OUT
21
+ <%= "Foo &amp; Bar" %>
22
+ <%= h("Foo &amp; Bar") %>
23
+ <%= "Foo &amp; Bar".mark_as_xss_protected %>
24
+ <%= h("Foo & Bar") %>
25
+ <%= "Foo & Bar" %>
26
+ IN
27
+ end
28
+
29
+ def test_erb_without_shield
30
+ assert_renders_erb <<OUT, <<IN, false
31
+ Foo &amp;amp; Bar
32
+ Foo &amp; Bar
33
+ Foo &amp; Bar
34
+ Foo &amp; Bar
35
+ Foo & Bar
36
+ OUT
37
+ <%= h("Foo &amp; Bar") %>
38
+ <%= "Foo &amp; Bar" %>
39
+ <%= "Foo &amp; Bar".mark_as_xss_protected %>
40
+ <%= h("Foo & Bar") %>
41
+ <%= "Foo & Bar" %>
42
+ IN
43
+ end
44
+ end
@@ -0,0 +1,43 @@
1
+ # Run from your Rails main directory
2
+ require 'test/test_helper'
3
+
4
+ class TestHaml < Test::Unit::TestCase
5
+ def setup
6
+ @base = ActionView::Base.new
7
+ end
8
+
9
+ def assert_haml_renders(expected, input)
10
+ actual = Haml::Engine.new(input).to_html(@base)
11
+ assert_equal expected, actual
12
+ end
13
+
14
+ def test_haml_engine
15
+ assert_haml_renders <<OUT, <<IN
16
+ A & B
17
+ C &amp; D
18
+ E &amp; F
19
+ G & H
20
+ I &amp; J
21
+ OUT
22
+ A & B
23
+ = "C & D"
24
+ = h("E & F")
25
+ = "G & H".mark_as_xss_protected
26
+ = "I & J".to_s_xss_protected
27
+ IN
28
+ end
29
+
30
+ def test_attribute_escaping_in_haml
31
+ @base.instance_eval {
32
+ @foo = "A < & > ' \" B"
33
+ }
34
+ assert_haml_renders <<OUT, <<IN
35
+ <div foo="A &lt; &amp; &gt; ' &quot; B" />
36
+ <div foo="A < & > ' " B" />
37
+ OUT
38
+ %div{:foo => @foo}/
39
+ %div{:foo => @foo.mark_as_xss_protected}/
40
+ IN
41
+ # Note that '/" explicitly marked as XSS-protected can break validity
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ # Run from your Rails main directory
2
+ require 'test/test_helper'
3
+
4
+ class TestHelpers < Test::Unit::TestCase
5
+ def setup
6
+ @base = ActionView::Base.new
7
+ end
8
+
9
+ def assert_haml_renders(expected, input)
10
+ actual = Haml::Engine.new(input).to_html(@base)
11
+ assert_equal expected, actual
12
+ end
13
+
14
+ def test_link_to
15
+ assert_haml_renders <<OUT, <<IN
16
+ <a href="/bar">Foo</a>
17
+ <a href="/bar">Foo &amp; Bar</a>
18
+ <a href="/bar">Foo & Bar</a>
19
+ OUT
20
+ = link_to "Foo", "/bar"
21
+ = link_to "Foo & Bar", "/bar"
22
+ = link_to "Foo & Bar".mark_as_xss_protected, "/bar"
23
+ IN
24
+ end
25
+ end
@@ -0,0 +1,55 @@
1
+ # Run from your Rails main directory
2
+ require 'test/test_helper'
3
+
4
+ class TestSafeString < Test::Unit::TestCase
5
+ def test_safe_string
6
+ assert_equal "foo", "foo".to_s_xss_protected
7
+ assert_equal "foo &amp; bar", "foo & bar".to_s_xss_protected
8
+ assert_equal "foo &amp; bar", "foo & bar".to_s_xss_protected
9
+ assert_equal "foo &amp;amp; bar", "foo &amp; bar".to_s_xss_protected
10
+ assert_equal "foo &amp; bar", "foo & bar".to_s_xss_protected.to_s_xss_protected
11
+ assert_equal "foo &amp; bar", h("foo & bar").to_s_xss_protected
12
+ assert_equal "foo &amp;amp; bar", h(h("foo & bar"))
13
+
14
+ assert_not_equal "foo".mark_as_xss_protected.object_id, "foo".mark_as_xss_protected.object_id
15
+ x = "foo & bar".mark_as_xss_protected
16
+ assert_equal x.mark_as_xss_protected, x
17
+ # Not sure if this makes sense
18
+ assert_not_equal x.mark_as_xss_protected.object_id, x.object_id
19
+
20
+ assert_equal x.to_s, x
21
+ assert_equal x.to_s.object_id, x.object_id
22
+ end
23
+
24
+ def test_nonstring_objects
25
+ assert_equal "15", 15.to_s_xss_protected
26
+ assert_equal SafeString, 15.to_s_xss_protected.class
27
+ end
28
+
29
+ def test_nil
30
+ assert_equal "", nil.to_s_xss_protected
31
+ assert_equal SafeString, nil.to_s_xss_protected.class
32
+ assert_equal nil, nil.mark_as_xss_protected
33
+ end
34
+
35
+ def test_join
36
+ assert_equal "", [].join_xss_protected
37
+ assert_equal "", [].join_xss_protected(",")
38
+ assert_equal "a", ["a"].join_xss_protected
39
+ assert_equal "a", ["a"].join_xss_protected(",")
40
+ assert_equal "ab", ["a", "b"].join_xss_protected
41
+ assert_equal "a,b", ["a", "b"].join_xss_protected(",")
42
+
43
+ assert_equal "a&amp;b", ["a", "b"].join_xss_protected("&")
44
+ assert_equal "a&amp;amp;b", ["a", "b"].join_xss_protected("&amp;")
45
+ assert_equal "a&amp;b", ["a", "b"].join_xss_protected("&amp;".mark_as_xss_protected)
46
+
47
+ assert_equal "&lt;&amp;&gt;", ["<", ">"].join_xss_protected("&")
48
+ assert_equal "&lt;&amp;amp;&gt;", ["<", ">"].join_xss_protected("&amp;")
49
+ assert_equal "&lt;&amp;&gt;", ["<", ">"].join_xss_protected("&amp;".mark_as_xss_protected)
50
+
51
+ assert_equal "< &amp; &gt;", ["<".mark_as_xss_protected, ">"].join_xss_protected(" & ")
52
+ assert_equal "&lt; &amp; >", ["<", ">".mark_as_xss_protected].join_xss_protected(" & ")
53
+ assert_equal "&lt; & &gt;", ["<", ">"].join_xss_protected(" & ".mark_as_xss_protected)
54
+ end
55
+ end