hanami-utils 2.0.3 → 2.1.0.beta1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b652af87ed75992d9e11acdfe997b8c8037ac034bdce97cb555904789b337844
4
- data.tar.gz: 179a36a649aadeb552c550ef104154ec64834bc89c0af25868184e6df89821c6
3
+ metadata.gz: 7d8408f6dcbf5d2b7a701c70130fe840c313114ce78f73ff5591f624b0fec635
4
+ data.tar.gz: 46423746a2dc76982974f54cd7c542f705aaf9ae36c3549056ec92136acb4f50
5
5
  SHA512:
6
- metadata.gz: d1a6db92d34b26615a48bf79f922bf214ca8517a9d84d7b255ade523a35df878fec93ebc33a1a923bb0026dc815cbf0da95bd608032cae3986dce75222bd0bdd
7
- data.tar.gz: d80d611dd33a3a4d897bd53e7db05617d363ab7f629a5ac4d10f58892ef546e9cad03710c114c796642b40f95bc43299fde88b5a32edef758dd35450f1940a24
6
+ metadata.gz: 5110f56db1184e39c4e741bb313f7aaff5ab8ff6a703b8bd8e3eaaf8608663ca88eec0ffa83054ac9ffbb961c9f4158b0ee56e1eea20031f539d74bf5470c30f
7
+ data.tar.gz: 58ce8d880d76a662f47e9ee19e96eaec06e02242b90ac456716c76aac7089a4b73db7a7630095227a08037ab26a040a05b7711554c471293c98d5b30ebb5c261
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  Ruby core extensions and class utilities for Hanami
4
4
 
5
+ ## v2.1.0.beta1 - 2023-06-29
6
+
7
+ ### Changed
8
+
9
+ - [Tim Riley] Remove `Hanami::Utils::Escape` (which was not public as of 2.0.0) (#410)
10
+
5
11
  ## v2.0.3 - 2023-02-01
6
12
 
7
13
  ### Fixed
data/LICENSE.md CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2014-2017 Luca Guidi
1
+ Copyright © 2014 Hanami Team
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -50,10 +50,6 @@ Or install it yourself as:
50
50
 
51
51
  ## Features
52
52
 
53
- ### Hanami::Logger
54
-
55
- Enhanced version of Ruby's `Logger`. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Logger)]
56
-
57
53
  ### Hanami::Utils::Blank
58
54
 
59
55
  Checks for blank. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Blank)]
@@ -74,10 +70,6 @@ Inheritable class attributes. [[API doc](http://www.rubydoc.info/gems/hanami-uti
74
70
 
75
71
  Deprecate Hanami features. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Deprecation)]
76
72
 
77
- ### Hanami::Utils::Escape
78
-
79
- Safe and fast escape for URLs, HTML content and attributes. Based on OWASP/ESAPI code. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/Escape)]
80
-
81
73
  ### Hanami::Utils::FileList
82
74
 
