diff --git a/src/content-handlers/iiif/extensions/uv-openseadragon-extension/DownloadDialogue.tsx b/src/content-handlers/iiif/extensions/uv-openseadragon-extension/DownloadDialogue.tsx index aa129f3c6..8d8d02e10 100644 --- a/src/content-handlers/iiif/extensions/uv-openseadragon-extension/DownloadDialogue.tsx +++ b/src/content-handlers/iiif/extensions/uv-openseadragon-extension/DownloadDialogue.tsx @@ -496,7 +496,7 @@ const DownloadDialogue = ({ defaultLabel: string; type: DownloadOption; }) { - const renderings: Rendering[] = resource.getRenderings(); + const renderings: Rendering[] = getSafeRenderings(resource.getRenderings()); return ( <> @@ -539,10 +539,23 @@ const DownloadDialogue = ({ // return resource.getRenderings().length > 0; // } + function isSafeRenderingUri(uri) { + try { + const parsed = new URL(uri, window.location.href); + return ["http:", "https:"].includes(parsed.protocol); + } catch { + return false; + } + } + + function getSafeRenderings(renderings: Rendering[]): Rendering[] { + return renderings.filter((r: Rendering) => isSafeRenderingUri(r.id)); + } + function hasRangeRenderings(): boolean { const canvas: Canvas = getSelectedCanvas(); return (canvas.ranges ?? []).some( - (range: Range) => range.getRenderings().length > 0 + (range: Range) => getSafeRenderings(range.getRenderings()).length > 0 ); } @@ -566,9 +579,9 @@ const DownloadDialogue = ({ function hasImageRenderings() { const canvas: Canvas = getSelectedCanvas(); const images: Annotation[] = canvas.getImages(); - return images.some( - (image: Annotation) => image.getResource().getRenderings().length > 0 + (image: Annotation) => + getSafeRenderings(image.getResource().getRenderings()).length > 0 ); } @@ -592,7 +605,7 @@ const DownloadDialogue = ({ function hasCanvasRenderings() { const canvas: Canvas = getSelectedCanvas(); - return canvas.getRenderings().length > 0; + return getSafeRenderings(canvas.getRenderings()).length > 0; } function CanvasRenderings() { @@ -609,7 +622,8 @@ const DownloadDialogue = ({ function hasManifestRenderings(): boolean { return ( - sequence.getRenderings().length > 0 || manifest.getRenderings().length > 0 + getSafeRenderings(sequence.getRenderings()).length > 0 || + getSafeRenderings(manifest.getRenderings()).length > 0 ); } diff --git a/src/content-handlers/iiif/modules/uv-dialogues-module/DownloadDialogue.ts b/src/content-handlers/iiif/modules/uv-dialogues-module/DownloadDialogue.ts index 8f35b1ded..fbca13b37 100644 --- a/src/content-handlers/iiif/modules/uv-dialogues-module/DownloadDialogue.ts +++ b/src/content-handlers/iiif/modules/uv-dialogues-module/DownloadDialogue.ts @@ -91,6 +91,15 @@ export class DownloadDialogue extends Dialogue< this.updateTermsOfUseButton(); } + isSafeRenderingUri(uri) { + try { + const parsed = new URL(uri, window.location.href); + return ["http:", "https:"].includes(parsed.protocol); + } catch { + return false; + } + } + addEntireFileDownloadOptions(): void { if ( this.isDownloadOptionAvailable(DownloadOption.ENTIRE_FILE_AS_ORIGINAL) @@ -104,7 +113,9 @@ export class DownloadDialogue extends Dialogue< let renderingFound: boolean = false; - const renderings: Rendering[] = canvas.getRenderings(); + const renderings: Rendering[] = canvas + .getRenderings() + .filter((r: Rendering) => this.isSafeRenderingUri(r.id)); for (let i = 0; i < renderings.length; i++) { const rendering: Rendering = renderings[i]; @@ -113,6 +124,7 @@ export class DownloadDialogue extends Dialogue< if (renderingFormat) { format = renderingFormat.toString(); } + this.addEntireFileDownloadOption( rendering.id, LanguageMap.getValue(rendering.getLabel()), @@ -130,7 +142,7 @@ export class DownloadDialogue extends Dialogue< const annotation: Annotation = annotations[i]; const body: AnnotationBody[] = annotation.getBody(); - if (body.length) { + if (body.length && this.isSafeRenderingUri(body[0].id)) { const format: MediaType | null = body[0].getFormat(); if (format) { @@ -172,13 +184,16 @@ export class DownloadDialogue extends Dialogue< label += " (" + fileType + ")"; } - this.$downloadOptions.append( - '
  • ' + - label + - "
  • " - ); + const $link = $("", { + href: uri, + target: "_blank", + download: "", + tabindex: "0", + text: label, + }); + + const $li = $("
  • ").append($link); + this.$downloadOptions.append($li); } resetDynamicDownloadOptions(): void { @@ -192,7 +207,9 @@ export class DownloadDialogue extends Dialogue< defaultLabel: string, type: DownloadOption ): IRenderingOption[] { - const renderings: Rendering[] = resource.getRenderings(); + const renderings: Rendering[] = resource + .getRenderings() + .filter((r: Rendering) => this.isSafeRenderingUri(r.id)); const downloadOptions: any[] = [];