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
data/MIT-LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2009 Novell, 2007 Trampoline Systems
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
= XSS Shield
|
2
|
+
|
3
|
+
This Rails plugin provides automatic cross site scripting
|
4
|
+
({XSS}[http://en.wikipedia.org/wiki/Cross-site_scripting]) protection for your
|
5
|
+
views. Once installed, you no longer have to manually and painstakingly sanitize
|
6
|
+
all your views with HTML escaping (eg. <tt><%= h(foo) %></tt>). Currently only
|
7
|
+
{ERB}[http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/index.html] templates are
|
8
|
+
supported.
|
9
|
+
|
10
|
+
For example with XSS Shield:
|
11
|
+
<%= link_to "A & B", "/foo" %>
|
12
|
+
will return a +SafeString+:
|
13
|
+
<a href="/foo">A & B</a>
|
14
|
+
and not a plain, unsafe +String+:
|
15
|
+
<a href="/foo">A & B</a>
|
16
|
+
|
17
|
+
This version has been tested to work with <b><i>Rails 2.1.2</i></b>. Your milage
|
18
|
+
may vary.
|
19
|
+
|
20
|
+
DISCLAIMER: Note that while no effort is spared to ensure that this plugin works as
|
21
|
+
advertised, we cannot guarantee that all your views are 100% XSS safe. Use it at
|
22
|
+
your own risk, but remember that {bug
|
23
|
+
reports}[http://github.com/jamestyj/xss_shield/issues] and patches are welcomed.
|
24
|
+
|
25
|
+
== How it works
|
26
|
+
|
27
|
+
It works by subclassing +String+ into +SafeString+. When the ERB engine sees a
|
28
|
+
<tt><%= foo %></tt> fragment, it checks if the result of executing +foo+ is a
|
29
|
+
+SafeString+. If so, it just uses it. Otherwise the string is HTML escaped
|
30
|
+
first.
|
31
|
+
|
32
|
+
The use of +SafeString+ avoids potential double-escaping. For example, with XSS
|
33
|
+
Shield, <tt><%= @foo %></tt> is the same as <tt><%= h(@foo) %></tt>.
|
34
|
+
|
35
|
+
If your string contains HTML that you don't want to escape (and you trust it),
|
36
|
+
just append <tt>.xss_safe</tt>:
|
37
|
+
<%= "<b>foobar</b>".xss_safe %>
|
38
|
+
|
39
|
+
It would be cumbersome to require xss_safe every time you use some helper like
|
40
|
+
<tt>render(:partial)</tt> or +link_to+, so some helpers are modified to return
|
41
|
+
+SafeString+.
|
42
|
+
|
43
|
+
If you trust your helpers, you can mark them as XSS safe:
|
44
|
+
|
45
|
+
module Some::Module
|
46
|
+
mark_methods_as_xss_safe :text_field, :check_box
|
47
|
+
end
|
48
|
+
|
49
|
+
You may need to manually tweak your helpers, views and layouts to avoid
|
50
|
+
unnecessary escaping.
|
51
|
+
|
52
|
+
== Other template engines
|
53
|
+
|
54
|
+
Currently only ERB templates is supported, but support for other templating
|
55
|
+
engines should be relatively straightforward. It's mostly a matter of changing
|
56
|
+
to_s to to_xss_safe in a few places in their source.
|
57
|
+
|
58
|
+
Patches that add support for other templating engines (along with supporting
|
59
|
+
tests) are welcomed.
|
60
|
+
|
61
|
+
== Running tests
|
62
|
+
|
63
|
+
This plugin monkey patches ERB in order to do its magic, so it's a good idea to
|
64
|
+
at least run the included tests to verify that things work in your environment.
|
65
|
+
|
66
|
+
You can run the XSS Shield tests by simply running:
|
67
|
+
|
68
|
+
rake
|
69
|
+
|
70
|
+
which should generate output looking like this:
|
71
|
+
|
72
|
+
(in /xss_shield)
|
73
|
+
/usr/bin/ruby -I"lib:lib" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb" ...
|
74
|
+
Loaded suite /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader
|
75
|
+
Started
|
76
|
+
..........................................................................................
|
77
|
+
Finished in 0.163422 seconds.
|
78
|
+
|
79
|
+
90 tests, 135 assertions, 0 failures, 0 errors
|
80
|
+
|
81
|
+
If you place this plugin inside the vendor/plugin directory of your Rails
|
82
|
+
application, the test suite will load your application environment by requiring
|
83
|
+
RAILS_ROOT/test/test_helper.rb.
|
84
|
+
|
85
|
+
Of course, you should also verify that your existing application tests still
|
86
|
+
pass with XSS Shield enabled.
|
87
|
+
|
88
|
+
== Bugs and feedback
|
89
|
+
|
90
|
+
Please report bugs and feature requests
|
91
|
+
{here}[http://github.com/jamestyj/xss_shield/issues]. Patches and suggestions
|
92
|
+
are welcomed too.
|
93
|
+
|
94
|
+
== Authors
|
95
|
+
|
96
|
+
- Updated to support Rails 2.1 and maintained by {James
|
97
|
+
Tan}[http://github.com/jamestyj], Novell.
|
98
|
+
- {Original code}[http://code.google.com/p/xss-shield/] written by {Tomasz
|
99
|
+
Wegrzanowski}[http://code.google.com/u/Tomasz.Wegrzanowski/], Trampoline Systems.
|
100
|
+
|
101
|
+
== License
|
102
|
+
|
103
|
+
Copyright (c) 2009 Novell. See MIT-LICENSE in this directory.
|
data/Rakefile
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
desc 'Test the xss-shield plugin.'
|
9
|
+
Rake::TestTask.new(:test) do |t|
|
10
|
+
t.libs << 'lib'
|
11
|
+
t.pattern = 'test/**/*_test.rb'
|
12
|
+
t.verbose = true
|
13
|
+
end
|
14
|
+
|
15
|
+
begin
|
16
|
+
require 'jeweler'
|
17
|
+
Jeweler::Tasks.new do |gemspec|
|
18
|
+
gemspec.name = 'xss_shield'
|
19
|
+
gemspec.summary = 'Protect your Rails site from XSS attacks.'
|
20
|
+
gemspec.description = 'This Rails plugin provides automatic cross site ' +
|
21
|
+
'scripting (XSS) protection for your views. Once installed, you no ' +
|
22
|
+
'longer have to manually and painstakingly sanitize all your views ' +
|
23
|
+
'with HTML escaping.'
|
24
|
+
gemspec.email = 'jamestyj@gmail.com'
|
25
|
+
gemspec.homepage = 'http://github.com/jamestyj/xss_shield'
|
26
|
+
gemspec.authors = [ 'James Tan' ]
|
27
|
+
end
|
28
|
+
Jeweler::GemcutterTasks.new
|
29
|
+
rescue LoadError
|
30
|
+
puts 'Jeweler (or a dependency) not available. ' +
|
31
|
+
'Install it with: sudo gem install jeweler.'
|
32
|
+
end
|
33
|
+
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/init.rb
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
# Create our own ERB compiler to handle <%= %> differently.
|
2
|
+
# See /usr/lib/ruby/1.8/erb.erb.
|
3
|
+
class XSSProtectedERB < ERB
|
4
|
+
class Compiler < ::ERB::Compiler
|
5
|
+
def compile(s)
|
6
|
+
out = Buffer.new(self)
|
7
|
+
|
8
|
+
content = ''
|
9
|
+
scanner = make_scanner(s)
|
10
|
+
scanner.scan do |token|
|
11
|
+
if scanner.stag.nil?
|
12
|
+
case token
|
13
|
+
when PercentLine
|
14
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
15
|
+
content = ''
|
16
|
+
out.push(token.to_s)
|
17
|
+
out.cr
|
18
|
+
when :cr
|
19
|
+
out.cr
|
20
|
+
when '<%', '<%=', '<%#'
|
21
|
+
scanner.stag = token
|
22
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
23
|
+
content = ''
|
24
|
+
when "\n"
|
25
|
+
content << "\n"
|
26
|
+
out.push("#{@put_cmd} #{content.dump}")
|
27
|
+
out.cr
|
28
|
+
content = ''
|
29
|
+
when '<%%'
|
30
|
+
content << '<%'
|
31
|
+
else
|
32
|
+
content << token
|
33
|
+
end
|
34
|
+
else
|
35
|
+
case token
|
36
|
+
when '%>'
|
37
|
+
case scanner.stag
|
38
|
+
when '<%'
|
39
|
+
if content[-1] == ?\n
|
40
|
+
content.chop!
|
41
|
+
out.push(content)
|
42
|
+
out.cr
|
43
|
+
else
|
44
|
+
out.push(content)
|
45
|
+
end
|
46
|
+
when '<%='
|
47
|
+
# NOTE: Changed lines
|
48
|
+
|
49
|
+
# Don't escape yield statements (they should already be safe)
|
50
|
+
if content =~ /^[ \t]*yield[ |\(]/
|
51
|
+
to_string = 'to_s'
|
52
|
+
else
|
53
|
+
to_string = 'to_xss_safe'
|
54
|
+
end
|
55
|
+
out.push("#{@insert_cmd}((#{content}).#{to_string})")
|
56
|
+
|
57
|
+
# NOTE: End changed lines
|
58
|
+
when '<%#'
|
59
|
+
# out.push("# #{content.dump}")
|
60
|
+
end
|
61
|
+
scanner.stag = nil
|
62
|
+
content = ''
|
63
|
+
when '%%>'
|
64
|
+
content << '%>'
|
65
|
+
else
|
66
|
+
content << token
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
out.push("#{@put_cmd} #{content.dump}") if content.size > 0
|
71
|
+
out.close
|
72
|
+
out.script
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
def initialize(str, safe_level=nil, trim_mode=nil, eoutvar='_erbout')
|
78
|
+
@safe_level = safe_level
|
79
|
+
# NOTE: Changed lines
|
80
|
+
|
81
|
+
compiler = XSSProtectedERB::Compiler.new(trim_mode)
|
82
|
+
|
83
|
+
# NOTE: End changed lines
|
84
|
+
set_eoutvar(compiler, eoutvar)
|
85
|
+
@src = compiler.compile(str)
|
86
|
+
@filename = nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Use our own ERB handler.
|
91
|
+
# See /usr/lib/ruby/gems/1.8/gems/actionpack-2.1.0/lib/action_view/template_handlers/erb.rb.
|
92
|
+
module ActionView
|
93
|
+
module TemplateHandlers
|
94
|
+
class ERB < TemplateHandler
|
95
|
+
def compile(template)
|
96
|
+
::XSSProtectedERB.new(template.source, nil, @view.erb_trim_mode).src
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class SafeString < String
|
2
|
+
def to_s
|
3
|
+
self
|
4
|
+
end
|
5
|
+
def to_xss_safe
|
6
|
+
self
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class String
|
11
|
+
def xss_safe
|
12
|
+
SafeString.new(self)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class NilClass
|
17
|
+
def xss_safe
|
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).xss_safe
|
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).xss_safe
|
33
|
+
end
|
34
|
+
alias_method_chain :h, :xss_protection
|
35
|
+
end
|
36
|
+
|
37
|
+
class Object
|
38
|
+
def to_xss_safe
|
39
|
+
ERB::Util.h(to_s).xss_safe
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class Module
|
2
|
+
def mark_methods_as_xss_safe(*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).xss_safe
|
9
|
+
end
|
10
|
+
alias_method_chain m, :xss_protection
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Mark known helpers as xss_safe only if their arguments are guaranteed to be
|
17
|
+
# safe. Don't mark methods that take a block as xss_safe.
|
18
|
+
class ActionView::Base
|
19
|
+
# ActionView::Helpers::AssetTagHelper
|
20
|
+
mark_methods_as_xss_safe :auto_discovery_link_tag,
|
21
|
+
:javascript_include_tag,
|
22
|
+
:stylesheet_link_tag,
|
23
|
+
:image_tag
|
24
|
+
|
25
|
+
# ActionView::Helpers::JavaScriptHelper
|
26
|
+
mark_methods_as_xss_safe :link_to_function,
|
27
|
+
:button_to_function,
|
28
|
+
:javascript_tag
|
29
|
+
|
30
|
+
# ActionView::Helpers::FormHelper
|
31
|
+
mark_methods_as_xss_safe :check_box,
|
32
|
+
:file_field,
|
33
|
+
:hidden_field,
|
34
|
+
:label,
|
35
|
+
:password_field,
|
36
|
+
:radio_button,
|
37
|
+
:text_area,
|
38
|
+
:text_field
|
39
|
+
|
40
|
+
# ActionView::Helpers::FormTagHelper
|
41
|
+
mark_methods_as_xss_safe :check_box_tag,
|
42
|
+
:file_field_tag,
|
43
|
+
:form_tag_html,
|
44
|
+
:hidden_field_tag,
|
45
|
+
:image_submit_tag,
|
46
|
+
:label_tag,
|
47
|
+
:password_field_tag,
|
48
|
+
:radio_button_tag,
|
49
|
+
:select_tag,
|
50
|
+
:submit_tag,
|
51
|
+
:text_area_tag,
|
52
|
+
:text_field_tag
|
53
|
+
|
54
|
+
# ActionView::Helpers::FormOptionsHelper
|
55
|
+
mark_methods_as_xss_safe :select,
|
56
|
+
:options_for_select,
|
57
|
+
:collection_select,
|
58
|
+
:country_select,
|
59
|
+
:time_zone_select,
|
60
|
+
:options_from_collection_for_select,
|
61
|
+
:option_groups_from_collection_for_select,
|
62
|
+
:country_options_for_select,
|
63
|
+
:time_zone_options_for_select
|
64
|
+
|
65
|
+
# ActionView::Helpers::PrototypeHelper
|
66
|
+
mark_methods_as_xss_safe :submit_to_remote
|
67
|
+
|
68
|
+
# ActionView::Helpers::ActiveRecordHelper
|
69
|
+
mark_methods_as_xss_safe :error_message_on,
|
70
|
+
:error_messages_for,
|
71
|
+
:input
|
72
|
+
|
73
|
+
# ActionView::Helpers::DateHelper
|
74
|
+
mark_methods_as_xss_safe :date_select,
|
75
|
+
:datetime_select,
|
76
|
+
:select_date,
|
77
|
+
:select_datetime,
|
78
|
+
:select_time,
|
79
|
+
:select_month,
|
80
|
+
:select_minute,
|
81
|
+
:select_hour,
|
82
|
+
:select_day,
|
83
|
+
:select_year,
|
84
|
+
:select_second,
|
85
|
+
:time_select
|
86
|
+
|
87
|
+
# ActionView::Helpers::UrlHelper
|
88
|
+
mark_methods_as_xss_safe :mail_to
|
89
|
+
|
90
|
+
# General
|
91
|
+
mark_methods_as_xss_safe :render
|
92
|
+
|
93
|
+
def link_to_with_xss_protection(text, *args)
|
94
|
+
link_to_without_xss_protection(text.to_xss_safe, *args).xss_safe
|
95
|
+
end
|
96
|
+
alias_method_chain :link_to, :xss_protection
|
97
|
+
|
98
|
+
def button_to_with_xss_protection(text, *args)
|
99
|
+
button_to_without_xss_protection(text.to_xss_safe, *args).xss_safe
|
100
|
+
end
|
101
|
+
alias_method_chain :button_to, :xss_protection
|
102
|
+
end
|
103
|
+
|
104
|
+
# AssetPackager plugin.
|
105
|
+
if defined? Synthesis
|
106
|
+
module Synthesis::AssetPackageHelper
|
107
|
+
mark_methods_as_xss_safe :stylesheet_link_merged,
|
108
|
+
:javascript_include_merged
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# WillPaginate plugin.
|
113
|
+
if defined? WillPaginate
|
114
|
+
module WillPaginate::ViewHelpers
|
115
|
+
mark_methods_as_xss_safe :will_paginate
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
data/lib/xss_shield.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::ActiveRecordHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class ActiveRecordHelper < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@errors = mock()
|
9
|
+
foobar = mock()
|
10
|
+
foobar.stubs(:collect).returns(['foo&name'])
|
11
|
+
Object.stubs(:content_columns).returns(foobar)
|
12
|
+
@foo = Object.new
|
13
|
+
@foo.stubs(:errors).returns(@errors)
|
14
|
+
@options = { :locals => { :@foo => @foo } }
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_error_message_on
|
18
|
+
@errors.stubs(:on).with(:bar).returns('foo&bar')
|
19
|
+
assert_render({
|
20
|
+
%(<%= error_message_on :foo, :bar %>) => %(
|
21
|
+
<div class="formError">foo&bar</div>)
|
22
|
+
}, @options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_error_messages_for
|
26
|
+
@errors.stubs(:count).returns(1)
|
27
|
+
@errors.stubs(:full_messages).returns('foo&bar')
|
28
|
+
assert_render({
|
29
|
+
%(<%= error_messages_for :foo %>) => %(
|
30
|
+
<div class="errorExplanation" id="errorExplanation"><h2>1 error \
|
31
|
+
prohibited this foo from being saved</h2><p>There were problems with the \
|
32
|
+
following fields:</p><ul><li>foo&bar</li></ul></div>)
|
33
|
+
}, @options)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_form
|
37
|
+
@foo.stubs(:new_record?).returns(true)
|
38
|
+
assert_render({
|
39
|
+
%(<%= form :foo %>) => %(
|
40
|
+
<form action="/test/foobar" method="post">foo&name<input name="commit" \
|
41
|
+
type="submit" value="Create"#{XHTML_TAGS}></form>)
|
42
|
+
}, @options)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_input
|
46
|
+
@foo.stubs(:column_for_attribute).returns(stub(:type => :string))
|
47
|
+
@foo.stubs(:bar).returns('foo&bar&val')
|
48
|
+
assert_render({
|
49
|
+
%(<%= input :foo, :bar %>) => %(
|
50
|
+
<input name="foo[bar]" size="30" type="text" id="foo_bar" value="\
|
51
|
+
foo&bar&val" />)
|
52
|
+
}, @options)
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from Synthesis::AssetPackagerHelper are properly escaped.
|
4
|
+
class AssetPackagerTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
$asset_packages_yml = {
|
7
|
+
"javascripts" => [{ "base" => [ "foobar" ] }],
|
8
|
+
"stylesheets" => [{ "base" => [ "foobar" ] }]
|
9
|
+
}
|
10
|
+
include Synthesis::AssetPackageHelper
|
11
|
+
|
12
|
+
rescue NameError
|
13
|
+
puts "AssetPackager plugin not found, skipping related tests"
|
14
|
+
|
15
|
+
else
|
16
|
+
|
17
|
+
def test_stylesheet_link_merged
|
18
|
+
assert_render(
|
19
|
+
%(<%= stylesheet_link_merged :base %>) => %(
|
20
|
+
<link href="/stylesheets/foobar.css" rel="stylesheet" media="screen"\
|
21
|
+
type="text/css"#{XHTML_TAGS}>)
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_javascript_include_merged
|
26
|
+
assert_render(
|
27
|
+
%(<%= javascript_include_merged :base %>) => %(
|
28
|
+
<script type="text/javascript" src="/javascripts/foobar.js"></script>)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::AssetTagHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class AssetTagHelper < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_auto_discovery_link_tag
|
8
|
+
assert_render(
|
9
|
+
%(<%= auto_discovery_link_tag "foo&bar" %>) => %(
|
10
|
+
<link href="/test/foobar" title="FOO&BAR" rel="alternate" type="\
|
11
|
+
foo&bar"#{XHTML_TAGS}>))
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_image_path
|
15
|
+
assert_render(
|
16
|
+
%(<%= image_path "foo&bar" %>) => %(/images/foo&bar))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_image_tag
|
20
|
+
assert_render(
|
21
|
+
%(<%= image_tag "foo&bar" %>) => %(
|
22
|
+
<img src="/images/foo&bar" alt="Foo&bar"#{XHTML_TAGS}>))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_javascript_include_tag
|
26
|
+
assert_render(
|
27
|
+
%(<%= javascript_include_tag "foo&bar" %>) => %(
|
28
|
+
<script type="text/javascript" src="/javascripts/foo&bar.js"></script>))
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_javascript_path
|
32
|
+
assert_render(
|
33
|
+
%(<%= javascript_path "foo&bar" %>) => %(/javascripts/foo&bar.js))
|
34
|
+
end
|
35
|
+
|
36
|
+
# Alias for image_path.
|
37
|
+
def test_path_to_image
|
38
|
+
assert_render(
|
39
|
+
%(<%= path_to_image "foo&bar" %>) => %(/images/foo&bar))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Alias for javascript_path.
|
43
|
+
def test_path_to_javascript
|
44
|
+
assert_render(
|
45
|
+
%(<%= path_to_javascript "foo&bar" %>) => %(/javascripts/foo&bar.js))
|
46
|
+
end
|
47
|
+
|
48
|
+
# Alias for stylesheet_path.
|
49
|
+
def test_path_to_stylesheet
|
50
|
+
assert_render(
|
51
|
+
%(<%= path_to_stylesheet "foo&bar" %>) => %(/stylesheets/foo&bar.css))
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_stylesheet_link_tag
|
55
|
+
assert_render(
|
56
|
+
%(<%= stylesheet_link_tag "foo&bar" %>) => %(
|
57
|
+
<link href="/stylesheets/foo&bar.css" rel="stylesheet" type=\
|
58
|
+
"text/css" media="screen"#{XHTML_TAGS}>))
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_stylesheet_path
|
62
|
+
assert_render(
|
63
|
+
%(<%= stylesheet_path "foo&bar" %>) => %(/stylesheets/foo&bar.css))
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test/test_helper'
|
2
|
+
|
3
|
+
# Test that helpers from ActionView::Helpers::DateHelper are properly
|
4
|
+
# escaped.
|
5
|
+
class DateHelperTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def test_date_select
|
8
|
+
assert_render_has_no_escaped_chars %(<%= date_select :foo, :created_on %>)
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_datetime_select
|
12
|
+
assert_render_has_no_escaped_chars(
|
13
|
+
%(<%= datetime_select :foo, :created_on %>))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_distance_of_time_in_words
|
17
|
+
assert_render({
|
18
|
+
%(<%= distance_of_time_in_words time, time+10 %>) => %(less than a minute)
|
19
|
+
}, { :locals => { :time => Time.now } })
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_distance_of_time_in_words_to_now
|
23
|
+
assert_render({
|
24
|
+
%(<%= distance_of_time_in_words 10 %>) => %(less than a minute)
|
25
|
+
})
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_select_date
|
29
|
+
assert_render_has_no_escaped_chars %(<%= select_date %>)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_select_datetime
|
33
|
+
assert_render_has_no_escaped_chars %(<%= select_datetime %>)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_select_day
|
37
|
+
assert_render_has_no_escaped_chars %(<%= select_day 1 %>)
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_select_hour
|
41
|
+
assert_render_has_no_escaped_chars %(<%= select_hour 1 %>)
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_select_minute
|
45
|
+
assert_render_has_no_escaped_chars %(<%= select_minute 1 %>)
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_select_month
|
49
|
+
assert_render_has_no_escaped_chars %(<%= select_month 1 %>)
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_select_second
|
53
|
+
assert_render_has_no_escaped_chars %(<%= select_second 1 %>)
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_select_time
|
57
|
+
assert_render_has_no_escaped_chars %(<%= select_time Time.now %>)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_select_year
|
61
|
+
assert_render_has_no_escaped_chars %(<%= select_year 2000 %>)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_time_ago_in_words
|
65
|
+
assert_render_has_no_escaped_chars %(<%= time_ago_in_words Time.now %>)
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_time_select
|
69
|
+
assert_render_has_no_escaped_chars %(<%= time_select :foo, :bar %>)
|
70
|
+
end
|
71
|
+
end
|