angular_xss 0.4.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +19 -9
  3. data/.ruby-version +1 -1
  4. data/CHANGELOG.md +20 -1
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +1 -1
  7. data/{Gemfile.rails-3.2 → Gemfile.rails-3.2.haml-4} +1 -1
  8. data/{Gemfile.rails-3.2.lock → Gemfile.rails-3.2.haml-4.lock} +4 -4
  9. data/Gemfile.rails-4.2.haml-4 +1 -1
  10. data/Gemfile.rails-4.2.haml-4.lock +4 -4
  11. data/Gemfile.rails-4.2.haml-5 +1 -1
  12. data/Gemfile.rails-4.2.haml-5.lock +4 -4
  13. data/Gemfile.rails-5.1.haml-4 +1 -1
  14. data/Gemfile.rails-5.1.haml-4.lock +8 -6
  15. data/Gemfile.rails-5.1.haml-5 +1 -1
  16. data/Gemfile.rails-5.1.haml-5.lock +9 -7
  17. data/Gemfile.rails-6.1.haml-5 +1 -1
  18. data/Gemfile.rails-6.1.haml-5.lock +3 -3
  19. data/Gemfile.rails-7.0.haml-5 +8 -0
  20. data/Gemfile.rails-7.0.haml-5.lock +88 -0
  21. data/Gemfile.rails-7.1.haml-5 +9 -0
  22. data/Gemfile.rails-7.1.haml-5.lock +105 -0
  23. data/Gemfile.rails-7.1.haml-6 +9 -0
  24. data/Gemfile.rails-7.1.haml-6.lock +122 -0
  25. data/README.md +11 -2
  26. data/angular_xss.gemspec +1 -0
  27. data/lib/angular_xss/erb.rb +17 -27
  28. data/lib/angular_xss/escaper.rb +8 -0
  29. data/lib/angular_xss/haml.rb +25 -19
  30. data/lib/angular_xss/output_buffer.rb +25 -0
  31. data/lib/angular_xss/safe_buffer.rb +31 -7
  32. data/lib/angular_xss/version.rb +1 -1
  33. data/lib/angular_xss.rb +1 -0
  34. data/spec/angular_xss/erb_spec.rb +46 -3
  35. data/spec/angular_xss/escaper_spec.rb +21 -0
  36. data/spec/angular_xss/haml_spec.rb +0 -2
  37. data/spec/angular_xss/output_buffer_spec.rb +45 -0
  38. data/spec/angular_xss/safe_buffer_spec.rb +16 -4
  39. data/spec/spec_helper.rb +5 -11
  40. data/spec/support/engine_preventing_angular_xss.rb +21 -17
  41. data/spec/templates/_test_erb.erb +14 -5
  42. data/spec/templates/_test_haml.haml +40 -23
  43. metadata +18 -6
