11
11
12
12
namespace Symfony \Component \HtmlSanitizer \Visitor ;
13
13
14
+ use Symfony \Component \HtmlSanitizer \HtmlSanitizerAction ;
14
15
use Symfony \Component \HtmlSanitizer \HtmlSanitizerConfig ;
15
16
use Symfony \Component \HtmlSanitizer \TextSanitizer \StringSanitizer ;
16
17
use Symfony \Component \HtmlSanitizer \Visitor \AttributeSanitizer \AttributeSanitizerInterface ;
33
34
*/
34
35
final class DomVisitor
35
36
{
37
+ private HtmlSanitizerAction $ defaultAction = HtmlSanitizerAction::Drop;
38
+
36
39
/**
37
40
* Registry of attributes to forcefully set on nodes, index by element and attribute.
38
41
*
@@ -49,11 +52,11 @@ final class DomVisitor
49
52
private array $ attributeSanitizers = [];
50
53
51
54
/**
52
- * @param array<string, false |array<string, bool>> $elementsConfig Registry of allowed/blocked elements:
53
- * * If an element is present as a key and contains an array, the element should be allowed
54
- * and the array is the list of allowed attributes.
55
- * * If an element is present as a key and contains "false", the element should be blocked .
56
- * * If an element is not present as a key, the element should be dropped .
55
+ * @param array<string, HtmlSanitizerAction |array<string, bool>> $elementsConfig Registry of allowed/blocked elements:
56
+ * * If an element is present as a key and contains an array, the element should be allowed
57
+ * and the array is the list of allowed attributes.
58
+ * * If an element is present as a key and contains an HtmlSanitizerAction, that action applies .
59
+ * * If an element is not present as a key, the default action applies .
57
60
*/
58
61
public function __construct (
59
62
private HtmlSanitizerConfig $ config ,
@@ -68,6 +71,8 @@ public function __construct(
68
71
}
69
72
}
70
73
}
74
+
75
+ $ this ->defaultAction = $ config ->getDefaultAction ();
71
76
}
72
77
73
78
public function visit (\DOMDocumentFragment $ domNode ): ?NodeInterface
@@ -82,32 +87,45 @@ private function visitNode(\DOMNode $domNode, Cursor $cursor): void
82
87
{
83
88
$ nodeName = StringSanitizer::htmlLower ($ domNode ->nodeName );
84
89
85
- // Element should be dropped, including its children
86
- if (!\array_key_exists ($ nodeName , $ this ->elementsConfig )) {
87
- return ;
90
+ // Visit recursively if the node was not dropped
91
+ if ($ this ->enterNode ($ nodeName , $ domNode , $ cursor )) {
92
+ $ this ->visitChildren ($ domNode , $ cursor );
93
+ $ cursor ->node = $ cursor ->node ->getParent ();
88
94
}
89
-
90
- // Otherwise, visit recursively
91
- $ this ->enterNode ($ nodeName , $ domNode , $ cursor );
92
- $ this ->visitChildren ($ domNode , $ cursor );
93
- $ cursor ->node = $ cursor ->node ->getParent ();
94
95
}
95
96
96
- private function enterNode (string $ domNodeName , \DOMNode $ domNode , Cursor $ cursor ): void
97
+ private function enterNode (string $ domNodeName , \DOMNode $ domNode , Cursor $ cursor ): bool
97
98
{
99
+ if (!\array_key_exists ($ domNodeName , $ this ->elementsConfig )) {
100
+ $ action = $ this ->defaultAction ;
101
+ $ allowedAttributes = [];
102
+ } else {
103
+ if (\is_array ($ this ->elementsConfig [$ domNodeName ])) {
104
+ $ action = HtmlSanitizerAction::Allow;
105
+ $ allowedAttributes = $ this ->elementsConfig [$ domNodeName ];
106
+ } else {
107
+ $ action = $ this ->elementsConfig [$ domNodeName ];
108
+ $ allowedAttributes = [];
109
+ }
110
+ }
111
+
112
+ if (HtmlSanitizerAction::Drop === $ action ) {
113
+ return false ;
114
+ }
115
+
98
116
// Element should be blocked, retaining its children
99
- if (false === $ this -> elementsConfig [ $ domNodeName ] ) {
117
+ if (HtmlSanitizerAction::Block === $ action ) {
100
118
$ node = new BlockedNode ($ cursor ->node );
101
119
102
120
$ cursor ->node ->addChild ($ node );
103
121
$ cursor ->node = $ node ;
104
122
105
- return ;
123
+ return true ;
106
124
}
107
125
108
126
// Otherwise create the node
109
127
$ node = new Node ($ cursor ->node , $ domNodeName );
110
- $ this ->setAttributes ($ domNodeName , $ domNode , $ node , $ this -> elementsConfig [ $ domNodeName ] );
128
+ $ this ->setAttributes ($ domNodeName , $ domNode , $ node , $ allowedAttributes );
111
129
112
130
// Force configured attributes
113
131
foreach ($ this ->forcedAttributes [$ domNodeName ] ?? [] as $ attribute => $ value ) {
@@ -116,6 +134,8 @@ private function enterNode(string $domNodeName, \DOMNode $domNode, Cursor $curso
116
134
117
135
$ cursor ->node ->addChild ($ node );
118
136
$ cursor ->node = $ node ;
137
+
138
+ return true ;
119
139
}
120
140
121
141
private function visitChildren (\DOMNode $ domNode , Cursor $ cursor ): void
0 commit comments