Merge branch 'release/v5.1' into ip-sorting-query

This commit is contained in:
Adam Warner
2020-07-16 18:38:53 +01:00
26 changed files with 1108 additions and 1092 deletions
+4 -2
View File
@@ -5,6 +5,8 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global utils:false */
var table;
var token = $("#token").text();
@@ -76,8 +78,8 @@ $(function () {
});
function addCustomDNS() {
var ip = $("#ip").val();
var domain = $("#domain").val();
var ip = utils.escapeHtml($("#ip").val());
var domain = utils.escapeHtml($("#domain").val());
showAlert("info");
$.ajax({
-5
View File
@@ -4,7 +4,6 @@
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global initpage:false */
//The following functions allow us to display time until pi-hole is enabled after disabling.
//Works between all pages
@@ -221,10 +220,6 @@ $(function () {
initCheckboxRadioStyle();
initCPUtemp();
if (typeof initpage === "function") {
setTimeout(initpage, 100);
}
// Run check immediately after page loading ...
checkMessages();
// ... and once again with five seconds delay
+7 -7
View File
@@ -55,9 +55,9 @@ function initTable() {
$(row).attr("data-id", data.id);
var tooltip =
"Added: " +
utils.datetime(data.date_added) +
utils.datetime(data.date_added, false) +
"\nLast modified: " +
utils.datetime(data.date_modified) +
utils.datetime(data.date_modified, false) +
"\nDatabase ID: " +
data.id;
$("td:eq(0)", row).html(
@@ -212,8 +212,8 @@ function initTable() {
}
function addAdlist() {
var address = $("#new_address").val();
var comment = $("#new_comment").val();
var address = utils.escapeHtml($("#new_address").val());
var comment = utils.escapeHtml($("#new_comment").val());
utils.disableAll();
utils.showAlert("info", "", "Adding adlist...", address);
@@ -258,9 +258,9 @@ function editAdlist() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
var comment = tr.find("#comment_" + id).val();
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
var groups = tr.find("#multiselect_" + id).val();
var address = tr.find("#address_" + id).text();
var address = utils.escapeHtml(tr.find("#address_" + id).text());
var done = "edited";
var notDone = "editing";
@@ -338,7 +338,7 @@ function editAdlist() {
function deleteAdlist() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var address = tr.find("#address_" + id).text();
var address = utils.escapeHtml(tr.find("#address_" + id).text());
utils.disableAll();
utils.showAlert("info", "", "Deleting adlist...", address);
+8 -8
View File
@@ -94,9 +94,9 @@ function initTable() {
$(row).attr("data-id", data.id);
var tooltip =
"Added: " +
utils.datetime(data.date_added) +
utils.datetime(data.date_added, false) +
"\nLast modified: " +
utils.datetime(data.date_modified) +
utils.datetime(data.date_modified, false) +
"\nDatabase ID: " +
data.id;
var ipName =
@@ -246,9 +246,9 @@ function initTable() {
function addClient() {
var ip = $("#select").val();
var comment = $("#new_comment").val();
var comment = utils.escapeHtml($("#new_comment").val());
if (ip === "custom") {
ip = $("#ip-custom").val().trim();
ip = utils.escapeHtml($("#ip-custom").val().trim());
}
utils.disableAll();
@@ -303,9 +303,9 @@ function editClient() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var groups = tr.find("#multiselect_" + id).val();
var ip = tr.find("#ip_" + id).text();
var name = tr.find("#name_" + id).text();
var comment = tr.find("#comment_" + id).val();
var ip = utils.escapeHtml(tr.find("#ip_" + id).text());
var name = utils.escapeHtml(tr.find("#name_" + id).text());
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
var done = "edited";
var notDone = "editing";
@@ -370,7 +370,7 @@ function deleteClient() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var ip = tr.find("#ip_" + id).text();
var name = tr.find("#name_" + id).text();
var name = utils.escapeHtml(tr.find("#name_" + id).text());
if (name.length > 0) {
ip += " (" + name + ")";
+7 -7
View File
@@ -85,9 +85,9 @@ function initTable() {
$(row).attr("data-id", data.id);
var tooltip =
"Added: " +
utils.datetime(data.date_added) +
utils.datetime(data.date_added, false) +
"\nLast modified: " +
utils.datetime(data.date_modified) +
utils.datetime(data.date_modified, false) +
"\nDatabase ID: " +
data.id;
$("td:eq(0)", row).html(
@@ -318,8 +318,8 @@ function addDomain() {
commentEl = $("#new_regex_comment");
}
var domain = domainEl.val();
var comment = commentEl.val();
var domain = utils.escapeHtml(domainEl.val());
var comment = utils.escapeHtml(commentEl.val());
utils.disableAll();
utils.showAlert("info", "", "Adding " + domainRegex + "...", domain);
@@ -385,10 +385,10 @@ function editDomain() {
var elem = $(this).attr("id");
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var domain = tr.find("#domain_" + id).text();
var domain = utils.escapeHtml(tr.find("#domain_" + id).text());
var type = tr.find("#type_" + id).val();
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
var comment = tr.find("#comment_" + id).val();
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
// Show group assignment field only if in full domain management mode
// if not included, just use the row data.
@@ -485,7 +485,7 @@ function editDomain() {
function deleteDomain() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var domain = tr.find("#domain_" + id).text();
var domain = utils.escapeHtml(tr.find("#domain_" + id).text());
var type = tr.find("#type_" + id).val();
var domainRegex;
+7 -7
View File
@@ -34,9 +34,9 @@ $(function () {
$(row).attr("data-id", data.id);
var tooltip =
"Added: " +
utils.datetime(data.date_added) +
utils.datetime(data.date_added, false) +
"\nLast modified: " +
utils.datetime(data.date_modified) +
utils.datetime(data.date_modified, false) +
"\nDatabase ID: " +
data.id;
$("td:eq(0)", row).html(
@@ -127,8 +127,8 @@ $(function () {
});
function addGroup() {
var name = $("#new_name").val();
var desc = $("#new_desc").val();
var name = utils.escapeHtml($("#new_name").val());
var desc = utils.escapeHtml($("#new_desc").val());
utils.disableAll();
utils.showAlert("info", "", "Adding group...", name);
@@ -166,9 +166,9 @@ function editGroup() {
var elem = $(this).attr("id");
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var name = tr.find("#name_" + id).val();
var name = utils.escapeHtml(tr.find("#name_" + id).val());
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
var desc = tr.find("#desc_" + id).val();
var desc = utils.escapeHtml(tr.find("#desc_" + id).val());
var done = "edited";
var notDone = "editing";
@@ -239,7 +239,7 @@ function editGroup() {
function deleteGroup() {
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var name = tr.find("#name_" + id).val();
var name = utils.escapeHtml(tr.find("#name_" + id).val());
utils.disableAll();
utils.showAlert("info", "", "Deleting group...", name);
+5 -3
View File
@@ -306,9 +306,11 @@ function updateQueryTypesPie() {
}
Object.keys(iter).forEach(function (key) {
v.push(iter[key]);
c.push(THEME_COLORS[i++ % THEME_COLORS.length]);
k.push(key);
if (iter[key] > 0) {
v.push(iter[key]);
c.push(THEME_COLORS[i++ % THEME_COLORS.length]);
k.push(key);
}
});
// Build a single dataset with the data to be pushed
+3 -3
View File
@@ -5,7 +5,7 @@
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
/* global moment:false, utils:false */
/* global utils:false */
var tableApi;
@@ -161,7 +161,7 @@ $(function () {
width: "8%",
render: function (data, type) {
if (type === "display") {
return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
return utils.datetime(data);
}
return data;
@@ -172,7 +172,7 @@ $(function () {
width: "8%",
render: function (data, type) {
if (type === "display") {
return moment.unix(data).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
return utils.datetime(data);
}
return data;
+197 -145
View File
@@ -8,6 +8,22 @@
/* global moment:false, utils:false */
var tableApi;
var tableFilters = [];
var replyTypes = [
"N/A",
"NODATA",
"NXDOMAIN",
"CNAME",
"IP",
"DOMAIN",
"RRNAME",
"SERVFAIL",
"REFUSED",
"NOTIMP",
"upstream error"
];
var colTypes = ["time", "query type", "domain", "client", "status", "reply type"];
function add(domain, list) {
var token = $("#token").text();
@@ -103,10 +119,6 @@ function handleAjaxError(xhr, textStatus) {
tableApi.draw();
}
function autofilter() {
return $("#autofilter").prop("checked");
}
$(function () {
// Do we want to filter queries?
var GETDict = {};
@@ -140,7 +152,7 @@ $(function () {
rowCallback: function (row, data) {
// DNSSEC status
var dnssecStatus;
switch (data[5]) {
switch (data[6]) {
case "1":
dnssecStatus = '<br><span class="text-green">SECURE</span>';
break;
@@ -162,37 +174,32 @@ $(function () {
}
// Query status
var blocked,
fieldtext,
var fieldtext,
buttontext,
colorClass,
colorClass = false,
isCNAME = false,
regexLink = false;
switch (data[4]) {
case "1":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked (gravity)";
buttontext =
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
break;
case "2":
blocked = false;
colorClass = "text-green";
fieldtext = "OK <br class='hidden-lg'>(forwarded)" + dnssecStatus;
buttontext =
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
break;
case "3":
blocked = false;
colorClass = "text-green";
fieldtext = "OK <br class='hidden-lg'>(cached)" + dnssecStatus;
buttontext =
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
break;
case "4":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(regex blacklist)";
@@ -204,32 +211,27 @@ $(function () {
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
break;
case "5":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(exact blacklist)";
buttontext =
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
break;
case "6":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(external, IP)";
buttontext = "";
break;
case "7":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(external, NULL)";
buttontext = "";
break;
case "8":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(external, NXRA)";
buttontext = "";
break;
case "9":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked (gravity, CNAME)";
buttontext =
@@ -237,7 +239,6 @@ $(function () {
isCNAME = true;
break;
case "10":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(regex blacklist, CNAME)";
@@ -250,7 +251,6 @@ $(function () {
isCNAME = true;
break;
case "11":
blocked = true;
colorClass = "text-red";
fieldtext = "Blocked <br class='hidden-lg'>(exact blacklist, CNAME)";
buttontext =
@@ -258,12 +258,13 @@ $(function () {
isCNAME = true;
break;
default:
blocked = false;
colorClass = false;
fieldtext = "Unknown (" + parseInt(data[4], 10) + ")";
buttontext = "";
}
fieldtext += '<input type="hidden" name="id" value="' + data[4] + '">';
if (colorClass !== false) {
$(row).addClass(colorClass);
}
@@ -306,49 +307,17 @@ $(function () {
}
// Check for existence of sixth column and display only if not Pi-holed
var replytext;
if (data.length > 6 && !blocked) {
switch (data[6]) {
case "0":
replytext = "N/A";
break;
case "1":
replytext = "NODATA";
break;
case "2":
replytext = "NXDOMAIN";
break;
case "3":
replytext = "CNAME";
break;
case "4":
replytext = "IP";
break;
case "5":
replytext = "DOMAIN";
break;
case "6":
replytext = "RRNAME";
break;
case "7":
replytext = "SERVFAIL";
break;
case "8":
replytext = "REFUSED";
break;
case "9":
replytext = "NOTIMP";
break;
case "10":
replytext = "upstream error";
break;
default:
replytext = "? (" + parseInt(data[6], 10) + ")";
}
var replytext,
replyid = data[5];
if (replyid >= 0 && replyid < replyTypes.length) {
replytext = replyTypes[replyid];
} else {
replytext = "-";
replytext = "? (" + replyid + ")";
}
replytext += '<input type="hidden" name="id" value="' + replyid + '">';
$("td:eq(5)", row).html(replytext);
if (data.length > 7) {
@@ -368,6 +337,10 @@ $(function () {
var dataIndex = 0;
return data.data.map(function (x) {
x[0] = x[0] * 1e6 + dataIndex++;
var dnssec = x[5];
var reply = x[6];
x[5] = reply;
x[6] = dnssec;
return x;
});
}
@@ -415,77 +388,100 @@ $(function () {
],
initComplete: function () {
var api = this.api();
// Query type IPv4 / IPv6
api.$("td:eq(1)").click(function () {
if (autofilter()) {
api.search(this.textContent).draw();
$("#resetButton").removeClass("hidden");
}
});
api.$("td:eq(1)").hover(
function () {
if (autofilter()) {
this.title = "Click to show only " + this.textContent + " queries";
this.style.color = "#72afd2";
} else {
this.title = "";
this.style.color = "";
api
.$("td:eq(1)")
.click(function (event) {
addColumnFilter(event, 1, this.textContent);
})
.hover(
function () {
$(this).addClass("pointer").attr("title", tooltipText(1, this.textContent));
},
function () {
$(this).removeClass("pointer");
}
},
function () {
this.style.color = "";
}
);
api.$("td:eq(1)").addClass("pointer");
);
// Domain
api.$("td:eq(2)").click(function () {
if (autofilter()) {
var domain = this.textContent.split("\n")[0];
api.search(domain).draw();
$("#resetButton").removeClass("hidden");
}
});
api.$("td:eq(2)").hover(
function () {
if (autofilter()) {
var domain = this.textContent.split("\n")[0];
this.title = "Click to show only queries with domain " + domain;
this.style.color = "#72afd2";
} else {
this.title = "";
this.style.color = "";
api
.$("td:eq(2)")
.click(function (event) {
addColumnFilter(event, 2, this.textContent.split("\n")[0]);
})
.hover(
function () {
$(this).addClass("pointer").attr("title", tooltipText(2, this.textContent));
},
function () {
$(this).removeClass("pointer");
}
},
function () {
this.style.color = "";
}
);
api.$("td:eq(2)").addClass("pointer");
);
// Client
api.$("td:eq(3)").click(function () {
if (autofilter()) {
api.search(this.textContent).draw();
$("#resetButton").removeClass("hidden");
}
});
api.$("td:eq(3)").hover(
function () {
if (autofilter()) {
this.title = "Click to show only queries made by " + this.textContent;
this.style.color = "#72afd2";
} else {
this.title = "";
this.style.color = "";
api
.$("td:eq(3)")
.click(function (event) {
addColumnFilter(event, 3, this.textContent);
})
.hover(
function () {
$(this).addClass("pointer").attr("title", tooltipText(3, this.textContent));
},
function () {
$(this).removeClass("pointer");
}
},
function () {
this.style.color = "";
}
);
api.$("td:eq(3)").addClass("pointer");
);
// Status
api
.$("td:eq(4)")
.click(function (event) {
var id = this.children.id.value;
var text = this.textContent;
addColumnFilter(event, 4, id + "#" + text);
})
.hover(
function () {
$(this).addClass("pointer").attr("title", tooltipText(4, this.textContent));
},
function () {
$(this).removeClass("pointer");
}
);
// Reply type
api
.$("td:eq(5)")
.click(function (event) {
var id = this.children.id.value;
var text = this.textContent.split(" ")[0];
addColumnFilter(event, 5, id + "#" + text);
})
.hover(
function () {
$(this).addClass("pointer").attr("title", tooltipText(5, this.textContent));
},
function () {
$(this).removeClass("pointer");
}
);
// Disable autocorrect in the search box
var input = $("input[type=search]");
if (input !== null) {
input.attr("autocomplete", "off");
input.attr("autocorrect", "off");
input.attr("autocapitalize", "off");
input.attr("spellcheck", false);
input.attr("placeholder", "Type / Domain / Client");
}
}
});
resetColumnsFilters();
$("#all-queries tbody").on("click", "button", function () {
var data = tableApi.row($(this).parents("tr")).data();
if (data[4] === "2" || data[4] === "3") {
@@ -496,28 +492,84 @@ $(function () {
});
$("#resetButton").click(function () {
tableApi.search("").draw();
$("#resetButton").addClass("hidden");
});
// Disable autocorrect in the search box
var input = document.querySelector("input[type=search]");
input.setAttribute("autocomplete", "off");
input.setAttribute("autocorrect", "off");
input.setAttribute("autocapitalize", "off");
input.setAttribute("spellcheck", false);
var chkboxData = localStorage.getItem("query_log_filter_chkbox");
if (chkboxData !== null) {
// Restore checkbox state
$("#autofilter").prop("checked", chkboxData === "true");
} else {
// Initialize checkbox
$("#autofilter").prop("checked", true);
localStorage.setItem("query_log_filter_chkbox", true);
}
$("#autofilter").click(function () {
localStorage.setItem("query_log_filter_chkbox", $("#autofilter").prop("checked"));
tableApi.search("");
resetColumnsFilters();
});
});
function tooltipText(index, text) {
if (index === 5) {
// Strip reply time from tooltip text
text = text.split(" ")[0];
}
if (index in tableFilters && tableFilters[index].length > 0) {
return "Clear filter on " + colTypes[index] + ' "' + text + '" using Shift + Click.';
}
return "Add filter on " + colTypes[index] + ' "' + text + '" using Ctrl + Click.';
}
function addColumnFilter(event, colID, filterstring) {
// Don't do anything when NOT explicitly requesting multi-selection functions
if (!event.ctrlKey && !event.metaKey && !event.shiftKey) {
return;
}
if (event.shiftKey) {
filterstring = "";
}
tableFilters[colID] = filterstring;
applyColumnFiltering();
}
function resetColumnsFilters() {
tableFilters.forEach(function (value, index) {
tableFilters[index] = "";
});
// Clear filter reset button
applyColumnFiltering();
}
function applyColumnFiltering() {
var showReset = false;
tableFilters.forEach(function (value, index) {
// Prepare regex filter string
var regex = "";
// Split filter string if we received a combined ID#Name column
var valArr = value.split("#");
if (valArr.length > 0) {
value = valArr[0];
}
if (value.length > 0) {
// Exact matching
regex = "^" + value + "$";
// Add background color
tableApi.$("td:eq(" + index + ")").addClass("highlight");
// Remember to show reset button
showReset = true;
} else {
// Clear background color
tableApi.$("td:eq(" + index + ")").removeClass("highlight");
}
// Apply filtering on this column (regex may be empty -> no filtering)
tableApi.column(index).search(regex, true, true);
});
if (showReset) {
$("#resetButton").removeClass("hidden");
} else {
$("#resetButton").addClass("hidden");
}
// Trigger table update
tableApi.draw();
}
+19 -11
View File
@@ -229,17 +229,6 @@ $(function () {
$('[data-toggle="tooltip"]').tooltip({ html: true, container: "body" });
});
// Change "?tab=" parameter in URL for save and reload
$(".nav-tabs a").on("shown.bs.tab", function (e) {
var tab = e.target.hash.substring(1);
window.history.pushState("", "", "?tab=" + tab);
if (tab === "piholedhcp") {
window.location.reload();
}
window.scrollTo(0, 0);
});
// Auto dismissal for info notifications
$(function () {
var alInfo = $("#alInfo");
@@ -255,6 +244,25 @@ $(function () {
input.setAttribute("autocorrect", "off");
input.setAttribute("autocapitalize", "off");
input.setAttribute("spellcheck", false);
// En-/disable conditional forwarding input fields based
// on the checkbox state
$('input[name="rev_server"]').click(function () {
$('input[name="rev_server_cidr"]').prop("disabled", !this.checked);
$('input[name="rev_server_target"]').prop("disabled", !this.checked);
$('input[name="rev_server_domain"]').prop("disabled", !this.checked);
});
});
// Change "?tab=" parameter in URL for save and reload
$(".nav-tabs a").on("shown.bs.tab", function (e) {
var tab = e.target.hash.substring(1);
window.history.pushState("", "", "?tab=" + tab);
if (tab === "piholedhcp") {
window.location.reload();
}
window.scrollTo(0, 0);
});
// Bar/Smooth chart toggle
+10 -2
View File
@@ -104,8 +104,9 @@ function showAlert(type, icon, title, message) {
}
}
function datetime(date) {
return moment.unix(Math.floor(date)).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
function datetime(date, html) {
var format = html === false ? "Y-MM-DD HH:mm:ss z" : "Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z";
return moment.unix(Math.floor(date)).format(format);
}
function disableAll() {
@@ -198,7 +199,14 @@ function stateLoadCallback(itemName) {
return null;
}
// Parse JSON string
data = JSON.parse(data);
// Clear possible filtering settings
data.columns.forEach(function (value, index) {
data.columns[index].search.search = "";
});
// Always start on the first page to show most recent queries
data.start = 0;
// Always start with empty search field
+2 -2
View File
@@ -161,9 +161,9 @@ function add_to_table($db, $table, $domains, $comment=null, $wildcardstyle=false
if($wildcardstyle)
$domain = "(\\.|^)".str_replace(".","\\.",$domain)."$";
$stmt->bindValue(":$field", $domain, SQLITE3_TEXT);
$stmt->bindValue(":$field", htmlentities($domain), SQLITE3_TEXT);
if($bindcomment) {
$stmt->bindValue(":comment", $comment, SQLITE3_TEXT);
$stmt->bindValue(":comment", htmlentities($comment), SQLITE3_TEXT);
}
if($stmt->execute() && $stmt->reset())
+21 -18
View File
@@ -214,31 +214,34 @@ function deleteCustomDNSEntry()
function deleteAllCustomDNSEntries()
{
$handle = fopen($customDNSFile, "r");
if ($handle)
if (isset($customDNSFile))
{
try
$handle = fopen($customDNSFile, "r");
if ($handle)
{
while (($line = fgets($handle)) !== false) {
$line = str_replace("\r","", $line);
$line = str_replace("\n","", $line);
$explodedLine = explode (" ", $line);
try
{
while (($line = fgets($handle)) !== false) {
$line = str_replace("\r","", $line);
$line = str_replace("\n","", $line);
$explodedLine = explode (" ", $line);
if (count($explodedLine) != 2)
continue;
if (count($explodedLine) != 2)
continue;
$ip = $explodedLine[0];
$domain = $explodedLine[1];
$ip = $explodedLine[0];
$domain = $explodedLine[1];
pihole_execute("-a removecustomdns ".$ip." ".$domain);
pihole_execute("-a removecustomdns ".$ip." ".$domain);
}
}
catch (\Exception $ex)
{
return errorJsonResponse($ex->getMessage());
}
}
catch (\Exception $ex)
{
return errorJsonResponse($ex->getMessage());
}
fclose($handle);
fclose($handle);
}
}
return successJsonResponse();
+14 -11
View File
@@ -58,7 +58,8 @@ if ($_POST['action'] == 'get_groups') {
} elseif ($_POST['action'] == 'add_group') {
// Add new group
try {
$names = str_getcsv(trim($_POST['name']), ' ');
$input = html_entity_decode(trim($_POST['name']));
$names = str_getcsv($input, ' ');
$total = count($names);
$added = 0;
$stmt = $db->prepare('INSERT INTO "group" (name,description) VALUES (:name,:desc)');
@@ -96,6 +97,9 @@ if ($_POST['action'] == 'get_groups') {
} elseif ($_POST['action'] == 'edit_group') {
// Edit group identified by ID
try {
$name = html_entity_decode($_POST['name']);
$desc = html_entity_decode($_POST['desc']);
$stmt = $db->prepare('UPDATE "group" SET enabled=:enabled, name=:name, description=:desc WHERE id = :id');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
@@ -106,11 +110,10 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':name', $_POST['name'], SQLITE3_TEXT)) {
if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) {
throw new Exception('While binding name: ' . $db->lastErrorMsg());
}
$desc = $_POST['desc'];
if (strlen($desc) === 0) {
// Store NULL in database for empty descriptions
$desc = null;
@@ -263,7 +266,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding ip: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
@@ -293,7 +296,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
@@ -453,7 +456,7 @@ if ($_POST['action'] == 'get_groups') {
} elseif ($_POST['action'] == 'add_domain') {
// Add new domain
try {
$domains = explode(' ', trim($_POST['domain']));
$domains = explode(' ', html_entity_decode(trim($_POST['domain'])));
$before = intval($db->querySingle("SELECT COUNT(*) FROM domainlist;"));
$total = count($domains);
$added = 0;
@@ -474,7 +477,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding type: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
@@ -573,7 +576,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
@@ -742,7 +745,7 @@ if ($_POST['action'] == 'get_groups') {
} elseif ($_POST['action'] == 'add_adlist') {
// Add new adlist
try {
$addresses = explode(' ', trim($_POST['address']));
$addresses = explode(' ', html_entity_decode(trim($_POST['address'])));
$total = count($addresses);
$added = 0;
@@ -751,7 +754,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
@@ -800,7 +803,7 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
$comment = html_entity_decode($_POST['comment']);
if (strlen($comment) === 0) {
// Store NULL in database for empty comments
$comment = null;
+1 -1
View File
@@ -162,7 +162,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; base-uri 'none'; child-src 'self'; form-action 'self'; frame-src 'self'; img-src 'self'; manifest-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; base-uri 'none'; child-src 'self'; form-action 'self'; frame-src 'self'; font-src 'self'; connect-src 'self'; img-src 'self'; manifest-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'">
<!-- Usually browsers proactively perform domain name resolution on links that the user may choose to follow. We disable DNS prefetching here -->
<meta http-equiv="x-dns-prefetch-control" content="off">
<meta http-equiv="cache-control" content="max-age=60,private">
+62 -37
View File
@@ -19,6 +19,30 @@ function validIP($address){
return !filter_var($address, FILTER_VALIDATE_IP) === false;
}
function validCIDRIP($address){
// This validation strategy has been taken from ../js/groups-common.js
$isIPv6 = strpos($address, ":") !== false;
if($isIPv6) {
// One IPv6 element is 16bit: 0000 - FFFF
$v6elem = "[0-9A-Fa-f]{1,4}";
// CIDR for IPv6 is any multiple of 4 from 4 up to 128 bit
$v6cidr = "(4";
for ($i=8; $i <= 128; $i+=4) {
$v6cidr .= "|$i";
}
$v6cidr .= ")";
$validator = "/^(((?:$v6elem))((?::$v6elem))*::((?:$v6elem))((?::$v6elem))*|((?:$v6elem))((?::$v6elem)){7})\/$v6cidr$/";
return preg_match($validator, $address);
} else {
// One IPv4 element is 8bit: 0 - 256
$v4elem = "(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9][0-9]?|0)";
// Note that rev-server accepts only /8, /16, /24, and /32
$allowedv4cidr = "(8|16|24|32)";
$validator = "/^$v4elem\.$v4elem\.$v4elem\.$v4elem\/$allowedv4cidr$/";
return preg_match($validator, $address);
}
}
// Check for existance of variable
// and test it only if it exists
function istrue(&$argument) {
@@ -263,25 +287,27 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
{
$exploded = explode("#", $_POST["custom".$i."val"], 2);
$IP = trim($exploded[0]);
if(count($exploded) > 1)
{
$port = trim($exploded[1]);
}
else
{
$port = "53";
}
if(!validIP($IP))
{
$error .= "IP (".htmlspecialchars($IP).") is invalid!<br>";
}
elseif(!is_numeric($port))
{
$error .= "Port (".htmlspecialchars($port).") is invalid!<br>";
}
else
{
array_push($DNSservers,$IP."#".$port);
if(count($exploded) > 1)
{
$port = trim($exploded[1]);
if(!is_numeric($port))
{
$error .= "Port (".htmlspecialchars($port).") is invalid!<br>";
}
else
{
$IP .= "#".$port;
}
}
array_push($DNSservers,$IP);
}
}
}
@@ -323,28 +349,35 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
$extra .= "no-dnssec";
}
// Check if Conditional Forwarding is requested
if(isset($_POST["conditionalForwarding"]))
// Check if rev-server is requested
if(isset($_POST["rev_server"]))
{
$conditionalForwardingIP = trim($_POST["conditionalForwardingIP"]);
$conditionalForwardingDomain = trim($_POST["conditionalForwardingDomain"]);
// Validate conditional forwarding IP
if (!validIP($conditionalForwardingIP))
// Validate CIDR IP
$cidr = trim($_POST["rev_server_cidr"]);
if (!validCIDRIP($cidr))
{
$error .= "Conditional forwarding IP (".htmlspecialchars($conditionalForwardingIP).") is invalid!<br>";
$error .= "Conditional forwarding subnet (\"".htmlspecialchars($cidr)."\") is invalid!<br>".
"This field requires CIDR notation for local subnets (e.g., 192.168.0.0/16).<br>".
"Please use only subnets /8, /16, /24, and /32.<br>";
}
// Validate conditional forwarding domain name
if(!validDomain($conditionalForwardingDomain))
// Validate target IP
$target = trim($_POST["rev_server_target"]);
if (!validIP($target))
{
$error .= "Conditional forwarding domain name (".htmlspecialchars($conditionalForwardingDomain).") is invalid!<br>";
$error .= "Conditional forwarding target IP (\"".htmlspecialchars($target)."\") is invalid!<br>";
}
// Validate conditional forwarding domain name (empty is okay)
$domain = trim($_POST["rev_server_domain"]);
if(strlen($domain) > 0 && !validDomain($domain))
{
$error .= "Conditional forwarding domain name (\"".htmlspecialchars($domain)."\") is invalid!<br>";
}
if(!$error)
{
$addressArray = explode(".", $conditionalForwardingIP);
$reverseAddress = $addressArray[2].".".$addressArray[1].".".$addressArray[0].".in-addr.arpa";
$extra .= " conditional_forwarding ".$conditionalForwardingIP." ".$conditionalForwardingDomain." $reverseAddress";
$extra .= " rev-server ".$cidr." ".$target." ".$domain;
}
}
@@ -376,16 +409,8 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
{
$IPs = implode (",", $DNSservers);
$return = pihole_execute("-a setdns \"".$IPs."\" ".$extra);
if(!empty($return))
{
$success .= htmlspecialchars(end($return))."<br>";
$success .= "The DNS settings have been updated (using ".$DNSservercount." DNS servers)";
}
else
{
$success .= "Updating DNS settings failed. Result:";
$success .= implode($return);
}
$success .= htmlspecialchars(end($return))."<br>";
$success .= "The DNS settings have been updated (using ".$DNSservercount." DNS servers)";
}
else
{
+2 -2
View File
@@ -173,7 +173,7 @@ function archive_restore_table($file, $table, $flush=false)
foreach($contents as $row)
{
// Limit max length for a domain entry to 253 chars
if(strlen($row[$field]) > 253)
if(isset($field) && strlen($row[$field]) > 253)
continue;
// Bind properties from JSON data
@@ -196,7 +196,7 @@ function archive_restore_table($file, $table, $flush=false)
default:
$sqltype = "UNK";
}
$stmt->bindValue(":".$key, $value, $sqltype);
$stmt->bindValue(":".$key, htmlentities($value), $sqltype);
}
if($stmt->execute() && $stmt->reset() && $stmt->clear())