@@ -0,0 +1,122 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ angular_xss (1.0.0)
5
+ activesupport
6
+ haml (>= 3.1.5)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ actionpack (7.1.3.4)
12
+ actionview (= 7.1.3.4)
13
+ activesupport (= 7.1.3.4)
14
+ nokogiri (>= 1.8.5)
15
+ racc
16
+ rack (>= 2.2.4)
17
+ rack-session (>= 1.0.1)
18
+ rack-test (>= 0.6.3)
19
+ rails-dom-testing (~> 2.2)
20
+ rails-html-sanitizer (~> 1.6)
21
+ actionview (7.1.3.4)
22
+ activesupport (= 7.1.3.4)
23
+ builder (~> 3.1)
24
+ erubi (~> 1.11)
25
+ rails-dom-testing (~> 2.2)
26
+ rails-html-sanitizer (~> 1.6)
27
+ activesupport (7.1.3.4)
28
+ base64
29
+ bigdecimal
30
+ concurrent-ruby (~> 1.0, >= 1.0.2)
31
+ connection_pool (>= 2.2.5)
32
+ drb
33
+ i18n (>= 1.6, < 2)
34
+ minitest (>= 5.1)
35
+ mutex_m
36
+ tzinfo (~> 2.0)
37
+ base64 (0.2.0)
38
+ bigdecimal (3.1.8)
39
+ builder (3.3.0)
40
+ byebug (11.1.3)
41
+ concurrent-ruby (1.3.3)
42
+ connection_pool (2.4.1)
43
+ crass (1.0.6)
44
+ diff-lcs (1.5.1)
45
+ drb (2.2.1)
46
+ erubi (1.13.0)
47
+ gemika (0.8.3)
48
+ haml (6.3.0)
49
+ temple (>= 0.8.2)
50
+ thor
51
+ tilt
52
+ i18n (1.14.5)
53
+ concurrent-ruby (~> 1.0)
54
+ loofah (2.22.0)
55
+ crass (~> 1.0.2)
56
+ nokogiri (>= 1.12.0)
57
+ minitest (5.24.0)
58
+ mutex_m (0.2.0)
59
+ nokogiri (1.16.6-aarch64-linux)
60
+ racc (~> 1.4)
61
+ nokogiri (1.16.6-arm-linux)
62
+ racc (~> 1.4)
63
+ nokogiri (1.16.6-arm64-darwin)
64
+ racc (~> 1.4)
65
+ nokogiri (1.16.6-x86-linux)
66
+ racc (~> 1.4)
67
+ nokogiri (1.16.6-x86_64-darwin)
68
+ racc (~> 1.4)
69
+ nokogiri (1.16.6-x86_64-linux)
70
+ racc (~> 1.4)
71
+ racc (1.8.0)
72
+ rack (3.1.3)
73
+ rack-session (2.0.0)
74
+ rack (>= 3.0.0)
75
+ rack-test (2.1.0)
76
+ rack (>= 1.3)
77
+ rails-dom-testing (2.2.0)
78
+ activesupport (>= 5.0.0)
79
+ minitest
80
+ nokogiri (>= 1.6)
81
+ rails-html-sanitizer (1.6.0)
82
+ loofah (~> 2.21)
83
+ nokogiri (~> 1.14)
84
+ rake (13.2.1)
85
+ rspec (3.13.0)
86
+ rspec-core (~> 3.13.0)
87
+ rspec-expectations (~> 3.13.0)
88
+ rspec-mocks (~> 3.13.0)
89
+ rspec-core (3.13.0)
90
+ rspec-support (~> 3.13.0)
91
+ rspec-expectations (3.13.1)
92
+ diff-lcs (>= 1.2.0, < 2.0)
93
+ rspec-support (~> 3.13.0)
94
+ rspec-mocks (3.13.1)
95
+ diff-lcs (>= 1.2.0, < 2.0)
96
+ rspec-support (~> 3.13.0)
97
+ rspec-support (3.13.1)
98
+ temple (0.10.3)
99
+ thor (1.3.1)
100
+ tilt (2.3.0)
101
+ tzinfo (2.0.6)
102
+ concurrent-ruby (~> 1.0)
103
+
104
+ PLATFORMS
105
+ aarch64-linux
106
+ arm-linux
107
+ arm64-darwin
108
+ x86-linux
109
+ x86_64-darwin
110
+ x86_64-linux
111
+
112
+ DEPENDENCIES
113
+ actionpack (~> 7.1)
114
+ angular_xss!
115
+ byebug
116
+ gemika (>= 0.8.3)
117
+ haml (~> 6)
118
+ rake
119
+ rspec
120
+
121
+ BUNDLED WITH
122
+ 2.5.13
data/README.md CHANGED
@@ -7,6 +7,12 @@ This gem patches ERB/rails_xss and Haml so Angular interpolation symbols are aut
7
7
 
