@angular/platform-browser 4.4.6 → 4.4.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @license Angular v4.4.6
2
+ * @license Angular v4.4.7
3
3
  * (c) 2010-2017 Google, Inc. https://angular.io/
4
4
  * License: MIT
5
5
  */
@@ -3276,6 +3276,172 @@ KeyEventsPlugin.ctorParameters = () => [
3276
3276
  { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT$1,] },] },
3277
3277
  ];
3278
3278
 
3279
+ /**
3280
+ * @license
3281
+ * Copyright Google Inc. All Rights Reserved.
3282
+ *
3283
+ * Use of this source code is governed by an MIT-style license that can be
3284
+ * found in the LICENSE file at https://angular.io/license
3285
+ */
3286
+ /**
3287
+ * This helper class is used to get hold of an inert tree of DOM elements containing dirty HTML
3288
+ * that needs sanitizing.
3289
+ * Depending upon browser support we must use one of three strategies for doing this.
3290
+ * Support: Safari 10.x -> XHR strategy
3291
+ * Support: Firefox -> DomParser strategy
3292
+ * Default: InertDocument strategy
3293
+ */
3294
+ class InertBodyHelper {
3295
+ /**
3296
+ * @param {?} defaultDoc
3297
+ * @param {?} DOM
3298
+ */
3299
+ constructor(defaultDoc, DOM) {
3300
+ this.defaultDoc = defaultDoc;
3301
+ this.DOM = DOM;
3302
+ const inertDocument = this.DOM.createHtmlDocument();
3303
+ this.inertBodyElement = inertDocument.body;
3304
+ if (this.inertBodyElement == null) {
3305
+ // usually there should be only one body element in the document, but IE doesn't have any, so
3306
+ // we need to create one.
3307
+ const inertHtml = this.DOM.createElement('html', inertDocument);
3308
+ this.inertBodyElement = this.DOM.createElement('body', inertDocument);
3309
+ this.DOM.appendChild(inertHtml, this.inertBodyElement);
3310
+ this.DOM.appendChild(inertDocument, inertHtml);
3311
+ }
3312
+ this.DOM.setInnerHTML(this.inertBodyElement, '<svg><g onload="this.parentNode.remove()"></g></svg>');
3313
+ if (this.inertBodyElement.querySelector && !this.inertBodyElement.querySelector('svg')) {
3314
+ // We just hit the Safari 10.1 bug - which allows JS to run inside the SVG G element
3315
+ // so use the XHR strategy.
3316
+ this.getInertBodyElement = this.getInertBodyElement_XHR;
3317
+ return;
3318
+ }
3319
+ this.DOM.setInnerHTML(this.inertBodyElement, '<svg><p><style><img src="</style><img src=x onerror=alert(1)//">');
3320
+ if (this.inertBodyElement.querySelector && this.inertBodyElement.querySelector('svg img')) {
3321
+ // We just hit the Firefox bug - which prevents the inner img JS from being sanitized
3322
+ // so use the DOMParser strategy, if it is available.
3323
+ // If the DOMParser is not available then we are not in Firefox (Server/WebWorker?) so we
3324
+ // fall through to the default strategy below.
3325
+ if (isDOMParserAvailable()) {
3326
+ this.getInertBodyElement = this.getInertBodyElement_DOMParser;
3327
+ return;
3328
+ }
3329
+ }
3330
+ // None of the bugs were hit so it is safe for us to use the default InertDocument strategy
3331
+ this.getInertBodyElement = this.getInertBodyElement_InertDocument;
3332
+ }
3333
+ /**
3334
+ * Use XHR to create and fill an inert body element (on Safari 10.1)
3335
+ * See
3336
+ * https://github.com/cure53/DOMPurify/blob/a992d3a75031cb8bb032e5ea8399ba972bdf9a65/src/purify.js#L439-L449
3337
+ * @param {?} html
3338
+ * @return {?}
3339
+ */
3340
+ getInertBodyElement_XHR(html) {
3341
+ // We add these extra elements to ensure that the rest of the content is parsed as expected
3342
+ // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
3343
+ // `<head>` tag.
3344
+ html = '<body><remove></remove>' + html + '</body>';
3345
+ try {
3346
+ html = encodeURI(html);
3347
+ }
3348
+ catch (e) {
3349
+ return null;
3350
+ }
3351
+ const /** @type {?} */ xhr = new XMLHttpRequest();
3352
+ xhr.responseType = 'document';
3353
+ xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false);
3354
+ xhr.send(null);
3355
+ const /** @type {?} */ body = xhr.response.body;
3356
+ body.removeChild(/** @type {?} */ ((body.firstChild)));
3357
+ return body;
3358
+ }
3359
+ /**
3360
+ * Use DOMParser to create and fill an inert body element (on Firefox)
3361
+ * See https://github.com/cure53/DOMPurify/releases/tag/0.6.7
3362
+ *
3363
+ * @param {?} html
3364
+ * @return {?}
3365
+ */
3366
+ getInertBodyElement_DOMParser(html) {
3367
+ // We add these extra elements to ensure that the rest of the content is parsed as expected
3368
+ // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the
3369
+ // `<head>` tag.
3370
+ html = '<body><remove></remove>' + html + '</body>';
3371
+ try {
3372
+ const /** @type {?} */ body = (new ((window))
3373
+ .DOMParser()
3374
+ .parseFromString(html, 'text/html')
3375
+ .body);
3376
+ body.removeChild(/** @type {?} */ ((body.firstChild)));
3377
+ return body;
3378
+ }
3379
+ catch (e) {
3380
+ return null;
3381
+ }
3382
+ }
3383
+ /**
3384
+ * Use an HTML5 `template` element, if supported, or an inert body element created via
3385
+ * `createHtmlDocument` to create and fill an inert DOM element.
3386
+ * This is the default sane strategy to use if the browser does not require one of the specialised
3387
+ * strategies above.
3388
+ * @param {?} html
3389
+ * @return {?}
3390
+ */
3391
+ getInertBodyElement_InertDocument(html) {
3392
+ // Prefer using <template> element if supported.
3393
+ const /** @type {?} */ templateEl = this.DOM.createElement('template');
3394
+ if ('content' in templateEl) {
3395
+ this.DOM.setInnerHTML(templateEl, html);
3396
+ return templateEl;
3397
+ }
3398
+ this.DOM.setInnerHTML(this.inertBodyElement, html);
3399
+ // Support: IE 9-11 only
3400
+ // strip custom-namespaced attributes on IE<=11
3401
+ if (this.defaultDoc.documentMode) {
3402
+ this.stripCustomNsAttrs(this.inertBodyElement);
3403
+ }
3404
+ return this.inertBodyElement;
3405
+ }
3406
+ /**
3407
+ * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
3408
+ * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g.
3409
+ * 'ns1:xlink:foo').
3410
+ *
3411
+ * This is undesirable since we don't want to allow any of these custom attributes. This method
3412
+ * strips them all.
3413
+ * @param {?} el
3414
+ * @return {?}
3415
+ */
3416
+ stripCustomNsAttrs(el) {
3417
+ this.DOM.attributeMap(el).forEach((_, attrName) => {
3418
+ if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
3419
+ this.DOM.removeAttribute(el, attrName);
3420
+ }
3421
+ });
3422
+ for (const /** @type {?} */ n of this.DOM.childNodesAsList(el)) {
3423
+ if (this.DOM.isElementNode(n))
3424
+ this.stripCustomNsAttrs(/** @type {?} */ (n));
3425
+ }
3426
+ }
3427
+ }
3428
+ /**
3429
+ * We need to determine whether the DOMParser exists in the global context.
3430
+ * The try-catch is because, on some browsers, trying to access this property
3431
+ * on window can actually throw an error.
3432
+ *
3433
+ * @suppress {uselessCode}
3434
+ * @return {?}
3435
+ */
3436
+ function isDOMParserAvailable() {
3437
+ try {
3438
+ return !!((window)).DOMParser;
3439
+ }
3440
+ catch (e) {
3441
+ return false;
3442
+ }
3443
+ }
3444
+
3279
3445
  /**
3280
3446
  * @license
3281
3447
  * Copyright Google Inc. All Rights Reserved.
@@ -3343,38 +3509,6 @@ function sanitizeSrcset(srcset) {
3343
3509
  * Use of this source code is governed by an MIT-style license that can be
3344
3510
  * found in the LICENSE file at https://angular.io/license
3345
3511
  */
