From f674336cc1fc9689b2237d68261715aa203f9dee Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 16 May 2023 18:17:25 +0400 Subject: [PATCH] Fixed external links in the viewer iframe Before this fix clicking an external link in the viewer iframe had no effect (other than an error being reported in the browser dev tools console) because the attempt to navigate the top browser context was suppressed due to sandboxing. This commit works around that limitation by providing message-based API for top context navigation. Now malicious pages can break out of the viewer iframe as soon as they learn about that API :) --- static/skin/viewer.js | 21 ++++++++++++++------- test/server.cpp | 4 ++-- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/static/skin/viewer.js b/static/skin/viewer.js index 2c3c80a14..98b4bf481 100644 --- a/static/skin/viewer.js +++ b/static/skin/viewer.js @@ -243,9 +243,10 @@ function matchingAncestorElement(el, context, selector) { const block_path = `${root}/catch/external`; -function blockLink(target) { - const encodedHref = encodeURIComponent(target.href); - target.setAttribute("href", block_path + "?source=" + encodedHref); +function blockLink(url) { + return viewerSettings.linkBlockingEnabled + ? block_path + "?source=" + encodeURIComponent(url) + : url; } function isExternalUrl(url) { @@ -262,10 +263,8 @@ function onClickEvent(e) { const target = matchingAncestorElement(e.target, iframeDocument, "a"); if (target !== null && "href" in target) { if ( isExternalUrl(target.href) ) { - target.setAttribute("target", "_top"); - if ( viewerSettings.linkBlockingEnabled ) { - return blockLink(target); - } + target.setAttribute("href", blockLink(target.href)); + contentIframe.contentWindow.parent.postMessage({ externalURL : target.href }, "*"); } } } @@ -446,6 +445,13 @@ function changeUILanguage() { }); } +function handleMessage(event) { + console.log("handleMessage"); + if ( event.data.externalURL ) { + window.location = event.data.externalURL; + } +} + function setupViewer() { // Defer the call of handle_visual_viewport_change() until after the // presence or absence of the taskbar as determined by this function @@ -453,6 +459,7 @@ function setupViewer() { setTimeout(handle_visual_viewport_change, 0); window.onresize = handle_visual_viewport_change; + window.addEventListener("message", handleMessage); const kiwixToolBarWrapper = document.getElementById('kiwixtoolbarwrapper'); if ( ! viewerSettings.toolbarEnabled ) { diff --git a/test/server.cpp b/test/server.cpp index 961ef9a06..97e1c6e74 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -73,7 +73,7 @@ const ResourceCollection resources200Compressible{ { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/taskbar.css?cacheid=bbdaf425" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/viewer.js" }, - { STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=b9a574d4" }, + { STATIC_CONTENT, "/ROOT%23%3F/skin/viewer.js?cacheid=d575e81a" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf" }, { STATIC_CONTENT, "/ROOT%23%3F/skin/fonts/Poppins.ttf?cacheid=af705837" }, { DYNAMIC_CONTENT, "/ROOT%23%3F/skin/fonts/Roboto.ttf" }, @@ -312,7 +312,7 @@ R"EXPECTEDRESULT( - + const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032";