angularjs-rails 1.5.8 → 1.8.0

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,6 +1,6 @@
1
1
  /**
2
- * @license AngularJS v1.5.8
3
- * (c) 2010-2016 Google, Inc. http://angularjs.org
2
+ * @license AngularJS v1.8.0
3
+ * (c) 2010-2020 Google, Inc. http://angularjs.org
4
4
  * License: MIT
5
5
  */
6
6
  (function(window, angular) {'use strict';
@@ -20,9 +20,11 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
20
20
  var bind;
21
21
  var extend;
22
22
  var forEach;
23
+ var isArray;
23
24
  var isDefined;
24
25
  var lowercase;
25
26
  var noop;
27
+ var nodeContains;
26
28
  var htmlParser;
27
29
  var htmlSanitizeWriter;
28
30
 
@@ -31,13 +33,8 @@ var htmlSanitizeWriter;
31
33
  * @name ngSanitize
32
34
  * @description
33
35
  *
34
- * # ngSanitize
35
- *
36
36
  * The `ngSanitize` module provides functionality to sanitize HTML.
37
37
  *
38
- *
39
- * <div doc-module-components="ngSanitize"></div>
40
- *
41
38
  * See {@link ngSanitize.$sanitize `$sanitize`} for usage.
42
39
  */
43
40
 
@@ -50,12 +47,11 @@ var htmlSanitizeWriter;
50
47
  * Sanitizes an html string by stripping all potentially dangerous tokens.
51
48
  *
52
49
  * The input is sanitized by parsing the HTML into tokens. All safe tokens (from a whitelist) are
53
- * then serialized back to properly escaped html string. This means that no unsafe input can make
50
+ * then serialized back to a properly escaped HTML string. This means that no unsafe input can make
54
51
  * it into the returned string.
55
52
  *
56
53
  * The whitelist for URL sanitization of attribute values is configured using the functions
57
- * `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
58
- * `$compileProvider`}.
54
+ * `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link $compileProvider}.
59
55
  *
60
56
  * The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
61
57
  *
@@ -63,7 +59,7 @@ var htmlSanitizeWriter;
63
59
  * @returns {string} Sanitized HTML.
64
60
  *
65
61
  * @example
66
- <example module="sanitizeExample" deps="angular-sanitize.js">
62
+ <example module="sanitizeExample" deps="angular-sanitize.js" name="sanitize-service">
67
63
  <file name="index.html">
68
64
  <script>
69
65
  angular.module('sanitizeExample', ['ngSanitize'])
@@ -112,19 +108,19 @@ var htmlSanitizeWriter;
112
108
  </file>
113
109
  <file name="protractor.js" type="protractor">
114
110
  it('should sanitize the html snippet by default', function() {
115
- expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
111
+ expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
116
112
  toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
117
113
  });
118
114
 
119
115
  it('should inline raw snippet if bound to a trusted value', function() {
120
- expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).
116
+ expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).
121
117
  toBe("<p style=\"color:blue\">an html\n" +
122
118
  "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
123
119
  "snippet</p>");
124
120
  });
125
121
 
