@@ -263,6 +263,19 @@ class DataTable {
263263 this . updateGlobus ( ) ;
264264 }
265265
266+ cleanHtml ( html ) {
267+ const parser = new DOMParser ( ) ;
268+ const ele = parser . parseFromString ( html , 'text/html' ) ;
269+
270+ const imgs = ele . querySelectorAll ( 'img' ) ;
271+ imgs . forEach ( img => { img . parentElement . removeChild ( img ) } ) ;
272+
273+ const scripts = ele . querySelectorAll ( 'script' ) ;
274+ scripts . forEach ( script => { script . parentElement . removeChild ( script ) } ) ;
275+
276+ return ele . body . innerHTML ;
277+ }
278+
266279 async reloadTable ( url ) {
267280 var request_url = url || history . state . currentDirectoryUrl ;
268281
@@ -272,7 +285,7 @@ class DataTable {
272285 const response = await fetch ( request_url , { headers : { 'Accept' : 'application/json' } , cache : 'no-store' } ) ;
273286 const data = await this . dataFromJsonResponse ( response ) ;
274287 history . state . currentFilenames = Array . from ( data . files , x => x . name ) ;
275- $ ( '#shell-wrapper' ) . replaceWith ( ( data . shell_dropdown_html ) ) ;
288+ $ ( '#shell-wrapper' ) . replaceWith ( this . cleanHtml ( data . shell_dropdown_html ) ) ;
276289
277290 this . _table . clear ( ) ;
278291 this . _table . rows . add ( data . files ) ;
@@ -358,6 +371,14 @@ class DataTable {
358371 return new Promise ( ( resolve , reject ) => {
359372 Promise . resolve ( response )
360373 . then ( response => response . ok ? Promise . resolve ( response ) : Promise . reject ( new Error ( response . statusText ) ) )
374+ . then ( response => {
375+ const disposition = response . headers . get ( 'content-disposition' ) ;
376+ if ( disposition === null ) {
377+ return response ;
378+ } else {
379+ throw new Error ( "Cannot navigate to a file." ) ;
380+ }
381+ } )
361382 . then ( response => response . json ( ) )
362383 . then ( data => data . error_message ? Promise . reject ( new Error ( data . error_message ) ) : resolve ( data ) )
363384 . catch ( ( e ) => reject ( e ) )
@@ -367,7 +388,7 @@ class DataTable {
367388 renderNameColumn ( data , type , row , meta ) {
368389 let element = undefined ;
369390
370- if ( ! downloadEnabled ( ) || row . url === undefined ) {
391+ if ( ! downloadEnabled ( ) || row . url === undefined || this . isInvalidURL ( row . url ) ) {
371392 element = document . createElement ( 'span' ) ;
372393 } else {
373394 element = document . createElement ( 'a' ) ;
@@ -382,6 +403,16 @@ class DataTable {
382403 return element . outerHTML ;
383404 }
384405
406+ isInvalidURL ( urlString ) {
407+ try {
408+ const url = new URL ( urlString , window . location . origin ) ;
409+ const protocol = url . protocol ;
410+ return protocol === "javascript:" || protocol === "data:" || protocol === "vbscript:" ;
411+ } catch ( error ) {
412+ return true ;
413+ }
414+ }
415+
385416 actionsBtnTemplate ( options ) {
386417 // options: { row_index: meta.row,
387418 // file: row.type != 'd',
@@ -501,7 +532,7 @@ class DataTable {
501532 this . reloadTable ( url )
502533 . then ( ( data ) => {
503534 if ( data ) {
504- $ ( '#path-breadcrumbs' ) . html ( data . breadcrumbs_html ) ;
535+ $ ( '#path-breadcrumbs' ) . html ( this . cleanHtml ( data . breadcrumbs_html ) ) ;
505536 if ( pushState ) {
506537 // Clear search query when moving to another directory.
507538 this . _table . search ( '' ) . draw ( ) ;
0 commit comments