From bee33239ed444f9724422fe5234cd79997500519 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Thu, 23 Jan 2020 22:26:38 +0100 Subject: Fix all relative link to work with new URL --- assets/default/js/base.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index d5c29c69..f61cfa92 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -27,7 +27,7 @@ function findParent(element, tagName, attributes) { */ function refreshToken() { const xhr = new XMLHttpRequest(); - xhr.open('GET', '?do=token'); + xhr.open('GET', './?do=token'); xhr.onload = () => { const token = document.getElementById('token'); token.setAttribute('value', xhr.responseText); @@ -546,7 +546,7 @@ function init(description) { const refreshedToken = document.getElementById('token').value; const fromtag = block.getAttribute('data-tag'); const xhr = new XMLHttpRequest(); - xhr.open('POST', '?do=changetag'); + xhr.open('POST', './?do=changetag'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { if (xhr.status !== 200) { @@ -558,8 +558,8 @@ function init(description) { input.setAttribute('value', totag); findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none'; block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); - block.querySelector('a.tag-link').setAttribute('href', `?searchtags=${encodeURIComponent(totag)}`); - block.querySelector('a.rename-tag').setAttribute('href', `?do=changetag&fromtag=${encodeURIComponent(totag)}`); + block.querySelector('a.tag-link').setAttribute('href', `./?searchtags=${encodeURIComponent(totag)}`); + block.querySelector('a.rename-tag').setAttribute('href', `./?do=changetag&fromtag=${encodeURIComponent(totag)}`); // Refresh awesomplete values existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag)); @@ -593,7 +593,7 @@ function init(description) { if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) { const xhr = new XMLHttpRequest(); - xhr.open('POST', '?do=changetag'); + xhr.open('POST', './?do=changetag'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { block.remove(); -- cgit v1.2.3 From 8eac2e54882d8adae8cbb45386dca1b465242632 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 30 May 2020 15:51:14 +0200 Subject: Process manage tags page through Slim controller --- assets/default/js/base.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index f61cfa92..8cc7eed5 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -546,7 +546,7 @@ function init(description) { const refreshedToken = document.getElementById('token').value; const fromtag = block.getAttribute('data-tag'); const xhr = new XMLHttpRequest(); - xhr.open('POST', './?do=changetag'); + xhr.open('POST', './manage-tags'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { if (xhr.status !== 200) { @@ -559,7 +559,7 @@ function init(description) { findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none'; block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); block.querySelector('a.tag-link').setAttribute('href', `./?searchtags=${encodeURIComponent(totag)}`); - block.querySelector('a.rename-tag').setAttribute('href', `./?do=changetag&fromtag=${encodeURIComponent(totag)}`); + block.querySelector('a.rename-tag').setAttribute('href', `./manage-tags?fromtag=${encodeURIComponent(totag)}`); // Refresh awesomplete values existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag)); @@ -593,7 +593,7 @@ function init(description) { if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) { const xhr = new XMLHttpRequest(); - xhr.open('POST', './?do=changetag'); + xhr.open('POST', './manage-tags'); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { block.remove(); -- cgit v1.2.3 From 818b3193ffabec57501e3bdfa997206e3c0671ef Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 11:22:14 +0200 Subject: Explicitly define base and asset path in templates With the new routes, all pages are not all at the same folder level anymore (e.g. /shaare and /shaare/123), so we can't just use './' everywhere. The most consistent way to handle this is to prefix all path with the proper variable, and handle the actual path in controllers. --- assets/default/js/base.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index 8cc7eed5..b428a420 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -25,9 +25,9 @@ function findParent(element, tagName, attributes) { /** * Ajax request to refresh the CSRF token. */ -function refreshToken() { +function refreshToken(basePath) { const xhr = new XMLHttpRequest(); - xhr.open('GET', './?do=token'); + xhr.open('GET', `${basePath}/?do=token`); xhr.onload = () => { const token = document.getElementById('token'); token.setAttribute('value', xhr.responseText); @@ -215,6 +215,8 @@ function init(description) { } (() => { + const basePath = document.querySelector('input[name="js_base_path"]').value; + /** * Handle responsive menu. * Source: http://purecss.io/layouts/tucked-menu-vertical/ @@ -461,7 +463,7 @@ function init(description) { }); if (window.confirm(message)) { - window.location = `?delete_link&lf_linkdate=${ids.join('+')}&token=${token.value}`; + window.location = `${basePath}/?delete_link&lf_linkdate=${ids.join('+')}&token=${token.value}`; } }); } @@ -483,7 +485,8 @@ function init(description) { }); const ids = links.map(item => item.id); - window.location = `?change_visibility&token=${token.value}&newVisibility=${visibility}&ids=${ids.join('+')}`; + window.location = + `${basePath}/?change_visibility&token=${token.value}&newVisibility=${visibility}&ids=${ids.join('+')}`; }); }); } @@ -546,7 +549,7 @@ function init(description) { const refreshedToken = document.getElementById('token').value; const fromtag = block.getAttribute('data-tag'); const xhr = new XMLHttpRequest(); - xhr.open('POST', './manage-tags'); + xhr.open('POST', `${basePath}/manage-tags`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { if (xhr.status !== 200) { @@ -558,8 +561,12 @@ function init(description) { input.setAttribute('value', totag); findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none'; block.querySelector('a.tag-link').innerHTML = htmlEntities(totag); - block.querySelector('a.tag-link').setAttribute('href', `./?searchtags=${encodeURIComponent(totag)}`); - block.querySelector('a.rename-tag').setAttribute('href', `./manage-tags?fromtag=${encodeURIComponent(totag)}`); + block + .querySelector('a.tag-link') + .setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`); + block + .querySelector('a.rename-tag') + .setAttribute('href', `${basePath}/manage-tags?fromtag=${encodeURIComponent(totag)}`); // Refresh awesomplete values existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag)); @@ -567,7 +574,7 @@ function init(description) { } }; xhr.send(`renametag=1&fromtag=${encodeURIComponent(fromtag)}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`); - refreshToken(); + refreshToken(basePath); }); }); @@ -593,13 +600,13 @@ function init(description) { if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) { const xhr = new XMLHttpRequest(); - xhr.open('POST', './manage-tags'); + xhr.open('POST', `${basePath}/manage-tags`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { block.remove(); }; xhr.send(encodeURI(`deletetag=1&fromtag=${tag}&token=${refreshedToken}`)); - refreshToken(); + refreshToken(basePath); existingTags = existingTags.filter(tagItem => tagItem !== tag); awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes); -- cgit v1.2.3 From 9c75f877935fa6adec951a4d8d32b328aaab314f Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 13:08:01 +0200 Subject: Use multi-level routes for existing controllers instead of 1 level everywhere Also prefix most admin routes with /admin/ --- assets/default/js/base.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index b428a420..9f67d980 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -463,7 +463,7 @@ function init(description) { }); if (window.confirm(message)) { - window.location = `${basePath}/?delete_link&lf_linkdate=${ids.join('+')}&token=${token.value}`; + window.location = `${basePath}/admin/shaare/delete?id=${ids.join('+')}&token=${token.value}`; } }); } @@ -549,7 +549,7 @@ function init(description) { const refreshedToken = document.getElementById('token').value; const fromtag = block.getAttribute('data-tag'); const xhr = new XMLHttpRequest(); - xhr.open('POST', `${basePath}/manage-tags`); + xhr.open('POST', `${basePath}/admin/tags`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { if (xhr.status !== 200) { @@ -566,7 +566,7 @@ function init(description) { .setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`); block .querySelector('a.rename-tag') - .setAttribute('href', `${basePath}/manage-tags?fromtag=${encodeURIComponent(totag)}`); + .setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`); // Refresh awesomplete values existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag)); @@ -600,7 +600,7 @@ function init(description) { if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) { const xhr = new XMLHttpRequest(); - xhr.open('POST', `${basePath}/manage-tags`); + xhr.open('POST', `${basePath}/admin/tags`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); xhr.onload = () => { block.remove(); -- cgit v1.2.3 From 7b8a6f2858248601d43c1b8247deb91b74392d2e Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sat, 13 Jun 2020 19:40:32 +0200 Subject: Process change visibility action through Slim controller --- assets/default/js/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index 9f67d980..af3d650c 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -486,7 +486,7 @@ function init(description) { const ids = links.map(item => item.id); window.location = - `${basePath}/?change_visibility&token=${token.value}&newVisibility=${visibility}&ids=${ids.join('+')}`; + `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`; }); }); } -- cgit v1.2.3 From 764d34a7d347d653414e5f5c632e02499edaef04 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Sun, 21 Jun 2020 12:21:31 +0200 Subject: Process token retrieve through Slim controller --- assets/default/js/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index af3d650c..76e4fe2a 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -27,7 +27,7 @@ function findParent(element, tagName, attributes) { */ function refreshToken(basePath) { const xhr = new XMLHttpRequest(); - xhr.open('GET', `${basePath}/?do=token`); + xhr.open('GET', `${basePath}/admin/token`); xhr.onload = () => { const token = document.getElementById('token'); token.setAttribute('value', xhr.responseText); -- cgit v1.2.3 From 301c7ab1a079d937ab41c6f52b8804e5731008e6 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 28 Jul 2020 20:46:11 +0200 Subject: Better support for notes permalink --- assets/default/js/base.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index 76e4fe2a..0f29799d 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -26,11 +26,15 @@ function findParent(element, tagName, attributes) { * Ajax request to refresh the CSRF token. */ function refreshToken(basePath) { + console.log('refresh'); const xhr = new XMLHttpRequest(); xhr.open('GET', `${basePath}/admin/token`); xhr.onload = () => { - const token = document.getElementById('token'); - token.setAttribute('value', xhr.responseText); + const elements = document.querySelectorAll('input[name="token"]'); + [...elements].forEach((element) => { + console.log(element); + element.setAttribute('value', xhr.responseText); + }); }; xhr.send(); } -- cgit v1.2.3 From cd10bc23e79c68d7a017e9284f95a166ea66ea08 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 1 Sep 2020 11:01:21 +0200 Subject: Export: refresh CRSF token after submit This allow users to submit the form multiple times, because there is no actual browser redirection to the page. Fixes #1532 --- assets/default/js/base.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index 0f29799d..27938823 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -25,16 +25,18 @@ function findParent(element, tagName, attributes) { /** * Ajax request to refresh the CSRF token. */ -function refreshToken(basePath) { - console.log('refresh'); +function refreshToken(basePath, callback) { const xhr = new XMLHttpRequest(); xhr.open('GET', `${basePath}/admin/token`); xhr.onload = () => { const elements = document.querySelectorAll('input[name="token"]'); [...elements].forEach((element) => { - console.log(element); element.setAttribute('value', xhr.responseText); }); + + if (callback) { + callback(xhr.response); + } }; xhr.send(); } @@ -622,4 +624,15 @@ function init(description) { [...autocompleteFields].forEach((autocompleteField) => { awesomepletes.push(createAwesompleteInstance(autocompleteField)); }); + + const exportForm = document.querySelector('#exportform'); + if (exportForm != null) { + exportForm.addEventListener('submit', (event) => { + event.preventDefault(); + + refreshToken(basePath, () => { + event.target.submit(); + }); + }); + } })(); -- cgit v1.2.3 From 9192a48be300fcfd2a6ede927b0611c66f250012 Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 22 Sep 2020 18:14:18 +0200 Subject: Fix ESLint after dependency upgrade --- assets/default/js/base.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index 27938823..d9933152 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -10,7 +10,7 @@ import Awesomplete from 'awesomplete'; * @returns Found element or null. */ function findParent(element, tagName, attributes) { - const parentMatch = key => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1; + const parentMatch = (key) => attributes[key] !== '' && element.getAttribute(key).indexOf(attributes[key]) !== -1; while (element) { if (element.tagName.toLowerCase() === tagName) { if (Object.keys(attributes).find(parentMatch)) { @@ -101,7 +101,7 @@ function updateAwesompleteList(selector, tags, instances) { * @see http://stackoverflow.com/questions/18749591/encode-html-entities-in-javascript */ function htmlEntities(str) { - return str.replace(/[\u00A0-\u9999<>&]/gim, i => `&#${i.charCodeAt(0)};`); + return str.replace(/[\u00A0-\u9999<>&]/gim, (i) => `&#${i.charCodeAt(0)};`); } /** @@ -194,8 +194,8 @@ function removeClass(element, classname) { function init(description) { function resize() { /* Fix jumpy resizing: https://stackoverflow.com/a/18262927/1484919 */ - const scrollTop = window.pageYOffset || - (document.documentElement || document.body.parentNode || document.body).scrollTop; + const scrollTop = window.pageYOffset + || (document.documentElement || document.body.parentNode || document.body).scrollTop; description.style.height = 'auto'; description.style.height = `${description.scrollHeight + 10}px`; @@ -490,9 +490,10 @@ function init(description) { }); }); - const ids = links.map(item => item.id); - window.location = - `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}`; + const ids = links.map((item) => item.id); + window.location = ( + `${basePath}/admin/shaare/visibility?token=${token.value}&newVisibility=${visibility}&id=${ids.join('+')}` + ); }); }); } @@ -575,7 +576,7 @@ function init(description) { .setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`); // Refresh awesomplete values - existingTags = existingTags.map(tag => (tag === fromtag ? totag : tag)); + existingTags = existingTags.map((tag) => (tag === fromtag ? totag : tag)); awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes); } }; @@ -614,7 +615,7 @@ function init(description) { xhr.send(encodeURI(`deletetag=1&fromtag=${tag}&token=${refreshedToken}`)); refreshToken(basePath); - existingTags = existingTags.filter(tagItem => tagItem !== tag); + existingTags = existingTags.filter((tagItem) => tagItem !== tag); awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes); } }); -- cgit v1.2.3 From 72fbbcd6794facea2cf06d9742359d190257b00f Mon Sep 17 00:00:00 2001 From: ArthurHoaro Date: Tue, 6 Oct 2020 17:30:18 +0200 Subject: Security: fix multiple XSS vulnerabilities + fix search tags with special chars XSS vulnerabilities fixed in editlink, linklist, tag.cloud and tag.list. Also fixed tag search with special characters: urlencode function needs to be applied on raw data, before espaping, otherwise the rendered URL is wrong. --- assets/default/js/base.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'assets/default/js/base.js') diff --git a/assets/default/js/base.js b/assets/default/js/base.js index d9933152..be986ae0 100644 --- a/assets/default/js/base.js +++ b/assets/default/js/base.js @@ -555,6 +555,7 @@ function init(description) { } const refreshedToken = document.getElementById('token').value; const fromtag = block.getAttribute('data-tag'); + const fromtagUrl = block.getAttribute('data-tag-url'); const xhr = new XMLHttpRequest(); xhr.open('POST', `${basePath}/admin/tags`); xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); @@ -564,6 +565,7 @@ function init(description) { location.reload(); } else { block.setAttribute('data-tag', totag); + block.setAttribute('data-tag-url', encodeURIComponent(totag)); input.setAttribute('name', totag); input.setAttribute('value', totag); findParent(input, 'div', { class: 'rename-tag-form' }).style.display = 'none'; @@ -571,6 +573,9 @@ function init(description) { block .querySelector('a.tag-link') .setAttribute('href', `${basePath}/?searchtags=${encodeURIComponent(totag)}`); + block + .querySelector('a.count') + .setAttribute('href', `${basePath}/add-tag/${encodeURIComponent(totag)}`); block .querySelector('a.rename-tag') .setAttribute('href', `${basePath}/admin/tags?fromtag=${encodeURIComponent(totag)}`); @@ -580,7 +585,7 @@ function init(description) { awesomepletes = updateAwesompleteList('.rename-tag-input', existingTags, awesomepletes); } }; - xhr.send(`renametag=1&fromtag=${encodeURIComponent(fromtag)}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`); + xhr.send(`renametag=1&fromtag=${fromtagUrl}&totag=${encodeURIComponent(totag)}&token=${refreshedToken}`); refreshToken(basePath); }); }); @@ -603,6 +608,7 @@ function init(description) { event.preventDefault(); const block = findParent(event.target, 'div', { class: 'tag-list-item' }); const tag = block.getAttribute('data-tag'); + const tagUrl = block.getAttribute('data-tag-url'); const refreshedToken = document.getElementById('token').value; if (confirm(`Are you sure you want to delete the tag "${tag}"?`)) { @@ -612,7 +618,7 @@ function init(description) { xhr.onload = () => { block.remove(); }; - xhr.send(encodeURI(`deletetag=1&fromtag=${tag}&token=${refreshedToken}`)); + xhr.send(`deletetag=1&fromtag=${tagUrl}&token=${refreshedToken}`); refreshToken(basePath); existingTags = existingTags.filter((tagItem) => tagItem !== tag); -- cgit v1.2.3