sanitize 6.1.3 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +32 -14
- data/LICENSE +3 -1
- data/README.md +120 -238
- data/lib/sanitize/config/basic.rb +15 -15
- data/lib/sanitize/config/default.rb +45 -45
- data/lib/sanitize/config/relaxed.rb +136 -32
- data/lib/sanitize/config/restricted.rb +2 -2
- data/lib/sanitize/config.rb +12 -14
- data/lib/sanitize/css.rb +308 -308
- data/lib/sanitize/transformers/clean_cdata.rb +9 -9
- data/lib/sanitize/transformers/clean_comment.rb +9 -9
- data/lib/sanitize/transformers/clean_css.rb +59 -55
- data/lib/sanitize/transformers/clean_doctype.rb +15 -15
- data/lib/sanitize/transformers/clean_element.rb +220 -237
- data/lib/sanitize/version.rb +3 -1
- data/lib/sanitize.rb +38 -38
- data/test/common.rb +4 -3
- data/test/test_clean_comment.rb +26 -25
- data/test/test_clean_css.rb +14 -13
- data/test/test_clean_doctype.rb +21 -20
- data/test/test_clean_element.rb +258 -273
- data/test/test_config.rb +22 -21
- data/test/test_malicious_css.rb +20 -19
- data/test/test_malicious_html.rb +100 -99
- data/test/test_parser.rb +26 -25
- data/test/test_sanitize.rb +70 -69
- data/test/test_sanitize_css.rb +149 -114
- data/test/test_transformers.rb +81 -83
- metadata +14 -43
@@ -1,30 +1,30 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Sanitize
|
4
4
|
module Config
|
5
5
|
BASIC = freeze_config(
|
6
|
-
:
|
6
|
+
elements: RESTRICTED[:elements] + %w[
|
7
7
|
a abbr blockquote br cite code dd dfn dl dt kbd li mark ol p pre q s
|
8
8
|
samp small strike sub sup time ul var
|
9
9
|
],
|
10
10
|
|
11
|
-
:
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
attributes: {
|
12
|
+
"a" => %w[href],
|
13
|
+
"abbr" => %w[title],
|
14
|
+
"blockquote" => %w[cite],
|
15
|
+
"dfn" => %w[title],
|
16
|
+
"q" => %w[cite],
|
17
|
+
"time" => %w[datetime pubdate]
|
18
18
|
},
|
19
19
|
|
20
|
-
:
|
21
|
-
|
20
|
+
add_attributes: {
|
21
|
+
"a" => {"rel" => "nofollow"}
|
22
22
|
},
|
23
23
|
|
24
|
-
:
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
protocols: {
|
25
|
+
"a" => {"href" => ["ftp", "http", "https", "mailto", :relative]},
|
26
|
+
"blockquote" => {"cite" => ["http", "https", :relative]},
|
27
|
+
"q" => {"cite" => ["http", "https", :relative]}
|
28
28
|
}
|
29
29
|
)
|
30
30
|
end
|
@@ -1,55 +1,55 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Sanitize
|
4
4
|
module Config
|
5
5
|
DEFAULT = freeze_config(
|
6
6
|
# HTML attributes to add to specific elements. By default, no attributes
|
7
7
|
# are added.
|
8
|
-
:
|
8
|
+
add_attributes: {},
|
9
9
|
|
10
10
|
# Whether or not to allow HTML comments. Allowing comments is strongly
|
11
11
|
# discouraged, since IE allows script execution within conditional
|
12
12
|
# comments.
|
13
|
-
:
|
13
|
+
allow_comments: false,
|
14
14
|
|
15
15
|
# Whether or not to allow well-formed HTML doctype declarations such as
|
16
16
|
# "<!DOCTYPE html>" when sanitizing a document. This setting is ignored
|
17
17
|
# when sanitizing fragments.
|
18
|
-
:
|
18
|
+
allow_doctype: false,
|
19
19
|
|
20
20
|
# HTML attributes to allow in specific elements. By default, no attributes
|
21
21
|
# are allowed. Use the symbol :data to indicate that arbitrary HTML5
|
22
22
|
# data-* attributes should be allowed.
|
23
|
-
:
|
23
|
+
attributes: {},
|
24
24
|
|
25
25
|
# CSS sanitization settings.
|
26
|
-
:
|
26
|
+
css: {
|
27
27
|
# Whether or not to allow CSS comments.
|
28
|
-
:
|
28
|
+
allow_comments: false,
|
29
29
|
|
30
30
|
# Whether or not to allow browser compatibility hacks such as the IE *
|
31
31
|
# and _ hacks. These are generally harmless, but technically result in
|
32
32
|
# invalid CSS.
|
33
|
-
:
|
33
|
+
allow_hacks: false,
|
34
34
|
|
35
35
|
# CSS at-rules to allow that may not have associated blocks (e.g.
|
36
36
|
# "import").
|
37
37
|
#
|
38
38
|
# https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
39
|
-
:
|
39
|
+
at_rules: [],
|
40
40
|
|
41
41
|
# CSS at-rules to allow whose blocks may contain properties (e.g.
|
42
42
|
# "font-face").
|
43
|
-
:
|
43
|
+
at_rules_with_properties: [],
|
44
44
|
|
45
45
|
# CSS at-rules to allow whose blocks may contain styles (e.g. "media").
|
46
|
-
:
|
46
|
+
at_rules_with_styles: [],
|
47
47
|
|
48
48
|
# CSS properties to allow.
|
49
|
-
:
|
49
|
+
properties: [],
|
50
50
|
|
51
51
|
# URL protocols to allow in CSS URLs.
|
52
|
-
:
|
52
|
+
protocols: []
|
53
53
|
},
|
54
54
|
|
55
55
|
# HTML elements to allow. By default, no elements are allowed (which means
|
@@ -59,16 +59,16 @@ class Sanitize
|
|
59
59
|
# elements (elements in the MathML or SVG namespaces). Do not add `math`
|
60
60
|
# or `svg` to this list! If you do, you may create a security
|
61
61
|
# vulnerability in your application.
|
62
|
-
:
|
62
|
+
elements: [],
|
63
63
|
|
64
64
|
# HTML parsing options to pass to Nokogumbo.
|
65
65
|
# https://github.com/rubys/nokogumbo/tree/v2.0.1#parsing-options
|
66
|
-
:
|
66
|
+
parser_options: {},
|
67
67
|
|
68
68
|
# URL handling protocols to allow in specific attributes. By default, no
|
69
69
|
# protocols are allowed. Use :relative in place of a protocol if you want
|
70
70
|
# to allow relative URLs sans protocol.
|
71
|
-
:
|
71
|
+
protocols: {},
|
72
72
|
|
73
73
|
# If this is true, Sanitize will remove the contents of any filtered
|
74
74
|
# elements in addition to the elements themselves. By default, Sanitize
|
@@ -78,45 +78,45 @@ class Sanitize
|
|
78
78
|
# If this is an Array or Set of element names, then only the contents of
|
79
79
|
# the specified elements (when filtered) will be removed, and the contents
|
80
80
|
# of all other filtered elements will be left behind.
|
81
|
-
:
|
81
|
+
remove_contents: %w[
|
82
82
|
iframe math noembed noframes noscript plaintext script style svg xmp
|
83
83
|
],
|
84
84
|
|
85
85
|
# Transformers allow you to filter or alter nodes using custom logic. See
|
86
86
|
# README.md for details and examples.
|
87
|
-
:
|
87
|
+
transformers: [],
|
88
88
|
|
89
89
|
# Elements which, when removed, should have their contents surrounded by
|
90
90
|
# values specified with `before` and `after` keys to preserve readability.
|
91
91
|
# For example, `foo<div>bar</div>baz` will become 'foo bar baz' when the
|
92
92
|
# <div> is removed.
|
93
|
-
:
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
93
|
+
whitespace_elements: {
|
94
|
+
"address" => {before: " ", after: " "},
|
95
|
+
"article" => {before: " ", after: " "},
|
96
|
+
"aside" => {before: " ", after: " "},
|
97
|
+
"blockquote" => {before: " ", after: " "},
|
98
|
+
"br" => {before: " ", after: " "},
|
99
|
+
"dd" => {before: " ", after: " "},
|
100
|
+
"div" => {before: " ", after: " "},
|
101
|
+
"dl" => {before: " ", after: " "},
|
102
|
+
"dt" => {before: " ", after: " "},
|
103
|
+
"footer" => {before: " ", after: " "},
|
104
|
+
"h1" => {before: " ", after: " "},
|
105
|
+
"h2" => {before: " ", after: " "},
|
106
|
+
"h3" => {before: " ", after: " "},
|
107
|
+
"h4" => {before: " ", after: " "},
|
108
|
+
"h5" => {before: " ", after: " "},
|
109
|
+
"h6" => {before: " ", after: " "},
|
110
|
+
"header" => {before: " ", after: " "},
|
111
|
+
"hgroup" => {before: " ", after: " "},
|
112
|
+
"hr" => {before: " ", after: " "},
|
113
|
+
"li" => {before: " ", after: " "},
|
114
|
+
"nav" => {before: " ", after: " "},
|
115
|
+
"ol" => {before: " ", after: " "},
|
116
|
+
"p" => {before: " ", after: " "},
|
117
|
+
"pre" => {before: " ", after: " "},
|
118
|
+
"section" => {before: " ", after: " "},
|
119
|
+
"ul" => {before: " ", after: " "}
|
120
120
|
}
|
121
121
|
)
|
122
122
|
end
|
@@ -1,46 +1,44 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class Sanitize
|
4
4
|
module Config
|
5
5
|
RELAXED = freeze_config(
|
6
|
-
:
|
6
|
+
elements: BASIC[:elements] + %w[
|
7
7
|
address article aside bdi bdo body caption col colgroup data del div
|
8
8
|
figcaption figure footer h1 h2 h3 h4 h5 h6 head header hgroup hr html
|
9
9
|
img ins main nav rp rt ruby section span style summary table tbody
|
10
10
|
td tfoot th thead title tr wbr
|
11
11
|
],
|
12
12
|
|
13
|
-
:
|
13
|
+
allow_doctype: true,
|
14
14
|
|
15
|
-
:
|
16
|
-
:all
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
),
|
15
|
+
attributes: merge(BASIC[:attributes],
|
16
|
+
:all => %w[class dir hidden id lang style tabindex title translate],
|
17
|
+
"a" => %w[href hreflang name rel],
|
18
|
+
"col" => %w[span width],
|
19
|
+
"colgroup" => %w[span width],
|
20
|
+
"data" => %w[value],
|
21
|
+
"del" => %w[cite datetime],
|
22
|
+
"img" => %w[align alt border height src srcset width],
|
23
|
+
"ins" => %w[cite datetime],
|
24
|
+
"li" => %w[value],
|
25
|
+
"ol" => %w[reversed start type],
|
26
|
+
"style" => %w[media scoped type],
|
27
|
+
"table" => %w[align bgcolor border cellpadding cellspacing frame rules sortable summary width],
|
28
|
+
"td" => %w[abbr align axis colspan headers rowspan valign width],
|
29
|
+
"th" => %w[abbr align axis colspan headers rowspan scope sorted valign width],
|
30
|
+
"ul" => %w[type]),
|
32
31
|
|
33
|
-
:
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
),
|
32
|
+
protocols: merge(BASIC[:protocols],
|
33
|
+
"del" => {"cite" => ["http", "https", :relative]},
|
34
|
+
"img" => {"src" => ["http", "https", :relative]},
|
35
|
+
"ins" => {"cite" => ["http", "https", :relative]}),
|
38
36
|
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
37
|
+
css: {
|
38
|
+
allow_comments: true,
|
39
|
+
allow_hacks: true,
|
42
40
|
|
43
|
-
:
|
41
|
+
at_rules_with_properties: %w[
|
44
42
|
bottom-center
|
45
43
|
bottom-left
|
46
44
|
bottom-left-corner
|
@@ -61,19 +59,20 @@ class Sanitize
|
|
61
59
|
top-right-corner
|
62
60
|
],
|
63
61
|
|
64
|
-
:
|
62
|
+
at_rules_with_styles: %w[
|
65
63
|
-moz-keyframes
|
66
64
|
-o-keyframes
|
67
65
|
-webkit-keyframes
|
66
|
+
container
|
68
67
|
document
|
69
68
|
keyframes
|
70
69
|
media
|
71
70
|
supports
|
72
71
|
],
|
73
72
|
|
74
|
-
:
|
73
|
+
protocols: ["http", "https", :relative],
|
75
74
|
|
76
|
-
:
|
75
|
+
properties: %w[
|
77
76
|
-moz-appearance
|
78
77
|
-moz-background-inline-policy
|
79
78
|
-moz-box-sizing
|
@@ -333,6 +332,7 @@ class Sanitize
|
|
333
332
|
-webkit-text-decoration-color
|
334
333
|
-webkit-text-decoration-line
|
335
334
|
-webkit-text-decoration-style
|
335
|
+
-webkit-text-fill-color
|
336
336
|
-webkit-text-size-adjust
|
337
337
|
-webkit-touch-callout
|
338
338
|
-webkit-transform
|
@@ -349,6 +349,7 @@ class Sanitize
|
|
349
349
|
-webkit-user-drag
|
350
350
|
-webkit-wrap-flow
|
351
351
|
-webkit-wrap-through
|
352
|
+
accent-color
|
352
353
|
align-content
|
353
354
|
align-items
|
354
355
|
align-self
|
@@ -356,7 +357,10 @@ class Sanitize
|
|
356
357
|
alignment-baseline
|
357
358
|
all
|
358
359
|
anchor-point
|
360
|
+
anchor-name
|
361
|
+
anchor-scope
|
359
362
|
animation
|
363
|
+
animation-composition
|
360
364
|
animation-delay
|
361
365
|
animation-direction
|
362
366
|
animation-duration
|
@@ -364,11 +368,18 @@ class Sanitize
|
|
364
368
|
animation-iteration-count
|
365
369
|
animation-name
|
366
370
|
animation-play-state
|
371
|
+
animation-range
|
372
|
+
animation-range-end
|
373
|
+
animation-range-start
|
374
|
+
animation-timeline
|
367
375
|
animation-timing-function
|
376
|
+
appearance
|
377
|
+
aspect-ratio
|
368
378
|
azimuth
|
369
379
|
backface-visibility
|
370
380
|
background
|
371
381
|
background-attachment
|
382
|
+
background-blend-mode
|
372
383
|
background-clip
|
373
384
|
background-color
|
374
385
|
background-image
|
@@ -379,24 +390,54 @@ class Sanitize
|
|
379
390
|
baseline-shift
|
380
391
|
binding
|
381
392
|
bleed
|
393
|
+
baseline-source
|
394
|
+
block-ellipsis
|
395
|
+
block-size
|
382
396
|
bookmark-label
|
383
397
|
bookmark-level
|
384
398
|
bookmark-state
|
385
399
|
border
|
400
|
+
border-block
|
401
|
+
border-block-color
|
402
|
+
border-block-end
|
403
|
+
border-block-end-color
|
404
|
+
border-block-end-style
|
405
|
+
border-block-end-width
|
406
|
+
border-block-start
|
407
|
+
border-block-start-color
|
408
|
+
border-block-start-style
|
409
|
+
border-block-start-width
|
410
|
+
border-block-style
|
411
|
+
border-block-width
|
386
412
|
border-bottom
|
387
413
|
border-bottom-color
|
388
414
|
border-bottom-left-radius
|
389
415
|
border-bottom-right-radius
|
390
416
|
border-bottom-style
|
391
417
|
border-bottom-width
|
418
|
+
border-boundary
|
392
419
|
border-collapse
|
393
420
|
border-color
|
421
|
+
border-end-end-radius
|
422
|
+
border-end-start-radius
|
394
423
|
border-image
|
395
424
|
border-image-outset
|
396
425
|
border-image-repeat
|
397
426
|
border-image-slice
|
398
427
|
border-image-source
|
399
428
|
border-image-width
|
429
|
+
border-inline
|
430
|
+
border-inline-color
|
431
|
+
border-inline-end
|
432
|
+
border-inline-end-color
|
433
|
+
border-inline-end-style
|
434
|
+
border-inline-end-width
|
435
|
+
border-inline-start
|
436
|
+
border-inline-start-color
|
437
|
+
border-inline-start-style
|
438
|
+
border-inline-start-width
|
439
|
+
border-inline-style
|
440
|
+
border-inline-width
|
400
441
|
border-left
|
401
442
|
border-left-color
|
402
443
|
border-left-style
|
@@ -407,6 +448,8 @@ class Sanitize
|
|
407
448
|
border-right-style
|
408
449
|
border-right-width
|
409
450
|
border-spacing
|
451
|
+
border-start-end-radius
|
452
|
+
border-start-start-radius
|
410
453
|
border-style
|
411
454
|
border-top
|
412
455
|
border-top-color
|
@@ -426,15 +469,20 @@ class Sanitize
|
|
426
469
|
break-inside
|
427
470
|
caption-side
|
428
471
|
chains
|
472
|
+
caret
|
473
|
+
caret-color
|
474
|
+
caret-shape
|
429
475
|
clear
|
430
476
|
clip
|
431
477
|
clip-path
|
432
478
|
clip-rule
|
433
479
|
color
|
434
480
|
color-interpolation
|
481
|
+
color-adjust
|
435
482
|
color-interpolation-filters
|
436
483
|
color-profile
|
437
484
|
color-rendering
|
485
|
+
color-scheme
|
438
486
|
column-count
|
439
487
|
column-fill
|
440
488
|
column-gap
|
@@ -446,7 +494,17 @@ class Sanitize
|
|
446
494
|
column-width
|
447
495
|
columns
|
448
496
|
contain
|
497
|
+
contain-intrinsic-block-size
|
498
|
+
contain-intrinsic-height
|
499
|
+
contain-intrinsic-inline-size
|
500
|
+
contain-intrinsic-size
|
501
|
+
contain-intrinsic-width
|
502
|
+
container
|
503
|
+
container-name
|
504
|
+
container-type
|
449
505
|
content
|
506
|
+
content-visibility
|
507
|
+
continue
|
450
508
|
counter-increment
|
451
509
|
counter-reset
|
452
510
|
counter-set
|
@@ -486,20 +544,33 @@ class Sanitize
|
|
486
544
|
font-feature-settings
|
487
545
|
font-kerning
|
488
546
|
font-language-override
|
547
|
+
font-optical-sizing
|
548
|
+
font-palette
|
489
549
|
font-size
|
490
550
|
font-size-adjust
|
491
551
|
font-stretch
|
492
552
|
font-style
|
493
553
|
font-synthesis
|
554
|
+
font-synthesis-position
|
555
|
+
font-synthesis-small-caps
|
556
|
+
font-synthesis-style
|
557
|
+
font-synthesis-weight
|
494
558
|
font-variant
|
495
559
|
font-variant-alternates
|
496
560
|
font-variant-caps
|
497
561
|
font-variant-east-asian
|
562
|
+
font-variant-emoji
|
498
563
|
font-variant-ligatures
|
499
564
|
font-variant-numeric
|
500
565
|
font-variant-position
|
566
|
+
font-variation-settings
|
501
567
|
font-weight
|
502
568
|
glyph-orientation-horizontal
|
569
|
+
font-width
|
570
|
+
footnote-display
|
571
|
+
footnote-policy
|
572
|
+
forced-color-adjust
|
573
|
+
gap
|
503
574
|
glyph-orientation-vertical
|
504
575
|
grid
|
505
576
|
grid-area
|
@@ -658,22 +729,33 @@ class Sanitize
|
|
658
729
|
tab-size
|
659
730
|
table-layout
|
660
731
|
text-align
|
732
|
+
text-align-all
|
661
733
|
text-align-last
|
662
734
|
text-anchor
|
663
735
|
text-combine-horizontal
|
736
|
+
text-autospace
|
737
|
+
text-box
|
738
|
+
text-box-edge
|
739
|
+
text-box-trim
|
664
740
|
text-combine-upright
|
665
741
|
text-decoration
|
666
742
|
text-decoration-color
|
667
743
|
text-decoration-line
|
668
744
|
text-decoration-skip
|
745
|
+
text-decoration-skip-box
|
669
746
|
text-decoration-skip-ink
|
747
|
+
text-decoration-skip-inset
|
748
|
+
text-decoration-skip-self
|
749
|
+
text-decoration-skip-spaces
|
670
750
|
text-decoration-style
|
671
751
|
text-decoration-thickness
|
672
752
|
text-emphasis
|
673
753
|
text-emphasis-color
|
674
754
|
text-emphasis-position
|
755
|
+
text-emphasis-skip
|
675
756
|
text-emphasis-style
|
676
757
|
text-height
|
758
|
+
text-group-align
|
677
759
|
text-indent
|
678
760
|
text-justify
|
679
761
|
text-orientation
|
@@ -682,12 +764,19 @@ class Sanitize
|
|
682
764
|
text-shadow
|
683
765
|
text-size-adjust
|
684
766
|
text-space-collapse
|
767
|
+
text-spacing
|
768
|
+
text-spacing-trim
|
685
769
|
text-transform
|
770
|
+
text-underline-offset
|
686
771
|
text-underline-position
|
687
772
|
text-wrap
|
773
|
+
text-wrap-mode
|
774
|
+
text-wrap-style
|
775
|
+
timeline-scope
|
688
776
|
top
|
689
777
|
touch-action
|
690
778
|
transform
|
779
|
+
transform-box
|
691
780
|
transform-origin
|
692
781
|
transform-style
|
693
782
|
transition
|
@@ -695,9 +784,18 @@ class Sanitize
|
|
695
784
|
transition-duration
|
696
785
|
transition-property
|
697
786
|
transition-timing-function
|
787
|
+
translate
|
698
788
|
unicode-bidi
|
699
789
|
unicode-range
|
790
|
+
user-select
|
700
791
|
vertical-align
|
792
|
+
view-timeline
|
793
|
+
view-timeline-axis
|
794
|
+
view-timeline-inset
|
795
|
+
view-timeline-name
|
796
|
+
view-transition-class
|
797
|
+
view-transition-group
|
798
|
+
view-transition-name
|
701
799
|
visibility
|
702
800
|
voice-balance
|
703
801
|
voice-duration
|
@@ -709,13 +807,19 @@ class Sanitize
|
|
709
807
|
voice-volume
|
710
808
|
volume
|
711
809
|
white-space
|
810
|
+
white-space-collapse
|
811
|
+
white-space-trim
|
712
812
|
widows
|
713
813
|
width
|
714
814
|
will-change
|
715
815
|
word-break
|
816
|
+
word-space-transform
|
716
817
|
word-spacing
|
717
818
|
word-wrap
|
819
|
+
wrap-after
|
820
|
+
wrap-before
|
718
821
|
wrap-flow
|
822
|
+
wrap-inside
|
719
823
|
wrap-through
|
720
824
|
writing-mode
|
721
825
|
z-index
|
data/lib/sanitize/config.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "set"
|
4
4
|
|
5
5
|
class Sanitize
|
6
6
|
module Config
|
7
|
-
|
8
7
|
# Deeply freezes and returns the given configuration Hash.
|
9
8
|
def self.freeze_config(config)
|
10
9
|
if Hash === config
|
11
|
-
config.each_value {|c| freeze_config(c) }
|
10
|
+
config.each_value { |c| freeze_config(c) }
|
12
11
|
elsif Array === config || Set === config
|
13
|
-
config.each {|c| freeze_config(c) }
|
12
|
+
config.each { |c| freeze_config(c) }
|
14
13
|
end
|
15
14
|
|
16
15
|
config.freeze
|
@@ -22,11 +21,11 @@ class Sanitize
|
|
22
21
|
# This is the safest way to use a built-in Sanitize config as the basis for
|
23
22
|
# your own custom config.
|
24
23
|
def self.merge(config, other_config = {})
|
25
|
-
raise ArgumentError,
|
26
|
-
raise ArgumentError,
|
24
|
+
raise ArgumentError, "config must be a Hash" unless Hash === config
|
25
|
+
raise ArgumentError, "other_config must be a Hash" unless Hash === other_config
|
27
26
|
|
28
27
|
merged = {}
|
29
|
-
keys
|
28
|
+
keys = Set.new(config.keys + other_config.keys)
|
30
29
|
|
31
30
|
keys.each do |key|
|
32
31
|
oldval = config[key]
|
@@ -34,12 +33,12 @@ class Sanitize
|
|
34
33
|
if other_config.has_key?(key)
|
35
34
|
newval = other_config[key]
|
36
35
|
|
37
|
-
if Hash === oldval && Hash === newval
|
38
|
-
|
36
|
+
merged[key] = if Hash === oldval && Hash === newval
|
37
|
+
oldval.empty? ? newval.dup : merge(oldval, newval)
|
39
38
|
elsif Array === newval && key != :transformers
|
40
|
-
|
39
|
+
Set.new(newval)
|
41
40
|
else
|
42
|
-
|
41
|
+
can_dupe?(newval) ? newval.dup : newval
|
43
42
|
end
|
44
43
|
else
|
45
44
|
merged[key] = can_dupe?(oldval) ? oldval.dup : oldval
|
@@ -52,9 +51,8 @@ class Sanitize
|
|
52
51
|
# Returns `true` if `dup` may be safely called on _value_, `false`
|
53
52
|
# otherwise.
|
54
53
|
def self.can_dupe?(value)
|
55
|
-
!(
|
54
|
+
!(value == true || value == false || value.nil? || Method === value || Numeric === value || Symbol === value)
|
56
55
|
end
|
57
56
|
private_class_method :can_dupe?
|
58
|
-
|
59
57
|
end
|
60
58
|
end
|