Forbid HTML injection using jQuery (#29843)

See
https://github.com/wikimedia/eslint-plugin-no-jquery/blob/master/docs/rules/no-append-html.md

Tested the following components and they work as before:
- notification table
- issue author dropdown
- comment edit box attachments div

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: Giteabot <teabot@gitea.io>
(cherry picked from commit f9b4efd42c17d7f75b689142b17575a478fe903c)
This commit is contained in:
Yarden Shoham 2024-03-16 15:25:27 +02:00 committed by Earl Warren
parent 9ea9b850da
commit c1b6182625
No known key found for this signature in database
GPG key ID: 0579CB2928A78A00
5 changed files with 12 additions and 9 deletions

View file

@ -400,7 +400,7 @@ rules:
no-jquery/no-and-self: [2] no-jquery/no-and-self: [2]
no-jquery/no-animate-toggle: [2] no-jquery/no-animate-toggle: [2]
no-jquery/no-animate: [2] no-jquery/no-animate: [2]
no-jquery/no-append-html: [0] no-jquery/no-append-html: [2]
no-jquery/no-attr: [0] no-jquery/no-attr: [0]
no-jquery/no-bind: [2] no-jquery/no-bind: [2]
no-jquery/no-box-model: [2] no-jquery/no-box-model: [2]

View file

@ -143,8 +143,8 @@ async function updateNotificationCountWithCallback(callback, timeout, lastCount)
} }
async function updateNotificationTable() { async function updateNotificationTable() {
const $notificationDiv = $('#notification_div'); const notificationDiv = document.getElementById('notification_div');
if ($notificationDiv.length > 0) { if (notificationDiv) {
try { try {
const params = new URLSearchParams(window.location.search); const params = new URLSearchParams(window.location.search);
params.set('div-only', true); params.set('div-only', true);
@ -158,7 +158,7 @@ async function updateNotificationTable() {
const data = await response.text(); const data = await response.text();
if ($(data).data('sequence-number') === notificationSequenceNumber) { if ($(data).data('sequence-number') === notificationSequenceNumber) {
$notificationDiv.replaceWith(data); notificationDiv.outerHTML = data;
initNotificationsTable(); initNotificationsTable();
} }
} catch (error) { } catch (error) {

View file

@ -125,7 +125,9 @@ function initRepoIssueListAuthorDropdown() {
if (newMenuHtml) { if (newMenuHtml) {
const $newMenuItems = $(newMenuHtml); const $newMenuItems = $(newMenuHtml);
$newMenuItems.addClass('dynamic-item'); $newMenuItems.addClass('dynamic-item');
$menu.append('<div class="divider dynamic-item"></div>', ...$newMenuItems); const div = document.createElement('div');
div.classList.add('divider', 'dynamic-item');
$menu[0].append(div, ...$newMenuItems);
} }
$searchDropdown.dropdown('refresh'); $searchDropdown.dropdown('refresh');
// defer our selection to the next tick, because dropdown will set the selection item after this `menu` function // defer our selection to the next tick, because dropdown will set the selection item after this `menu` function

View file

@ -436,13 +436,12 @@ async function onEditContent(event) {
const $content = $segment; const $content = $segment;
if (!$content.find('.dropzone-attachments').length) { if (!$content.find('.dropzone-attachments').length) {
if (data.attachments !== '') { if (data.attachments !== '') {
$content.append(`<div class="dropzone-attachments"></div>`); $content[0].append(data.attachments);
$content.find('.dropzone-attachments').replaceWith(data.attachments);
} }
} else if (data.attachments === '') { } else if (data.attachments === '') {
$content.find('.dropzone-attachments').remove(); $content.find('.dropzone-attachments').remove();
} else { } else {
$content.find('.dropzone-attachments').replaceWith(data.attachments); $content.find('.dropzone-attachments')[0].outerHTML = data.attachments;
} }
if (dz) { if (dz) {
dz.emit('submit'); dz.emit('submit');

View file

@ -73,7 +73,9 @@ function delegateOne($dropdown) {
dropdownTemplates.menu = function(response, fields, preserveHTML, className) { dropdownTemplates.menu = function(response, fields, preserveHTML, className) {
// when the dropdown menu items are loaded from AJAX requests, the items are created dynamically // when the dropdown menu items are loaded from AJAX requests, the items are created dynamically
const menuItems = dropdownTemplatesMenuOld(response, fields, preserveHTML, className); const menuItems = dropdownTemplatesMenuOld(response, fields, preserveHTML, className);
const $wrapper = $('<div>').append(menuItems); const div = document.createElement('div');
div.innerHTML = menuItems;
const $wrapper = $(div);
const $items = $wrapper.find('> .item'); const $items = $wrapper.find('> .item');
$items.each((_, item) => updateMenuItem($dropdown[0], item)); $items.each((_, item) => updateMenuItem($dropdown[0], item));
$dropdown[0][ariaPatchKey].deferredRefreshAriaActiveItem(); $dropdown[0][ariaPatchKey].deferredRefreshAriaActiveItem();