erb_safe_ext 1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 4b0b6a5f0daa578acddae3d8949d930a82785e59
4
+ data.tar.gz: 1c853f1d551d56c70c6fc61461e63f85a6dd99d3
5
+ SHA512:
6
+ metadata.gz: fc649276d7b03e42808a468a92209cb40aa802036f7efddbe19f03c3dc6524c72c644b73ef5c5b901c181b030aaa8ea26598fe01f47a6b2d092f43ca566b4aad
7
+ data.tar.gz: 1624272061c380efd61ed94b731e210308ce35f84bf6e4bca722c9ec7a72e8f07c18c0286cb590fd35ca43b2d3a7b7c2e172b0a487e4e01dd4a1fe6a5be9f36d
data/README.md ADDED
@@ -0,0 +1,45 @@
1
+ # erb_safe_ext
2
+
3
+ a gem make ERB html safe default.Protect from XSS attack.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ $ gem install erb_safe_ext
9
+ ```
10
+
11
+ ## Introduction
12
+
13
+ ``` erb
14
+ <%= "<script>alert('safety:)');</script>" %>
15
+ ## => &lt;script&gt;alert(&#x27;safety:)&#x27;);&lt;&#x2F;script&gt;
16
+ ```
17
+
18
+ it will default wrap the dangerous code with `Rack::Utils.escape_html(code)`
19
+
20
+ works fine with ruby2.1.
21
+
22
+ I didn't test this code with other version ruby, you may test yourself.
23
+
24
+ the `<%==` is the backup of ERB's original `<%=` function.
25
+
26
+ ``` erb
27
+ <%== "<script>alert('danger!');</script>" %>
28
+ ## => <script>alert('danger!');</script>
29
+ ```
30
+
31
+
32
+ Test code
33
+
34
+ ``` ruby
35
+ require 'erb_safe_ext'
36
+ template = ERB.new <<-EOF
37
+ <%= "<script>alert('safety:)');</script>" %>
38
+ <%#= 'here' -%>
39
+ <%== "<script>alert('danger!');</script>" %>
40
+ ----finish----
41
+ EOF
42
+ puts template.result
43
+ ```
44
+
45
+
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sinarey_cache/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "erb_safe_ext"
8
+ spec.version = '1.0'
9
+ spec.authors = ["Jeffrey"]
10
+ spec.email = ["jeffrey6052@163.com"]
11
+ spec.description = "make ERB default html safe.protect from XSS attack."
12
+ spec.summary = "wrap the dangerous code with Rack::Utils.escape_html()"
13
+ spec.homepage = "https://github.com/maymay25/erb_safe_ext"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = ['lib/erb_safe_ext.rb',
17
+ 'test/erb_safe_test.rb',
18
+ 'erb_safe_ext.gemspec',
19
+ 'README.md']
20
+ end
@@ -0,0 +1,190 @@
1
+ require 'erb'
2
+ require 'rack'
3
+
4
+ class ERB
5
+ class Compiler
6
+ def compile(s)
7
+ enc = s.encoding
8
+ raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy?
9
+ s = s.dup.force_encoding("ASCII-8BIT") # don't use constant Enoding::ASCII_8BIT for miniruby
10
+ enc = detect_magic_comment(s) || enc
11
+ out = Buffer.new(self, enc)
12
+ content = ''
13
+ scanner = make_scanner(s)
14
+ scanner.scan do |token|
15
+ next if token.nil?
16
+ next if token == ''
17
+ if scanner.stag.nil?
18
+ case token
19
+ when PercentLine
20
+ add_put_cmd(out, content) if content.size > 0
21
+ content = ''
22
+ out.push(token.to_s)
23
+ out.cr
24
+ when :cr
25
+ out.cr
26
+ when '<%', '<%==', '<%=', '<%#'
27
+ scanner.stag = token
28
+ add_put_cmd(out, content) if content.size > 0
29
+ content = ''
30
+ when "\n"
31
+ content << "\n"
32
+ add_put_cmd(out, content)
33
+ content = ''
34
+ when '<%%'
35
+ content << '<%'
36
+ else
37
+ content << token
38
+ end
39
+ else
40
+ case token
41
+ when '%>'
42
+ case scanner.stag
43
+ when '<%'
44
+ if content[-1] == ?\n
45
+ content.chop!
46
+ out.push(content)
47
+ out.cr
48
+ else
49
+ out.push(content)
50
+ end
51
+ when '<%=='
52
+ add_insert_cmd(out, content)
53
+ when '<%='
54
+ add_insert_escapehtml_cmd(out, content)
55
+ when '<%#'
56
+ # out.push("# #{content_dump(content)}")
57
+ end
58
+ scanner.stag = nil
59
+ content = ''
60
+ when '%%>'
61
+ content << '%>'
62
+ else
63
+ content << token
64
+ end
65
+ end
66
+ end
67
+ add_put_cmd(out, content) if content.size > 0
68
+ out.close
69
+ return out.script, enc
70
+ end
71
+ def add_insert_escapehtml_cmd(out, content)
72
+ out.push("#{@insert_cmd}(('#{Rack::Utils.escape_html(eval(content))}').to_s)")
73
+ end
74
+ class TrimScanner < Scanner
75
+ def scan_line(line)
76
+ line.scan(/(.*?)(<%%|%%>|<%==|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
77
+ tokens.each do |token|
78
+ next if token.empty?
79
+ yield(token)
80
+ end
81
+ end
82
+ end
83
+ def trim_line1(line)
84
+ line.scan(/(.*?)(<%%|%%>|<%==|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
85
+ tokens.each do |token|
86
+ next if token.empty?
87
+ if token == "%>\n"
88
+ yield('%>')
89
+ yield(:cr)
90
+ else
91
+ yield(token)
92
+ end
93
+ end
94
+ end
95
+ end
96
+ def trim_line2(line)
97
+ head = nil
98
+ line.scan(/(.*?)(<%%|%%>|<%==|<%=|<%#|<%|%>\n|%>|\n|\z)/m) do |tokens|
99
+ tokens.each do |token|
100
+ next if token.empty?
101
+ head = token unless head
102
+ if token == "%>\n"
103
+ yield('%>')
104
+ if is_erb_stag?(head)
105
+ yield(:cr)
106
+ else
107
+ yield("\n")
108
+ end
109
+ head = nil
110
+ else
111
+ yield(token)
112
+ head = nil if token == "\n"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ def explicit_trim_line(line)
118
+ line.scan(/(.*?)(^[ \t]*<%\-|<%\-|<%%|%%>|<%==|<%=|<%#|<%|-%>\n|-%>|%>|\z)/m) do |tokens|
119
+ tokens.each do |token|
120
+ next if token.empty?
121
+ if @stag.nil? && /[ \t]*<%-/ =~ token
122
+ yield('<%')
123
+ elsif @stag && token == "-%>\n"
124
+ yield('%>')
125
+ yield(:cr)
126
+ elsif @stag && token == '-%>'
127
+ yield('%>')
128
+ else
129
+ yield(token)
130
+ end
131
+ end
132
+ end
133
+ end
134
+ ERB_STAG << '<%=='
135
+ def is_erb_stag?(s)
136
+ ERB_STAG.member?(s)
137
+ end
138
+ end
139
+ Scanner.default_scanner = TrimScanner
140
+ class SimpleScanner < Scanner # :nodoc:
141
+ def scan
142
+ @src.scan(/(.*?)(<%%|%%>|<%==|<%=|<%#|<%|%>|\n|\z)/m) do |tokens|
143
+ tokens.each do |token|
144
+ next if token.empty?
145
+ yield(token)
146
+ end
147
+ end
148
+ end
149
+ end
150
+ Scanner.regist_scanner(SimpleScanner, nil, false)
151
+ begin
152
+ require 'strscan'
153
+ class SimpleScanner2 < Scanner # :nodoc:
154
+ def scan
155
+ stag_reg = /(.*?)(<%%|<%==|<%=|<%#|<%|\z)/m
156
+ etag_reg = /(.*?)(%%>|%>|\z)/m
157
+ scanner = StringScanner.new(@src)
158
+ while ! scanner.eos?
159
+ scanner.scan(@stag ? etag_reg : stag_reg)
160
+ yield(scanner[1])
161
+ yield(scanner[2])
162
+ end
163
+ end
164
+ end
165
+ Scanner.regist_scanner(SimpleScanner2, nil, false)
166
+ class ExplicitScanner < Scanner # :nodoc:
167
+ def scan
168
+ stag_reg = /(.*?)(^[ \t]*<%-|<%%|<%==|<%=|<%#|<%-|<%|\z)/m
169
+ etag_reg = /(.*?)(%%>|-%>|%>|\z)/m
170
+ scanner = StringScanner.new(@src)
171
+ while ! scanner.eos?
172
+ scanner.scan(@stag ? etag_reg : stag_reg)
173
+ yield(scanner[1])
174
+ elem = scanner[2]
175
+ if /[ \t]*<%-/ =~ elem
176
+ yield('<%')
177
+ elsif elem == '-%>'
178
+ yield('%>')
179
+ yield(:cr) if scanner.scan(/(\n|\z)/)
180
+ else
181
+ yield(elem)
182
+ end
183
+ end
184
+ end
185
+ end
186
+ Scanner.regist_scanner(ExplicitScanner, '-', false)
187
+ rescue LoadError
188
+ end
189
+ end
190
+ end
@@ -0,0 +1,14 @@
1
+
2
+ $:.unshift File.expand_path("../lib", __dir__)
3
+
4
+ require 'erb_safe_ext'
5
+
6
+ template = ERB.new <<-EOF
7
+ <%= "hello, #{'world'}." %>
8
+ <%= "<script>alert('safety:)');</script>" %>
9
+ <%== "<script>alert('danger!');</script>" %>
10
+ this is the end.
11
+ EOF
12
+ puts template.result
13
+
14
+
metadata ADDED
@@ -0,0 +1,48 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: erb_safe_ext
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Jeffrey
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: make ERB default html safe.protect from XSS attack.
14
+ email:
15
+ - jeffrey6052@163.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - lib/erb_safe_ext.rb
21
+ - test/erb_safe_test.rb
22
+ - erb_safe_ext.gemspec
23
+ - README.md
24
+ homepage: https://github.com/maymay25/erb_safe_ext
25
+ licenses:
26
+ - MIT
27
+ metadata: {}
28
+ post_install_message:
29
+ rdoc_options: []
30
+ require_paths:
31
+ - lib
32
+ required_ruby_version: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: '0'
37
+ required_rubygems_version: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ requirements: []
43
+ rubyforge_project:
44
+ rubygems_version: 2.0.14
45
+ signing_key:
46
+ specification_version: 4
47
+ summary: wrap the dangerous code with Rack::Utils.escape_html()
48
+ test_files: []