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

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

Issue 1894713002: Strong html (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: ptal Created 4 years, 8 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
« no previous file with comments | « tools/dom/src/KeyboardEventStream.dart ('k') | tools/dom/src/WrappedList.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.dom.html; 5 part of dart.dom.html;
6 6
7
8 /** 7 /**
9 * Class which helps construct standard node validation policies. 8 * Class which helps construct standard node validation policies.
10 * 9 *
11 * By default this will not accept anything, but the 'allow*' functions can be 10 * 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. 11 * used to expand what types of elements or attributes are allowed.
13 * 12 *
14 * All allow functions are additive- elements will be accepted if they are 13 * All allow functions are additive- elements will be accepted if they are
15 * accepted by any specific rule. 14 * accepted by any specific rule.
16 * 15 *
17 * It is important to remember that sanitization is not just intended to prevent 16 * It is important to remember that sanitization is not just intended to prevent
18 * cross-site scripting attacks, but also to prevent information from being 17 * cross-site scripting attacks, but also to prevent information from being
19 * displayed in unexpected ways. For example something displaying basic 18 * displayed in unexpected ways. For example something displaying basic
20 * formatted text may not expect `<video>` tags to appear. In this case an 19 * formatted text may not expect `<video>` tags to appear. In this case an
21 * empty NodeValidatorBuilder with just [allowTextElements] might be 20 * empty NodeValidatorBuilder with just [allowTextElements] might be
22 * appropriate. 21 * appropriate.
23 */ 22 */
24 class NodeValidatorBuilder implements NodeValidator { 23 class NodeValidatorBuilder implements NodeValidator {
25
26 final List<NodeValidator> _validators = <NodeValidator>[]; 24 final List<NodeValidator> _validators = <NodeValidator>[];
27 25
28 NodeValidatorBuilder() { 26 NodeValidatorBuilder() {}
29 }
30 27
31 /** 28 /**
32 * Creates a new NodeValidatorBuilder which accepts common constructs. 29 * Creates a new NodeValidatorBuilder which accepts common constructs.
33 * 30 *
34 * By default this will accept HTML5 elements and attributes with the default 31 * By default this will accept HTML5 elements and attributes with the default
35 * [UriPolicy] and templating elements. 32 * [UriPolicy] and templating elements.
36 * 33 *
37 * Notable syntax which is filtered: 34 * Notable syntax which is filtered:
38 * 35 *
39 * * Only known-good HTML5 elements and attributes are allowed. 36 * * Only known-good HTML5 elements and attributes are allowed.
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 * Allow custom elements with the specified tag name and specified attributes. 145 * Allow custom elements with the specified tag name and specified attributes.
149 * 146 *
150 * This will allow the elements as custom tags (such as <x-foo></x-foo>), 147 * This will allow the elements as custom tags (such as <x-foo></x-foo>),
151 * but will not allow tag extensions. Use [allowTagExtension] to allow 148 * but will not allow tag extensions. Use [allowTagExtension] to allow
152 * tag extensions. 149 * tag extensions.
153 */ 150 */
154 void allowCustomElement(String tagName, 151 void allowCustomElement(String tagName,
155 {UriPolicy uriPolicy, 152 {UriPolicy uriPolicy,
156 Iterable<String> attributes, 153 Iterable<String> attributes,
157 Iterable<String> uriAttributes}) { 154 Iterable<String> uriAttributes}) {
158
159 var tagNameUpper = tagName.toUpperCase(); 155 var tagNameUpper = tagName.toUpperCase();
160 var attrs; 156 var attrs = attributes
161 if (attributes != null) { 157 ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
162 attrs = 158 var uriAttrs = uriAttributes
163 attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}'); 159 ?.map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}');
164 }
165 var uriAttrs;
166 if (uriAttributes != null) {
167 uriAttrs =
168 uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
169 }
170 if (uriPolicy == null) { 160 if (uriPolicy == null) {
171 uriPolicy = new UriPolicy(); 161 uriPolicy = new UriPolicy();
172 } 162 }
173 163
174 add(new _CustomElementNodeValidator( 164 add(new _CustomElementNodeValidator(
175 uriPolicy, 165 uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
176 [tagNameUpper],
177 attrs,
178 uriAttrs,
179 false,
180 true));
181 } 166 }
182 167
183 /** 168 /**
184 * Allow custom tag extensions with the specified type name and specified 169 * Allow custom tag extensions with the specified type name and specified
185 * attributes. 170 * attributes.
186 * 171 *
187 * This will allow tag extensions (such as <div is="x-foo"></div>), 172 * This will allow tag extensions (such as <div is="x-foo"></div>),
188 * but will not allow custom tags. Use [allowCustomElement] to allow 173 * but will not allow custom tags. Use [allowCustomElement] to allow
189 * custom tags. 174 * custom tags.
190 */ 175 */
191 void allowTagExtension(String tagName, String baseName, 176 void allowTagExtension(String tagName, String baseName,
192 {UriPolicy uriPolicy, 177 {UriPolicy uriPolicy,
193 Iterable<String> attributes, 178 Iterable<String> attributes,
194 Iterable<String> uriAttributes}) { 179 Iterable<String> uriAttributes}) {
195
196 var baseNameUpper = baseName.toUpperCase(); 180 var baseNameUpper = baseName.toUpperCase();
197 var tagNameUpper = tagName.toUpperCase(); 181 var tagNameUpper = tagName.toUpperCase();
198 var attrs; 182 var attrs = attributes
199 if (attributes != null) { 183 ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
200 attrs = 184 var uriAttrs = uriAttributes
201 attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}'); 185 ?.map /*<String>*/ ((name) => '$baseNameUpper::${name.toLowerCase()}');
202 }
203 var uriAttrs;
204 if (uriAttributes != null) {
205 uriAttrs =
206 uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
207 }
208 if (uriPolicy == null) { 186 if (uriPolicy == null) {
209 uriPolicy = new UriPolicy(); 187 uriPolicy = new UriPolicy();
210 } 188 }
211 189
212 add(new _CustomElementNodeValidator( 190 add(new _CustomElementNodeValidator(uriPolicy,
213 uriPolicy, 191 [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
214 [tagNameUpper, baseNameUpper],
215 attrs,
216 uriAttrs,
217 true,
218 false));
219 } 192 }
220 193
221 void allowElement(String tagName, {UriPolicy uriPolicy, 194 void allowElement(String tagName,
222 Iterable<String> attributes, 195 {UriPolicy uriPolicy,
223 Iterable<String> uriAttributes}) { 196 Iterable<String> attributes,
224 197 Iterable<String> uriAttributes}) {
225 allowCustomElement(tagName, uriPolicy: uriPolicy, 198 allowCustomElement(tagName,
199 uriPolicy: uriPolicy,
226 attributes: attributes, 200 attributes: attributes,
227 uriAttributes: uriAttributes); 201 uriAttributes: uriAttributes);
228 } 202 }
229 203
230 /** 204 /**
231 * Allow templating elements (such as <template> and template-related 205 * Allow templating elements (such as <template> and template-related
232 * attributes. 206 * attributes.
233 * 207 *
234 * This still requires other validators to allow regular attributes to be 208 * This still requires other validators to allow regular attributes to be
235 * bound (such as [allowHtml5]). 209 * bound (such as [allowHtml5]).
(...skipping 10 matching lines...) Expand all
246 */ 220 */
247 void add(NodeValidator validator) { 221 void add(NodeValidator validator) {
248 _validators.add(validator); 222 _validators.add(validator);
249 } 223 }
250 224
251 bool allowsElement(Element element) { 225 bool allowsElement(Element element) {
252 return _validators.any((v) => v.allowsElement(element)); 226 return _validators.any((v) => v.allowsElement(element));
253 } 227 }
254 228
255 bool allowsAttribute(Element element, String attributeName, String value) { 229 bool allowsAttribute(Element element, String attributeName, String value) {
256 return _validators.any( 230 return _validators
257 (v) => v.allowsAttribute(element, attributeName, value)); 231 .any((v) => v.allowsAttribute(element, attributeName, value));
258 } 232 }
259 } 233 }
260 234
261 class _SimpleNodeValidator implements NodeValidator { 235 class _SimpleNodeValidator implements NodeValidator {
262 final Set<String> allowedElements = new Set<String>(); 236 final Set<String> allowedElements = new Set<String>();
263 final Set<String> allowedAttributes = new Set<String>(); 237 final Set<String> allowedAttributes = new Set<String>();
264 final Set<String> allowedUriAttributes = new Set<String>(); 238 final Set<String> allowedUriAttributes = new Set<String>();
265 final UriPolicy uriPolicy; 239 final UriPolicy uriPolicy;
266 240
267 factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) { 241 factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
268 return new _SimpleNodeValidator(uriPolicy, 242 return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
269 allowedElements: const [ 243 'A',
270 'A', 244 'FORM'
271 'FORM'], 245 ], allowedAttributes: const [
272 allowedAttributes: const [ 246 'A::accesskey',
273 'A::accesskey', 247 'A::coords',
274 'A::coords', 248 'A::hreflang',
275 'A::hreflang', 249 'A::name',
276 'A::name', 250 'A::shape',
277 'A::shape', 251 'A::tabindex',
278 'A::tabindex', 252 'A::target',
279 'A::target', 253 'A::type',
280 'A::type', 254 'FORM::accept',
281 'FORM::accept', 255 'FORM::autocomplete',
282 'FORM::autocomplete', 256 'FORM::enctype',
283 'FORM::enctype', 257 'FORM::method',
284 'FORM::method', 258 'FORM::name',
285 'FORM::name', 259 'FORM::novalidate',
286 'FORM::novalidate', 260 'FORM::target',
287 'FORM::target', 261 ], allowedUriAttributes: const [
288 ], 262 'A::href',
289 allowedUriAttributes: const [ 263 'FORM::action',
290 'A::href', 264 ]);
291 'FORM::action',
292 ]);
293 } 265 }
294 266
295 factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) { 267 factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
296 return new _SimpleNodeValidator(uriPolicy, 268 return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
297 allowedElements: const [ 269 'IMG'
298 'IMG' 270 ], allowedAttributes: const [
299 ], 271 'IMG::align',
300 allowedAttributes: const [ 272 'IMG::alt',
301 'IMG::align', 273 'IMG::border',
302 'IMG::alt', 274 'IMG::height',
303 'IMG::border', 275 'IMG::hspace',
304 'IMG::height', 276 'IMG::ismap',
305 'IMG::hspace', 277 'IMG::name',
306 'IMG::ismap', 278 'IMG::usemap',
307 'IMG::name', 279 'IMG::vspace',
308 'IMG::usemap', 280 'IMG::width',
309 'IMG::vspace', 281 ], allowedUriAttributes: const [
310 'IMG::width', 282 'IMG::src',
311 ], 283 ]);
312 allowedUriAttributes: const [
313 'IMG::src',
314 ]);
315 } 284 }
316 285
317 factory _SimpleNodeValidator.allowTextElements() { 286 factory _SimpleNodeValidator.allowTextElements() {
318 return new _SimpleNodeValidator(null, 287 return new _SimpleNodeValidator(null, allowedElements: const [
319 allowedElements: const [ 288 'B',
320 'B', 289 'BLOCKQUOTE',
321 'BLOCKQUOTE', 290 'BR',
322 'BR', 291 'EM',
323 'EM', 292 'H1',
324 'H1', 293 'H2',
325 'H2', 294 'H3',
326 'H3', 295 'H4',
327 'H4', 296 'H5',
328 'H5', 297 'H6',
329 'H6', 298 'HR',
330 'HR', 299 'I',
331 'I', 300 'LI',
332 'LI', 301 'OL',
333 'OL', 302 'P',
334 'P', 303 'SPAN',
335 'SPAN', 304 'UL',
336 'UL', 305 ]);
337 ]);
338 } 306 }
339 307
340 /** 308 /**
341 * Elements must be uppercased tag names. For example `'IMG'`. 309 * Elements must be uppercased tag names. For example `'IMG'`.
342 * Attributes must be uppercased tag name followed by :: followed by 310 * Attributes must be uppercased tag name followed by :: followed by
343 * lowercase attribute name. For example `'IMG:src'`. 311 * lowercase attribute name. For example `'IMG:src'`.
344 */ 312 */
345 _SimpleNodeValidator(this.uriPolicy, 313 _SimpleNodeValidator(this.uriPolicy,
346 {Iterable<String> allowedElements, Iterable<String> allowedAttributes, 314 {Iterable<String> allowedElements,
347 Iterable<String> allowedUriAttributes}) { 315 Iterable<String> allowedAttributes,
316 Iterable<String> allowedUriAttributes}) {
348 this.allowedElements.addAll(allowedElements ?? const []); 317 this.allowedElements.addAll(allowedElements ?? const []);
349 allowedAttributes = allowedAttributes ?? const []; 318 allowedAttributes = allowedAttributes ?? const [];
350 allowedUriAttributes = allowedUriAttributes ?? const []; 319 allowedUriAttributes = allowedUriAttributes ?? const [];
351 var legalAttributes = allowedAttributes.where( 320 var legalAttributes = allowedAttributes
352 (x) => !_Html5NodeValidator._uriAttributes.contains(x)); 321 .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
353 var extraUriAttributes = allowedAttributes.where( 322 var extraUriAttributes = allowedAttributes
354 (x) => _Html5NodeValidator._uriAttributes.contains(x)); 323 .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
355 this.allowedAttributes.addAll(legalAttributes); 324 this.allowedAttributes.addAll(legalAttributes);
356 this.allowedUriAttributes.addAll(allowedUriAttributes); 325 this.allowedUriAttributes.addAll(allowedUriAttributes);
357 this.allowedUriAttributes.addAll(extraUriAttributes); 326 this.allowedUriAttributes.addAll(extraUriAttributes);
358 } 327 }
359 328
360 bool allowsElement(Element element) { 329 bool allowsElement(Element element) {
361 return allowedElements.contains(Element._safeTagName(element)); 330 return allowedElements.contains(Element._safeTagName(element));
362 } 331 }
363 332
364 bool allowsAttribute(Element element, String attributeName, String value) { 333 bool allowsAttribute(Element element, String attributeName, String value) {
(...skipping 12 matching lines...) Expand all
377 return true; 346 return true;
378 } 347 }
379 return false; 348 return false;
380 } 349 }
381 } 350 }
382 351
383 class _CustomElementNodeValidator extends _SimpleNodeValidator { 352 class _CustomElementNodeValidator extends _SimpleNodeValidator {
384 final bool allowTypeExtension; 353 final bool allowTypeExtension;
385 final bool allowCustomTag; 354 final bool allowCustomTag;
386 355
387 _CustomElementNodeValidator(UriPolicy uriPolicy, 356 _CustomElementNodeValidator(
357 UriPolicy uriPolicy,
388 Iterable<String> allowedElements, 358 Iterable<String> allowedElements,
389 Iterable<String> allowedAttributes, 359 Iterable<String> allowedAttributes,
390 Iterable<String> allowedUriAttributes, 360 Iterable<String> allowedUriAttributes,
391 bool allowTypeExtension, 361 bool allowTypeExtension,
392 bool allowCustomTag): 362 bool allowCustomTag)
393 363 : this.allowTypeExtension = allowTypeExtension == true,
394 super(uriPolicy, 364 this.allowCustomTag = allowCustomTag == true,
395 allowedElements: allowedElements, 365 super(uriPolicy,
396 allowedAttributes: allowedAttributes, 366 allowedElements: allowedElements,
397 allowedUriAttributes: allowedUriAttributes), 367 allowedAttributes: allowedAttributes,
398 this.allowTypeExtension = allowTypeExtension == true, 368 allowedUriAttributes: allowedUriAttributes);
399 this.allowCustomTag = allowCustomTag == true;
400 369
401 bool allowsElement(Element element) { 370 bool allowsElement(Element element) {
402 if (allowTypeExtension) { 371 if (allowTypeExtension) {
403 var isAttr = element.attributes['is']; 372 var isAttr = element.attributes['is'];
404 if (isAttr != null) { 373 if (isAttr != null) {
405 return allowedElements.contains(isAttr.toUpperCase()) && 374 return allowedElements.contains(isAttr.toUpperCase()) &&
406 allowedElements.contains(Element._safeTagName(element)); 375 allowedElements.contains(Element._safeTagName(element));
407 } 376 }
408 } 377 }
409 return allowCustomTag && allowedElements.contains(Element._safeTagName(eleme nt)); 378 return allowCustomTag &&
379 allowedElements.contains(Element._safeTagName(element));
410 } 380 }
411 381
412 bool allowsAttribute(Element element, String attributeName, String value) { 382 bool allowsAttribute(Element element, String attributeName, String value) {
413 if (allowsElement(element)) { 383 if (allowsElement(element)) {
414 if (allowTypeExtension && attributeName == 'is' && 384 if (allowTypeExtension &&
385 attributeName == 'is' &&
415 allowedElements.contains(value.toUpperCase())) { 386 allowedElements.contains(value.toUpperCase())) {
416 return true; 387 return true;
417 } 388 }
418 return super.allowsAttribute(element, attributeName, value); 389 return super.allowsAttribute(element, attributeName, value);
419 } 390 }
420 return false; 391 return false;
421 } 392 }
422 } 393 }
423 394
424 class _TemplatingNodeValidator extends _SimpleNodeValidator { 395 class _TemplatingNodeValidator extends _SimpleNodeValidator {
425 static const _TEMPLATE_ATTRS = 396 static const _TEMPLATE_ATTRS = const <String>[
426 const <String>['bind', 'if', 'ref', 'repeat', 'syntax']; 397 'bind',
398 'if',
399 'ref',
400 'repeat',
401 'syntax'
402 ];
427 403
428 final Set<String> _templateAttrs; 404 final Set<String> _templateAttrs;
429 405
430 _TemplatingNodeValidator(): 406 _TemplatingNodeValidator()
431 super(null, 407 : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
432 allowedElements: [ 408 super(null,
433 'TEMPLATE' 409 allowedElements: ['TEMPLATE'],
434 ], 410 allowedAttributes:
435 allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')), 411 _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
436 _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
437 }
438 412
439 bool allowsAttribute(Element element, String attributeName, String value) { 413 bool allowsAttribute(Element element, String attributeName, String value) {
440 if (super.allowsAttribute(element, attributeName, value)) { 414 if (super.allowsAttribute(element, attributeName, value)) {
441 return true; 415 return true;
442 } 416 }
443 417
444 if (attributeName == 'template' && value == "") { 418 if (attributeName == 'template' && value == "") {
445 return true; 419 return true;
446 } 420 }
447 421
448 if (element.attributes['template'] == "" ) { 422 if (element.attributes['template'] == "") {
449 return _templateAttrs.contains(attributeName); 423 return _templateAttrs.contains(attributeName);
450 } 424 }
451 return false; 425 return false;
452 } 426 }
453 } 427 }
454 428
455
456 class _SvgNodeValidator implements NodeValidator { 429 class _SvgNodeValidator implements NodeValidator {
457 bool allowsElement(Element element) { 430 bool allowsElement(Element element) {
458 if (element is svg.ScriptElement) { 431 if (element is svg.ScriptElement) {
459 return false; 432 return false;
460 } 433 }
461 // Firefox 37 has issues with creating foreign elements inside a 434 // Firefox 37 has issues with creating foreign elements inside a
462 // foreignobject tag as SvgElement. We don't want foreignobject contents 435 // foreignobject tag as SvgElement. We don't want foreignobject contents
463 // anyway, so just remove the whole tree outright. And we can't rely 436 // anyway, so just remove the whole tree outright. And we can't rely
464 // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144 437 // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
465 if (element is svg.SvgElement && Element._safeTagName(element) == 'foreignOb ject') { 438 if (element is svg.SvgElement &&
439 Element._safeTagName(element) == 'foreignObject') {
466 return false; 440 return false;
467 } 441 }
468 if (element is svg.SvgElement) { 442 if (element is svg.SvgElement) {
469 return true; 443 return true;
470 } 444 }
471 return false; 445 return false;
472 } 446 }
473 447
474 bool allowsAttribute(Element element, String attributeName, String value) { 448 bool allowsAttribute(Element element, String attributeName, String value) {
475 if (attributeName == 'is' || attributeName.startsWith('on')) { 449 if (attributeName == 'is' || attributeName.startsWith('on')) {
476 return false; 450 return false;
477 } 451 }
478 return allowsElement(element); 452 return allowsElement(element);
479 } 453 }
480 } 454 }
OLDNEW
« no previous file with comments | « tools/dom/src/KeyboardEventStream.dart ('k') | tools/dom/src/WrappedList.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698