Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
A
angular-sanitize
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Custom Issue Tracker
Custom Issue Tracker
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
angularjs
angular-sanitize
Commits
486430be
Commit
486430be
authored
Mar 21, 2021
by
bingchuan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[dev] version 1.8.2
parent
68fa4f84
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
765 additions
and
591 deletions
+765
-591
angular-sanitize.js
angular-sanitize.js
+765
-591
No files found.
angular-sanitize.js
View file @
486430be
/**
* @license AngularJS v1.
5.7
* (c) 2010-20
16 Google, Inc
. http://angularjs.org
* @license AngularJS v1.
8.2
* (c) 2010-20
20 Google LLC
. http://angularjs.org
* License: MIT
*/
(
function
(
window
,
angular
)
{
'use strict'
;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Any commits to this file should be reviewed with security in mind. *
* Changes to this file can potentially create security vulnerabilities. *
* An approval from 2 Core members with history of modifying *
...
...
@@ -16,24 +16,29 @@
* Or gives undesired access to variables likes document or window? *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
var
$sanitizeMinErr
=
angular
.
$$minErr
(
'$sanitize'
);
var
$sanitizeMinErr
=
angular
.
$$minErr
(
'$sanitize'
);
var
bind
;
var
extend
;
var
forEach
;
var
isArray
;
var
isDefined
;
var
lowercase
;
var
noop
;
var
nodeContains
;
var
htmlParser
;
var
htmlSanitizeWriter
;
/**
/**
* @ngdoc module
* @name ngSanitize
* @description
*
* # ngSanitize
*
* The `ngSanitize` module provides functionality to sanitize HTML.
*
*
* <div doc-module-components="ngSanitize"></div>
*
* See {@link ngSanitize.$sanitize `$sanitize`} for usage.
*/
/**
/**
* @ngdoc service
* @name $sanitize
* @kind function
...
...
@@ -41,13 +46,12 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
* @description
* Sanitizes an html string by stripping all potentially dangerous tokens.
*
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a white
list) are
* then serialized back to properly escaped html
string. This means that no unsafe input can make
* The input is sanitized by parsing the HTML into tokens. All safe tokens (from a trusted URI
list) are
* then serialized back to a properly escaped HTML
string. This means that no unsafe input can make
* it into the returned string.
*
* The whitelist for URL sanitization of attribute values is configured using the functions
* `aHrefSanitizationWhitelist` and `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider
* `$compileProvider`}.
* The trusted URIs for URL sanitization of attribute values is configured using the functions
* `aHrefSanitizationTrustedUrlList` and `imgSrcSanitizationTrustedUrlList` of {@link $compileProvider}.
*
* The input may also contain SVG markup if this is enabled via {@link $sanitizeProvider}.
*
...
...
@@ -55,7 +59,7 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
* @returns {string} Sanitized HTML.
*
* @example
<example module="sanitizeExample" deps="angular-sanitize.js">
<example module="sanitizeExample" deps="angular-sanitize.js"
name="sanitize-service"
>
<file name="index.html">
<script>
angular.module('sanitizeExample', ['ngSanitize'])
...
...
@@ -89,7 +93,7 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
<td>Bypass $sanitize by explicitly trusting the dangerous value</td>
<td>
<pre><div ng-bind-html="deliberatelyTrustDangerousSnippet()">
</div></pre>
</div></pre>
</td>
<td><div ng-bind-html="deliberatelyTrustDangerousSnippet()"></div></td>
</tr>
...
...
@@ -104,19 +108,19 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
</file>
<file name="protractor.js" type="protractor">
it('should sanitize the html snippet by default', function() {
expect(element(by.css('#bind-html-with-sanitize div')).get
InnerHtml(
)).
expect(element(by.css('#bind-html-with-sanitize div')).get
Attribute('innerHTML'
)).
toBe('<p>an html\n<em>click here</em>\nsnippet</p>');
});
it('should inline raw snippet if bound to a trusted value', function() {
expect(element(by.css('#bind-html-with-trust div')).get
InnerHtml(
)).
expect(element(by.css('#bind-html-with-trust div')).get
Attribute('innerHTML'
)).
toBe("<p style=\"color:blue\">an html\n" +
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
"snippet</p>");
});
it('should escape snippet without any filter', function() {
expect(element(by.css('#bind-default div')).get
InnerHtml(
)).
expect(element(by.css('#bind-default div')).get
Attribute('innerHTML'
)).
toBe("<p style=\"color:blue\">an html\n" +
"<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" +
"snippet</p>");
...
...
@@ -125,11 +129,11 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
it('should update', function() {
element(by.model('snippet')).clear();
element(by.model('snippet')).sendKeys('new <b onclick="alert(1)">text</b>');
expect(element(by.css('#bind-html-with-sanitize div')).get
InnerHtml(
)).
expect(element(by.css('#bind-html-with-sanitize div')).get
Attribute('innerHTML'
)).
toBe('new <b>text</b>');
expect(element(by.css('#bind-html-with-trust div')).get
InnerHtml(
)).toBe(
expect(element(by.css('#bind-html-with-trust div')).get
Attribute('innerHTML'
)).toBe(
'new <b onclick="alert(1)">text</b>');
expect(element(by.css('#bind-default div')).get
InnerHtml(
)).toBe(
expect(element(by.css('#bind-default div')).get
Attribute('innerHTML'
)).toBe(
"new <b onclick=\"alert(1)\">text</b>");
});
</file>
...
...
@@ -137,19 +141,22 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
*/
/**
/**
* @ngdoc provider
* @name $sanitizeProvider
* @this
*
* @description
* Creates and configures {@link $sanitize} instance.
*/
function
$SanitizeProvider
()
{
function
$SanitizeProvider
()
{
var
hasBeenInstantiated
=
false
;
var
svgEnabled
=
false
;
this
.
$get
=
[
'$$sanitizeUri'
,
function
(
$$sanitizeUri
)
{
hasBeenInstantiated
=
true
;
if
(
svgEnabled
)
{
angular
.
extend
(
validElements
,
svgElements
);
extend
(
validElements
,
svgElements
);
}
return
function
(
html
)
{
var
buf
=
[];
...
...
@@ -188,88 +195,198 @@ function $SanitizeProvider() {
* </div>
*
* @param {boolean=} flag Enable or disable SVG support in the sanitizer.
* @returns {boolean|ng.
$sanitizeProvider} Returns the currently configured value if called
* @returns {boolean|
$sanitizeProvider} Returns the currently configured value if called
* without an argument or self for chaining otherwise.
*/
this
.
enableSvg
=
function
(
enableSvg
)
{
if
(
angular
.
isDefined
(
enableSvg
))
{
if
(
isDefined
(
enableSvg
))
{
svgEnabled
=
enableSvg
;
return
this
;
}
else
{
return
svgEnabled
;
}
};
}
function
sanitizeText
(
chars
)
{
var
buf
=
[];
var
writer
=
htmlSanitizeWriter
(
buf
,
angular
.
noop
);
writer
.
chars
(
chars
);
return
buf
.
join
(
''
);
}
/**
* @ngdoc method
* @name $sanitizeProvider#addValidElements
* @kind function
*
* @description
* Extends the built-in lists of valid HTML/SVG elements, i.e. elements that are considered safe
* and are not stripped off during sanitization. You can extend the following lists of elements:
*
* - `htmlElements`: A list of elements (tag names) to extend the current list of safe HTML
* elements. HTML elements considered safe will not be removed during sanitization. All other
* elements will be stripped off.
*
* - `htmlVoidElements`: This is similar to `htmlElements`, but marks the elements as
* "void elements" (similar to HTML
* [void elements](https://rawgit.com/w3c/html/html5.1-2/single-page.html#void-elements)). These
* elements have no end tag and cannot have content.
*
* - `svgElements`: This is similar to `htmlElements`, but for SVG elements. This list is only
* taken into account if SVG is {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for
* `$sanitize`.
*
* <div class="alert alert-info">
* This method must be called during the {@link angular.Module#config config} phase. Once the
* `$sanitize` service has been instantiated, this method has no effect.
* </div>
*
* <div class="alert alert-warning">
* Keep in mind that extending the built-in lists of elements may expose your app to XSS or
* other vulnerabilities. Be very mindful of the elements you add.
* </div>
*
* @param {Array<String>|Object} elements - A list of valid HTML elements or an object with one or
* more of the following properties:
* - **htmlElements** - `{Array<String>}` - A list of elements to extend the current list of
* HTML elements.
* - **htmlVoidElements** - `{Array<String>}` - A list of elements to extend the current list of
* void HTML elements; i.e. elements that do not have an end tag.
* - **svgElements** - `{Array<String>}` - A list of elements to extend the current list of SVG
* elements. The list of SVG elements is only taken into account if SVG is
* {@link ngSanitize.$sanitizeProvider#enableSvg enabled} for `$sanitize`.
*
* Passing an array (`[...]`) is equivalent to passing `{htmlElements: [...]}`.
*
* @return {$sanitizeProvider} Returns self for chaining.
*/
this
.
addValidElements
=
function
(
elements
)
{
if
(
!
hasBeenInstantiated
)
{
if
(
isArray
(
elements
))
{
elements
=
{
htmlElements
:
elements
};
}
addElementsTo
(
svgElements
,
elements
.
svgElements
);
addElementsTo
(
voidElements
,
elements
.
htmlVoidElements
);
addElementsTo
(
validElements
,
elements
.
htmlVoidElements
);
addElementsTo
(
validElements
,
elements
.
htmlElements
);
}
return
this
;
};
/**
* @ngdoc method
* @name $sanitizeProvider#addValidAttrs
* @kind function
*
* @description
* Extends the built-in list of valid attributes, i.e. attributes that are considered safe and are
* not stripped off during sanitization.
*
* **Note**:
* The new attributes will not be treated as URI attributes, which means their values will not be
* sanitized as URIs using `$compileProvider`'s
* {@link ng.$compileProvider#aHrefSanitizationTrustedUrlList aHrefSanitizationTrustedUrlList} and
* {@link ng.$compileProvider#imgSrcSanitizationTrustedUrlList imgSrcSanitizationTrustedUrlList}.
*
* <div class="alert alert-info">
* This method must be called during the {@link angular.Module#config config} phase. Once the
* `$sanitize` service has been instantiated, this method has no effect.
* </div>
*
* <div class="alert alert-warning">
* Keep in mind that extending the built-in list of attributes may expose your app to XSS or
* other vulnerabilities. Be very mindful of the attributes you add.
* </div>
*
* @param {Array<String>} attrs - A list of valid attributes.
*
* @returns {$sanitizeProvider} Returns self for chaining.
*/
this
.
addValidAttrs
=
function
(
attrs
)
{
if
(
!
hasBeenInstantiated
)
{
extend
(
validAttrs
,
arrayToMap
(
attrs
,
true
));
}
return
this
;
};
//////////////////////////////////////////////////////////////////////////////////////////////////
// Private stuff
//////////////////////////////////////////////////////////////////////////////////////////////////
bind
=
angular
.
bind
;
extend
=
angular
.
extend
;
forEach
=
angular
.
forEach
;
isArray
=
angular
.
isArray
;
isDefined
=
angular
.
isDefined
;
lowercase
=
angular
.
$$lowercase
;
noop
=
angular
.
noop
;
htmlParser
=
htmlParserImpl
;
htmlSanitizeWriter
=
htmlSanitizeWriterImpl
;
nodeContains
=
window
.
Node
.
prototype
.
contains
||
/** @this */
function
(
arg
)
{
// eslint-disable-next-line no-bitwise
return
!!
(
this
.
compareDocumentPosition
(
arg
)
&
16
);
};
// Regular Expressions for parsing tags and attributes
var
SURROGATE_PAIR_REGEXP
=
/
[\u
D800-
\u
DBFF
][\u
DC00-
\u
DFFF
]
/g
,
// Regular Expressions for parsing tags and attributes
var
SURROGATE_PAIR_REGEXP
=
/
[\u
D800-
\u
DBFF
][\u
DC00-
\u
DFFF
]
/g
,
// Match everything outside of normal chars and " (quote character)
NON_ALPHANUMERIC_REGEXP
=
/
([^\
#
-~ |!
])
/g
;
NON_ALPHANUMERIC_REGEXP
=
/
([^
#-~ |!
])
/g
;
// Good source of info about elements and attributes
// http://dev.w3.org/html5/spec/Overview.html#semantics
// http://simon.html5.org/html-elements
// Good source of info about elements and attributes
// http://dev.w3.org/html5/spec/Overview.html#semantics
// http://simon.html5.org/html-elements
// Safe Void Elements - HTML5
// http://dev.w3.org/html5/spec/Overview.html#void-elements
var
voidElements
=
toMap
(
"area,br,col,hr,img,wbr"
);
// Safe Void Elements - HTML5
// http://dev.w3.org/html5/spec/Overview.html#void-elements
var
voidElements
=
stringToMap
(
'area,br,col,hr,img,wbr'
);
// Elements that you can, intentionally, leave open (and which close themselves)
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
var
optionalEndTagBlockElements
=
toMap
(
"colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"
),
optionalEndTagInlineElements
=
toMap
(
"rp,rt"
),
optionalEndTagElements
=
angular
.
extend
({},
// Elements that you can, intentionally, leave open (and which close themselves)
// http://dev.w3.org/html5/spec/Overview.html#optional-tags
var
optionalEndTagBlockElements
=
stringToMap
(
'colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr'
),
optionalEndTagInlineElements
=
stringToMap
(
'rp,rt'
),
optionalEndTagElements
=
extend
({},
optionalEndTagInlineElements
,
optionalEndTagBlockElements
);
// Safe Block Elements - HTML5
var
blockElements
=
angular
.
extend
({},
optionalEndTagBlockElements
,
toMap
(
"address,article,"
+
"aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,"
+
"h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul"
));
// Safe Block Elements - HTML5
var
blockElements
=
extend
({},
optionalEndTagBlockElements
,
stringToMap
(
'address,article,'
+
'aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5,'
+
'h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,section,table,ul'
));
// Inline Elements - HTML5
var
inlineElements
=
angular
.
extend
({},
optionalEndTagInlineElements
,
toMap
(
"a,abbr,acronym,b,"
+
"bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,"
+
"samp,small,span,strike,strong,sub,sup,time,tt,u,var"
));
// Inline Elements - HTML5
var
inlineElements
=
extend
({},
optionalEndTagInlineElements
,
stringToMap
(
'a,abbr,acronym,b,'
+
'bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s,'
+
'samp,small,span,strike,strong,sub,sup,time,tt,u,var'
));
// SVG Elements
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
// They can potentially allow for arbitrary javascript to be executed. See #11290
var
svgElements
=
toMap
(
"circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,"
+
"hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,"
+
"radialGradient,rect,stop,svg,switch,text,title,tspan"
);
// SVG Elements
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements
// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted.
// They can potentially allow for arbitrary javascript to be executed. See #11290
var
svgElements
=
stringToMap
(
'circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph,'
+
'hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline,'
+
'radialGradient,rect,stop,svg,switch,text,title,tspan'
);
// Blocked Elements (will be stripped)
var
blockedElements
=
toMap
(
"script,style"
);
// Blocked Elements (will be stripped)
var
blockedElements
=
stringToMap
(
'script,style'
);
var
validElements
=
angular
.
extend
({},
var
validElements
=
extend
({},
voidElements
,
blockElements
,
inlineElements
,
optionalEndTagElements
);
//Attributes that have href and hence need to be sanitized
var
uriAttrs
=
toMap
(
"background,cite,href,longdesc,src,xlink:href"
);
//Attributes that have href and hence need to be sanitized
var
uriAttrs
=
stringToMap
(
'background,cite,href,longdesc,src,xlink:href,xml:base'
);
var
htmlAttrs
=
t
oMap
(
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'
+
var
htmlAttrs
=
stringT
oMap
(
'abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,'
+
'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,'
+
'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,'
+
'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,'
+
'valign,value,vspace,width'
);
// SVG attributes (without "id" and "name" attributes)
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
var
svgAttrs
=
t
oMap
(
'accent-height,accumulate,additive,alphabetic,arabic-form,ascent,'
+
// SVG attributes (without "id" and "name" attributes)
// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes
var
svgAttrs
=
stringT
oMap
(
'accent-height,accumulate,additive,alphabetic,arabic-form,ascent,'
+
'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,'
+
'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,'
+
'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,'
+
...
...
@@ -285,42 +402,81 @@ var svgAttrs = toMap('accent-height,accumulate,additive,alphabetic,arabic-form,a
'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,'
+
'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan'
,
true
);
var
validAttrs
=
angular
.
extend
({},
var
validAttrs
=
extend
({},
uriAttrs
,
svgAttrs
,
htmlAttrs
);
function
toMap
(
str
,
lowercaseKeys
)
{
var
obj
=
{},
items
=
str
.
split
(
','
),
i
;
function
stringToMap
(
str
,
lowercaseKeys
)
{
return
arrayToMap
(
str
.
split
(
','
),
lowercaseKeys
);
}
function
arrayToMap
(
items
,
lowercaseKeys
)
{
var
obj
=
{},
i
;
for
(
i
=
0
;
i
<
items
.
length
;
i
++
)
{
obj
[
lowercaseKeys
?
angular
.
lowercase
(
items
[
i
])
:
items
[
i
]]
=
true
;
obj
[
lowercaseKeys
?
lowercase
(
items
[
i
])
:
items
[
i
]]
=
true
;
}
return
obj
;
}
}
var
inertBodyElement
;
(
function
(
window
)
{
var
doc
;
if
(
window
.
document
&&
window
.
document
.
implementation
)
{
doc
=
window
.
document
.
implementation
.
createHTMLDocument
(
"inert"
);
}
else
{
throw
$sanitizeMinErr
(
'noinert'
,
"Can't create an inert html document"
);
function
addElementsTo
(
elementsMap
,
newElements
)
{
if
(
newElements
&&
newElements
.
length
)
{
extend
(
elementsMap
,
arrayToMap
(
newElements
));
}
}
var
docElement
=
doc
.
documentElement
||
doc
.
getDocumentElement
();
var
bodyElements
=
docElement
.
getElementsByTagName
(
'body'
);
// usually there should be only one body element in the document, but IE doesn't have any, so we need to create one
if
(
bodyElements
.
length
===
1
)
{
inertBodyElement
=
bodyElements
[
0
];
}
else
{
var
html
=
doc
.
createElement
(
'html'
);
inertBodyElement
=
doc
.
createElement
(
'body'
);
html
.
appendChild
(
inertBodyElement
);
doc
.
appendChild
(
html
)
;
/**
* Create an inert document that contains the dirty HTML that needs sanitizing.
* We use the DOMParser API by default and fall back to createHTMLDocument if DOMParser is not
* available.
*/
var
getInertBodyElement
/* function(html: string): HTMLBodyElement */
=
(
function
(
window
,
document
)
{
if
(
isDOMParserAvailable
())
{
return
getInertBodyElement_DOMParser
;
}
})(
window
);
/**
if
(
!
document
||
!
document
.
implementation
)
{
throw
$sanitizeMinErr
(
'noinert'
,
'Can
\'
t create an inert html document'
);
}
var
inertDocument
=
document
.
implementation
.
createHTMLDocument
(
'inert'
);
var
inertBodyElement
=
(
inertDocument
.
documentElement
||
inertDocument
.
getDocumentElement
()).
querySelector
(
'body'
);
return
getInertBodyElement_InertDocument
;
function
isDOMParserAvailable
()
{
try
{
return
!!
getInertBodyElement_DOMParser
(
''
);
}
catch
(
e
)
{
return
false
;
}
}
function
getInertBodyElement_DOMParser
(
html
)
{
// We add this dummy element to ensure that the rest of the content is parsed as expected
// e.g. leading whitespace is maintained and tags like `<meta>` do not get hoisted to the `<head>` tag.
html
=
'<remove></remove>'
+
html
;
try
{
var
body
=
new
window
.
DOMParser
().
parseFromString
(
html
,
'text/html'
).
body
;
body
.
firstChild
.
remove
();
return
body
;
}
catch
(
e
)
{
return
undefined
;
}
}
function
getInertBodyElement_InertDocument
(
html
)
{
inertBodyElement
.
innerHTML
=
html
;
// Support: IE 9-11 only
// strip custom-namespaced attributes on IE<=11
if
(
document
.
documentMode
)
{
stripCustomNsAttrs
(
inertBodyElement
);
}
return
inertBodyElement
;
}
})(
window
,
window
.
document
);
/**
* @example
* htmlParser(htmlString, {
* start: function(tag, attrs) {},
...
...
@@ -332,28 +488,27 @@ var inertBodyElement;
* @param {string} html string
* @param {object} handler
*/
function
htmlParser
(
html
,
handler
)
{
function
htmlParserImpl
(
html
,
handler
)
{
if
(
html
===
null
||
html
===
undefined
)
{
html
=
''
;
}
else
if
(
typeof
html
!==
'string'
)
{
html
=
''
+
html
;
}
inertBodyElement
.
innerHTML
=
html
;
var
inertBodyElement
=
getInertBodyElement
(
html
);
if
(
!
inertBodyElement
)
return
''
;
//mXSS protection
var
mXSSAttempts
=
5
;
do
{
if
(
mXSSAttempts
===
0
)
{
throw
$sanitizeMinErr
(
'uinput'
,
"Failed to sanitize html because the input is unstable"
);
throw
$sanitizeMinErr
(
'uinput'
,
'Failed to sanitize html because the input is unstable'
);
}
mXSSAttempts
--
;
// strip custom-namespaced attributes on IE<=11
if
(
window
.
document
.
documentMode
)
{
stripCustomNsAttrs
(
inertBodyElement
);
}
html
=
inertBodyElement
.
innerHTML
;
//trigger mXSS
inertBodyElement
.
innerHTML
=
html
;
// trigger mXSS if it is going to happen by reading and writing the innerHTML
html
=
inertBodyElement
.
innerHTML
;
inertBodyElement
=
getInertBodyElement
(
html
);
}
while
(
html
!==
inertBodyElement
.
innerHTML
);
var
node
=
inertBodyElement
.
firstChild
;
...
...
@@ -369,16 +524,16 @@ function htmlParser(html, handler) {
var
nextNode
;
if
(
!
(
nextNode
=
node
.
firstChild
))
{
if
(
node
.
nodeType
==
1
)
{
if
(
node
.
nodeType
=
==
1
)
{
handler
.
end
(
node
.
nodeName
.
toLowerCase
());
}
nextNode
=
node
.
nextSibling
;
nextNode
=
getNonDescendant
(
'nextSibling'
,
node
)
;
if
(
!
nextNode
)
{
while
(
nextNode
==
null
)
{
node
=
node
.
parentNode
;
node
=
getNonDescendant
(
'parentNode'
,
node
)
;
if
(
node
===
inertBodyElement
)
break
;
nextNode
=
node
.
nextSibling
;
if
(
node
.
nodeType
==
1
)
{
nextNode
=
getNonDescendant
(
'nextSibling'
,
node
)
;
if
(
node
.
nodeType
=
==
1
)
{
handler
.
end
(
node
.
nodeName
.
toLowerCase
());
}
}
...
...
@@ -387,29 +542,29 @@ function htmlParser(html, handler) {
node
=
nextNode
;
}
while
(
node
=
inertBodyElement
.
firstChild
)
{
while
((
node
=
inertBodyElement
.
firstChild
)
)
{
inertBodyElement
.
removeChild
(
node
);
}
}
}
function
attrToMap
(
attrs
)
{
function
attrToMap
(
attrs
)
{
var
map
=
{};
for
(
var
i
=
0
,
ii
=
attrs
.
length
;
i
<
ii
;
i
++
)
{
var
attr
=
attrs
[
i
];
map
[
attr
.
name
]
=
attr
.
value
;
}
return
map
;
}
}
/**
/**
* Escapes all potentially dangerous characters, so that the
* resulting string can be safely inserted into attribute or
* element text.
* @param value
* @returns {string} escaped text
*/
function
encodeEntities
(
value
)
{
function
encodeEntities
(
value
)
{
return
value
.
replace
(
/&/g
,
'&'
).
replace
(
SURROGATE_PAIR_REGEXP
,
function
(
value
)
{
...
...
@@ -422,9 +577,9 @@ function encodeEntities(value) {
}).
replace
(
/</g
,
'<'
).
replace
(
/>/g
,
'>'
);
}
}
/**
/**
* create an HTML/XML writer which writes to buffer
* @param {Array} buf use buf.join('') to get out sanitized html string
* @returns {object} in the form of {
...
...
@@ -434,20 +589,20 @@ function encodeEntities(value) {
* comment: function(text) {}
* }
*/
function
htmlSanitizeWriter
(
buf
,
uriValidator
)
{
function
htmlSanitizeWriterImpl
(
buf
,
uriValidator
)
{
var
ignoreCurrentElement
=
false
;
var
out
=
angular
.
bind
(
buf
,
buf
.
push
);
var
out
=
bind
(
buf
,
buf
.
push
);
return
{
start
:
function
(
tag
,
attrs
)
{
tag
=
angular
.
lowercase
(
tag
);
tag
=
lowercase
(
tag
);
if
(
!
ignoreCurrentElement
&&
blockedElements
[
tag
])
{
ignoreCurrentElement
=
tag
;
}
if
(
!
ignoreCurrentElement
&&
validElements
[
tag
]
===
true
)
{
out
(
'<'
);
out
(
tag
);
angular
.
forEach
(
attrs
,
function
(
value
,
key
)
{
var
lkey
=
angular
.
lowercase
(
key
);
forEach
(
attrs
,
function
(
value
,
key
)
{
var
lkey
=
lowercase
(
key
);
var
isImage
=
(
tag
===
'img'
&&
lkey
===
'src'
)
||
(
lkey
===
'background'
);
if
(
validAttrs
[
lkey
]
===
true
&&
(
uriAttrs
[
lkey
]
!==
true
||
uriValidator
(
value
,
isImage
)))
{
...
...
@@ -462,12 +617,13 @@ function htmlSanitizeWriter(buf, uriValidator) {
}
},
end
:
function
(
tag
)
{
tag
=
angular
.
lowercase
(
tag
);
tag
=
lowercase
(
tag
);
if
(
!
ignoreCurrentElement
&&
validElements
[
tag
]
===
true
&&
voidElements
[
tag
]
!==
true
)
{
out
(
'</'
);
out
(
tag
);
out
(
'>'
);
}
// eslint-disable-next-line eqeqeq
if
(
tag
==
ignoreCurrentElement
)
{
ignoreCurrentElement
=
false
;
}
...
...
@@ -478,17 +634,18 @@ function htmlSanitizeWriter(buf, uriValidator) {
}
}
};
}
}
/**
/**
* When IE9-11 comes across an unknown namespaced attribute e.g. 'xlink:foo' it adds 'xmlns:ns1' attribute to declare
* ns1 namespace and prefixes the attribute with 'ns1' (e.g. 'ns1:xlink:foo'). This is undesirable since we don't want
* to allow any of these custom attributes. This method strips them all.
*
* @param node Root element to process
*/
function
stripCustomNsAttrs
(
node
)
{
function
stripCustomNsAttrs
(
node
)
{
while
(
node
)
{
if
(
node
.
nodeType
===
window
.
Node
.
ELEMENT_NODE
)
{
var
attrs
=
node
.
attributes
;
for
(
var
i
=
0
,
l
=
attrs
.
length
;
i
<
l
;
i
++
)
{
...
...
@@ -507,32 +664,46 @@ function stripCustomNsAttrs(node) {
stripCustomNsAttrs
(
nextNode
);
}
nextNode
=
node
.
nextSibling
;
if
(
nextNode
)
{
stripCustomNsAttrs
(
nextNode
);
node
=
getNonDescendant
(
'nextSibling'
,
node
);
}
}
}
function
getNonDescendant
(
propName
,
node
)
{
// An element is clobbered if its `propName` property points to one of its descendants
var
nextNode
=
node
[
propName
];
if
(
nextNode
&&
nodeContains
.
call
(
node
,
nextNode
))
{
throw
$sanitizeMinErr
(
'elclob'
,
'Failed to sanitize html because the element is clobbered: {0}'
,
node
.
outerHTML
||
node
.
outerText
);
}
return
nextNode
;
}
}
function
sanitizeText
(
chars
)
{
var
buf
=
[];
var
writer
=
htmlSanitizeWriter
(
buf
,
noop
);
writer
.
chars
(
chars
);
return
buf
.
join
(
''
);
}
// define ngSanitize module and register $sanitize service
angular
.
module
(
'ngSanitize'
,
[]).
provider
(
'$sanitize'
,
$SanitizeProvider
);
/* global sanitizeText: false */
angular
.
module
(
'ngSanitize'
,
[])
.
provider
(
'$sanitize'
,
$SanitizeProvider
)
.
info
({
angularVersion
:
'1.8.2'
});
/**
/**
* @ngdoc filter
* @name linky
* @kind function
*
* @description
* Finds links in text input and turns them into html links. Supports `http/https/
ftp/mailto` and
* Finds links in text input and turns them into html links. Supports `http/https/ftp/s
ftp/mailto` and
* plain email address links.
*
* Requires the {@link ngSanitize `ngSanitize`} module to be installed.
*
* @param {string} text Input text.
* @param {string} target
Window (`_blank|_self|_parent|_top`) or named frame to open links in.
* @param {string} [target]
Window (`_blank|_self|_parent|_top`) or named frame to open links in.
* @param {object|function(url)} [attributes] Add custom attributes to the link element.
*
* Can be one of:
...
...
@@ -550,7 +721,7 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
<span ng-bind-html="linky_expression | linky"></span>
*
* @example
<example module="linkyExample" deps="angular-sanitize.js">
<example module="linkyExample" deps="angular-sanitize.js"
name="linky-filter"
>
<file name="index.html">
<div ng-controller="ExampleController">
Snippet: <textarea ng-model="snippet" cols="60" rows="3"></textarea>
...
...
@@ -598,10 +769,10 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
angular.module('linkyExample', ['ngSanitize'])
.controller('ExampleController', ['$scope', function($scope) {
$scope.snippet =
'Pretty text with some links:\n'+
'http://angularjs.org/,\n'+
'mailto:us@somewhere.org,\n'+
'another@somewhere.org,\n'+
'Pretty text with some links:\n'
+
'http://angularjs.org/,\n'
+
'mailto:us@somewhere.org,\n'
+
'another@somewhere.org,\n'
+
'and one more: ftp://127.0.0.1/.';
$scope.snippetWithSingleURL = 'http://angularjs.org/';
}]);
...
...
@@ -647,12 +818,15 @@ angular.module('ngSanitize', []).provider('$sanitize', $SanitizeProvider);
</file>
</example>
*/
angular
.
module
(
'ngSanitize'
).
filter
(
'linky'
,
[
'$sanitize'
,
function
(
$sanitize
)
{
angular
.
module
(
'ngSanitize'
).
filter
(
'linky'
,
[
'$sanitize'
,
function
(
$sanitize
)
{
var
LINKY_URL_REGEXP
=
/
((
ftp|https
?)
:
\/\/
|
(
www
\.)
|
(
mailto:
)?[
A-Za-z0-9._%+-
]
+@
)\S
*
[^\s
.;,(){}<>"
\u
201d
\u
2019
]
/i
,
/
((
s
?
ftp|https
?)
:
\/\/
|
(
www
\.)
|
(
mailto:
)?[
A-Za-z0-9._%+-
]
+@
)\S
*
[^\s
.;,(){}<>"
\u
201d
\u
2019
]
/i
,
MAILTO_REGEXP
=
/^mailto:/i
;
var
linkyMinErr
=
angular
.
$$minErr
(
'linky'
);
var
isDefined
=
angular
.
isDefined
;
var
isFunction
=
angular
.
isFunction
;
var
isObject
=
angular
.
isObject
;
var
isString
=
angular
.
isString
;
return
function
(
text
,
target
,
attributes
)
{
...
...
@@ -660,8 +834,8 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
if
(
!
isString
(
text
))
throw
linkyMinErr
(
'notstring'
,
'Expected string but received: {0}'
,
text
);
var
attributesFn
=
angular
.
isFunction
(
attributes
)
?
attributes
:
angular
.
isObject
(
attributes
)
?
function
getAttributesObject
()
{
return
attributes
;}
:
isFunction
(
attributes
)
?
attributes
:
isObject
(
attributes
)
?
function
getAttributesObject
()
{
return
attributes
;}
:
function
getEmptyAttributesObject
()
{
return
{};};
var
match
;
...
...
@@ -699,7 +873,7 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
html
.
push
(
key
+
'="'
+
linkAttributes
[
key
]
+
'" '
);
}
if
(
angular
.
isDefined
(
target
)
&&
!
(
'target'
in
linkAttributes
))
{
if
(
isDefined
(
target
)
&&
!
(
'target'
in
linkAttributes
))
{
html
.
push
(
'target="'
,
target
,
'" '
);
...
...
@@ -711,7 +885,7 @@ angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) {
html
.
push
(
'</a>'
);
}
};
}]);
}]);
})(
window
,
window
.
angular
);
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment