xss_shield 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|