From dde7ec8e64c496fec23b3e6249b86873660a8324 Mon Sep 17 00:00:00 2001 From: David Baker Date: Wed, 10 Sep 2014 15:43:27 +0100 Subject: Upgrade angularjs to 1.3.0-rc1 since this is new development --- webclient/js/angular-sanitize.js | 278 ++++++++++++++++++++++++--------------- 1 file changed, 174 insertions(+), 104 deletions(-) (limited to 'webclient/js/angular-sanitize.js') diff --git a/webclient/js/angular-sanitize.js b/webclient/js/angular-sanitize.js index d34522ac8d..ec46895f68 100644 --- a/webclient/js/angular-sanitize.js +++ b/webclient/js/angular-sanitize.js @@ -1,6 +1,6 @@ /** - * @license AngularJS v1.2.0 - * (c) 2010-2012 Google, Inc. http://angularjs.org + * @license AngularJS v1.3.0-rc.1 + * (c) 2010-2014 Google, Inc. http://angularjs.org * License: MIT */ (function(window, angular, undefined) {'use strict'; @@ -8,7 +8,7 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); /** - * @ngdoc overview + * @ngdoc module * @name ngSanitize * @description * @@ -16,7 +16,6 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); * * The `ngSanitize` module provides functionality to sanitize HTML. * - * {@installModule sanitize} * *
* @@ -42,8 +41,8 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); /** * @ngdoc service - * @name ngSanitize.$sanitize - * @function + * @name $sanitize + * @kind function * * @description * The input is sanitized by parsing the html into tokens. All safe tokens (from a whitelist) are @@ -51,25 +50,28 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize'); * it into the returned string, however, since our parser is more strict than a typical browser * parser, it's possible that some obscure input, which would be recognized as valid HTML by a * browser, won't make it through the sanitizer. + * The whitelist is configured using the functions `aHrefSanitizationWhitelist` and + * `imgSrcSanitizationWhitelist` of {@link ng.$compileProvider `$compileProvider`}. * * @param {string} html Html input. * @returns {string} Sanitized html. * * @example - - + + -
+
Snippet: @@ -101,56 +103,71 @@ var $sanitizeMinErr = angular.$$minErr('$sanitize');
- - + + it('should sanitize the html snippet by default', function() { - expect(using('#bind-html-with-sanitize').element('div').html()). + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). toBe('

an html\nclick here\nsnippet

'); }); it('should inline raw snippet if bound to a trusted value', function() { - expect(using('#bind-html-with-trust').element("div").html()). + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()). toBe("

an html\n" + "click here\n" + "snippet

"); }); it('should escape snippet without any filter', function() { - expect(using('#bind-default').element('div').html()). + expect(element(by.css('#bind-default div')).getInnerHtml()). toBe("<p style=\"color:blue\">an html\n" + "<em onmouseover=\"this.textContent='PWN3D!'\">click here</em>\n" + "snippet</p>"); }); it('should update', function() { - input('snippet').enter('new text'); - expect(using('#bind-html-with-sanitize').element('div').html()).toBe('new text'); - expect(using('#bind-html-with-trust').element('div').html()).toBe( + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new text'); + expect(element(by.css('#bind-html-with-sanitize div')).getInnerHtml()). + toBe('new text'); + expect(element(by.css('#bind-html-with-trust div')).getInnerHtml()).toBe( 'new text'); - expect(using('#bind-default').element('div').html()).toBe( + expect(element(by.css('#bind-default div')).getInnerHtml()).toBe( "new <b onclick=\"alert(1)\">text</b>"); }); -
- + + */ -var $sanitize = function(html) { +function $SanitizeProvider() { + this.$get = ['$$sanitizeUri', function($$sanitizeUri) { + return function(html) { + var buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function(uri, isImage) { + return !/^unsafe/.test($$sanitizeUri(uri, isImage)); + })); + return buf.join(''); + }; + }]; +} + +function sanitizeText(chars) { var buf = []; - htmlParser(html, htmlSanitizeWriter(buf)); - return buf.join(''); -}; + var writer = htmlSanitizeWriter(buf, angular.noop); + writer.chars(chars); + return buf.join(''); +} // Regular Expressions for parsing tags and attributes var START_TAG_REGEXP = - /^<\s*([\w:-]+)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*>/, - END_TAG_REGEXP = /^<\s*\/\s*([\w:-]+)[^>]*>/, + /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, + END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, BEGIN_TAG_REGEXP = /^/g, DOCTYPE_REGEXP = /]*?)>/i, CDATA_REGEXP = //g, - URI_REGEXP = /^((ftp|https?):\/\/|mailto:|tel:|#)/i, + SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, // Match everything outside of normal chars and " (quote character) NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; @@ -197,7 +214,7 @@ var validAttrs = angular.extend({}, uriAttrs, makeMap( '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,span,start,summary,target,title,type,'+ + 'scope,scrolling,shape,size,span,start,summary,target,title,type,'+ 'valign,value,vspace,width')); function makeMap(str) { @@ -220,10 +237,18 @@ function makeMap(str) { * @param {object} handler */ function htmlParser( html, handler ) { - var index, chars, match, stack = [], last = html; + if (typeof html !== 'string') { + if (html === null || typeof html === 'undefined') { + html = ''; + } else { + html = '' + html; + } + } + var index, chars, match, stack = [], last = html, text; stack.last = function() { return stack[ stack.length - 1 ]; }; while ( html ) { + text = ''; chars = true; // Make sure we're not in a script or style element @@ -244,7 +269,7 @@ function htmlParser( html, handler ) { match = html.match( DOCTYPE_REGEXP ); if ( match ) { - html = html.replace( match[0] , ''); + html = html.replace( match[0], ''); chars = false; } // end tag @@ -262,16 +287,23 @@ function htmlParser( html, handler ) { match = html.match( START_TAG_REGEXP ); if ( match ) { - html = html.substring( match[0].length ); - match[0].replace( START_TAG_REGEXP, parseStartTag ); + // We only have a valid start-tag if there is a '>'. + if ( match[4] ) { + html = html.substring( match[0].length ); + match[0].replace( START_TAG_REGEXP, parseStartTag ); + } chars = false; + } else { + // no ending tag found --- this piece should be encoded as an entity. + text += '<'; + html = html.substring(1); } } if ( chars ) { index = html.indexOf("<"); - var text = index < 0 ? html : html.substring( 0, index ); + text += index < 0 ? html : html.substring( 0, index ); html = index < 0 ? "" : html.substring( index ); if (handler.chars) handler.chars( decodeEntities(text) ); @@ -351,15 +383,32 @@ function htmlParser( html, handler ) { } } +var hiddenPre=document.createElement("pre"); +var spaceRe = /^(\s*)([\s\S]*?)(\s*)$/; /** * decodes all entities into regular string * @param value * @returns {string} A string with decoded entities. */ -var hiddenPre=document.createElement("pre"); function decodeEntities(value) { - hiddenPre.innerHTML=value.replace(/ * * @example - - + + -
+
Snippet: @@ -503,43 +560,44 @@ angular.module('ngSanitize', []).value('$sanitize', $sanitize);
- - + + it('should linkify the snippet with urls', function() { - expect(using('#linky-filter').binding('snippet | linky')). - toBe('Pretty text with some links: ' + - 'http://angularjs.org/, ' + - 'us@somewhere.org, ' + - 'another@somewhere.org, ' + - 'and one more: ftp://127.0.0.1/.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(4); }); - it ('should not linkify snippet without the linky filter', function() { - expect(using('#escaped-html').binding('snippet')). - toBe("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/."); + it('should not linkify snippet without the linky filter', function() { + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()). + toBe('Pretty text with some links: http://angularjs.org/, mailto:us@somewhere.org, ' + + 'another@somewhere.org, and one more: ftp://127.0.0.1/.'); + expect(element.all(by.css('#escaped-html a')).count()).toEqual(0); }); it('should update', function() { - input('snippet').enter('new http://link.'); - expect(using('#linky-filter').binding('snippet | linky')). - toBe('new http://link.'); - expect(using('#escaped-html').binding('snippet')).toBe('new http://link.'); + element(by.model('snippet')).clear(); + element(by.model('snippet')).sendKeys('new http://link.'); + expect(element(by.id('linky-filter')).element(by.binding('snippet | linky')).getText()). + toBe('new http://link.'); + expect(element.all(by.css('#linky-filter a')).count()).toEqual(1); + expect(element(by.id('escaped-html')).element(by.binding('snippet')).getText()) + .toBe('new http://link.'); }); it('should work with the target property', function() { - expect(using('#linky-target').binding("snippetWithTarget | linky:'_blank'")). - toBe('http://angularjs.org/'); + expect(element(by.id('linky-target')). + element(by.binding("snippetWithTarget | linky:'_blank'")).getText()). + toBe('http://angularjs.org/'); + expect(element(by.css('#linky-target a')).getAttribute('target')).toEqual('_blank'); }); - - + + */ -angular.module('ngSanitize').filter('linky', function() { +angular.module('ngSanitize').filter('linky', ['$sanitize', function($sanitize) { var LINKY_URL_REGEXP = - /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>]/, + /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s.;,(){}<>"]/, MAILTO_REGEXP = /^mailto:/; return function(text, target) { @@ -547,31 +605,43 @@ angular.module('ngSanitize').filter('linky', function() { var match; var raw = text; var html = []; - // TODO(vojta): use $sanitize instead - var writer = htmlSanitizeWriter(html); var url; var i; - var properties = {}; - if (angular.isDefined(target)) { - properties.target = target; - } while ((match = raw.match(LINKY_URL_REGEXP))) { // We can not end in these as they are sometimes found at the end of the sentence url = match[0]; // if we did not match ftp/http/mailto then assume mailto if (match[2] == match[3]) url = 'mailto:' + url; i = match.index; - writer.chars(raw.substr(0, i)); - properties.href = url; - writer.start('a', properties); - writer.chars(match[0].replace(MAILTO_REGEXP, '')); - writer.end('a'); + addText(raw.substr(0, i)); + addLink(url, match[0].replace(MAILTO_REGEXP, '')); raw = raw.substring(i + match[0].length); } - writer.chars(raw); - return html.join(''); + addText(raw); + return $sanitize(html.join('')); + + function addText(text) { + if (!text) { + return; + } + html.push(sanitizeText(text)); + } + + function addLink(url, text) { + html.push(''); + addText(text); + html.push(''); + } }; -}); +}]); })(window, window.angular); -- cgit 1.4.1