xss_shield 1.0.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.
- data/MIT-LICENSE +19 -0
- data/README.rdoc +103 -0
- data/Rakefile +33 -0
- data/VERSION +1 -0
- data/init.rb +15 -0
- data/lib/xss_shield/erb_hacks.rb +101 -0
- data/lib/xss_shield/safe_string.rb +42 -0
- data/lib/xss_shield/secure_helpers.rb +118 -0
- data/lib/xss_shield.rb +3 -0
- data/test/active_record_helper_test.rb +55 -0
- data/test/asset_package_test.rb +32 -0
- data/test/asset_tag_helper_test.rb +66 -0
- data/test/date_helper_test.rb +71 -0
- data/test/erb_util_test.rb +30 -0
- data/test/fixtures/hello_world.erb +1 -0
- data/test/form_helper_test.rb +79 -0
- data/test/form_options_helper_test.rb +69 -0
- data/test/form_tag_helper_test.rb +88 -0
- data/test/javascript_helper_test.rb +33 -0
- data/test/prototype_helper_test.rb +60 -0
- data/test/safe_string_test.rb +37 -0
- data/test/template_object_test.rb +33 -0
- data/test/test_helper.rb +71 -0
- data/test/url_helper_test.rb +53 -0
- data/xss_shield.gemspec +76 -0
- metadata +92 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ERB::Util are properly escaped.
|
4
|
+
class ErbUtilTest< Test::Unit::TestCase
|
5
|
+
|
6
|
+
# h is an alias for html_escape.
|
7
|
+
def test_html_escape
|
8
|
+
assert_render({
|
9
|
+
# Test that we automatically escape
|
10
|
+
%(<%= "Foo & Bar" %>) => %(Foo & Bar),
|
11
|
+
%(<%= "Foo & Bar" %>) => %(Foo &amp; Bar),
|
12
|
+
|
13
|
+
# Test that we don't escape twice with h
|
14
|
+
%(<%= h "Foo & Bar" %>) => %(Foo & Bar),
|
15
|
+
%(<%= h "Foo & Bar" %>) => %(Foo &amp; Bar),
|
16
|
+
|
17
|
+
# Test that xss_safe works
|
18
|
+
%(<%= "Foo & Bar".xss_safe %>) => %(Foo & Bar),
|
19
|
+
%(<%= "Foo & Bar".xss_safe %>) => %(Foo & Bar),
|
20
|
+
})
|
21
|
+
end
|
22
|
+
|
23
|
+
# j is an alias for json_escape.
|
24
|
+
def test_json_escape
|
25
|
+
assert_render(
|
26
|
+
%(<%= j "is a > 0 & a < 10?" %>) =>
|
27
|
+
%(is a \\u003E 0 \\u0026 a \\u003C 10?))
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Hello world!
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::FormHelper are properly escaped.
|
4
|
+
class FormHelperTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@options = { :locals => { :@foo => stub(:bar => "f&b") } }
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_check_box
|
11
|
+
assert_render({
|
12
|
+
%(<%= check_box :foo, :bar %>) => %(
|
13
|
+
<input name="foo[bar]" type="checkbox" id="foo_bar" value="1" /><input name="foo[bar]" type="hidden" value="0" />)
|
14
|
+
}, @options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_fields_for
|
18
|
+
assert_render({
|
19
|
+
%(<% fields_for @foo.bar do |fields| %>Field: <%= fields.check_box :field %><% end %>) => %(
|
20
|
+
Field: <input name="f&b[field]" type="checkbox" id="f_b_field" value="1" /><input name="f&b[field]" type="hidden" value="0" />)
|
21
|
+
}, @options)
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_file_field
|
25
|
+
assert_render({
|
26
|
+
%(<%= file_field :foo, :bar, :class => "f&b" %>) => %(
|
27
|
+
<input name="foo[bar]" size="30" class="f&b" type="file" id="foo_bar" />)
|
28
|
+
}, @options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_form_for
|
32
|
+
assert_render({
|
33
|
+
%(<% form_for :foo do |f| %>Bar: <%= f.text_field :bar %><% end %>) => %(
|
34
|
+
<form action="/test/foobar" method="post">Bar: <input name="foo[bar]" size="30" type="text" id="foo_bar" value="f&b" /></form>)
|
35
|
+
}, @options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_hidden_field
|
39
|
+
assert_render({
|
40
|
+
%(<%= hidden_field :foo, :bar %>) => %(
|
41
|
+
<input name="foo[bar]" type="hidden" id="foo_bar" value="f&b" />)
|
42
|
+
}, @options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_label
|
46
|
+
assert_render({
|
47
|
+
%(<%= label :foo, :bar, 'f&b' %>) => %(<label for="foo_bar">f&b</label>)
|
48
|
+
}, @options)
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_password_field
|
52
|
+
assert_render({
|
53
|
+
%(<%= password_field :foo, :bar %>) => %(
|
54
|
+
<input name="foo[bar]" size="30" type="password" id="foo_bar" value="f&b" />)
|
55
|
+
}, @options)
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_radio_button
|
59
|
+
assert_render({
|
60
|
+
%(<%= radio_button :foo, :bar, 'f&b' %>) => %(
|
61
|
+
<input name="foo[bar]" checked="checked" type="radio" id="foo_bar_fb" value="f&b" />)
|
62
|
+
}, @options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_text_area
|
66
|
+
assert_render({
|
67
|
+
%(<%= text_area :foo, :bar %>) => %(
|
68
|
+
<textarea name="foo[bar]" id="foo_bar" rows="20" cols="40">f&b</textarea>)
|
69
|
+
}, @options)
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_text_field
|
73
|
+
assert_render({
|
74
|
+
%(<%= text_field :foo, :bar %>) => %(
|
75
|
+
<input name="foo[bar]" size="30" type="text" id="foo_bar" value="f&b" />)
|
76
|
+
}, @options)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::FormOptionsHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class FormOptionsHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@options = {
|
9
|
+
:locals => { :@collection => [ stub(:key => 'a&b', :val => 'c&d') ] }
|
10
|
+
}
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_collection_select
|
14
|
+
assert_render({
|
15
|
+
%(<%= collection_select :foo, :bar, @collection, :key, :val %>) => %(
|
16
|
+
<select name="foo[bar]" id="foo_bar"><option value="a&b">c&d</option></select>)
|
17
|
+
}, @options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_country_options_for_select
|
21
|
+
assert_render_has_no_escaped_chars %(<%= country_options_for_select %>")
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_country_select
|
25
|
+
assert_render_has_no_escaped_chars %(<%= country_select :foo, :bar %>)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_option_groups_from_collection_for_select
|
29
|
+
continents = [
|
30
|
+
stub(:id => 1,
|
31
|
+
:name => 'a&b',
|
32
|
+
:countries => [ stub(:id => 1, :name => 'c&d') ])
|
33
|
+
]
|
34
|
+
assert_render({
|
35
|
+
%(<%= option_groups_from_collection_for_select @continents, :countries, :name, :id, :name %>) => %(
|
36
|
+
<optgroup label="a&b"><option value="1">c&d</option></optgroup>)
|
37
|
+
},
|
38
|
+
{ :locals => { :@continents => continents } })
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_options_for_select
|
42
|
+
assert_render(
|
43
|
+
%(<%= options_for_select 'a&b', 'c&d' %>) => %(
|
44
|
+
<option value="a&b">a&b</option>))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_options_from_collection_for_select
|
48
|
+
assert_render({
|
49
|
+
%(<%= options_from_collection_for_select @collection, :key, :val %>) => %(
|
50
|
+
<option value="a&b">c&d</option>)
|
51
|
+
}, @options)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_select
|
55
|
+
assert_render({
|
56
|
+
%(<%= select :foo, :bar, [['a&b', 'c&d']] %>) => %(
|
57
|
+
<select name="foo[bar]" id="foo_bar"><option value="c&d">a&b</option></select>)
|
58
|
+
})
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_time_zone_options_for_select
|
62
|
+
assert_render_has_no_escaped_chars %(<%= time_zone_options_for_select %>")
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_time_zone_select
|
66
|
+
assert_render_has_no_escaped_chars %(<%= time_zone_select :foo, :bar %>)
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::FormTagHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class FormTagHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_check_box_tag
|
8
|
+
assert_render(
|
9
|
+
%(<%= check_box_tag 'foobar' %>) => %(
|
10
|
+
<input name="foobar" type="checkbox" id="foobar" value="1"#{XHTML_TAGS}>))
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_field_set_tag
|
14
|
+
assert_render(
|
15
|
+
%(<% field_set_tag 'foo&bar' do %><%= text_field_tag 'boo' %><% end %>) => %(
|
16
|
+
<fieldset><legend>foo&bar</legend><input name="boo" type="text" id=\
|
17
|
+
"boo"#{XHTML_TAGS}></fieldset>))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_file_field_tag
|
21
|
+
assert_render(
|
22
|
+
%(<%= file_field_tag 'foo&bar' %>) => %(
|
23
|
+
<input name="foo&bar" type="file" id="foo&bar"#{XHTML_TAGS}>))
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_form_tag
|
27
|
+
assert_render(
|
28
|
+
%(<% form_tag '/foobar' do %><%= submit_tag 'f&b' %><% end %>) => %(
|
29
|
+
<form action="/foobar" method="post"><input name="commit" type="submit"\
|
30
|
+
value="f&b"#{XHTML_TAGS}></form>))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_hidden_field_tag
|
34
|
+
assert_render(
|
35
|
+
%(<%= hidden_field_tag 'foo&bar' %>) => %(
|
36
|
+
<input name="foo&bar" type="hidden" id="foo&bar"#{XHTML_TAGS}>))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_image_submit_tag
|
40
|
+
assert_render(
|
41
|
+
%(<%= image_submit_tag 'foo&bar.png' %>) => %(
|
42
|
+
<input type="image" src="/images/foo&bar.png"#{XHTML_TAGS}>))
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_label_tag
|
46
|
+
assert_render(
|
47
|
+
%(<%= label_tag 'foo&bar' %>) => %(
|
48
|
+
<label for="foo&bar">Foo&bar</label>))
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_password_field_tag
|
52
|
+
assert_render(
|
53
|
+
%(<%= password_field_tag 'foo&bar' %>) => %(
|
54
|
+
<input name="foo&bar" type="password" id="foo&bar"#{XHTML_TAGS}>))
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_radio_button_tag
|
58
|
+
assert_render(
|
59
|
+
%(<%= radio_button_tag 'foo&bar', 'a&b' %>) => %(
|
60
|
+
<input name="foo&bar" type="radio" id="foo&bar_ab" value=\
|
61
|
+
"a&b"#{XHTML_TAGS}>))
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_select_tag
|
65
|
+
assert_render(
|
66
|
+
%(<%= select_tag 'foo&bar' %>) => %(
|
67
|
+
<select name="foo&bar" id="foo&bar"></select>))
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_submit_tag
|
71
|
+
assert_render(
|
72
|
+
%(<%= submit_tag 'foo&bar' %>) => %(
|
73
|
+
<input name="commit" type="submit" value="foo&bar"#{XHTML_TAGS}>))
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_text_area_tag
|
77
|
+
assert_render(
|
78
|
+
%(<%= text_area_tag 'foo&bar' %>) => %(
|
79
|
+
<textarea name="foo&bar" id="foo&bar"></textarea>))
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_text_field_tag
|
83
|
+
assert_render(
|
84
|
+
%(<%= text_field_tag 'foo&bar' %>) => %(
|
85
|
+
<input name="foo&bar" type="text" id="foo&bar"#{XHTML_TAGS}>))
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::JavaScriptHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class JavascriptHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_button_to_function
|
8
|
+
assert_render(
|
9
|
+
%(<%= button_to_function 'foo&bar', "alert('foo&bar')" %>) => %(
|
10
|
+
<input type="button" value="foo&bar" onclick="alert('foo&bar');\
|
11
|
+
"#{XHTML_TAGS}>))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_escape_javascript
|
15
|
+
assert_render(
|
16
|
+
%(<%= escape_javascript "alert('foo&bar');" %>) =>
|
17
|
+
%(alert(\\'foo&bar\\');))
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_javascript_tag
|
21
|
+
assert_render(
|
22
|
+
%(<%= javascript_tag "alert('foo&bar');" %>) => %(
|
23
|
+
<script type="text/javascript">\n//<![CDATA[\nalert('foo&bar');\n//]]>\
|
24
|
+
\n</script>))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_link_to_function
|
28
|
+
assert_render(
|
29
|
+
%(<%= link_to_function 'foo&bar', "alert('foo&bar')" %>) => %(
|
30
|
+
<a href="#" onclick="alert('foo&bar'); return false;">foo&bar</a>))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::PrototypeHelper are escaped
|
4
|
+
# correctly.
|
5
|
+
class PrototypeHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_evaluate_remote_response
|
8
|
+
assert_render(
|
9
|
+
%(<%= evaluate_remote_response %>) => %(eval(request.responseText)))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Alias for remote_form_for.
|
13
|
+
def test_form_remote_for
|
14
|
+
assert_render_has_no_escaped_chars(
|
15
|
+
%(<% form_remote_for :post do |f| %><% end %>))
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_form_remote_tag
|
19
|
+
assert_render_has_no_escaped_chars(%(<% form_remote_tag do %><% end %>))
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_link_to_remote
|
23
|
+
assert_render_has_no_escaped_chars(
|
24
|
+
%(<%= link_to_remote 'foo&bar', :update => "alert('foo&bar')" %>))
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_observe_field
|
28
|
+
assert_render_has_no_escaped_chars(%(<%= observe_field 'foo&bar' %>))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_observe_form
|
32
|
+
assert_render_has_no_escaped_chars %(<%= observe_form 'foo&bar' %>)
|
33
|
+
end
|
34
|
+
def test_periodically_call_remote
|
35
|
+
assert_render(
|
36
|
+
%(<%= periodically_call_remote %>) => %(
|
37
|
+
<script type="text/javascript">\n//<![CDATA[
|
38
|
+
new PeriodicalExecuter(function() {new Ajax.Request('/test/foobar', \
|
39
|
+
{asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_remote_form_for
|
43
|
+
assert_render_has_no_escaped_chars(
|
44
|
+
%(<% remote_form_for :post do |f| %><% end %>))
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_remote_function
|
48
|
+
assert_render_has_no_escaped_chars(
|
49
|
+
%(<% remote_form_for :post do |f| %><% end %>))
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_submit_to_remote
|
53
|
+
assert_render(
|
54
|
+
%(<%= submit_to_remote 'foo&bar', 'f&b' %>) => %(
|
55
|
+
<input name="foo&bar" value="f&b" type="button" onclick="\
|
56
|
+
new Ajax.Request('/test/foobar', {asynchronous:true, evalScripts:true, \
|
57
|
+
parameters:Form.serialize(this.form)}); return false;"#{XHTML_TAGS}>))
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
class SafeStringTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include ERB::Util
|
6
|
+
|
7
|
+
def test_safe_string
|
8
|
+
assert_equal "foo", "foo".to_xss_safe
|
9
|
+
assert_equal "foo & bar", "foo & bar".to_xss_safe
|
10
|
+
assert_equal "foo & bar", "foo & bar".to_xss_safe
|
11
|
+
assert_equal "foo &amp; bar", "foo & bar".to_xss_safe
|
12
|
+
assert_equal "foo & bar", "foo & bar".to_xss_safe.to_xss_safe
|
13
|
+
assert_equal "foo & bar", h("foo & bar").to_xss_safe
|
14
|
+
assert_equal "foo &amp; bar", h(h("foo & bar"))
|
15
|
+
|
16
|
+
assert_not_equal "foo".xss_safe.object_id, "foo".xss_safe.object_id
|
17
|
+
x = "foo & bar".xss_safe
|
18
|
+
assert_equal x.xss_safe, x
|
19
|
+
# Not sure if this makes sense
|
20
|
+
assert_not_equal x.xss_safe.object_id, x.object_id
|
21
|
+
|
22
|
+
assert_equal x.to_s, x
|
23
|
+
assert_equal x.to_s.object_id, x.object_id
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_nonstring_objects
|
27
|
+
assert_equal "15", 15.to_xss_safe
|
28
|
+
assert_equal SafeString, 15.to_xss_safe.class
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_nil
|
32
|
+
assert_equal "", nil.to_xss_safe
|
33
|
+
assert_equal SafeString, nil.to_xss_safe.class
|
34
|
+
assert_equal nil, nil.xss_safe
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that ERBs still work correctly.
|
4
|
+
# See /usr/lib/ruby/gems/1.8/gems/actionpack-2.1.0/test/template/template_object_test.rb.
|
5
|
+
class TemplateObjectTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@view = ActionView::Base.new(VIEW_PATH)
|
9
|
+
@path = "hello_world.erb"
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_should_create_valid_template
|
13
|
+
template = ActionView::Template.new(@view, @path, true)
|
14
|
+
|
15
|
+
assert_kind_of ActionView::TemplateHandlers::ERB, template.handler
|
16
|
+
assert_equal "hello_world.erb", template.path
|
17
|
+
assert_nil template.instance_variable_get(:"@source")
|
18
|
+
assert_equal "erb", template.extension
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_should_prepare_template_properly
|
22
|
+
template = ActionView::Template.new(@view, @path, true)
|
23
|
+
view = template.instance_variable_get(:"@view")
|
24
|
+
|
25
|
+
view.expects(:evaluate_assigns)
|
26
|
+
template.handler.expects(:compile_template).with(template)
|
27
|
+
view.expects(:method_names).returns({})
|
28
|
+
|
29
|
+
template.prepare!
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# Loads the test environment. First try to load the Rails environment if we're
|
2
|
+
# in a Rails project. Otherwise just load the libraries that we need.
|
3
|
+
CUR_DIR = File.dirname(__FILE__)
|
4
|
+
$LOAD_PATH << "#{CUR_DIR}/../lib"
|
5
|
+
begin
|
6
|
+
require File.expand_path "#{CUR_DIR}/../../../../test/test_helper"
|
7
|
+
rescue LoadError
|
8
|
+
require 'rubygems'
|
9
|
+
gem 'rails', '=2.1.2'
|
10
|
+
require 'active_record'
|
11
|
+
require 'action_controller'
|
12
|
+
require 'action_controller/test_process'
|
13
|
+
require 'action_view/test_case'
|
14
|
+
require 'mocha'
|
15
|
+
require 'test/unit'
|
16
|
+
end
|
17
|
+
require 'init'
|
18
|
+
|
19
|
+
# Disable deprecation warnings.
|
20
|
+
ActiveSupport::Deprecation.silenced = true
|
21
|
+
|
22
|
+
# Rails creates all HTML form elements as XHTML by default. We override this in
|
23
|
+
# Studio, so make sure the tests here handle that.
|
24
|
+
XHTML_TAGS = ' /' # set this to ' /' if you don't override this in your app
|
25
|
+
|
26
|
+
class ActionView::Base
|
27
|
+
# Disable forgery protection.
|
28
|
+
def protect_against_forgery?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Define helper methods here for use in the rest of the test classes.
|
34
|
+
class Test::Unit::TestCase
|
35
|
+
|
36
|
+
VIEW_PATH = File.join(File.dirname(__FILE__), 'fixtures')
|
37
|
+
ActionView::TemplateFinder.process_view_paths(VIEW_PATH)
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def assert_render_has_no_escaped_chars(input, options = {})
|
42
|
+
actual = render_erb(input, options[:locals])
|
43
|
+
assert !actual.include?('<'), "Output contains <"
|
44
|
+
assert !actual.include?('>'), "Output contains >"
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_render(args, options = {})
|
48
|
+
args.each do |erb, expected|
|
49
|
+
expected.strip!
|
50
|
+
actual = render_erb(erb, options[:locals])
|
51
|
+
assert_dom_equal expected, actual, "#{erb} => #{expected}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def render_erb(erb, locals = {})
|
56
|
+
# Need this to make asset packager happy.
|
57
|
+
request = mock()
|
58
|
+
request.stubs(:relative_url_root).returns('')
|
59
|
+
request.stubs(:request_uri).returns('/test/foobar')
|
60
|
+
request.stubs(:url_for).returns('/test/foobar')
|
61
|
+
request.stubs(:protocol).returns('http://')
|
62
|
+
request.stubs(:ssl?).returns(false)
|
63
|
+
controller = mock()
|
64
|
+
controller.stubs(:request).returns(request)
|
65
|
+
controller.stubs(:url_for).returns('/test/foobar')
|
66
|
+
|
67
|
+
view = ActionView::Base.new(VIEW_PATH, {}, controller)
|
68
|
+
ActionView::InlineTemplate.new(view, erb, locals).render.strip
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::UrlHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class UrlHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_button_to
|
8
|
+
assert_render(
|
9
|
+
%(<%= button_to 'foo&bar', :action => :boo %>) => %(
|
10
|
+
<form class="button-to" action="/test/foobar" method="post"><div>\
|
11
|
+
<input type="submit" value="foo&bar"#{XHTML_TAGS}></div></form>))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_current_page?
|
15
|
+
assert_render(
|
16
|
+
%(<%= current_page? :action => :foobar %>) => %(true))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_link_to
|
20
|
+
assert_render(
|
21
|
+
%(<%= link_to 'foo&bar', :action => :boo %>) => %(
|
22
|
+
<a href="/test/foobar">foo&bar</a>))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_link_to_if
|
26
|
+
assert_render(
|
27
|
+
%(<%= link_to_if true, 'foo&bar', :action => :boo %>) => %(
|
28
|
+
<a href="/test/foobar">foo&bar</a>))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_link_to_unless
|
32
|
+
assert_render(
|
33
|
+
%(<%= link_to_unless false, 'foo&bar', :action => :boo %>) => %(
|
34
|
+
<a href="/test/foobar">foo&bar</a>))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_link_to_unless_current
|
38
|
+
assert_render(
|
39
|
+
%(<%= link_to_unless_current 'foo&bar', :action => :boo %>) => %(
|
40
|
+
foo&bar))
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_mail_to
|
44
|
+
assert_render(
|
45
|
+
%(<%= mail_to 'foo@bar.com' %>) => %(
|
46
|
+
<a href="mailto:foo@bar.com">foo@bar.com</a>))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_url_for
|
50
|
+
assert_render %(<%= url_for :action => :foobar %>) => %(/test/foobar)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/xss_shield.gemspec
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{xss_shield}
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["James Tan"]
|
12
|
+
s.date = %q{2009-10-07}
|
13
|
+
s.description = %q{This Rails plugin provides automatic cross site scripting (XSS) protection for your views. Once installed, you no longer have to manually and painstakingly sanitize all your views with HTML escaping.}
|
14
|
+
s.email = %q{jamestyj@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"MIT-LICENSE",
|
20
|
+
"README.rdoc",
|
21
|
+
"Rakefile",
|
22
|
+
"VERSION",
|
23
|
+
"init.rb",
|
24
|
+
"lib/xss_shield.rb",
|
25
|
+
"lib/xss_shield/erb_hacks.rb",
|
26
|
+
"lib/xss_shield/safe_string.rb",
|
27
|
+
"lib/xss_shield/secure_helpers.rb",
|
28
|
+
"test/active_record_helper_test.rb",
|
29
|
+
"test/asset_package_test.rb",
|
30
|
+
"test/asset_tag_helper_test.rb",
|
31
|
+
"test/date_helper_test.rb",
|
32
|
+
"test/erb_util_test.rb",
|
33
|
+
"test/fixtures/hello_world.erb",
|
34
|
+
"test/form_helper_test.rb",
|
35
|
+
"test/form_options_helper_test.rb",
|
36
|
+
"test/form_tag_helper_test.rb",
|
37
|
+
"test/javascript_helper_test.rb",
|
38
|
+
"test/prototype_helper_test.rb",
|
39
|
+
"test/safe_string_test.rb",
|
40
|
+
"test/template_object_test.rb",
|
41
|
+
"test/test_helper.rb",
|
42
|
+
"test/url_helper_test.rb",
|
43
|
+
"xss_shield.gemspec"
|
44
|
+
]
|
45
|
+
s.homepage = %q{http://github.com/jamestyj/xss_shield}
|
46
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
47
|
+
s.require_paths = ["lib"]
|
48
|
+
s.rubygems_version = %q{1.3.5}
|
49
|
+
s.summary = %q{Protect your Rails site from XSS attacks.}
|
50
|
+
s.test_files = [
|
51
|
+
"test/asset_tag_helper_test.rb",
|
52
|
+
"test/asset_package_test.rb",
|
53
|
+
"test/prototype_helper_test.rb",
|
54
|
+
"test/erb_util_test.rb",
|
55
|
+
"test/date_helper_test.rb",
|
56
|
+
"test/template_object_test.rb",
|
57
|
+
"test/form_options_helper_test.rb",
|
58
|
+
"test/url_helper_test.rb",
|
59
|
+
"test/test_helper.rb",
|
60
|
+
"test/active_record_helper_test.rb",
|
61
|
+
"test/javascript_helper_test.rb",
|
62
|
+
"test/safe_string_test.rb",
|
63
|
+
"test/form_helper_test.rb",
|
64
|
+
"test/form_tag_helper_test.rb"
|
65
|
+
]
|
66
|
+
|
67
|
+
if s.respond_to? :specification_version then
|
68
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
69
|
+
s.specification_version = 3
|
70
|
+
|
71
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
72
|
+
else
|
73
|
+
end
|
74
|
+
else
|
75
|
+
end
|
76
|
+
end
|