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