WebUI: migrate away from inline HTML code

`innerHTML` &  `outerHTML` setter will more or less evaluate the value which could be used to
inject malicious code. So replace them with safer alternatives.

PR #21163.
This commit is contained in:
Chocobo1
2024-08-10 12:55:48 +08:00
committed by GitHub
parent 4570c0ef9e
commit 5afeecbf18
7 changed files with 201 additions and 114 deletions

View File

@@ -428,7 +428,7 @@ window.qBittorrent.ContextMenu ??= (() => {
const contextTagList = $("contextTagList");
tagList.forEach((tag, tagHash) => {
const checkbox = contextTagList.getElement(`a[href="#Tag/${tagHash}"] input[type="checkbox"]`);
const checkbox = contextTagList.getElement(`a[href="#Tag/${tag.name}"] input[type="checkbox"]`);
const count = tagCount.get(tag.name);
const hasCount = (count !== undefined);
const isLesser = (count < selectedRows.length);
@@ -438,7 +438,7 @@ window.qBittorrent.ContextMenu ??= (() => {
const contextCategoryList = document.getElementById("contextCategoryList");
category_list.forEach((category, categoryHash) => {
const categoryIcon = contextCategoryList.querySelector(`a[href$="(${categoryHash});"] img`);
const categoryIcon = contextCategoryList.querySelector(`a[href$="#Category/${category.name}"] img`);
const count = categoryCount.get(category.name);
const isEqual = ((count !== undefined) && (count === selectedRows.length));
categoryIcon.classList.toggle("highlightedCategoryIcon", isEqual);
@@ -448,12 +448,24 @@ window.qBittorrent.ContextMenu ??= (() => {
updateCategoriesSubMenu: function(categoryList) {
const contextCategoryList = $("contextCategoryList");
contextCategoryList.getChildren().each(c => c.destroy());
contextCategoryList.appendChild(new Element("li", {
html: '<a href="javascript:torrentNewCategoryFN();"><img src="images/list-add.svg" alt="QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]"/>QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]</a>'
}));
contextCategoryList.appendChild(new Element("li", {
html: '<a href="javascript:torrentSetCategoryFN(0);"><img src="images/edit-clear.svg" alt="QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]"/>QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]</a>'
}));
const createMenuItem = (text, imgURL, clickFn) => {
const anchor = document.createElement("a");
anchor.textContent = text;
anchor.addEventListener("click", clickFn);
const img = document.createElement("img");
img.src = imgURL;
img.alt = text;
anchor.prepend(img);
const item = document.createElement("li");
item.appendChild(anchor);
return item;
};
contextCategoryList.appendChild(createMenuItem("QBT_TR(New...)QBT_TR[CONTEXT=TransferListWidget]", "images/list-add.svg", torrentNewCategoryFN));
contextCategoryList.appendChild(createMenuItem("QBT_TR(Reset)QBT_TR[CONTEXT=TransferListWidget]", "images/edit-clear.svg", () => { torrentSetCategoryFN(0); }));
const sortedCategories = [];
categoryList.forEach((category, hash) => sortedCategories.push({
@@ -465,14 +477,25 @@ window.qBittorrent.ContextMenu ??= (() => {
let first = true;
for (const { categoryName, categoryHash } of sortedCategories) {
const el = new Element("li", {
html: `<a href="javascript:torrentSetCategoryFN(${categoryHash});"><img src="images/view-categories.svg"/>${window.qBittorrent.Misc.escapeHtml(categoryName)}</a>`
const anchor = document.createElement("a");
anchor.href = `#Category/${categoryName}`;
anchor.textContent = categoryName;
anchor.addEventListener("click", (event) => {
torrentSetCategoryFN(categoryHash);
});
const img = document.createElement("img");
img.src = "images/view-categories.svg";
anchor.prepend(img);
const setCategoryItem = document.createElement("li");
setCategoryItem.appendChild(anchor);
if (first) {
el.addClass("separator");
setCategoryItem.addClass("separator");
first = false;
}
contextCategoryList.appendChild(el);
contextCategoryList.appendChild(setCategoryItem);
}
},
@@ -481,18 +504,23 @@ window.qBittorrent.ContextMenu ??= (() => {
while (contextTagList.firstChild !== null)
contextTagList.removeChild(contextTagList.firstChild);
contextTagList.appendChild(new Element("li", {
html: '<a href="javascript:torrentAddTagsFN();">'
+ '<img src="images/list-add.svg" alt="QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]"/>'
+ " QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]"
+ "</a>"
}));
contextTagList.appendChild(new Element("li", {
html: '<a href="javascript:torrentRemoveAllTagsFN();">'
+ '<img src="images/edit-clear.svg" alt="QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]"/>'
+ " QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]"
+ "</a>"
}));
const createMenuItem = (text, imgURL, clickFn) => {
const anchor = document.createElement("a");
anchor.textContent = text;
anchor.addEventListener("click", clickFn);
const img = document.createElement("img");
img.src = imgURL;
img.alt = text;
anchor.prepend(img);
const item = document.createElement("li");
item.appendChild(anchor);
return item;
};
contextTagList.appendChild(createMenuItem("QBT_TR(Add...)QBT_TR[CONTEXT=TransferListWidget]", "images/list-add.svg", torrentAddTagsFN));
contextTagList.appendChild(createMenuItem("QBT_TR(Remove All)QBT_TR[CONTEXT=TransferListWidget]", "images/edit-clear.svg", torrentRemoveAllTagsFN));
const sortedTags = [];
tagList.forEach((tag, hash) => sortedTags.push({
@@ -503,14 +531,28 @@ window.qBittorrent.ContextMenu ??= (() => {
for (let i = 0; i < sortedTags.length; ++i) {
const { tagName, tagHash } = sortedTags[i];
const el = new Element("li", {
html: `<a href="#Tag/${tagHash}" onclick="event.preventDefault(); torrentSetTagsFN(${tagHash}, !event.currentTarget.getElement('input[type=checkbox]').checked);">`
+ '<input type="checkbox" onclick="this.checked = !this.checked;"> ' + window.qBittorrent.Misc.escapeHtml(tagName)
+ "</a>"
const input = document.createElement("input");
input.type = "checkbox";
input.addEventListener("click", (event) => {
input.checked = !input.checked;
});
const anchor = document.createElement("a");
anchor.href = `#Tag/${tagName}`;
anchor.textContent = tagName;
anchor.addEventListener("click", (event) => {
event.preventDefault();
torrentSetTagsFN(tagHash, !input.checked);
});
anchor.prepend(input);
const setTagItem = document.createElement("li");
setTagItem.appendChild(anchor);
if (i === 0)
el.addClass("separator");
contextTagList.appendChild(el);
setTagItem.addClass("separator");
contextTagList.appendChild(setTagItem);
}
}
});