83
75
  Recursive, cross-platform ordered list of files. [[API doc](http://www.rubydoc.info/gems/hanami-utils/Hanami/Utils/FileList)]
@@ -136,4 +128,4 @@ Enhanced version of Ruby's `String`. [[API doc](http://www.rubydoc.info/gems/han
136
128
 
137
129
  ## Copyright
138
130
 
139
- Copyright © 2014-2022 Hanami Team – Released under MIT License
131
+ Copyright © 2014 Hanami Team – Released under MIT License
@@ -6,6 +6,6 @@ module Hanami
6
6
  #
7
7
  # @since 0.1.0
8
8
  # @api public
9
- VERSION = "2.0.3"
9
+ VERSION = "2.1.0.beta1"
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami-utils
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.1.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-01 00:00:00.000000000 Z
11
+ date: 2023-06-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dry-core
@@ -146,7 +146,6 @@ files:
146
146
  - lib/hanami/utils/class_attribute.rb
147
147
  - lib/hanami/utils/class_attribute/attributes.rb
148
148
  - lib/hanami/utils/deprecation.rb
149
- - lib/hanami/utils/escape.rb
150
149
  - lib/hanami/utils/file_list.rb
151
150
  - lib/hanami/utils/files.rb
152
151
  - lib/hanami/utils/hash.rb
@@ -175,11 +174,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
175
174
  version: '3.0'
176
175
  required_rubygems_version: !ruby/object:Gem::Requirement
177
176
  requirements:
178
- - - ">="
177
+ - - ">"
179
178
  - !ruby/object:Gem::Version
180
- version: '0'
179
+ version: 1.3.1
181
180
  requirements: []
182
- rubygems_version: 3.4.5
181
+ rubygems_version: 3.4.13
183
182
  signing_key:
184
183
  specification_version: 4
185
184
  summary: Ruby core extentions and Hanami utilities
@@ -1,583 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Hanami
4
- module Utils
5
- # HTML escape utilities
6
- #
7
- # Based on OWASP research and OWASP ESAPI code
8
- #
9
- # @since 0.4.0
10
- #
11
- # @see https://www.owasp.org
12
- # @see https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29
13
- # @see https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
14
- # @see https://www.owasp.org/index.php/ESAPI
15
- # @see https://github.com/ESAPI/esapi-java-legacy
16
- module Escape # rubocop:disable Metrics/ModuleLength
17
- # Hex base for base 10 integer conversion
18
- #
19
- # @since 0.4.0
20
- # @api private
21
- #
22
- # @see http://www.ruby-doc.org/core/Fixnum.html#method-i-to_s
23
- HEX_BASE = 16
24
-
25
- # Limit for non printable chars
26
- #
27
- # @since 0.4.0
28
- # @api private
29
- LOW_HEX_CODE_LIMIT = 0xff
30
-
31
- # Replacement hex for non printable characters
32
- #
33
- # @since 0.4.0
34
- # @api private
35
- REPLACEMENT_HEX = "fffd"
36
-
37
- # Low hex codes lookup table
38
- #
39
- # @since 0.4.0
40
- # @api private
41
- HEX_CODES = (0..255).each_with_object({}) do |c, codes|
42
- if (c >= 0x30 && c <= 0x39) || (c >= 0x41 && c <= 0x5A) || (c >= 0x61 && c <= 0x7A)
43
- codes[c] = nil
44
- else
45
- codes[c] = c.to_s(HEX_BASE)
46
- end
47
- end.freeze
48
-
49
- # Non printable chars
50
- #
51
- # This is a Hash instead of a Set, to make lookup faster.
52
- #
53
- # @since 0.4.0
54
- # @api private
55
- #
56
- # @see https://gist.github.com/jodosha/ac5dd54416de744b9600
57
- NON_PRINTABLE_CHARS = {
58
- 0x0 => true, 0x1 => true, 0x2 => true, 0x3 => true, 0x4 => true,
59
- 0x5 => true, 0x6 => true, 0x7 => true, 0x8 => true, 0x11 => true,
60
- 0x12 => true, 0x14 => true, 0x15 => true, 0x16 => true, 0x17 => true,
61
- 0x18 => true, 0x19 => true, 0x1a => true, 0x1b => true, 0x1c => true,
62
- 0x1d => true, 0x1e => true, 0x1f => true, 0x7f => true, 0x80 => true,
63
- 0x81 => true, 0x82 => true, 0x83 => true, 0x84 => true, 0x85 => true,
64
- 0x86 => true, 0x87 => true, 0x88 => true, 0x89 => true, 0x8a => true,
65
- 0x8b => true, 0x8c => true, 0x8d => true, 0x8e => true, 0x8f => true,
66
- 0x90 => true, 0x91 => true, 0x92 => true, 0x93 => true, 0x94 => true,
67
- 0x95 => true, 0x96 => true, 0x97 => true, 0x98 => true, 0x99 => true,
68
- 0x9a => true, 0x9b => true, 0x9c => true, 0x9d => true, 0x9e => true,
69
- 0x9f => true
70
- }.freeze
71
-
72
- # Lookup table for HTML escape
73
- #
74
- # @since 0.4.0
75
- # @api private
76
- #
77
- # @see Hanami::Utils::Escape.html
78
- HTML_CHARS = {
79
- "&" => "&amp;",
80
- "<" => "&lt;",
81
- ">" => "&gt;",
82
- '"' => "&quot;",
83
- "'" => "&apos;",
84
- "/" => "&#x2F;"
85
- }.freeze
86
-
87
- # Lookup table for safe chars for HTML attributes.
88
- #
89
- # This is a Hash instead of a Set, to make lookup faster.
90
- #
91
- # @since 0.4.0
92
- # @api private
93
- #
94
- # @see Lookup::Utils::Escape.html_attribute
95
- # @see https://gist.github.com/jodosha/ac5dd54416de744b9600
96
- HTML_ATTRIBUTE_SAFE_CHARS = {
97
- "," => true, "." => true, "-" => true, "_" => true
98
- }.freeze
99
-
100
- # Lookup table for HTML attribute escape
101
- #
102
- # @since 0.4.0
103
- # @api private
104
- #
105
- # @see Hanami::Utils::Escape.html_attribute
106
- HTML_ENTITIES = {
107
- 34 => "quot", # quotation mark
108
- 38 => "amp", # ampersand
109
- 60 => "lt", # less-than sign
110
- 62 => "gt", # greater-than sign
111
- 160 => "nbsp", # no-break space
112
- 161 => "iexcl", # inverted exclamation mark
113
- 162 => "cent", # cent sign
114
- 163 => "pound", # pound sign
115
- 164 => "curren", # currency sign
116
- 165 => "yen", # yen sign
117
- 166 => "brvbar", # broken bar
118
- 167 => "sect", # section sign
119
- 168 => "uml", # diaeresis
120
- 169 => "copy", # copyright sign
121
- 170 => "ordf", # feminine ordinal indicator
122
- 171 => "laquo", # left-pointing double angle quotation mark
123
- 172 => "not", # not sign
124
- 173 => "shy", # soft hyphen
125
- 174 => "reg", # registered sign
126
- 175 => "macr", # macron
127
- 176 => "deg", # degree sign
128
- 177 => "plusmn", # plus-minus sign
129
- 178 => "sup2", # superscript two
130
- 179 => "sup3", # superscript three
131
- 180 => "acute", # acute accent
132
- 181 => "micro", # micro sign
133
- 182 => "para", # pilcrow sign
134
- 183 => "middot", # middle dot
135
- 184 => "cedil", # cedilla
136
- 185 => "sup1", # superscript one
137
- 186 => "ordm", # masculine ordinal indicator
138
- 187 => "raquo", # right-pointing double angle quotation mark
139
- 188 => "frac14", # vulgar fraction one quarter
140
- 189 => "frac12", # vulgar fraction one half
141
- 190 => "frac34", # vulgar fraction three quarters
142
- 191 => "iquest", # inverted question mark
143
- 192 => "Agrave", # Latin capital letter a with grave
144
- 193 => "Aacute", # Latin capital letter a with acute
145
- 194 => "Acirc", # Latin capital letter a with circumflex
146
- 195 => "Atilde", # Latin capital letter a with tilde
147
- 196 => "Auml", # Latin capital letter a with diaeresis
148
- 197 => "Aring", # Latin capital letter a with ring above
149
- 198 => "AElig", # Latin capital letter ae
150
- 199 => "Ccedil", # Latin capital letter c with cedilla
151
- 200 => "Egrave", # Latin capital letter e with grave
152
- 201 => "Eacute", # Latin capital letter e with acute
153
- 202 => "Ecirc", # Latin capital letter e with circumflex
154
- 203 => "Euml", # Latin capital letter e with diaeresis
155
- 204 => "Igrave", # Latin capital letter i with grave
156
- 205 => "Iacute", # Latin capital letter i with acute
157
- 206 => "Icirc", # Latin capital letter i with circumflex
158
- 207 => "Iuml", # Latin capital letter i with diaeresis
159
- 208 => "ETH", # Latin capital letter eth
160
- 209 => "Ntilde", # Latin capital letter n with tilde
161
- 210 => "Ograve", # Latin capital letter o with grave
162
- 211 => "Oacute", # Latin capital letter o with acute
163
- 212 => "Ocirc", # Latin capital letter o with circumflex
164
- 213 => "Otilde", # Latin capital letter o with tilde
165
- 214 => "Ouml", # Latin capital letter o with diaeresis
166
- 215 => "times", # multiplication sign
167
- 216 => "Oslash", # Latin capital letter o with stroke
168
- 217 => "Ugrave", # Latin capital letter u with grave
169
- 218 => "Uacute", # Latin capital letter u with acute
170
- 219 => "Ucirc", # Latin capital letter u with circumflex
171
- 220 => "Uuml", # Latin capital letter u with diaeresis
172
- 221 => "Yacute", # Latin capital letter y with acute
173
- 222 => "THORN", # Latin capital letter thorn
174
- 223 => "szlig", # Latin small letter sharp sXCOMMAX German Eszett
175
- 224 => "agrave", # Latin small letter a with grave
176
- 225 => "aacute", # Latin small letter a with acute
177
- 226 => "acirc", # Latin small letter a with circumflex
178
- 227 => "atilde", # Latin small letter a with tilde
179
- 228 => "auml", # Latin small letter a with diaeresis
180
- 229 => "aring", # Latin small letter a with ring above
181
- 230 => "aelig", # Latin lowercase ligature ae
182
- 231 => "ccedil", # Latin small letter c with cedilla
183
- 232 => "egrave", # Latin small letter e with grave
184
- 233 => "eacute", # Latin small letter e with acute
185
- 234 => "ecirc", # Latin small letter e with circumflex
186
- 235 => "euml", # Latin small letter e with diaeresis
187
- 236 => "igrave", # Latin small letter i with grave
188
- 237 => "iacute", # Latin small letter i with acute
189
- 238 => "icirc", # Latin small letter i with circumflex
190
- 239 => "iuml", # Latin small letter i with diaeresis
191
- 240 => "eth", # Latin small letter eth
192
- 241 => "ntilde", # Latin small letter n with tilde
193
- 242 => "ograve", # Latin small letter o with grave
194
- 243 => "oacute", # Latin small letter o with acute
195
- 244 => "ocirc", # Latin small letter o with circumflex
196
- 245 => "otilde", # Latin small letter o with tilde
197
- 246 => "ouml", # Latin small letter o with diaeresis
198
- 247 => "divide", # division sign
199
- 248 => "oslash", # Latin small letter o with stroke
200
- 249 => "ugrave", # Latin small letter u with grave
201
- 250 => "uacute", # Latin small letter u with acute
202
- 251 => "ucirc", # Latin small letter u with circumflex
203
- 252 => "uuml", # Latin small letter u with diaeresis
204
- 253 => "yacute", # Latin small letter y with acute
205
- 254 => "thorn", # Latin small letter thorn
206
- 255 => "yuml", # Latin small letter y with diaeresis
207
- 338 => "OElig", # Latin capital ligature oe
208
- 339 => "oelig", # Latin small ligature oe
209
- 352 => "Scaron", # Latin capital letter s with caron
210
- 353 => "scaron", # Latin small letter s with caron
211
- 376 => "Yuml", # Latin capital letter y with diaeresis
212
- 402 => "fnof", # Latin small letter f with hook
213
- 710 => "circ", # modifier letter circumflex accent
214
- 732 => "tilde", # small tilde
215
- 913 => "Alpha", # Greek capital letter alpha
216
- 914 => "Beta", # Greek capital letter beta
217
- 915 => "Gamma", # Greek capital letter gamma
218
- 916 => "Delta", # Greek capital letter delta
219
- 917 => "Epsilon", # Greek capital letter epsilon
220
- 918 => "Zeta", # Greek capital letter zeta
221
- 919 => "Eta", # Greek capital letter eta
222
- 920 => "Theta", # Greek capital letter theta
223
- 921 => "Iota", # Greek capital letter iota
224
- 922 => "Kappa", # Greek capital letter kappa
225
- 923 => "Lambda", # Greek capital letter lambda
226
- 924 => "Mu", # Greek capital letter mu
227
- 925 => "Nu", # Greek capital letter nu
228
- 926 => "Xi", # Greek capital letter xi
229
- 927 => "Omicron", # Greek capital letter omicron
230
- 928 => "Pi", # Greek capital letter pi
231
- 929 => "Rho", # Greek capital letter rho
232
- 931 => "Sigma", # Greek capital letter sigma
233
- 932 => "Tau", # Greek capital letter tau
234
- 933 => "Upsilon", # Greek capital letter upsilon
235
- 934 => "Phi", # Greek capital letter phi
236
- 935 => "Chi", # Greek capital letter chi
237
- 936 => "Psi", # Greek capital letter psi
238
- 937 => "Omega", # Greek capital letter omega
239
- 945 => "alpha", # Greek small letter alpha
240
- 946 => "beta", # Greek small letter beta
241
- 947 => "gamma", # Greek small letter gamma
242
- 948 => "delta", # Greek small letter delta
243
- 949 => "epsilon", # Greek small letter epsilon
244
- 950 => "zeta", # Greek small letter zeta
245
- 951 => "eta", # Greek small letter eta
246
- 952 => "theta", # Greek small letter theta
247
- 953 => "iota", # Greek small letter iota
248
- 954 => "kappa", # Greek small letter kappa
249
- 955 => "lambda", # Greek small letter lambda
250
- 956 => "mu", # Greek small letter mu
251
- 957 => "nu", # Greek small letter nu
252
- 958 => "xi", # Greek small letter xi
253
- 959 => "omicron", # Greek small letter omicron
254
- 960 => "pi", # Greek small letter pi
255
- 961 => "rho", # Greek small letter rho
256
- 962 => "sigmaf", # Greek small letter final sigma
257
- 963 => "sigma", # Greek small letter sigma
258
- 964 => "tau", # Greek small letter tau
259
- 965 => "upsilon", # Greek small letter upsilon
260
- 966 => "phi", # Greek small letter phi
261
- 967 => "chi", # Greek small letter chi
262
- 968 => "psi", # Greek small letter psi
263
- 969 => "omega", # Greek small letter omega
264
- 977 => "thetasym", # Greek theta symbol
265
- 978 => "upsih", # Greek upsilon with hook symbol
266
- 982 => "piv", # Greek pi symbol
267
- 8194 => "ensp", # en space
268
- 8195 => "emsp", # em space
269
- 8201 => "thinsp", # thin space
270
- 8204 => "zwnj", # zero width non-joiner
271
- 8205 => "zwj", # zero width joiner
272
- 8206 => "lrm", # left-to-right mark
273
- 8207 => "rlm", # right-to-left mark
274
- 8211 => "ndash", # en dash
275
- 8212 => "mdash", # em dash
276
- 8216 => "lsquo", # left single quotation mark
277
- 8217 => "rsquo", # right single quotation mark
278
- 8218 => "sbquo", # single low-9 quotation mark
279
- 8220 => "ldquo", # left double quotation mark
280
- 8221 => "rdquo", # right double quotation mark
281
- 8222 => "bdquo", # double low-9 quotation mark
282
- 8224 => "dagger", # dagger
283
- 8225 => "Dagger", # double dagger
284
- 8226 => "bull", # bullet
285
- 8230 => "hellip", # horizontal ellipsis
286
- 8240 => "permil", # per mille sign
287
- 8242 => "prime", # prime
288
- 8243 => "Prime", # double prime
289
- 8249 => "lsaquo", # single left-pointing angle quotation mark
290
- 8250 => "rsaquo", # single right-pointing angle quotation mark
291
- 8254 => "oline", # overline
292
- 8260 => "frasl", # fraction slash
293
- 8364 => "euro", # euro sign
294
- 8465 => "image", # black-letter capital i
295
- 8472 => "weierp", # script capital pXCOMMAX Weierstrass p
296
- 8476 => "real", # black-letter capital r
297
- 8482 => "trade", # trademark sign
298
- 8501 => "alefsym", # alef symbol
299
- 8592 => "larr", # leftwards arrow
300
- 8593 => "uarr", # upwards arrow
301
- 8594 => "rarr", # rightwards arrow
302
- 8595 => "darr", # downwards arrow
303
- 8596 => "harr", # left right arrow
304
- 8629 => "crarr", # downwards arrow with corner leftwards
305
- 8656 => "lArr", # leftwards double arrow
306
- 8657 => "uArr", # upwards double arrow
307
- 8658 => "rArr", # rightwards double arrow
308
- 8659 => "dArr", # downwards double arrow
309
- 8660 => "hArr", # left right double arrow
310
- 8704 => "forall", # for all
311
- 8706 => "part", # partial differential
312
- 8707 => "exist", # there exists
313
- 8709 => "empty", # empty set
314
- 8711 => "nabla", # nabla
315
- 8712 => "isin", # element of
316
- 8713 => "notin", # not an element of
317
- 8715 => "ni", # contains as member
318
- 8719 => "prod", # n-ary product
319
- 8721 => "sum", # n-ary summation
320
- 8722 => "minus", # minus sign
321
- 8727 => "lowast", # asterisk operator
322
- 8730 => "radic", # square root
323
- 8733 => "prop", # proportional to
324
- 8734 => "infin", # infinity
325
- 8736 => "ang", # angle
326
- 8743 => "and", # logical and
327
- 8744 => "or", # logical or
328
- 8745 => "cap", # intersection
329
- 8746 => "cup", # union
330
- 8747 => "int", # integral
331
- 8756 => "there4", # therefore
332
- 8764 => "sim", # tilde operator
333
- 8773 => "cong", # congruent to
334
- 8776 => "asymp", # almost equal to
335
- 8800 => "ne", # not equal to
336
- 8801 => "equiv", # identical toXCOMMAX equivalent to
337
- 8804 => "le", # less-than or equal to
338
- 8805 => "ge", # greater-than or equal to
339
- 8834 => "sub", # subset of
340
- 8835 => "sup", # superset of
341
- 8836 => "nsub", # not a subset of
342
- 8838 => "sube", # subset of or equal to
343
- 8839 => "supe", # superset of or equal to
344
- 8853 => "oplus", # circled plus
345
- 8855 => "otimes", # circled times
346
- 8869 => "perp", # up tack
347
- 8901 => "sdot", # dot operator
348
- 8968 => "lceil", # left ceiling
349
- 8969 => "rceil", # right ceiling
350
- 8970 => "lfloor", # left floor
351
- 8971 => "rfloor", # right floor
352
- 9001 => "lang", # left-pointing angle bracket
353
- 9002 => "rang", # right-pointing angle bracket
354
- 9674 => "loz", # lozenge
355
- 9824 => "spades", # black spade suit
356
- 9827 => "clubs", # black club suit
357
- 9829 => "hearts", # black heart suit
358
- 9830 => "diams" # black diamond suit
359
- }.freeze
360
-
361
- # Allowed URL schemes
362
- #
363
- # @since 0.4.0
364
- # @api private
365
- #
366
- # @see Hanami::Utils::Escape.url
367
- DEFAULT_URL_SCHEMES = %w[http https mailto].freeze
368
-
369
- # The output of an escape.
370
- #
371
- # It's marked with this special class for two reasons:
372
- #
373
- # * Don't double escape the same string (this is for `Hanami::Helpers`
374
- # compatibility)
375
- # * Leave open the possibility to developers to mark a string as safe
376
- # with an higher API (eg. `#raw` in `Hanami::View` or `Hanami::Helpers`)
377
- #
378
- # @since 0.4.0
379
- # @api private
380
- class SafeString < ::String
381
- # @return [SafeString] the duped string
382
- #
383
- # @since 0.4.0
384
- # @api private
385
- #
386
- # @see http://www.ruby-doc.org/core/String.html#method-i-to_s
387
- def to_s
388
- dup
389
- end
390
-
391
- # Encode the string the given encoding
392
- #
393
- # @return [SafeString] an encoded SafeString
394
- #
395
- # @since 0.4.0
396
- # @api private
397
- #
398
- # @see http://www.ruby-doc.org/core/String.html#method-i-encode
399
- def encode(*args)
400
- self.class.new super
401
- end
402
- end
403
-
404
- # Escapes HTML contents
405
- #
406
- # This MUST be used only for tag contents.
407
- # Please use `html_attribute` for escaping HTML attributes.
408
- #
409
- # @param input [String] the input
410
- #
411
- # @return [String] the escaped string
412
- #
413
- # @since 0.4.0
414
- #
415
- # @see https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet OWASP XSS Cheat Sheet Rule #1
416
- #
417
- # @example Good practice
418
- # <div><%= Hanami::Utils::Escape.html('<script>alert(1);</script>') %></div>
419
- # <div>&lt;script&gt;alert(1);&lt;&#x2F;script&gt;</div>
420
- #
421
- # @example Bad practice
422
- # # WRONG Use Escape.html_attribute instead
423
- # <a title="<%= Hanami::Utils::Escape.html('...') %>">link</a>
424
- def self.html(input)
425
- input = encode(input)
426
- return input if input.is_a?(SafeString)
427
-
428
- result = SafeString.new
429
-
430
- input.each_char do |chr|
431
- result << HTML_CHARS.fetch(chr, chr)
432
- end
433
-
434
- result
435
- end
436
-
437
- # Escapes HTML attributes
438
- #
439
- # This can be used both for HTML attributes and contents.
440
- # Please note that this is more computational expensive.
441
- # If you need to escape only HTML contents, please use `.html`.
442
- #
443
- # @param input [String] the input
444
- #
445
- # @return [String] the escaped string
446
- #
447
- # @since 0.4.0
448
- #
449
- # @see https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet OWASP XSS Cheat Sheet Rule #2
450
- #
451
- # @example Good practice
452
- # <a title="<%= Hanami::Utils::Escape.html_attribute('...') %>">link</a>
453
- #
454
- # @example Good but expensive practice
455
- # # Alternatively you can use Escape.html
456
- # <p><%= Hanami::Utils::Escape.html_attribute('...') %></p>
457
- def self.html_attribute(input)
458
- input = encode(input)
459
- return input if input.is_a?(SafeString)
460
-
461
- result = SafeString.new
462
-
463
- input.each_char do |chr|
464
- result << encode_char(chr, HTML_ATTRIBUTE_SAFE_CHARS)
465
- end
466
-
467
- result
468
- end
469
-
470
- # Escapes URL for HTML attributes (href, src, etc..).
471
- #
472
- # It extracts from the given input the first valid URL that matches the
473
- # whitelisted schemes (default: http, https and mailto).
474
- #
475
- # It's possible to pass a second optional argument to specify different
476
- # schemes.
477
- #
478
- # @param input [String] the input
479
- # @param schemes [Array<String>] an array of whitelisted schemes
480
- #
481
- # @return [String] the escaped string
482
- #
483
- # @since 0.4.0
484
- #
485
- # @see Hanami::Utils::Escape::DEFAULT_URL_SCHEMES
486
- # @see http://www.ruby-doc.org/stdlib/libdoc/uri/rdoc/URI.html#method-c-extract
487
- #
488
- # @example Basic usage
489
- # <%
490
- # good_input = "http://hanamirb.org"
491
- # evil_input = "javascript:alert('xss')"
492
- #
493
- # escaped_good_input = Hanami::Utils::Escape.url(good_input) # => "http://hanamirb.org"
494
- # escaped_evil_input = Hanami::Utils::Escape.url(evil_input) # => ""
495
- # %>
496
- #
497
- # <a href="<%= escaped_good_input %>">personal website</a>
498
- # <a href="<%= escaped_evil_input %>">personal website</a>
499
- #
500
- # @example Custom scheme
501
- # <%
502
- # schemes = ['ftp', 'ftps']
503
- #
504
- # accepted = "ftps://ftp.example.org"
505
- # rejected = "http://www.example.org"
506
- #
507
- # escaped_accepted = Hanami::Utils::Escape.url(accepted) # => "ftps://ftp.example.org"
508
- # escaped_rejected = Hanami::Utils::Escape.url(rejected) # => ""
509
- # %>
510
- #
511
- # <a href="<%= escaped_accepted %>">FTP</a>
512
- # <a href="<%= escaped_rejected %>">FTP</a>
513
- def self.url(input, schemes = DEFAULT_URL_SCHEMES)
514
- input = encode(input)
515
- return input if input.is_a?(SafeString)
516
-
517
- SafeString.new(
518
- URI::DEFAULT_PARSER.extract(
519
- URI.decode_www_form_component(input),
520
- schemes
521
- ).first.to_s
522
- )
523
- end
524
-
525
- class << self
526
- private
527
-
528
- # Encodes the given string into UTF-8
529
- #
530
- # @param input [String] the input
531
- #
532
- # @return [String] an UTF-8 encoded string
533
- #
534
- # @since 0.4.0
535
- # @api private
536
- def encode(input)
537
- return "" if input.nil?
538
-
539
- input.to_s.encode(Encoding::UTF_8)
540
- rescue Encoding::UndefinedConversionError
541
- input.dup.force_encoding(Encoding::UTF_8)
542
- end
543
-
544
- # Encode the given UTF-8 char.
545
- #
546
- # @param char [String] an UTF-8 char
547
- # @param safe_chars [Hash] a table of safe chars
548
- #
549
- # @return [String] an HTML encoded string
550
- #
551
- # @since 0.4.0
552
- # @api private
553
- def encode_char(char, safe_chars = {})
554
- return char if safe_chars[char]
555
-
556
- code = char.ord
557
- hex = hex_for_non_alphanumeric_code(code)
558
- return char if hex.nil?
559
-
560
- hex = REPLACEMENT_HEX if NON_PRINTABLE_CHARS[code]
561
-
562
- if entity = HTML_ENTITIES[code]
563
- "&#{entity};"
564
- else
565
- "&#x#{hex};"
566
- end
567
- end
568
-
569
- # Transforms the given char code
570
- #
571
- # @since 0.4.0
572
- # @api private
573
- def hex_for_non_alphanumeric_code(input)
574
- if input < LOW_HEX_CODE_LIMIT
575
- HEX_CODES[input]
576
- else
577
- input.to_s(HEX_BASE)
578
- end
579
- end
580
- end
581
- end
582
- end
583
- end