8
8
  **This is an unsatisfactory hack.** A better solution is very much desired, but is not possible without some changes in AngularJS. See the [related AngularJS issue](https://github.com/angular/angular.js/issues/5601).
9
9
 
10
+ 🚧 Notice: unmaintained gem
11
+ ------------------
12
+
13
+ We are no longer actively maintaining this gem.
14
+
15
+ The `1.0` release added support for HAML 6 and Rails 7.1, so the gem will at least support Rails 3.2 - 7.1 and HAML 4 - 6. `angular_xss` might still work for future versions HAML and Rails, but we won't actively ensure it does.
10
16
 
11
17
  Disable escaping locally
12
18
  ------------------------
@@ -56,10 +62,13 @@ Development
56
62
  -----------
57
63
 
58
64
  - Fork the repository.
59
- - Push your changes with specs. There is a Rails 3 test application in `spec/app_root` if you need to test integration with a live Rails app.
65
+ - Prepare your changes, and ensure existing and new test are green:
66
+ - `bundle exec rake matrix:install` installs all dependencies for all Gemfiles
67
+ - `bundle exec rake matrix:spec` runs all specs in all configurations
68
+ - You may run single tests with a specified Rails version via `BUNDLE_GEMFILE=Gemfile.rails-7.0.haml-5 bundle exec rspec ./spec/angular_xss`
69
+ - Push your changes with specs. There is a test application in `spec/app_root` if you need to test integration with a live Rails app.
60
70
  - Send a pull request.
61
71
 
62
-
63
72
  Credits
64
73
  -------
65
74
 
data/angular_xss.gemspec CHANGED
@@ -10,6 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.summary = 'Patches rails_xss and Haml so AngularJS interpolations are auto-escaped in unsafe strings.'
11
11
  s.description = s.summary
12
12
  s.license = 'MIT'
13
+ s.metadata = { 'rubygems_mfa_required' => 'true' }
13
14
 
14
15
  s.files = `git ls-files`.split($\)
15
16
  s.test_files = s.files.grep(%r{^spec/})
@@ -1,33 +1,25 @@
1
- # Use module_eval so we crash when ERB::Util has not yet been loaded.
2
- ERB::Util.module_eval do
3
-
4
- if private_method_defined? :unwrapped_html_escape # Rails 4.2+
5
-
6
- def unwrapped_html_escape_with_escaping_angular_expressions(s)
7
- s = s.to_s
8
- if s.html_safe?
9
- s
10
- else
11
- unwrapped_html_escape_without_escaping_angular_expressions(AngularXss::Escaper.escape(s))
12
- end
1
+ if ERB::Util.private_method_defined? :unwrapped_html_escape
2
+ # Rails 4.2+
3
+ # https://github.com/rails/rails/blob/main/activesupport/lib/active_support/core_ext/erb/util.rb
4
+ module ERBUtilExt
5
+ def html_escape_once(s)
6
+ super(AngularXss::Escaper.escape_if_unsafe(s))
13
7
  end
14
8
 
15
- alias_method :unwrapped_html_escape_without_escaping_angular_expressions, :unwrapped_html_escape
16
- alias_method :unwrapped_html_escape, :unwrapped_html_escape_with_escaping_angular_expressions
17
-
18
- singleton_class.send(:remove_method, :unwrapped_html_escape)
19
- module_function :unwrapped_html_escape
20
- module_function :unwrapped_html_escape_without_escaping_angular_expressions
9
+ def unwrapped_html_escape(s)
10
+ super(AngularXss::Escaper.escape_if_unsafe(s))
11
+ end
12
+ # Note that html_escape() and h() are passively fixed as they are calling the two methods above
13
+ end
14
+ ERB::Util.prepend ERBUtilExt
15
+ ERB::Util.singleton_class.prepend ERBUtilExt
21
16
 
22
- else # Rails < 4.2
17
+ else
18
+ ERB::Util.module_eval do
19
+ # Rails < 4.2
23
20
 
24
21
  def html_escape_with_escaping_angular_expressions(s)
25
- s = s.to_s
26
- if s.html_safe?
27
- s
28
- else
29
- html_escape_without_escaping_angular_expressions(AngularXss::Escaper.escape(s))
30
- end
22
+ html_escape_without_escaping_angular_expressions(AngularXss::Escaper.escape_if_unsafe(s))
31
23
  end
32
24
 
33
25
  alias_method_chain :html_escape, :escaping_angular_expressions
@@ -41,7 +33,5 @@ ERB::Util.module_eval do
41
33
  singleton_class.send(:remove_method, :html_escape)
42
34
  module_function :html_escape
43
35
  module_function :html_escape_without_escaping_angular_expressions
44
-
45
36
  end
46
-
47
37
  end
@@ -27,6 +27,14 @@ module AngularXss
27
27
  end
28
28
  end
29
29
 
30
+ def self.escape_if_unsafe(string)
31
+ if string.nil? || string.to_s.html_safe?
32
+ string
33
+ else
34
+ escape(string.to_s)
35
+ end
36
+ end
37
+
30
38
  def self.disabled?
31
39
  !!Thread.current[XSS_DISABLED_KEY]
32
40
  end
@@ -1,32 +1,38 @@
1
- # Haml 5.0 and 5.1 fall back to erb
2
- if Haml::VERSION < '5'
1
+ haml_version = Gem::Version.new(Haml::VERSION)
2
+
3
+ if haml_version < Gem::Version.new(5)
3
4
  # Use module_eval so we crash when Haml::Helpers has not yet been loaded.
4
5
  Haml::Helpers.module_eval do
5
-
6
6
  def html_escape_with_escaping_angular_expressions(s)
7
- s = s.to_s
8
- if s.html_safe?
9
- s
10
- else
11
- html_escape_without_escaping_angular_expressions(AngularXss::Escaper.escape(s))
12
- end
7
+ html_escape_without_escaping_angular_expressions(AngularXss::Escaper.escape_if_unsafe(s))
13
8
  end
14
9
 
15
10
  alias_method :html_escape_without_escaping_angular_expressions, :html_escape
16
11
  alias_method :html_escape, :html_escape_with_escaping_angular_expressions
17
12
  end
13
+ elsif haml_version < Gem::Version.new('5.2')
14
+ # Haml 5.0 and 5.1 fall back to erb
15
+ elsif haml_version < Gem::Version.new(6)
16
+ # HAML 5.2+
17
+ module HTMLEscapeWithoutHAMLWithAngularXSS
18
+ def html_escape_without_haml_xss(html)
19
+ super(AngularXss::Escaper.escape_if_unsafe(html))
20
+ end
21
+ end
18
22
 
19
- elsif Haml::VERSION >= '5.2'
20
- Haml::Helpers.module_eval do
21
-
22
- def html_escape_without_haml_xss_with_escaping_angular_expressions(s)
23
- s = s.to_s
24
- return s if s.html_safe?
23
+ Haml::Helpers.singleton_class.prepend HTMLEscapeWithoutHAMLWithAngularXSS
24
+ else
25
+ # Haml 6+
26
+ # It ditched most of is own helpers in favor of Haml::Util.escape_html
27
+ # https://github.com/haml/haml/blob/main/CHANGELOG.md#600
28
+ # https://github.com/haml/haml/compare/v5.2.2...v6.3.0
29
+ # https://github.com/haml/haml/blob/v6.3.0/lib/haml/util.rb
25
30
 
26
- html_escape_without_haml_xss_without_escaping_angular_expressions(AngularXss::Escaper.escape(s))
31
+ module EscapeHTMLWithAngularXSS
32
+ def escape_html(html)
33
+ super(AngularXss::Escaper.escape_if_unsafe(html))
27
34
  end
28
-
29
- alias_method :html_escape_without_haml_xss_without_escaping_angular_expressions, :html_escape_without_haml_xss
30
- alias_method :html_escape_without_haml_xss, :html_escape_without_haml_xss_with_escaping_angular_expressions
31
35
  end
36
+
37
+ Haml::Util.singleton_class.prepend EscapeHTMLWithAngularXSS
32
38
  end
@@ -0,0 +1,25 @@
1
+ ##
2
+ # Monkey patch ActionView::OutputBuffer to escape double braces from Angular
3
+ #
4
+ # Link to the original implementation without Angular XSS escaping:
5
+ # https://github.com/rails/rails/blob/v7.1.3.4/actionview/lib/action_view/buffers.rb
6
+
7
+
8
+ if defined?(ActionView::VERSION) && Gem::Version.new(ActionView::VERSION::STRING) >= Gem::Version.new('7.1')
9
+ # ActionView < 7.1 used our patched ERB::Util.h to escape, 7.1 switched to CGI.escapeHTML
10
+ module OutputBufferWithEscapedAngularXSS
11
+ def <<(value)
12
+ super(AngularXss::Escaper.escape_if_unsafe(value))
13
+ end
14
+
15
+ def concat(value)
16
+ super(AngularXss::Escaper.escape_if_unsafe(value))
17
+ end
18
+
19
+ def append=(value)
20
+ super(AngularXss::Escaper.escape_if_unsafe(value))
21
+ end
22
+ end
23
+
24
+ ActionView::OutputBuffer.prepend OutputBufferWithEscapedAngularXSS
25
+ end
@@ -1,20 +1,44 @@
1
+ ##
2
+ # Monkey patch ActiveSupport::SafeBuffer to escape double braces from Angular
3
+ #
4
+ # Link to the original implementation without Angular XSS escaping:
5
+ # https://github.com/rails/rails/blob/7-0-stable/activesupport/lib/active_support/core_ext/string/output_safety.rb#L295
6
+ #
1
7
  ActiveSupport::SafeBuffer.class_eval do
2
8
 
3
- if private_method_defined? :html_escape_interpolated_argument
9
+ html_escape = :html_escape_interpolated_argument
10
+
11
+ if private_method_defined?(html_escape) || # Rails < 6.1
12
+ private_method_defined?(:"explicit_#{html_escape}") # Rails >= 6.1
4
13
 
5
14
  private
6
15
 
7
- def html_escape_interpolated_argument_with_angular_xss(arg)
8
- if arg.html_safe?
16
+ def explicit_html_escape_interpolated_argument_with_angular_xss(arg)
17
+ if !html_safe? || arg.html_safe?
9
18
  arg
10
19
  else
11
- html_escape_interpolated_argument_without_angular_xss(AngularXss::Escaper.escape(arg))
20
+ explicit_html_escape_interpolated_argument_without_angular_xss(AngularXss::Escaper.escape(arg))
12
21
  end
13
22
  end
14
23
 
15
- alias_method :html_escape_interpolated_argument_without_angular_xss, :html_escape_interpolated_argument
16
- alias_method :html_escape_interpolated_argument, :html_escape_interpolated_argument_with_angular_xss
24
+ if private_method_defined?(html_escape)
25
+ alias_method :"explicit_#{html_escape}_without_angular_xss", html_escape
26
+ alias_method html_escape, :"explicit_#{html_escape}_with_angular_xss"
27
+ elsif private_method_defined?(:"explicit_#{html_escape}")
28
+ alias_method :"explicit_#{html_escape}_without_angular_xss", :"explicit_#{html_escape}"
29
+ alias_method :"explicit_#{html_escape}", :"explicit_#{html_escape}_with_angular_xss"
30
+ end
17
31
 
32
+ if private_method_defined?(:"implicit_#{html_escape}")
33
+ def implicit_html_escape_interpolated_argument_with_angular_xss(arg)
34
+ if !html_safe? || arg.html_safe?
35
+ arg
36
+ else
37
+ implicit_html_escape_interpolated_argument_without_angular_xss(AngularXss::Escaper.escape(arg))
38
+ end
39
+ end
40
+ alias_method :"implicit_#{html_escape}_without_angular_xss", :"implicit_#{html_escape}"
41
+ alias_method :"implicit_#{html_escape}", :"implicit_#{html_escape}_with_angular_xss"
42
+ end
18
43
  end
19
-
20
44
  end
@@ -1,3 +1,3 @@
1
1
  module AngularXss
2
- VERSION = '0.4.0'
2
+ VERSION = '1.0.0'
3
3
  end
data/lib/angular_xss.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  #"string".respond_to?(:html_safe?) or raise "No rails_xss implementation present"
2
2
 
3
3
  require 'angular_xss/escaper'
4
+ require 'angular_xss/output_buffer'
4
5
  require 'angular_xss/safe_buffer'
5
6
  require 'angular_xss/erb'
6
7
  require 'angular_xss/haml'
@@ -1,7 +1,50 @@
1
- require 'spec_helper'
2
-
3
1
  describe 'Angular XSS prevention in ERB', :type => :view do
4
-
5
2
  it_should_behave_like 'engine preventing Angular XSS', :partial => 'test_erb'
3
+ end
4
+
5
+ describe ERB::Util do
6
+ describe '#html_escape' do
7
+ it 'escapes angular braces' do
8
+ expect(described_class.html_escape("{{unsafe}}")).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
9
+ end
10
+
11
+ it 'does not modify already HTML safe strings' do
12
+ expect(described_class.html_escape("{{safe}}".html_safe)).to eq("{{safe}}")
13
+ end
14
+ end
15
+
16
+ describe '#h' do
17
+ it 'escapes angular braces' do
18
+ expect(described_class.h("{{unsafe}}")).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
19
+ end
20
+
21
+ it 'does not modify already HTML safe strings' do
22
+ expect(described_class.h("{{safe}}".html_safe)).to eq("{{safe}}")
23
+ end
24
+ end
25
+
26
+ # Rails < 4 does not implement unwrapped_html_escape and html_escape_once
27
+ if described_class.method_defined? :unwrapped_html_escape
28
+ describe '#unwrapped_html_escape' do
29
+ it 'escapes angular braces' do
30
+ expect(described_class.unwrapped_html_escape("{{unsafe}}")).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
31
+ end
32
+
33
+ it 'does not modify already HTML safe strings' do
34
+ expect(described_class.unwrapped_html_escape("{{safe}}".html_safe)).to eq("{{safe}}")
35
+ end
36
+ end
37
+ end
38
+
39
+ if described_class.method_defined? :html_escape_once
40
+ describe '#html_escape_once' do
41
+ it 'escapes angular braces' do
42
+ expect(described_class.html_escape_once("{{unsafe}}")).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
43
+ end
6
44
 
45
+ it 'does not modify already HTML safe strings' do
46
+ expect(described_class.html_escape_once("{{safe}}".html_safe)).to eq("{{safe}}")
47
+ end
48
+ end
49
+ end
7
50
  end
@@ -0,0 +1,21 @@
1
+ describe AngularXss::Escaper do
2
+ describe '.escape' do
3
+ it 'replaces double braces with a closed variant' do
4
+ expect(described_class.escape('{{')).to eq('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}')
5
+ end
6
+
7
+ it 'does not handle HTML safe strings differently' do
8
+ expect(described_class.escape('{{'.html_safe)).to eq('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}')
9
+ end
10
+ end
11
+
12
+ describe '.escape_if_unsafe' do
13
+ it 'replaces double braces with a closed variant' do
14
+ expect(described_class.escape_if_unsafe('{{')).to eq('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}')
15
+ end
16
+
17
+ it 'does not modify HTML safe strings' do
18
+ expect(described_class.escape_if_unsafe('{{'.html_safe)).to eq('{{')
19
+ end
20
+ end
21
+ end
@@ -1,5 +1,3 @@
1
- require 'spec_helper'
2
-
3
1
  describe 'Angular XSS prevention in Haml', :type => :view do
4
2
 
5
3
  it_should_behave_like 'engine preventing Angular XSS', :partial => 'test_haml'
@@ -0,0 +1,45 @@
1
+ describe ActionView::OutputBuffer do
2
+ describe '#<<' do
3
+ it 'escapes angular braces' do
4
+ expect((subject << "{{unsafe}}").to_s).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
5
+ end
6
+
7
+ it 'does not change behavior for already HTML safe strings' do
8
+ expect((subject << "{{safe}}".html_safe).to_s).to eq("{{safe}}")
9
+ end
10
+
11
+ it 'allows concatting nil' do
12
+ expect { subject << nil }.to_not raise_error
13
+ end
14
+ end
15
+
16
+ describe '#concat' do
17
+ it 'escapes angular braces' do
18
+ expect((subject.concat "{{unsafe}}").to_s).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
19
+ end
20
+
21
+ it 'does not change behavior for already HTML safe strings' do
22
+ expect((subject.concat "{{safe}}".html_safe).to_s).to eq("{{safe}}")
23
+ end
24
+
25
+ it 'allows concatting nil' do
26
+ expect { subject.concat nil }.to_not raise_error
27
+ end
28
+ end
29
+
30
+ describe '#append=' do
31
+ it 'escapes angular braces' do
32
+ subject.append = "{{unsafe}}"
33
+ expect(subject.to_s).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
34
+ end
35
+
36
+ it 'does not change behavior for already HTML safe strings' do
37
+ subject.append = "{{safe}}".html_safe
38
+ expect(subject.to_s).to eq("{{safe}}")
39
+ end
40
+
41
+ it 'allows concatting nil' do
42
+ expect { subject.append = nil }.to_not raise_error
43
+ end
44
+ end
45
+ end
@@ -1,9 +1,21 @@
1
- require 'spec_helper'
2
-
3
1
  describe ActiveSupport::SafeBuffer do
4
2
 
5
- it 'still allows concatting nil' do
6
- expect { subject << nil }.to_not raise_error
3
+ describe '#<<' do
4
+ it 'escapes angular braces' do
5
+ subject << "{{unsafe}}"
6
+ expect(subject.to_s).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
7
+ end
8
+
9
+ it 'allows concatting nil' do
10
+ expect { subject << nil }.to_not raise_error
11
+ end
12
+ end
13
+
14
+ describe '#+' do
15
+ it 'escapes angular braces' do
16
+ combined_string = subject + "{{unsafe}}"
17
+ expect(combined_string.to_s).to eq("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
18
+ end
7
19
  end
8
20
 
9
21
  end
data/spec/spec_helper.rb CHANGED
@@ -17,7 +17,11 @@ module Rails
17
17
  end
18
18
 
19
19
  require 'haml'
20
- require 'haml/template'
20
+ if Gem::Version.new(Haml::VERSION) < Gem::Version.new(6)
21
+ require 'haml/template'
22
+ else
23
+ require 'haml/rails_template'
24
+ end
21
25
 
22
26
  require 'angular_xss'
23
27
 
@@ -25,13 +29,3 @@ require 'angular_xss'
25
29
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
26
30
 
27
31
  TEMPLATE_ROOT = Pathname.new(__dir__).join('templates')
28
-
29
-
30
- RSpec.configure do |config|
31
- config.mock_with :rspec do |c|
32
- c.syntax = [:should, :expect]
33
- end
34
- config.expect_with :rspec do |c|
35
- c.syntax = [:should, :expect]
36
- end
37
- end
@@ -2,7 +2,7 @@ shared_examples_for 'engine preventing Angular XSS' do |partial:|
2
2
 
3
3
  let(:path_set) { ActionView::LookupContext.new([TEMPLATE_ROOT]) }
4
4
 
5
- if defined?(ActionView::VERSION) && ActionView::VERSION::MAJOR >= 6
5
+ if defined?(ActionView::VERSION) && Gem::Version.new(ActionView::VERSION::MAJOR) >= Gem::Version.new(6)
6
6
  let(:engine) { ActionView::Base.with_empty_template_cache.new(path_set, {}, nil) }
7
7
  else
8
8
  let(:engine) { ActionView::Base.new(path_set) }
@@ -11,14 +11,18 @@ shared_examples_for 'engine preventing Angular XSS' do |partial:|
11
11
  let(:html) { engine.render(partial) }
12
12
 
13
13
  it 'escapes Angular interpolation marks in unsafe strings' do
14
- html.should_not include('{{unsafe}}')
15
- html.should include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
14
+ expect(html).not_to include('{{unsafe}}')
15
+ expect(html).to include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
16
16
  end
17
17
 
18
18
  it 'recognizes the many ways to express an opening curly brace in HTML' do
19
+ # Only unsafe strings are escaped
20
+ expect(html).to include("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
21
+ expect(html).not_to include("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}safe}}")
19
22
 
20
- html.should include("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}")
21
- html.should_not include("{{unsafe}}")
23
+ # Only safe strings with braces are left untouched
24
+ expect(html).to include("{{safe}}")
25
+ expect(html).not_to include("{{unsafe}}")
22
26
 
23
27
  braces = [
24
28
  '{',
@@ -35,15 +39,15 @@ shared_examples_for 'engine preventing Angular XSS' do |partial:|
35
39
 
36
40
  braces.each do |brace1|
37
41
  braces.each do |brace2|
38
- html.should_not include("#{brace1}#{brace2}unsafe}}")
42
+ expect(html).not_to include("#{brace1}#{brace2}unsafe}}")
39
43
  end
40
44
  end
41
45
 
42
46
  end
43
47
 
44
48
  it 'does not escape Angular interpolation marks in safe strings' do
45
- html.should include("{{safe}}")
46
- html.should_not include("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}safe}}")
49
+ expect(html).to include("{{safe}}")
50
+ expect(html).not_to include("{{ $root.DOUBLE_LEFT_CURLY_BRACE }}safe}}")
47
51
  end
48
52
 
49
53
  it 'does not escape Angular interpolation marks in a block where AngularXSS is disabled' do
@@ -52,8 +56,8 @@ shared_examples_for 'engine preventing Angular XSS' do |partial:|
52
56
  result = html
53
57
  end
54
58
 
55
- result.should include('{{unsafe}}')
56
- result.should_not include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
59
+ expect(result).to include('{{unsafe}}')
60
+ expect(result).not_to include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
57
61
  end
58
62
 
59
63
  it 'does escape Angular interpolation marks after the block where AngularXSS is disabled' do
@@ -61,27 +65,27 @@ shared_examples_for 'engine preventing Angular XSS' do |partial:|
61
65
  end
62
66
  result = html
63
67
 
64
- result.should include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
65
- result.should_not include('{{unsafe}}')
68
+ expect(result).to include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
69
+ expect(result).not_to include('{{unsafe}}')
66
70
  end
67
71
 
68
72
  it 'is not confused by exceptions in disable blocks' do
69
73
  class SomeException < StandardError; end
70
74
 
71
- proc {
75
+ expect do
72
76
  AngularXss.disable do
73
77
  raise SomeException
74
78
  end
75
- }.should raise_error(SomeException)
79
+ end.to raise_error(SomeException)
76
80
 
77
- html.should include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
78
- html.should_not include('{{unsafe}}')
81
+ expect(html).to include('{{ $root.DOUBLE_LEFT_CURLY_BRACE }}unsafe}}')
82
+ expect(html).not_to include('{{unsafe}}')
79
83
  end
80
84
 
81
85
  it 'does not escape twice' do
82
86
  escaped = AngularXss::Escaper.escape('{{')
83
87
  double_escaped = AngularXss::Escaper.escape(escaped)
84
- html.should_not include(double_escaped)
88
+ expect(html).not_to include(double_escaped)
85
89
  end
86
90
 
87
91
  end