From 9c4c37f1830f02f65f10f83e0647b27f01943faf Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Tue, 9 May 2023 16:28:59 +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. A workaround is to let the external link blocker page to be loaded in the viewer iframe and then detect that situation and handle it in the viewer JS code. This commit makes external links clickable but (temporarily) handles them by unconditionally displaying the confirmation page (as if kiwix-serve has been started with the --blockexternal option). This will be fixed shortly. A small defect is that the browsing history entry preceding the external resource access confirmation page is duplicated. --- static/skin/viewer.js | 29 ++++++++++++++++++++++------- test/server.cpp | 4 ++-- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/static/skin/viewer.js b/static/skin/viewer.js index 2c3c80a14..d1e7bb1ae 100644 --- a/static/skin/viewer.js +++ b/static/skin/viewer.js @@ -23,7 +23,7 @@ function userUrl2IframeUrl(url) { } function getBookFromUserUrl(url) { - if ( url == '' ) { + if ( url == '' || url.startsWith('catch/external?') ) { return null; } @@ -131,6 +131,10 @@ function iframeUrl2UserUrl(url, query) { return ''; } + if ( url == `${root}/catch/external` ) { + return `catch/external${query}`; + } + if ( url == `${root}/search` ) { return `search${query}`; } @@ -224,8 +228,12 @@ function handle_content_url_change() { const iframeContentUrl = iframeLocation.pathname; const iframeContentQuery = iframeLocation.search; const newHash = iframeUrl2UserUrl(iframeContentUrl, iframeContentQuery); - history.replaceState(viewerState, null, makeURL(location.search, newHash)); - updateCurrentBookIfNeeded(newHash); + if ( newHash.startsWith('catch/external?') ) { + handleInterceptedExternalLink(newHash); + } else { + history.replaceState(viewerState, null, makeURL(location.search, newHash)); + updateCurrentBookIfNeeded(newHash); + } }; //////////////////////////////////////////////////////////////////////////////// @@ -262,10 +270,7 @@ 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); - } + return blockLink(target); } } } @@ -304,6 +309,16 @@ function setup_external_link_blocker() { setupEventHandler(contentIframe.contentDocument, 'a', 'click', onClickEvent); } +function handleInterceptedExternalLink(catchExternalUrl) { + // The external link blocking page was loaded in the viewer iframe. + // We need to get rid of the viewer taskbar and display the confirmation + // page in the top frame. + const urlpath = `${root}/` + catchExternalUrl; + history.back(); // drop from the browsing history the state where the + // external link catcher page is loaded in the iframe ... + window.location = urlpath; // ... and load it in the top frame instead +} + //////////////////////////////////////////////////////////////////////////////// // End of external link blocking //////////////////////////////////////////////////////////////////////////////// diff --git a/test/server.cpp b/test/server.cpp index 961ef9a06..862dd3ba5 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=202f8641" }, { 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";