From d59afde5743766b23f2db04b45e6166bc3529b86 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 27 Feb 2022 15:14:26 +0100 Subject: [PATCH] Add ability to batch-delete messages Signed-off-by: DL6ER --- scripts/pi-hole/js/messages.js | 54 +++++++++++++++++++++------------ scripts/pi-hole/php/message.php | 16 +++++----- 2 files changed, 43 insertions(+), 27 deletions(-) diff --git a/scripts/pi-hole/js/messages.js b/scripts/pi-hole/js/messages.js index 8bae1e78..67f79f54 100644 --- a/scripts/pi-hole/js/messages.js +++ b/scripts/pi-hole/js/messages.js @@ -213,10 +213,13 @@ $(function () { className: "btn-sm datatable-bt", action: function () { // For each ".selected" row ... + var ids = []; $("tr.selected").each(function () { - // ... delete the row identified by "data-id". - delMsg($(this).attr("data-id")); + // ... add the row identified by "data-id". + ids.push(parseInt($(this).attr("data-id"), 10)); }); + // Delete all selected rows at once + delMsg(ids); }, }, ], @@ -264,34 +267,50 @@ $.fn.dataTable.Buttons.defaults.dom.container.className = "dt-buttons"; function deleteMessage() { // Passes the button data-del-id attribute as ID - delMsg($(this).attr("data-del-id")); + var ids = [parseInt($(this).attr("data-del-id"), 10)]; + delMsg(ids); } -function delMsg(id) { +function delMsg(ids) { + // Check input validity + if (!Array.isArray(ids)) return; + // Finding out which should be deleted, based on ID - var tr = $("tr[data-id='" + id + "']"); + var trs = []; + for (var id in ids) { + if (Object.hasOwnProperty.call(ids, id)) { + // Exploit prevention: Return early for non-numeric IDs + if (typeof ids[id] !== "number") return; + trs.push(ids[id]); + } + } utils.disableAll(); - utils.showAlert("info", "", "Deleting message with ID " + parseInt(id, 10), "..."); + var idstring = JSON.stringify(ids); + utils.showAlert("info", "", "Deleting messages: " + idstring, "..."); $.ajax({ url: "scripts/pi-hole/php/message.php", method: "post", dataType: "json", - data: { action: "delete_message", id: id, token: token }, + data: { action: "delete_message", id: idstring, token: token }, }) .done(function (response) { utils.enableAll(); if (response.success) { - utils.showAlert("success", "far fa-trash-alt", "Successfully deleted message # " + id, ""); - table.row(tr).remove().draw(false).ajax.reload(null, false); - } else { utils.showAlert( - "error", - "", - "Error while deleting message with ID " + id, - response.message + "success", + "far fa-trash-alt", + "Successfully deleted messages: " + idstring, + "" ); + for (var tr in trs) { + if (Object.hasOwnProperty.call(trs, tr)) { + table.row(tr).remove().draw(false).ajax.reload(null, false); + } + } + } else { + utils.showAlert("error", "", "Error while deleting message: " + idstring, response.message); } }) .done( @@ -299,12 +318,7 @@ function delMsg(id) { ) .fail(function (jqXHR, exception) { utils.enableAll(); - utils.showAlert( - "error", - "", - "Error while deleting message with ID " + id, - jqXHR.responseText - ); + utils.showAlert("error", "", "Error while deleting message: " + idstring, jqXHR.responseText); console.log(exception); // eslint-disable-line no-console }); } diff --git a/scripts/pi-hole/php/message.php b/scripts/pi-hole/php/message.php index 9a653a0e..ae6c78b1 100644 --- a/scripts/pi-hole/php/message.php +++ b/scripts/pi-hole/php/message.php @@ -42,19 +42,21 @@ function JSON_error($message = null) echo json_encode($response); } +// Delete message identified by IDs if ($_POST['action'] == 'delete_message' && isset($_POST['id'])) { -// Delete message identified by ID try { - - $stmt = $db->prepare('DELETE FROM message WHERE id=:id'); + $ids = json_decode($_POST['id']); + // Explot prevention: Ensure all entries in the ID array are integers + foreach($ids as $value) { + if (!is_numeric($value)) { + throw new Exception('Invalid payload: id'); + } + } + $stmt = $db->prepare('DELETE FROM message WHERE id IN ('.implode(",",$ids).')'); if (!$stmt) { throw new Exception('While preparing message statement: ' . $db->lastErrorMsg()); } - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id to message statement: ' . $db->lastErrorMsg()); - } - if (!$stmt->execute()) { throw new Exception('While executing message statement: ' . $db->lastErrorMsg()); }