@@ -117,12 +117,12 @@ describe('svg+text utils', function() {
117117
118118 it ( 'whitelists http hrefs' , function ( ) {
119119 var node = mockTextSVGElement (
120- '<a href="https ://bl.ocks.org/">bl.ocks.org</a>'
120+ '<a href="http ://bl.ocks.org/">bl.ocks.org</a>'
121121 ) ;
122122
123123 expect ( node . text ( ) ) . toEqual ( 'bl.ocks.org' ) ;
124124 assertAnchorAttrs ( node ) ;
125- assertAnchorLink ( node , 'https ://bl.ocks.org/' ) ;
125+ assertAnchorLink ( node , 'http ://bl.ocks.org/' ) ;
126126 } ) ;
127127
128128 it ( 'whitelists https hrefs' , function ( ) {
@@ -512,3 +512,113 @@ describe('svg+text utils', function() {
512512 } ) ;
513513 } ) ;
514514} ) ;
515+
516+ describe ( 'sanitizeHTML' , function ( ) {
517+ 'use strict' ;
518+
519+ var stringFromCodePoint ;
520+
521+ beforeAll ( function ( ) {
522+ stringFromCodePoint = String . fromCodePoint ;
523+ } ) ;
524+
525+ afterEach ( function ( ) {
526+ String . fromCodePoint = stringFromCodePoint ;
527+ } ) ;
528+
529+ function mockHTML ( txt ) {
530+ return util . sanitizeHTML ( txt ) ;
531+ }
532+
533+ afterEach ( function ( ) {
534+ d3 . selectAll ( '.text-tester' ) . remove ( ) ;
535+ } ) ;
536+
537+ it ( 'checks for XSS attack in href' , function ( ) {
538+ var innerHTML = mockHTML (
539+ '<a href="javascript:alert(\'attack\')">XSS</a>'
540+ ) ;
541+
542+ expect ( innerHTML ) . toEqual ( '<a>XSS</a>' ) ;
543+ } ) ;
544+
545+ it ( 'checks for XSS attack in href (with plenty of white spaces)' , function ( ) {
546+ var innerHTML = mockHTML (
547+ '<a href = " javascript:alert(\'attack\')">XSS</a>'
548+ ) ;
549+
550+ expect ( innerHTML ) . toEqual ( '<a>XSS</a>' ) ;
551+ } ) ;
552+
553+ it ( 'whitelists relative hrefs (interpreted as http)' , function ( ) {
554+ var innerHTML = mockHTML (
555+ '<a href="/mylink">mylink</a>'
556+ ) ;
557+
558+ expect ( innerHTML ) . toEqual ( '<a href="/mylink">mylink</a>' ) ;
559+ } ) ;
560+
561+ it ( 'whitelists http hrefs' , function ( ) {
562+ var innerHTML = mockHTML (
563+ '<a href="http://bl.ocks.org/">bl.ocks.org</a>'
564+ ) ;
565+
566+ expect ( innerHTML ) . toEqual ( '<a href="http://bl.ocks.org/">bl.ocks.org</a>' ) ;
567+ } ) ;
568+
569+ it ( 'whitelists https hrefs' , function ( ) {
570+ var innerHTML = mockHTML (
571+ '<a href="https://chart-studio.plotly.com">plotly</a>'
572+ ) ;
573+
574+ expect ( innerHTML ) . toEqual ( '<a href="https://chart-studio.plotly.com">plotly</a>' ) ;
575+ } ) ;
576+
577+ it ( 'whitelists mailto hrefs' , function ( ) {
578+ var innerHTML = mockHTML (
579+ '<a href="mailto:support@plotly.com">support</a>'
580+ ) ;
581+
582+ expect ( innerHTML ) . toEqual ( '<a href="mailto:support@plotly.com">support</a>' ) ;
583+ } ) ;
584+
585+ it ( 'drops XSS attacks in href' , function ( ) {
586+ // "XSS" gets interpreted as a relative link (http)
587+ var textCases = [
588+ '<a href="XSS\" onmouseover="alert(1)\" style="font-size:300px">Subtitle</a>' ,
589+ '<a href="XSS" onmouseover="alert(1)" style="font-size:300px">Subtitle</a>'
590+ ] ;
591+
592+ textCases . forEach ( function ( textCase ) {
593+ var innerHTML = mockHTML ( textCase ) ;
594+
595+ expect ( innerHTML ) . toEqual ( '<a style="font-size:300px" href="XSS">Subtitle</a>' ) ;
596+ } ) ;
597+ } ) ;
598+
599+ it ( 'accepts href and style in <a> in any order and tosses other stuff' , function ( ) {
600+ var textCases = [
601+ '<a href="x" style="y">z</a>' ,
602+ '<a href=\'x\' style="y">z</a>' ,
603+ '<A HREF="x"StYlE=\'y\'>z</a>' ,
604+ '<a style=\'y\'href=\'x\'>z</A>' ,
605+ '<a \t\r\n href="x" \n\r\t style="y" \n \t \r>z</a>' ,
606+ '<a magic="true" href="x" weather="cloudy" style="y" speed="42">z</a>' ,
607+ '<a href="x" style="y">z</a href="nope" style="for real?">' ,
608+ ] ;
609+
610+ textCases . forEach ( function ( textCase ) {
611+ var innerHTML = mockHTML ( textCase ) ;
612+
613+ expect ( innerHTML ) . toEqual ( '<a style="y" href="x">z</a>' ) ;
614+ } ) ;
615+ } ) ;
616+
617+ it ( 'allows encoded URIs in href' , function ( ) {
618+ var innerHTML = mockHTML (
619+ '<a href="https://example.com/?q=date%20%3E=%202018-01-01">click</a>'
620+ ) ;
621+
622+ expect ( innerHTML ) . toEqual ( '<a href="https://example.com/?q=date%20%3E=%202018-01-01">click</a>' ) ;
623+ } ) ;
624+ } ) ;
0 commit comments