Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(381)

Side by Side Diff: tools/dom/src/NodeValidatorBuilder.dart

Issue 16374007: First rev of Safe DOM (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 part of dart.dom.html;
6
7
8 /**
9 * Class which helps construct standard node validation policies.
10 *
11 * By default this will not accept anything, but the 'allow*' functions can be
12 * used to expand what types of elements or attributes are allowed.
13 *
14 * All allow functions are additive- elements will be accepted if they are
15 * accepted by any specific rule.
16 */
17 class NodeValidatorBuilder implements NodeValidator {
18
19 final List<NodeValidator> _validators = <NodeValidator>[];
20
21 NodeValidatorBuilder() {
22 }
23
24 /**
25 * Creates a new NodeValidatorBuilder which accepts common constructs.
26 *
27 * By default this will accept HTML5 elements and attributes with the default
28 * [UriPolicy] and templating elements.
29 */
30 factory NodeValidatorBuilder.common() {
31 return new NodeValidatorBuilder()
32 ..allowHtml5()
33 ..allowTemplating();
34 }
35
36 /**
37 * Allows navigation elements- Form and Anchor tags, along with common
38 * attributes.
39 *
40 * The UriPolicy can be used to restrict the locations the navigation elements
41 * are allowed to direct to. By default this will use the default [UriPolicy].
42 */
43 void allowNavigation([UriPolicy uriPolicy]) {
44 if (uriPolicy == null) {
45 uriPolicy = new UriPolicy();
46 }
47 add(new _SimpleNodeValidator.allowNavigation(uriPolicy));
48 }
49
50 /**
51 * Allows image elements.
52 *
53 * The UriPolicy can be used to restrict the locations the images may be
54 * loaded from. By default this will use the default [UriPolicy].
55 */
56 void allowImages([UriPolicy uriPolicy]) {
57 if (uriPolicy == null) {
58 uriPolicy = new UriPolicy();
59 }
60 add(new _SimpleNodeValidator.allowImages(uriPolicy));
61 }
62
63 /**
64 * Allow basic text elements.
65 *
66 * This allows a subset of HTML5 elements, specifically just these tags and
67 * no attributes.
68 *
69 * * B
70 * * BLOCKQUOTE
71 * * BR
72 * * EM
73 * * H1
74 * * H2
75 * * H3
76 * * H4
77 * * H5
78 * * H6
79 * * HR
80 * * I
81 * * LI
82 * * OL
83 * * P
84 * * SPAN
85 * * UL
86 */
87 void allowTextElements() {
88 add(new _SimpleNodeValidator.allowTextElements());
89 }
90
91 /**
92 * Allow common safe HTML5 elements and attributes.
93 *
94 * This list is based off of the Caja whitelists at:
95 * https://code.google.com/p/google-caja/wiki/CajaWhitelists.
96 *
97 * Common things which are not allowed are script elements, style attributes
98 * and any script handlers.
99 */
100 void allowHtml5({UriPolicy uriPolicy}) {
101 add(new _Html5NodeValidator(uriPolicy: uriPolicy));
102 }
103
104 /**
105 * Allow SVG elements and attributes except for known bad ones.
106 */
107 void allowSvg() {
108 add(new _SvgNodeValidator());
109 }
110
111 /**
112 * Allow custom elements with the specified tag name and specified attributes.
113 *
114 * This will allow the elements as custom tags (such as <x-foo></x-foo>),
115 * but will not allow tag extensions. Use [allowTagExtension] to allow
116 * tag extensions.
117 */
118 void allowCustomElement(String tagName,
119 {UriPolicy uriPolicy,
120 Iterable<String> attributes,
121 Iterable<String> uriAttributes}) {
122
123 var tagNameUpper = tagName.toUpperCase();
Jennifer Messerly 2013/06/06 05:55:53 validate that the tagName is actually a custom ele
blois 2013/06/06 16:59:42 As-is this method works for allowing additional ta
Jennifer Messerly 2013/06/06 19:31:32 Ah good point. Yeah that's a nice use case. Maybe
124 var attrs;
125 if (attributes != null) {
126 attrs =
127 attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
128 }
129 var uriAttrs;
130 if (uriAttributes != null) {
131 uriAttrs =
132 uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
133 }
134 if (uriPolicy == null) {
135 uriPolicy = new UriPolicy();
136 }
137
138 add(new _CustomElementNodeValidator(
139 uriPolicy,
140 [tagNameUpper],
141 attrs,
142 uriAttrs,
143 false,
144 true));
145 }
146
147 /**
148 * Allow custom tag extensions with the specified type name and specified
149 * attributes.
150 *
151 * This will allow tag extensions (such as <div is="x-foo"></div>),
152 * but will not allow custom tags. Use [allowCustomElement] to allow
153 * custom tags.
154 */
155 void allowTagExtension(String tagName, String baseName,
156 {UriPolicy uriPolicy,
157 Iterable<String> attributes,
158 Iterable<String> uriAttributes}) {
159
160 var baseNameUpper = baseName.toUpperCase();
161 var tagNameUpper = tagName.toUpperCase();
162 var attrs;
163 if (attributes != null) {
164 attrs =
165 attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
166 }
167 var uriAttrs;
168 if (uriAttributes != null) {
169 uriAttrs =
170 uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
171 }
172 if (uriPolicy == null) {
173 uriPolicy = new UriPolicy();
174 }
175
176 add(new _CustomElementNodeValidator(
177 uriPolicy,
178 [tagNameUpper, baseNameUpper],
179 attrs,
180 uriAttrs,
181 true,
182 false));
183 }
184
185 void allowElement(String tagName, {UriPolicy uriPolicy,
186 Iterable<String> attributes,
187 Iterable<String> uriAttributes}) {
188
189 allowCustomElement(tagName, uriPolicy: uriPolicy,
190 attributes: attributes,
191 uriAttributes: uriAttributes);
192 }
193
194 /**
195 * Allow templating elements (such as <template> and template-related
196 * attributes.
197 *
198 * This still requires other validators to allow regular attributes to be
199 * bound (such as [allowHtml5]).
200 */
201 void allowTemplating() {
202 add(new _TemplatingNodeValidator());
203 }
204
205 /**
206 * Add an additional validator to the current list of validators.
207 *
208 * Elements and attributes will be accepted if they are accepted by any
209 * validators.
210 */
211 void add(NodeValidator validator) {
212 _validators.add(validator);
213 }
214
215 bool allowsElement(Element element) {
216 return _validators.any((v) => v.allowsElement(element));
217 }
218
219 bool allowsAttribute(Element element, String attributeName, String value) {
220 return _validators.any(
221 (v) => v.allowsAttribute(element, attributeName, value));
222 }
223 }
224
225 class _SimpleNodeValidator implements NodeValidator {
226 final Set<String> allowedElements;
227 final Set<String> allowedAttributes;
228 final Set<String> allowedUriAttributes;
229 final UriPolicy uriPolicy;
230
231 factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
232 return new _SimpleNodeValidator(uriPolicy,
233 allowedElements: [
234 'A',
235 'FORM'],
236 allowedAttributes: [
237 'A::accesskey',
238 'A::coords',
239 'A::hreflang',
240 'A::name',
241 'A::shape',
242 'A::tabindex',
243 'A::target',
244 'A::type',
245 'FORM::accept',
246 'FORM::autocomplete',
247 'FORM::enctype',
248 'FORM::method',
249 'FORM::name',
250 'FORM::novalidate',
251 'FORM::target',
252 ],
253 allowedUriAttributes: [
254 'A::href',
255 'FORM::action',
256 ]);
257 }
258
259 factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
260 return new _SimpleNodeValidator(uriPolicy,
261 allowedElements: [
262 'IMG'
263 ],
264 allowedAttributes: [
265 'IMG::align',
266 'IMG::alt',
267 'IMG::border',
268 'IMG::height',
269 'IMG::hspace',
270 'IMG::ismap',
271 'IMG::name',
272 'IMG::usemap',
273 'IMG::vspace',
274 'IMG::width',
275 ],
276 allowedUriAttributes: [
277 'IMG::src',
278 ]);
279 }
280
281 factory _SimpleNodeValidator.allowTextElements() {
282 return new _SimpleNodeValidator(null,
283 allowedElements: [
284 'B',
285 'BLOCKQUOTE',
286 'BR',
287 'EM',
288 'H1',
289 'H2',
290 'H3',
291 'H4',
292 'H5',
293 'H6',
294 'HR',
295 'I',
296 'LI',
297 'OL',
298 'P',
299 'SPAN',
300 'UL',
301 ]);
302 }
303
304 /**
305 * Elements must be uppercased tag names. For example `'IMG'`.
306 * Attributes must be uppercased tag name followed by :: followed by
307 * lowercase attribute name. For example `'IMG:src'`.
308 */
309 _SimpleNodeValidator(this.uriPolicy,
310 {Iterable<String> allowedElements, Iterable<String> allowedAttributes,
311 Iterable<String> allowedUriAttributes}):
312 this.allowedElements = allowedElements != null ?
313 new Set.from(allowedElements) : new Set(),
314 this.allowedAttributes = allowedAttributes != null ?
315 new Set.from(allowedAttributes) : new Set(),
316 this.allowedUriAttributes = allowedUriAttributes != null ?
317 new Set.from(allowedUriAttributes) : new Set();
318
319 bool allowsElement(Element element) {
320 return allowedElements.contains(element.tagName);
321 }
322
323 bool allowsAttribute(Element element, String attributeName, String value) {
324 var tagName = element.tagName;
325 if (allowedUriAttributes.contains('$tagName::$attributeName')) {
326 return uriPolicy.allowsUri(value);
327 } else if (allowedUriAttributes.contains('*::$attributeName')) {
328 return uriPolicy.allowsUri(value);
329 } else if (allowedAttributes.contains('$tagName::$attributeName')) {
330 return true;
331 } else if (allowedAttributes.contains('*::$attributeName')) {
332 return true;
333 } else if (allowedAttributes.contains('$tagName::*')) {
334 return true;
335 } else if (allowedAttributes.contains('*::*')) {
336 return true;
337 }
338 return false;
339 }
340 }
341
342 class _CustomElementNodeValidator extends _SimpleNodeValidator {
343 final bool allowTypeExtension;
344 final bool allowCustomTag;
345
346 _CustomElementNodeValidator(UriPolicy uriPolicy,
347 Iterable<String> allowedElements,
348 Iterable<String> allowedAttributes,
349 Iterable<String> allowedUriAttributes,
350 bool allowTypeExtension,
351 bool allowCustomTag):
352
353 super(uriPolicy,
354 allowedElements: allowedElements,
355 allowedAttributes: allowedAttributes,
356 allowedUriAttributes: allowedUriAttributes),
357 this.allowTypeExtension = allowTypeExtension == true,
358 this.allowCustomTag = allowCustomTag == true;
359
360 bool allowsElement(Element element) {
361 if (allowTypeExtension) {
362 var isAttr = element.attributes['is'];
363 if (isAttr != null) {
364 return allowedElements.contains(isAttr.toUpperCase()) &&
365 allowedElements.contains(element.tagName);
366 }
367 }
368 return allowCustomTag && allowedElements.contains(element.tagName);
369 }
370
371 bool allowsAttribute(Element element, String attributeName, String value) {
372 if (allowsElement(element)) {
373 if (allowTypeExtension && attributeName == 'is' &&
374 allowedElements.contains(value.toUpperCase())) {
375 return true;
376 }
377 return super.allowsAttribute(element, attributeName, value);
378 }
379 return false;
380 }
381 }
382
383 class _TemplatingNodeValidator extends _SimpleNodeValidator {
384 static const _TEMPLATE_ATTRS =
385 const <String>['bind', 'if', 'ref', 'repeat', 'syntax'];
386
387 final Set<String> _templateAttrs;
388
389 _TemplatingNodeValidator():
390 super(null,
391 allowedElements: [
392 'TEMPLATE'
393 ],
394 allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')),
395 _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
396 }
397
398 bool allowsAttribute(Element element, String attributeName, String value) {
399 if (super.allowsAttribute(element, attributeName, value)) {
400 return true;
401 }
402
403 if (attributeName == 'template' && value == "") {
404 return true;
405 }
406
407 if (element.attributes['template'] == "" ) {
408 return _templateAttrs.contains(attributeName);
409 }
410 return false;
411 }
412 }
413
414
415 class _SvgNodeValidator implements NodeValidator {
416 bool allowsElement(Element element) {
417 if (element is svg.ScriptElement) {
418 return false;
419 }
420 if (element is svg.SvgElement) {
421 return true;
422 }
423 return false;
424 }
425
426 bool allowsAttribute(Element element, String attributeName, String value) {
427 if (attributeName == 'is' || attributeName.startsWith('on')) {
428 return false;
429 }
430 return allowsElement(element);
431 }
432 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698