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

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: Ran formatter on NodeValidatorBuilder.dart instead of manually mucking with my bad formatting. 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
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 != null
161 if (attributes != null) { 157 ? attributes
162 attrs = 158 .map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}')
Alan Knight 2016/04/19 18:24:34 A null-aware operator to simplify this? I think it
Jacob 2016/04/19 21:50:46 Much better... Done.
163 attributes.map((name) => '$tagNameUpper::${name.toLowerCase()}'); 159 : null;
164 } 160 var uriAttrs = uriAttributes != null
165 var uriAttrs; 161 ? uriAttributes
166 if (uriAttributes != null) { 162 .map /*<String>*/ ((name) => '$tagNameUpper::${name.toLowerCase()}')
167 uriAttrs = 163 : null;
168 uriAttributes.map((name) => '$tagNameUpper::${name.toLowerCase()}');
169 }
170 if (uriPolicy == null) { 164 if (uriPolicy == null) {
171 uriPolicy = new UriPolicy(); 165 uriPolicy = new UriPolicy();
172 } 166 }
173 167
174 add(new _CustomElementNodeValidator( 168 add(new _CustomElementNodeValidator(
175 uriPolicy, 169 uriPolicy, [tagNameUpper], attrs, uriAttrs, false, true));
176 [tagNameUpper],
177 attrs,
178 uriAttrs,
179 false,
180 true));
181 } 170 }
182 171
183 /** 172 /**
184 * Allow custom tag extensions with the specified type name and specified 173 * Allow custom tag extensions with the specified type name and specified
185 * attributes. 174 * attributes.
186 * 175 *
187 * This will allow tag extensions (such as <div is="x-foo"></div>), 176 * This will allow tag extensions (such as <div is="x-foo"></div>),
188 * but will not allow custom tags. Use [allowCustomElement] to allow 177 * but will not allow custom tags. Use [allowCustomElement] to allow
189 * custom tags. 178 * custom tags.
190 */ 179 */
191 void allowTagExtension(String tagName, String baseName, 180 void allowTagExtension(String tagName, String baseName,
192 {UriPolicy uriPolicy, 181 {UriPolicy uriPolicy,
193 Iterable<String> attributes, 182 Iterable<String> attributes,
194 Iterable<String> uriAttributes}) { 183 Iterable<String> uriAttributes}) {
195
196 var baseNameUpper = baseName.toUpperCase(); 184 var baseNameUpper = baseName.toUpperCase();
197 var tagNameUpper = tagName.toUpperCase(); 185 var tagNameUpper = tagName.toUpperCase();
198 var attrs; 186 var attrs = attributes != null
199 if (attributes != null) { 187 ? attributes.map /*<String>*/ (
200 attrs = 188 (name) => '$baseNameUpper::${name.toLowerCase()}')
201 attributes.map((name) => '$baseNameUpper::${name.toLowerCase()}'); 189 : null;
202 } 190 var uriAttrs = uriAttributes != null
203 var uriAttrs; 191 ? uriAttributes.map /*<String>*/ (
204 if (uriAttributes != null) { 192 (name) => '$baseNameUpper::${name.toLowerCase()}')
205 uriAttrs = 193 : null;
206 uriAttributes.map((name) => '$baseNameUpper::${name.toLowerCase()}');
207 }
208 if (uriPolicy == null) { 194 if (uriPolicy == null) {
209 uriPolicy = new UriPolicy(); 195 uriPolicy = new UriPolicy();
210 } 196 }
211 197
212 add(new _CustomElementNodeValidator( 198 add(new _CustomElementNodeValidator(uriPolicy,
213 uriPolicy, 199 [tagNameUpper, baseNameUpper], attrs, uriAttrs, true, false));
214 [tagNameUpper, baseNameUpper],
215 attrs,
216 uriAttrs,
217 true,
218 false));
219 } 200 }
220 201
221 void allowElement(String tagName, {UriPolicy uriPolicy, 202 void allowElement(String tagName,
222 Iterable<String> attributes, 203 {UriPolicy uriPolicy,
223 Iterable<String> uriAttributes}) { 204 Iterable<String> attributes,
224 205 Iterable<String> uriAttributes}) {
225 allowCustomElement(tagName, uriPolicy: uriPolicy, 206 allowCustomElement(tagName,
207 uriPolicy: uriPolicy,
226 attributes: attributes, 208 attributes: attributes,
227 uriAttributes: uriAttributes); 209 uriAttributes: uriAttributes);
228 } 210 }
229 211
230 /** 212 /**
231 * Allow templating elements (such as <template> and template-related 213 * Allow templating elements (such as <template> and template-related
232 * attributes. 214 * attributes.
233 * 215 *
234 * This still requires other validators to allow regular attributes to be 216 * This still requires other validators to allow regular attributes to be
235 * bound (such as [allowHtml5]). 217 * bound (such as [allowHtml5]).
(...skipping 10 matching lines...) Expand all
246 */ 228 */
247 void add(NodeValidator validator) { 229 void add(NodeValidator validator) {
248 _validators.add(validator); 230 _validators.add(validator);
249 } 231 }
250 232
251 bool allowsElement(Element element) { 233 bool allowsElement(Element element) {
252 return _validators.any((v) => v.allowsElement(element)); 234 return _validators.any((v) => v.allowsElement(element));
253 } 235 }
254 236
255 bool allowsAttribute(Element element, String attributeName, String value) { 237 bool allowsAttribute(Element element, String attributeName, String value) {
256 return _validators.any( 238 return _validators
257 (v) => v.allowsAttribute(element, attributeName, value)); 239 .any((v) => v.allowsAttribute(element, attributeName, value));
258 } 240 }
259 } 241 }
260 242
261 class _SimpleNodeValidator implements NodeValidator { 243 class _SimpleNodeValidator implements NodeValidator {
262 final Set<String> allowedElements = new Set<String>(); 244 final Set<String> allowedElements = new Set<String>();
263 final Set<String> allowedAttributes = new Set<String>(); 245 final Set<String> allowedAttributes = new Set<String>();
264 final Set<String> allowedUriAttributes = new Set<String>(); 246 final Set<String> allowedUriAttributes = new Set<String>();
265 final UriPolicy uriPolicy; 247 final UriPolicy uriPolicy;
266 248
267 factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) { 249 factory _SimpleNodeValidator.allowNavigation(UriPolicy uriPolicy) {
268 return new _SimpleNodeValidator(uriPolicy, 250 return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
269 allowedElements: const [ 251 'A',
270 'A', 252 'FORM'
271 'FORM'], 253 ], allowedAttributes: const [
272 allowedAttributes: const [ 254 'A::accesskey',
273 'A::accesskey', 255 'A::coords',
274 'A::coords', 256 'A::hreflang',
275 'A::hreflang', 257 'A::name',
276 'A::name', 258 'A::shape',
277 'A::shape', 259 'A::tabindex',
278 'A::tabindex', 260 'A::target',
279 'A::target', 261 'A::type',
280 'A::type', 262 'FORM::accept',
281 'FORM::accept', 263 'FORM::autocomplete',
282 'FORM::autocomplete', 264 'FORM::enctype',
283 'FORM::enctype', 265 'FORM::method',
284 'FORM::method', 266 'FORM::name',
285 'FORM::name', 267 'FORM::novalidate',
286 'FORM::novalidate', 268 'FORM::target',
287 'FORM::target', 269 ], allowedUriAttributes: const [
288 ], 270 'A::href',
289 allowedUriAttributes: const [ 271 'FORM::action',
290 'A::href', 272 ]);
291 'FORM::action',
292 ]);
293 } 273 }
294 274
295 factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) { 275 factory _SimpleNodeValidator.allowImages(UriPolicy uriPolicy) {
296 return new _SimpleNodeValidator(uriPolicy, 276 return new _SimpleNodeValidator(uriPolicy, allowedElements: const [
297 allowedElements: const [ 277 'IMG'
298 'IMG' 278 ], allowedAttributes: const [
299 ], 279 'IMG::align',
300 allowedAttributes: const [ 280 'IMG::alt',
301 'IMG::align', 281 'IMG::border',
302 'IMG::alt', 282 'IMG::height',
303 'IMG::border', 283 'IMG::hspace',
304 'IMG::height', 284 'IMG::ismap',
305 'IMG::hspace', 285 'IMG::name',
306 'IMG::ismap', 286 'IMG::usemap',
307 'IMG::name', 287 'IMG::vspace',
308 'IMG::usemap', 288 'IMG::width',
309 'IMG::vspace', 289 ], allowedUriAttributes: const [
310 'IMG::width', 290 'IMG::src',
311 ], 291 ]);
312 allowedUriAttributes: const [
313 'IMG::src',
314 ]);
315 } 292 }
316 293
317 factory _SimpleNodeValidator.allowTextElements() { 294 factory _SimpleNodeValidator.allowTextElements() {
318 return new _SimpleNodeValidator(null, 295 return new _SimpleNodeValidator(null, allowedElements: const [
319 allowedElements: const [ 296 'B',
320 'B', 297 'BLOCKQUOTE',
321 'BLOCKQUOTE', 298 'BR',
322 'BR', 299 'EM',
323 'EM', 300 'H1',
324 'H1', 301 'H2',
325 'H2', 302 'H3',
326 'H3', 303 'H4',
327 'H4', 304 'H5',
328 'H5', 305 'H6',
329 'H6', 306 'HR',
330 'HR', 307 'I',
331 'I', 308 'LI',
332 'LI', 309 'OL',
333 'OL', 310 'P',
334 'P', 311 'SPAN',
335 'SPAN', 312 'UL',
336 'UL', 313 ]);
337 ]);
338 } 314 }
339 315
340 /** 316 /**
341 * Elements must be uppercased tag names. For example `'IMG'`. 317 * Elements must be uppercased tag names. For example `'IMG'`.
342 * Attributes must be uppercased tag name followed by :: followed by 318 * Attributes must be uppercased tag name followed by :: followed by
343 * lowercase attribute name. For example `'IMG:src'`. 319 * lowercase attribute name. For example `'IMG:src'`.
344 */ 320 */
345 _SimpleNodeValidator(this.uriPolicy, 321 _SimpleNodeValidator(this.uriPolicy,
346 {Iterable<String> allowedElements, Iterable<String> allowedAttributes, 322 {Iterable<String> allowedElements,
347 Iterable<String> allowedUriAttributes}) { 323 Iterable<String> allowedAttributes,
324 Iterable<String> allowedUriAttributes}) {
348 this.allowedElements.addAll(allowedElements ?? const []); 325 this.allowedElements.addAll(allowedElements ?? const []);
349 allowedAttributes = allowedAttributes ?? const []; 326 allowedAttributes = allowedAttributes ?? const [];
350 allowedUriAttributes = allowedUriAttributes ?? const []; 327 allowedUriAttributes = allowedUriAttributes ?? const [];
351 var legalAttributes = allowedAttributes.where( 328 var legalAttributes = allowedAttributes
352 (x) => !_Html5NodeValidator._uriAttributes.contains(x)); 329 .where((x) => !_Html5NodeValidator._uriAttributes.contains(x));
353 var extraUriAttributes = allowedAttributes.where( 330 var extraUriAttributes = allowedAttributes
354 (x) => _Html5NodeValidator._uriAttributes.contains(x)); 331 .where((x) => _Html5NodeValidator._uriAttributes.contains(x));
355 this.allowedAttributes.addAll(legalAttributes); 332 this.allowedAttributes.addAll(legalAttributes);
356 this.allowedUriAttributes.addAll(allowedUriAttributes); 333 this.allowedUriAttributes.addAll(allowedUriAttributes);
357 this.allowedUriAttributes.addAll(extraUriAttributes); 334 this.allowedUriAttributes.addAll(extraUriAttributes);
358 } 335 }
359 336
360 bool allowsElement(Element element) { 337 bool allowsElement(Element element) {
361 return allowedElements.contains(Element._safeTagName(element)); 338 return allowedElements.contains(Element._safeTagName(element));
362 } 339 }
363 340
364 bool allowsAttribute(Element element, String attributeName, String value) { 341 bool allowsAttribute(Element element, String attributeName, String value) {
(...skipping 12 matching lines...) Expand all
377 return true; 354 return true;
378 } 355 }
379 return false; 356 return false;
380 } 357 }
381 } 358 }
382 359
383 class _CustomElementNodeValidator extends _SimpleNodeValidator { 360 class _CustomElementNodeValidator extends _SimpleNodeValidator {
384 final bool allowTypeExtension; 361 final bool allowTypeExtension;
385 final bool allowCustomTag; 362 final bool allowCustomTag;
386 363
387 _CustomElementNodeValidator(UriPolicy uriPolicy, 364 _CustomElementNodeValidator(
365 UriPolicy uriPolicy,
388 Iterable<String> allowedElements, 366 Iterable<String> allowedElements,
389 Iterable<String> allowedAttributes, 367 Iterable<String> allowedAttributes,
390 Iterable<String> allowedUriAttributes, 368 Iterable<String> allowedUriAttributes,
391 bool allowTypeExtension, 369 bool allowTypeExtension,
392 bool allowCustomTag): 370 bool allowCustomTag)
393 371 : this.allowTypeExtension = allowTypeExtension == true,
394 super(uriPolicy, 372 this.allowCustomTag = allowCustomTag == true,
395 allowedElements: allowedElements, 373 super(uriPolicy,
396 allowedAttributes: allowedAttributes, 374 allowedElements: allowedElements,
397 allowedUriAttributes: allowedUriAttributes), 375 allowedAttributes: allowedAttributes,
398 this.allowTypeExtension = allowTypeExtension == true, 376 allowedUriAttributes: allowedUriAttributes);
399 this.allowCustomTag = allowCustomTag == true;
400 377
401 bool allowsElement(Element element) { 378 bool allowsElement(Element element) {
402 if (allowTypeExtension) { 379 if (allowTypeExtension) {
403 var isAttr = element.attributes['is']; 380 var isAttr = element.attributes['is'];
404 if (isAttr != null) { 381 if (isAttr != null) {
405 return allowedElements.contains(isAttr.toUpperCase()) && 382 return allowedElements.contains(isAttr.toUpperCase()) &&
406 allowedElements.contains(Element._safeTagName(element)); 383 allowedElements.contains(Element._safeTagName(element));
407 } 384 }
408 } 385 }
409 return allowCustomTag && allowedElements.contains(Element._safeTagName(eleme nt)); 386 return allowCustomTag &&
387 allowedElements.contains(Element._safeTagName(element));
410 } 388 }
411 389
412 bool allowsAttribute(Element element, String attributeName, String value) { 390 bool allowsAttribute(Element element, String attributeName, String value) {
413 if (allowsElement(element)) { 391 if (allowsElement(element)) {
414 if (allowTypeExtension && attributeName == 'is' && 392 if (allowTypeExtension &&
393 attributeName == 'is' &&
415 allowedElements.contains(value.toUpperCase())) { 394 allowedElements.contains(value.toUpperCase())) {
416 return true; 395 return true;
417 } 396 }
418 return super.allowsAttribute(element, attributeName, value); 397 return super.allowsAttribute(element, attributeName, value);
419 } 398 }
420 return false; 399 return false;
421 } 400 }
422 } 401 }
423 402
424 class _TemplatingNodeValidator extends _SimpleNodeValidator { 403 class _TemplatingNodeValidator extends _SimpleNodeValidator {
425 static const _TEMPLATE_ATTRS = 404 static const _TEMPLATE_ATTRS = const <String>[
426 const <String>['bind', 'if', 'ref', 'repeat', 'syntax']; 405 'bind',
406 'if',
407 'ref',
408 'repeat',
409 'syntax'
410 ];
427 411
428 final Set<String> _templateAttrs; 412 final Set<String> _templateAttrs;
429 413
430 _TemplatingNodeValidator(): 414 _TemplatingNodeValidator()
431 super(null, 415 : _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS),
432 allowedElements: [ 416 super(null,
433 'TEMPLATE' 417 allowedElements: ['TEMPLATE'],
434 ], 418 allowedAttributes:
435 allowedAttributes: _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')), 419 _TEMPLATE_ATTRS.map((attr) => 'TEMPLATE::$attr')) {}
436 _templateAttrs = new Set<String>.from(_TEMPLATE_ATTRS) {
437 }
438 420
439 bool allowsAttribute(Element element, String attributeName, String value) { 421 bool allowsAttribute(Element element, String attributeName, String value) {
440 if (super.allowsAttribute(element, attributeName, value)) { 422 if (super.allowsAttribute(element, attributeName, value)) {
441 return true; 423 return true;
442 } 424 }
443 425
444 if (attributeName == 'template' && value == "") { 426 if (attributeName == 'template' && value == "") {
445 return true; 427 return true;
446 } 428 }
447 429
448 if (element.attributes['template'] == "" ) { 430 if (element.attributes['template'] == "") {
449 return _templateAttrs.contains(attributeName); 431 return _templateAttrs.contains(attributeName);
450 } 432 }
451 return false; 433 return false;
452 } 434 }
453 } 435 }
454 436
455
456 class _SvgNodeValidator implements NodeValidator { 437 class _SvgNodeValidator implements NodeValidator {
457 bool allowsElement(Element element) { 438 bool allowsElement(Element element) {
458 if (element is svg.ScriptElement) { 439 if (element is svg.ScriptElement) {
459 return false; 440 return false;
460 } 441 }
461 // Firefox 37 has issues with creating foreign elements inside a 442 // Firefox 37 has issues with creating foreign elements inside a
462 // foreignobject tag as SvgElement. We don't want foreignobject contents 443 // foreignobject tag as SvgElement. We don't want foreignobject contents
463 // anyway, so just remove the whole tree outright. And we can't rely 444 // 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 445 // on IE recognizing the SvgForeignObject type, so go by tagName. Bug 23144
465 if (element is svg.SvgElement && Element._safeTagName(element) == 'foreignOb ject') { 446 if (element is svg.SvgElement &&
447 Element._safeTagName(element) == 'foreignObject') {
466 return false; 448 return false;
467 } 449 }
468 if (element is svg.SvgElement) { 450 if (element is svg.SvgElement) {
469 return true; 451 return true;
470 } 452 }
471 return false; 453 return false;
472 } 454 }
473 455
474 bool allowsAttribute(Element element, String attributeName, String value) { 456 bool allowsAttribute(Element element, String attributeName, String value) {
475 if (attributeName == 'is' || attributeName.startsWith('on')) { 457 if (attributeName == 'is' || attributeName.startsWith('on')) {
476 return false; 458 return false;
477 } 459 }
478 return allowsElement(element); 460 return allowsElement(element);
479 } 461 }
480 } 462 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698