126
122
  it('should escape snippet without any filter', function() {
127
- expect(element(by.css('#bind-default div')).getInnerHtml()).
123
+ expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).
128
124
  toBe("&lt;p style=\"color:blue\"&gt;an html\n" +
129
125
  "&lt;em onmouseover=\"this.textContent='PWN3D!'\"&gt;click here&lt;/em&gt;\n" +
130
126
  "snippet&lt;/p&gt;");
@@ -133,11 +129,11 @@ var htmlSanitizeWriter;
133
129
  it('should update', function() {
134
130
  element(by.model('snippet')).clear();
135
131
  element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
136
- expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()).
132
+ expect(element(by.css('#bind-html-with-sanitize div')).getAttribute('innerHTML')).
137
133
  toBe('new <b>text</b>');
138
- expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe(
134
+ expect(element(by.css('#bind-html-with-trust div')).getAttribute('innerHTML')).toBe(
139
135
  'new <b onclick="alert(1)">text</b>');
140
- expect(element(by.css('#bind-default div')).getInnerHtml()).toBe(
136
+ expect(element(by.css('#bind-default div')).getAttribute('innerHTML')).toBe(
141
137
  "new &lt;b onclick=\"alert(1)\"&gt;text&lt;/b&gt;");
142
138
  });
143
139
  </file>
@@ -148,14 +144,17 @@ var htmlSanitizeWriter;
148
144
  /**
149
145
  * @ngdoc provider
150
146
  * @name $sanitizeProvider
147
+ * @this
151
148
  *
152
149
  * @description
153
150
  * Creates and configures {@link $sanitize} instance.
154
151
  */
155
152
  function $SanitizeProvider() {
153
+ var hasBeenInstantiated = false;
156
154
  var svgEnabled = false;
157
155
 
158
156
  this.$get = ['$$sanitizeUri', function($$sanitizeUri) {
157
+ hasBeenInstantiated = true;
159
158
  if (svgEnabled) {
160
159
  extend(validElements, svgElements);
161
160
  }
@@ -196,7 +195,7 @@ function $SanitizeProvider() {
196
195
  * </div>
197
196
  *
198
197
  * @param {boolean=} flag Enable or disable SVG support in the sanitizer.
199
- * @returns {boolean|ng.$sanitizeProvider} Returns the currently configured value if called
198
+ * @returns {boolean|$sanitizeProvider} Returns the currently configured value if called
200
199
  * without an argument or self for chaining otherwise.
201
200
  */
202
201
  this.enableSvg = function(enableSvg) {
@@ -208,6 +207,105 @@ function $SanitizeProvider() {
208
207
  }
209
208
  };
210
209
 
210
+
211
+ /**
212
+ * @ngdoc method
213
+ * @name $sanitizeProvider#addValidElements
214
+ * @kind function
215
+ *
216
+ * @description
217
+ * Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe
218
+ * and are not stripped off during sanitization. You can extend the following lists of elements:
219
+ *
220
+ * - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML
221
+ * elements. HTML elements considered safe will not be removed during sanitization. All other
222
+ * elements will be stripped off.
223
+ *
224
+ * - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as
225
+ * "void elements" (similar to HTML
226
+ * [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These
227
+ * elements have no end tag and cannot have content.
228
+ *
229
+ * - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only
230
+ * taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for
231
+ * `$sanitize`.
232
+ *
233
+ * <div class="alert alert-info">
234
+ * This method must be called during the {@link angular.Module#config config} phase. Once the
235
+ * `$sanitize` service has been instantiated, this method has no effect.
236
+ * </div>
237
+ *
238
+ * <div class="alert alert-warning">
239
+ * Keep in mind that extending the built-in lists of elements may expose your app to XSS or
240
+ * other vulnerabilities. Be very mindful of the elements you add.
241
+ * </div>
242
+ *
243
+ * @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or
244
+ * more of the following properties:
245
+ * - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of
246
+ * HTML elements.
247
+ * - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of
248
+ * void HTML elements; i.e. elements that do not have an end tag.
249
+ * - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG
250
+ * elements. The list of SVG elements is only taken into account if SVG is
251
+ * {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`.
252
+ *
253
+ * Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`.
254
+ *
255
+ * @return {$sanitizeProvider} Returns self for chaining.
256
+ */
257
+ this.addValidElements = function(elements) {
258
+ if (!hasBeenInstantiated) {
259
+ if (isArray(elements)) {
260
+ elements = {htmlElements: elements};
261
+ }
262
+
263
+ addElementsTo(svgElements, elements.svgElements);
264
+ addElementsTo(voidElements, elements.htmlVoidElements);
265
+ addElementsTo(validElements, elements.htmlVoidElements);
266
+ addElementsTo(validElements, elements.htmlElements);
267
+ }
268
+
269
+ return this;
270
+ };
271
+
272
+
273
+ /**
274
+ * @ngdoc method
275
+ * @name $sanitizeProvider#addValidAttrs
276
+ * @kind function
277
+ *
278
+ * @description
279
+ * Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are
280
+ * not stripped off during sanitization.
281
+ *
282
+ * **Note**:
283
+ * The new attributes will not be treated as URI attributes, which means their values will not be
284
+ * sanitized as URIs using `$compileProvider`'s
285
+ * {@link ng.$compileProvider#aHrefSanitizationWhitelist aHrefSanitizationWhitelist} and
286
+ * {@link ng.$compileProvider#imgSrcSanitizationWhitelist imgSrcSanitizationWhitelist}.
287
+ *
288
+ * <div class="alert alert-info">
289
+ * This method must be called during the {@link angular.Module#config config} phase. Once the
290
+ * `$sanitize` service has been instantiated, this method has no effect.
291
+ * </div>
292
+ *
293
+ * <div class="alert alert-warning">
294
+ * Keep in mind that extending the built-in list of attributes may expose your app to XSS or
295
+ * other vulnerabilities. Be very mindful of the attributes you add.
296
+ * </div>
297
+ *
298
+ * @param {Array<String>} attrs - A list of valid attributes.
299
+ *
300
+ * @returns {$sanitizeProvider} Returns self for chaining.
301
+ */
302
+ this.addValidAttrs = function(attrs) {
303
+ if (!hasBeenInstantiated) {
304
+ extend(validAttrs, arrayToMap(attrs, true));
305
+ }
306
+ return this;
307
+ };
308
+
211
309
  //////////////////////////////////////////////////////////////////////////////////////////////////
212
310
  // Private stuff
213
311
  //////////////////////////////////////////////////////////////////////////////////////////////////
@@ -215,17 +313,23 @@ function $SanitizeProvider() {
215
313
  bind = angular.bind;
216
314
  extend = angular.extend;
217
315
  forEach = angular.forEach;
316
+ isArray = angular.isArray;
218
317
  isDefined = angular.isDefined;
219
- lowercase = angular.lowercase;
318
+ lowercase = angular.$$lowercase;
220
319
  noop = angular.noop;
221
320
 
222
321
  htmlParser = htmlParserImpl;
223
322
  htmlSanitizeWriter = htmlSanitizeWriterImpl;
224
323
 
324
+ nodeContains = window.Node.prototype.contains || /** @this */ function(arg) {
325
+ // eslint-disable-next-line no-bitwise
326
+ return !!(this.compareDocumentPosition(arg) & 16);
327
+ };
328
+
225
329
  // Regular Expressions for parsing tags and attributes
226
330
  var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
227
331
  // Match everything outside of normal chars and " (quote character)
228
- NON_ALPHANUMERIC_REGEXP = /([^\#-~ |!])/g;
332
+ NON_ALPHANUMERIC_REGEXP = /([^#-~ |!])/g;
229
333
 
230
334
 
231
335
  // Good source of info about elements and attributes
@@ -234,36 +338,36 @@ function $SanitizeProvider() {
234
338
 
235
339
  // Safe Void Elements - HTML5
236
340
  // http://dev.w3.org/html5/spec/Overview.html#void-elements
237
- var voidElements = toMap("area,br,col,hr,img,wbr");
341
+ var voidElements = stringToMap('area,br,col,hr,img,wbr');
238
342
 
239
343
  // Elements that you can, intentionally, leave open (and which close themselves)
240
344
  // http://dev.w3.org/html5/spec/Overview.html#optional-tags
241
- var optionalEndTagBlockElements = toMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"),
242
- optionalEndTagInlineElements = toMap("rp,rt"),
345
+ var optionalEndTagBlockElements = stringToMap('colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'),
346
+ optionalEndTagInlineElements = stringToMap('rp,rt'),
243
347
  optionalEndTagElements = extend({},
244
348
  optionalEndTagInlineElements,
245
349
  optionalEndTagBlockElements);
246
350
 
247
351
  // Safe Block Elements - HTML5
248
- var blockElements = extend({}, optionalEndTagBlockElements, toMap("address,article," +
249
- "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," +
250
- "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"));
352
+ var blockElements = extend({}, optionalEndTagBlockElements, stringToMap('address,article,' +
353
+ 'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,' +
354
+ 'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul'));
251
355
 
252
356
  // Inline Elements - HTML5
253
- var inlineElements = extend({}, optionalEndTagInlineElements, toMap("a,abbr,acronym,b," +
254
- "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," +
255
- "samp,small,span,strike,strong,sub,sup,time,tt,u,var"));
357
+ var inlineElements = extend({}, optionalEndTagInlineElements, stringToMap('a,abbr,acronym,b,' +
358
+ 'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,' +
359
+ 'samp,small,span,strike,strong,sub,sup,time,tt,u,var'));
256
360
 
257
361
  // SVG Elements
258
362
  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
259
363
  // Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
260
364
  // They can potentially allow for arbitrary javascript to be executed. See #11290
261
- var svgElements = toMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," +
262
- "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," +
263
- "radialGradient,rect,stop,svg,switch,text,title,tspan");
365
+ var svgElements = stringToMap('circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,' +
366
+ 'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,' +
367
+ 'radialGradient,rect,stop,svg,switch,text,title,tspan');
264
368
 
265
369
  // Blocked Elements (will be stripped)
266
- var blockedElements = toMap("script,style");
370
+ var blockedElements = stringToMap('script,style');
267
371
 
268
372
  var validElements = extend({},
269
373
  voidElements,
@@ -272,9 +376,9 @@ function $SanitizeProvider() {
272
376
  optionalEndTagElements);
273
377
 
274
378
  //Attributes that have href and hence need to be sanitized
275
- var uriAttrs = toMap("background,cite,href,longdesc,src,xlink:href");
379
+ var uriAttrs = stringToMap('background,cite,href,longdesc,src,xlink:href,xml:base');
276
380
 
277
- var htmlAttrs = toMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
381
+ var htmlAttrs = stringToMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' +
278
382
  'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' +
279
383
  'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' +
280
384
  'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' +
@@ -282,7 +386,7 @@ function $SanitizeProvider() {
282
386
 
283
387
  // SVG attributes (without "id" and "name" attributes)
284
388
  // https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
285
- var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
389
+ var svgAttrs = stringToMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' +
286
390
  'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' +
287
391
  'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' +
288
392
  'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' +
@@ -303,35 +407,96 @@ function $SanitizeProvider() {
303
407
  svgAttrs,
304
408
  htmlAttrs);
305
409
 
306
- function toMap(str, lowercaseKeys) {
307
- var obj = {}, items = str.split(','), i;
410
+ function stringToMap(str, lowercaseKeys) {
411
+ return arrayToMap(str.split(','), lowercaseKeys);
412
+ }
413
+
414
+ function arrayToMap(items, lowercaseKeys) {
415
+ var obj = {}, i;
308
416
  for (i = 0; i < items.length; i++) {
309
417
  obj[lowercaseKeys ? lowercase(items[i]) : items[i]] = true;
310
418
  }
311
419
  return obj;
312
420
  }
313
421
 
314
- var inertBodyElement;
315
- (function(window) {
316
- var doc;
317
- if (window.document && window.document.implementation) {
318
- doc = window.document.implementation.createHTMLDocument("inert");
422
+ function addElementsTo(elementsMap, newElements) {
423
+ if (newElements && newElements.length) {
424
+ extend(elementsMap, arrayToMap(newElements));
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Create an inert document that contains the dirty HTML that needs sanitizing
430
+ * Depending upon browser support we use one of three strategies for doing this.
431
+ * Support: Safari 10.x -> XHR strategy
432
+ * Support: Firefox -> DomParser strategy
433
+ */
434
+ var getInertBodyElement /* function(html: string): HTMLBodyElement */ = (function(window, document) {
435
+ var inertDocument;
436
+ if (document && document.implementation) {
437
+ inertDocument = document.implementation.createHTMLDocument('inert');
319
438
  } else {
320
- throw $sanitizeMinErr('noinert', "Can't create an inert html document");
439
+ throw $sanitizeMinErr('noinert', 'Can\'t create an inert html document');
321
440
  }
322
- var docElement = doc.documentElement || doc.getDocumentElement();
323
- var bodyElements = docElement.getElementsByTagName('body');
441
+ var inertBodyElement = (inertDocument.documentElement || inertDocument.getDocumentElement()).querySelector('body');
324
442
 
325
- // usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
326
- if (bodyElements.length === 1) {
327
- inertBodyElement = bodyElements[0];
443
+ // Check for the Safari 10.1 bug - which allows JS to run inside the SVG G element
444
+ inertBodyElement.innerHTML = '<svg><g onload="this.parentNode.remove()"></g></svg>';
445
+ if (!inertBodyElement.querySelector('svg')) {
446
+ return getInertBodyElement_XHR;
328
447
  } else {
329
- var html = doc.createElement('html');
330
- inertBodyElement = doc.createElement('body');
331
- html.appendChild(inertBodyElement);
332
- doc.appendChild(html);
448
+ // Check for the Firefox bug - which prevents the inner img JS from being sanitized
449
+ inertBodyElement.innerHTML = '<svg><p><style><img src="</style><img src=x onerror=alert(1)//">';
450
+ if (inertBodyElement.querySelector('svg img')) {
451
+ return getInertBodyElement_DOMParser;
452
+ } else {
453
+ return getInertBodyElement_InertDocument;
454
+ }
455
+ }
456
+
457
+ function getInertBodyElement_XHR(html) {
458
+ // We add this dummy element to ensure that the rest of the content is parsed as expected
459
+ // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
460
+ html = '<remove></remove>' + html;
461
+ try {
462
+ html = encodeURI(html);
463
+ } catch (e) {
464
+ return undefined;
465
+ }
466
+ var xhr = new window.XMLHttpRequest();
467
+ xhr.responseType = 'document';
468
+ xhr.open('GET', 'data:text/html;charset=utf-8,' + html, false);
469
+ xhr.send(null);
470
+ var body = xhr.response.body;
471
+ body.firstChild.remove();
472
+ return body;
473
+ }
474
+
475
+ function getInertBodyElement_DOMParser(html) {
476
+ // We add this dummy element to ensure that the rest of the content is parsed as expected
477
+ // e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
478
+ html = '<remove></remove>' + html;
479
+ try {
480
+ var body = new window.DOMParser().parseFromString(html, 'text/html').body;
481
+ body.firstChild.remove();
482
+ return body;
483
+ } catch (e) {
484
+ return undefined;
485
+ }
486
+ }
487
+
488
+ function getInertBodyElement_InertDocument(html) {
489
+ inertBodyElement.innerHTML = html;
490
+
491
+ // Support: IE 9-11 only
492
+ // strip custom-namespaced attributes on IE<=11
493
+ if (document.documentMode) {
494
+ stripCustomNsAttrs(inertBodyElement);
495
+ }
496
+
497
+ return inertBodyElement;
333
498
  }
334
- })(window);
499
+ })(window, window.document);
335
500
 
336
501
  /**
337
502
  * @example
@@ -351,22 +516,21 @@ function $SanitizeProvider() {
351
516
  } else if (typeof html !== 'string') {
352
517
  html = '' + html;
353
518
  }
354
- inertBodyElement.innerHTML = html;
519
+
520
+ var inertBodyElement = getInertBodyElement(html);
521
+ if (!inertBodyElement) return '';
355
522
 
356
523
  //mXSS protection
357
524
  var mXSSAttempts = 5;
358
525
  do {
359
526
  if (mXSSAttempts === 0) {
360
- throw $sanitizeMinErr('uinput', "Failed to sanitize html because the input is unstable");
527
+ throw $sanitizeMinErr('uinput', 'Failed to sanitize html because the input is unstable');
361
528
  }
362
529
  mXSSAttempts--;
363
530
 
364
- // strip custom-namespaced attributes on IE<=11
365
- if (window.document.documentMode) {
366
- stripCustomNsAttrs(inertBodyElement);
367
- }
368
- html = inertBodyElement.innerHTML; //trigger mXSS
369
- inertBodyElement.innerHTML = html;
531
+ // trigger mXSS if it is going to happen by reading and writing the innerHTML
532
+ html = inertBodyElement.innerHTML;
533
+ inertBodyElement = getInertBodyElement(html);
370
534
  } while (html !== inertBodyElement.innerHTML);
371
535
 
372
536
  var node = inertBodyElement.firstChild;
@@ -382,16 +546,16 @@ function $SanitizeProvider() {
382
546
 
383
547
  var nextNode;
384
548
  if (!(nextNode = node.firstChild)) {
385
- if (node.nodeType == 1) {
549
+ if (node.nodeType === 1) {
386
550
  handler.end(node.nodeName.toLowerCase());
387
551
  }
388
- nextNode = node.nextSibling;
552
+ nextNode = getNonDescendant('nextSibling', node);
389
553
  if (!nextNode) {
390
554
  while (nextNode == null) {
391
- node = node.parentNode;
555
+ node = getNonDescendant('parentNode', node);
392
556
  if (node === inertBodyElement) break;
393
- nextNode = node.nextSibling;
394
- if (node.nodeType == 1) {
557
+ nextNode = getNonDescendant('nextSibling', node);
558
+ if (node.nodeType === 1) {
395
559
  handler.end(node.nodeName.toLowerCase());
396
560
  }
397
561
  }
@@ -400,7 +564,7 @@ function $SanitizeProvider() {
400
564
  node = nextNode;
401
565
  }
402
566
 
403
- while (node = inertBodyElement.firstChild) {
567
+ while ((node = inertBodyElement.firstChild)) {
404
568
  inertBodyElement.removeChild(node);
405
569
  }
406
570
  }
@@ -481,6 +645,7 @@ function $SanitizeProvider() {
481
645
  out(tag);
482
646
  out('>');
483
647
  }
648
+ // eslint-disable-next-line eqeqeq
484
649
  if (tag == ignoreCurrentElement) {
485
650
  ignoreCurrentElement = false;
486
651
  }
@@ -502,28 +667,36 @@ function $SanitizeProvider() {
502
667
  * @param node Root element to process
503
668
  */
504
669
  function stripCustomNsAttrs(node) {
505
- if (node.nodeType === window.Node.ELEMENT_NODE) {
506
- var attrs = node.attributes;
507
- for (var i = 0, l = attrs.length; i < l; i++) {
508
- var attrNode = attrs[i];
509
- var attrName = attrNode.name.toLowerCase();
510
- if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
511
- node.removeAttributeNode(attrNode);
512
- i--;
513
- l--;
670
+ while (node) {
671
+ if (node.nodeType === window.Node.ELEMENT_NODE) {
672
+ var attrs = node.attributes;
673
+ for (var i = 0, l = attrs.length; i < l; i++) {
674
+ var attrNode = attrs[i];
675
+ var attrName = attrNode.name.toLowerCase();
676
+ if (attrName === 'xmlns:ns1' || attrName.lastIndexOf('ns1:', 0) === 0) {
677
+ node.removeAttributeNode(attrNode);
678
+ i--;
679
+ l--;
680
+ }
514
681
  }
515
682
  }
516
- }
517
683
 
518
- var nextNode = node.firstChild;
519
- if (nextNode) {
520
- stripCustomNsAttrs(nextNode);
684
+ var nextNode = node.firstChild;
685
+ if (nextNode) {
686
+ stripCustomNsAttrs(nextNode);
687
+ }
688
+
689
+ node = getNonDescendant('nextSibling', node);
521
690
  }
691
+ }
522
692
 
523
- nextNode = node.nextSibling;
524
- if (nextNode) {
525
- stripCustomNsAttrs(nextNode);
693
+ function getNonDescendant(propName, node) {
694
+ // An element is clobbered if its `propName` property points to one of its descendants
695
+ var nextNode = node[propName];
696
+ if (nextNode && nodeContains.call(node, nextNode)) {
697
+ throw $sanitizeMinErr('elclob', 'Failed to sanitize html because the element is clobbered: {0}', node.outerHTML || node.outerText);
526
698
  }
699
+ return nextNode;
527
700
  }
528
701
  }
529
702
 
@@ -536,7 +709,9 @@ function sanitizeText(chars) {
536
709
 
537
710
 
538
711
  // define ngSanitize module and register $sanitize service
539
- angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
712
+ angular.module('ngSanitize', [])
713
+ .provider('$sanitize', $SanitizeProvider)
714
+ .info({ angularVersion: '1.8.0' });
540
715
 
541
716
  /**
542
717
  * @ngdoc filter
@@ -544,13 +719,13 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
544
719
  * @kind function
545
720
  *
546
721
  * @description
547
- * Finds links in text input and turns them into html links. Supports `http/https/ftp/mailto` and
722
+ * Finds links in text input and turns them into html links. Supports `http/https/ftp/sftp/mailto` and
548
723
  * plain email address links.
549
724
  *
550
725
  * Requires the {@link ngSanitize `ngSanitize`} module to be installed.
551
726
  *
552
727
  * @param {string} text Input text.
553
- * @param {string} target Window (`_blank|_self|_parent|_top`) or named frame to open links in.
728
+ * @param {string} [target] Window (`_blank|_self|_parent|_top`) or named frame to open links in.
554
729
  * @param {object|function(url)} [attributes] Add custom attributes to the link element.
555
730
  *
556
731
  * Can be one of:
@@ -568,7 +743,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
568
743
  <span ng-bind-html="linky_expression | linky"></span>
569
744
  *
570
745
  * @example
571
- <example module="linkyExample" deps="angular-sanitize.js">
746
+ <example module="linkyExample" deps="angular-sanitize.js" name="linky-filter">
572
747
  <file name="index.html">
573
748
  <div ng-controller="ExampleController">
574
749
  Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
@@ -616,10 +791,10 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
616
791
  angular.module('linkyExample', ['ngSanitize'])
617
792
  .controller('ExampleController', ['$scope', function($scope) {
618
793
  $scope.snippet =
619
- 'Pretty text with some links:\n'+
620
- 'http://angularjs.org/,\n'+
621
- 'mailto:us@somewhere.org,\n'+
622
- 'another@somewhere.org,\n'+
794
+ 'Pretty text with some links:\n' +
795
+ 'http://angularjs.org/,\n' +
796
+ 'mailto:us@somewhere.org,\n' +
797
+ 'another@somewhere.org,\n' +
623
798
  'and one more: ftp://127.0.0.1/.';
624
799
  $scope.snippetWithSingleURL = 'http://angularjs.org/';
625
800
  }]);
@@ -667,7 +842,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
667
842
  */
668
843
  angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
669
844
  var LINKY_URL_REGEXP =
670
- /((ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
845
+ /((s?ftp|https?):\/\/|(www\.)|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"\u201d\u2019]/i,
671
846
  MAILTO_REGEXP = /^mailto:/i;
672
847
 
673
848
  var linkyMinErr = angular.$$minErr('linky');