3346
- /**
3347
- * A <body> element that can be safely used to parse untrusted HTML. Lazily initialized below.
3348
- */
3349
- let inertElement = null;
3350
- /**
3351
- * Lazily initialized to make sure the DOM adapter gets set before use.
3352
- */
3353
- let DOM = null;
3354
- /**
3355
- * Returns an HTML element that is guaranteed to not execute code when creating elements in it.
3356
- * @return {?}
3357
- */
3358
- function getInertElement() {
3359
- if (inertElement)
3360
- return inertElement;
3361
- DOM = getDOM();
3362
- // Prefer using <template> element if supported.
3363
- const /** @type {?} */ templateEl = DOM.createElement('template');
3364
- if ('content' in templateEl)
3365
- return templateEl;
3366
- const /** @type {?} */ doc = DOM.createHtmlDocument();
3367
- inertElement = DOM.querySelector(doc, 'body');
3368
- if (inertElement == null) {
3369
- // usually there should be only one body element in the document, but IE doesn't have any, so we
3370
- // need to create one.
3371
- const /** @type {?} */ html = DOM.createElement('html', doc);
3372
- inertElement = DOM.createElement('body', doc);
3373
- DOM.appendChild(html, inertElement);
3374
- DOM.appendChild(doc, html);
3375
- }
3376
- return inertElement;
3377
- }
3378
3512
  /**
3379
3513
  * @param {?} tags
3380
3514
  * @return {?}
@@ -3443,6 +3577,7 @@ class SanitizingHtmlSerializer {
3443
3577
  constructor() {
3444
3578
  this.sanitizedSomething = false;
3445
3579
  this.buf = [];
3580
+ this.DOM = getDOM();
3446
3581
  }
3447
3582
  /**
3448
3583
  * @param {?} el
@@ -3452,33 +3587,33 @@ class SanitizingHtmlSerializer {
3452
3587
  // This cannot use a TreeWalker, as it has to run on Angular's various DOM adapters.
3453
3588
  // However this code never accesses properties off of `document` before deleting its contents
3454
3589
  // again, so it shouldn't be vulnerable to DOM clobbering.
3455
- let /** @type {?} */ current = ((el.firstChild));
3590
+ let /** @type {?} */ current = ((this.DOM.firstChild(el)));
3456
3591
  while (current) {
3457
- if (DOM.isElementNode(current)) {
3592
+ if (this.DOM.isElementNode(current)) {
3458
3593
  this.startElement(/** @type {?} */ (current));
3459
3594
  }
3460
- else if (DOM.isTextNode(current)) {
3461
- this.chars(/** @type {?} */ ((DOM.nodeValue(current))));
3595
+ else if (this.DOM.isTextNode(current)) {
3596
+ this.chars(/** @type {?} */ ((this.DOM.nodeValue(current))));
3462
3597
  }
3463
3598
  else {
3464
3599
  // Strip non-element, non-text nodes.
3465
3600
  this.sanitizedSomething = true;
3466
3601
  }
3467
- if (DOM.firstChild(current)) {
3468
- current = ((DOM.firstChild(current)));
3602
+ if (this.DOM.firstChild(current)) {
3603
+ current = ((this.DOM.firstChild(current)));
3469
3604
  continue;
3470
3605
  }
3471
3606
  while (current) {
3472
3607
  // Leaving the element. Walk up and to the right, closing tags as we go.
3473
- if (DOM.isElementNode(current)) {
3608
+ if (this.DOM.isElementNode(current)) {
3474
3609
  this.endElement(/** @type {?} */ (current));
3475
3610
  }
3476
- let /** @type {?} */ next = checkClobberedElement(current, /** @type {?} */ ((DOM.nextSibling(current))));
3611
+ let /** @type {?} */ next = this.checkClobberedElement(current, /** @type {?} */ ((this.DOM.nextSibling(current))));
3477
3612
  if (next) {
3478
3613
  current = next;
3479
3614
  break;
3480
3615
  }
3481
- current = checkClobberedElement(current, /** @type {?} */ ((DOM.parentElement(current))));
3616
+ current = this.checkClobberedElement(current, /** @type {?} */ ((this.DOM.parentElement(current))));
3482
3617
  }
3483
3618
  }
3484
3619
  return this.buf.join('');
@@ -3488,14 +3623,14 @@ class SanitizingHtmlSerializer {
3488
3623
  * @return {?}
3489
3624
  */
3490
3625
  startElement(element) {
3491
- const /** @type {?} */ tagName = DOM.nodeName(element).toLowerCase();
3626
+ const /** @type {?} */ tagName = this.DOM.nodeName(element).toLowerCase();
3492
3627
  if (!VALID_ELEMENTS.hasOwnProperty(tagName)) {
3493
3628
  this.sanitizedSomething = true;
3494
3629
  return;
3495
3630
  }
3496
3631
  this.buf.push('<');
3497
3632
  this.buf.push(tagName);
3498
- DOM.attributeMap(element).forEach((value, attrName) => {
3633
+ this.DOM.attributeMap(element).forEach((value, attrName) => {
3499
3634
  const /** @type {?} */ lower = attrName.toLowerCase();
3500
3635
  if (!VALID_ATTRS.hasOwnProperty(lower)) {
3501
3636
  this.sanitizedSomething = true;
@@ -3519,7 +3654,7 @@ class SanitizingHtmlSerializer {
3519
3654
  * @return {?}
3520
3655
  */
3521
3656
  endElement(current) {
3522
- const /** @type {?} */ tagName = DOM.nodeName(current).toLowerCase();
3657
+ const /** @type {?} */ tagName = this.DOM.nodeName(current).toLowerCase();
3523
3658
  if (VALID_ELEMENTS.hasOwnProperty(tagName) && !VOID_ELEMENTS.hasOwnProperty(tagName)) {
3524
3659
  this.buf.push('</');
3525
3660
  this.buf.push(tagName);
@@ -3531,17 +3666,17 @@ class SanitizingHtmlSerializer {
3531
3666
  * @return {?}
3532
3667
  */
3533
3668
  chars(chars) { this.buf.push(encodeEntities(chars)); }
3534
- }
3535
- /**
3536
- * @param {?} node
3537
- * @param {?} nextNode
3538
- * @return {?}
3539
- */
3540
- function checkClobberedElement(node, nextNode) {
3541
- if (nextNode && DOM.contains(node, nextNode)) {
3542
- throw new Error(`Failed to sanitize html because the element is clobbered: ${DOM.getOuterHTML(node)}`);
3669
+ /**
3670
+ * @param {?} node
3671
+ * @param {?} nextNode
3672
+ * @return {?}
3673
+ */
3674
+ checkClobberedElement(node, nextNode) {
3675
+ if (nextNode && this.DOM.contains(node, nextNode)) {
3676
+ throw new Error(`Failed to sanitize html because the element is clobbered: ${this.DOM.getOuterHTML(node)}`);
3677
+ }
3678
+ return nextNode;
3543
3679
  }
3544
- return nextNode;
3545
3680
  }
3546
3681
  // Regular Expressions for parsing tags and attributes
3547
3682
  const SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
@@ -3565,26 +3700,7 @@ function encodeEntities(value) {
3565
3700
  .replace(/</g, '&lt;')
3566
3701
  .replace(/>/g, '&gt;');
3567
3702
  }
3568
- /**
3569
- * When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1'
3570
- * attribute to declare ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo').
3571
- *
3572
- * This is undesirable since we don't want to allow any of these custom attributes. This method
3573
- * strips them all.
3574
- * @param {?} el
3575
- * @return {?}
3576
- */
3577
- function stripCustomNsAttrs(el) {
3578
- DOM.attributeMap(el).forEach((_, attrName) => {
3579
- if (attrName === 'xmlns:ns1' || attrName.indexOf('ns1:') === 0) {
3580
- DOM.removeAttribute(el, attrName);
3581
- }
3582
- });
3583
- for (const /** @type {?} */ n of DOM.childNodesAsList(el)) {
3584
- if (DOM.isElementNode(n))
3585
- stripCustomNsAttrs(/** @type {?} */ (n));
3586
- }
3587
- }
3703
+ let inertBodyHelper;
3588
3704
  /**
3589
3705
  * Sanitizes the given unsafe, untrusted HTML fragment, and returns HTML text that is safe to add to
3590
3706
  * the DOM in a browser environment.
@@ -3593,10 +3709,13 @@ function stripCustomNsAttrs(el) {
3593
3709
  * @return {?}
3594
3710
  */
3595
3711
  function sanitizeHtml(defaultDoc, unsafeHtmlInput) {
3712
+ const /** @type {?} */ DOM = getDOM();
3713
+ let /** @type {?} */ inertBodyElement = null;
3596
3714
  try {
3597
- const /** @type {?} */ containerEl = getInertElement();
3715
+ inertBodyHelper = inertBodyHelper || new InertBodyHelper(defaultDoc, DOM);
3598
3716
  // Make sure unsafeHtml is actually a string (TypeScript types are not enforced at runtime).
3599
3717
  let /** @type {?} */ unsafeHtml = unsafeHtmlInput ? String(unsafeHtmlInput) : '';
3718
+ inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
3600
3719
  // mXSS protection. Repeatedly parse the document to make sure it stabilizes, so that a browser
3601
3720
  // trying to auto-correct incorrect HTML cannot cause formerly inert HTML to become dangerous.
3602
3721
  let /** @type {?} */ mXSSAttempts = 5;
@@ -3607,29 +3726,24 @@ function sanitizeHtml(defaultDoc, unsafeHtmlInput) {
3607
3726
  }
3608
3727
  mXSSAttempts--;
3609
3728
  unsafeHtml = parsedHtml;
3610
- DOM.setInnerHTML(containerEl, unsafeHtml);
3611
- if (defaultDoc.documentMode) {
3612
- // strip custom-namespaced attributes on IE<=11
3613
- stripCustomNsAttrs(containerEl);
3614
- }
3615
- parsedHtml = DOM.getInnerHTML(containerEl);
3729
+ parsedHtml = DOM.getInnerHTML(inertBodyElement);
3730
+ inertBodyElement = inertBodyHelper.getInertBodyElement(unsafeHtml);
3616
3731
  } while (unsafeHtml !== parsedHtml);
3617
3732
  const /** @type {?} */ sanitizer = new SanitizingHtmlSerializer();
3618
- const /** @type {?} */ safeHtml = sanitizer.sanitizeChildren(DOM.getTemplateContent(containerEl) || containerEl);
3619
- // Clear out the body element.
3620
- const /** @type {?} */ parent = DOM.getTemplateContent(containerEl) || containerEl;
3621
- for (const /** @type {?} */ child of DOM.childNodesAsList(parent)) {
3622
- DOM.removeChild(parent, child);
3623
- }
3733
+ const /** @type {?} */ safeHtml = sanitizer.sanitizeChildren(DOM.getTemplateContent(inertBodyElement) || inertBodyElement);
3624
3734
  if (isDevMode() && sanitizer.sanitizedSomething) {
3625
3735
  DOM.log('WARNING: sanitizing HTML stripped some content (see http://g.co/ng/security#xss).');
3626
3736
  }
3627
3737
  return safeHtml;
3628
3738
  }
3629
- catch (e) {
3739
+ finally {
3630
3740
  // In case anything goes wrong, clear out inertElement to reset the entire DOM structure.
3631
- inertElement = null;
3632
- throw e;
3741
+ if (inertBodyElement) {
3742
+ const /** @type {?} */ parent = DOM.getTemplateContent(inertBodyElement) || inertBodyElement;
3743
+ for (const /** @type {?} */ child of DOM.childNodesAsList(parent)) {
3744
+ DOM.removeChild(parent, child);
3745
+ }
3746
+ }
3633
3747
  }
3634
3748
  }
3635
3749
 
@@ -4295,7 +4409,7 @@ class By {
4295
4409
  /**
4296
4410
  * \@stable
4297
4411
  */
4298
- const VERSION = new Version('4.4.6');
4412
+ const VERSION = new Version('4.4.7');
4299
4413
 
4300
4414
  /**
4301
4415
  * @license