From c7d8081e9a5a3a68029891f7a797016a4ab09eb8 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 15 Dec 2022 18:21:22 +0400 Subject: [PATCH 1/3] gotoUrl() takes URLs relative to root location --- static/skin/viewer.js | 10 +++++----- test/server.cpp | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/static/skin/viewer.js b/static/skin/viewer.js index 10e8b48d9..50d91ea6c 100644 --- a/static/skin/viewer.js +++ b/static/skin/viewer.js @@ -43,17 +43,17 @@ function gotoMainPageOfCurrentBook() { } function gotoUrl(url) { - contentIframe.src = url; + contentIframe.src = root + url; } function gotoRandomPage() { - gotoUrl(`${root}/random?content=${currentBook}`); + gotoUrl(`/random?content=${currentBook}`); } function performSearch() { const searchbox = document.getElementById('kiwixsearchbox'); const q = encodeURIComponent(searchbox.value); - gotoUrl(`${root}/search?books.name=${currentBook}&pattern=${q}`); + gotoUrl(`/search?books.name=${currentBook}&pattern=${q}`); } function suggestionsApiURL() @@ -338,9 +338,9 @@ function setupSuggestions() { element: (item, data) => { let searchLink; if (data.value.kind == "path") { - searchLink = `${root}/${currentBook}/${htmlDecode(data.value.path)}`; + searchLink = `/${currentBook}/${htmlDecode(data.value.path)}`; } else { - searchLink = `${root}/search?content=${encodeURIComponent(currentBook)}&pattern=${encodeURIComponent(htmlDecode(data.value.value))}`; + searchLink = `/search?content=${encodeURIComponent(currentBook)}&pattern=${encodeURIComponent(htmlDecode(data.value.value))}`; } const jsAction = `gotoUrl('${searchLink}')`; // Values of the href attribute are assumed by the browser to be diff --git a/test/server.cpp b/test/server.cpp index 2c6156c23..c757be4b6 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -69,7 +69,7 @@ const ResourceCollection resources200Compressible{ { DYNAMIC_CONTENT, "/ROOT/skin/taskbar.css" }, { STATIC_CONTENT, "/ROOT/skin/taskbar.css?cacheid=216d6b5d" }, { DYNAMIC_CONTENT, "/ROOT/skin/viewer.js" }, - { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=0933a233" }, + { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=fa85ec82" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf" }, { STATIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Roboto.ttf" }, @@ -291,7 +291,7 @@ R"EXPECTEDRESULT( - + const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032"; From 12140098e60703812ce6cfb7cc73b75376b17b94 Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 15 Dec 2022 18:48:16 +0400 Subject: [PATCH 2/3] Extracted makeJSLink() --- static/skin/viewer.js | 19 ++++++++++++------- test/server.cpp | 4 ++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/static/skin/viewer.js b/static/skin/viewer.js index 50d91ea6c..9571b1eea 100644 --- a/static/skin/viewer.js +++ b/static/skin/viewer.js @@ -56,6 +56,16 @@ function performSearch() { gotoUrl(`/search?books.name=${currentBook}&pattern=${q}`); } +function makeJSLink(jsCodeString, linkText, linkAttr="") { + // Values of the href attribute are assumed by the browser to be + // fully URI-encoded (no matter what the scheme is). Therefore, in + // order to prevent the browser from decoding any URI-encoded parts + // in the JS code we have to URI-encode a second time. + // (see https://stackoverflow.com/questions/33721510) + const uriEncodedJSCode = encodeURIComponent(jsCodeString); + return `${linkText}`; +} + function suggestionsApiURL() { return `${root}/suggest?content=${encodeURIComponent(currentBook)}`; @@ -343,13 +353,8 @@ function setupSuggestions() { searchLink = `/search?content=${encodeURIComponent(currentBook)}&pattern=${encodeURIComponent(htmlDecode(data.value.value))}`; } const jsAction = `gotoUrl('${searchLink}')`; - // Values of the href attribute are assumed by the browser to be - // fully URI-encoded (no matter what the scheme is). Therefore, in - // order to prevent the browser from decoding the URI-encoded parts - // of searchLink we have to URI-encode a second time. - // (see https://stackoverflow.com/questions/33721510) - const jsActionURIEncoded = encodeURIComponent(jsAction); - item.innerHTML = `${htmlDecode(data.value.label)}`; + const linkText = htmlDecode(data.value.label); + item.innerHTML = makeJSLink(jsAction, linkText, 'class="suggest"'); }, highlight: "autoComplete_highlight", selected: "autoComplete_selected" diff --git a/test/server.cpp b/test/server.cpp index c757be4b6..a166fa0ae 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -69,7 +69,7 @@ const ResourceCollection resources200Compressible{ { DYNAMIC_CONTENT, "/ROOT/skin/taskbar.css" }, { STATIC_CONTENT, "/ROOT/skin/taskbar.css?cacheid=216d6b5d" }, { DYNAMIC_CONTENT, "/ROOT/skin/viewer.js" }, - { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=fa85ec82" }, + { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=e250a5c9" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf" }, { STATIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Roboto.ttf" }, @@ -291,7 +291,7 @@ R"EXPECTEDRESULT( - + const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032"; From f3d2f474a75d367e04a5b9e379541c5298a588ca Mon Sep 17 00:00:00 2001 From: Veloman Yunkan Date: Thu, 15 Dec 2022 18:49:23 +0400 Subject: [PATCH 3/3] Handling of suggestions containing special symbols This change fixes two issues: 1. Presence of URL-specific special symbols (such as ? or #) in the book and/or article name resulted in a wrong suggestion link. This is fixed by URI-encoding the book name and the path, too. 2. Presence of a single quote symbol in the book and/or article name resulted in invalid javascript code in the href attribute of the suggestion link. The single quote (') symbol is not URL-encoded (unlike its double quote counterpart). As a result, enclosing a URL-encoded string in single quotes may result in invalid javascript. Using double quotes instead is safe, since both double quote (") and backslash (\) symbols (which are the only special symbols for such quoting) undergo URL-encoding. --- static/skin/viewer.js | 14 ++++++++++---- test/server.cpp | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/static/skin/viewer.js b/static/skin/viewer.js index 9571b1eea..24050a3b7 100644 --- a/static/skin/viewer.js +++ b/static/skin/viewer.js @@ -346,13 +346,19 @@ function setupSuggestions() { }, resultItem: { element: (item, data) => { - let searchLink; + const uriEncodedBookName = encodeURIComponent(currentBook); + let url; if (data.value.kind == "path") { - searchLink = `/${currentBook}/${htmlDecode(data.value.path)}`; + const path = encodeURIComponent(htmlDecode(data.value.path)); + url = `/${uriEncodedBookName}/${path}`; } else { - searchLink = `/search?content=${encodeURIComponent(currentBook)}&pattern=${encodeURIComponent(htmlDecode(data.value.value))}`; + const pattern = encodeURIComponent(htmlDecode(data.value.value)); + url = `/search?content=${uriEncodedBookName}&pattern=${pattern}`; } - const jsAction = `gotoUrl('${searchLink}')`; + // url can't contain any double quote and/or backslash symbols + // since they should have been URI-encoded. Therefore putting it + // inside double quotes should result in valid javascript. + const jsAction = `gotoUrl("${url}")`; const linkText = htmlDecode(data.value.label); item.innerHTML = makeJSLink(jsAction, linkText, 'class="suggest"'); }, diff --git a/test/server.cpp b/test/server.cpp index a166fa0ae..9b2da29a8 100644 --- a/test/server.cpp +++ b/test/server.cpp @@ -69,7 +69,7 @@ const ResourceCollection resources200Compressible{ { DYNAMIC_CONTENT, "/ROOT/skin/taskbar.css" }, { STATIC_CONTENT, "/ROOT/skin/taskbar.css?cacheid=216d6b5d" }, { DYNAMIC_CONTENT, "/ROOT/skin/viewer.js" }, - { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=e250a5c9" }, + { STATIC_CONTENT, "/ROOT/skin/viewer.js?cacheid=23966598" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf" }, { STATIC_CONTENT, "/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837" }, { DYNAMIC_CONTENT, "/ROOT/skin/fonts/Roboto.ttf" }, @@ -291,7 +291,7 @@ R"EXPECTEDRESULT( - + const blankPageUrl = root + "/skin/blank.html?cacheid=6b1fa032";