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
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
|