Ported groups.lp

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2023-05-05 14:05:35 +02:00
parent 2c9ed17c9b
commit 8a794ca69b
5 changed files with 95 additions and 273 deletions

View File

@@ -1,84 +0,0 @@
<?php
/*
* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license.
*/
mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
?>
<!-- Title -->
<div class="page-header">
<h1>Local CNAME Records</h1>
<small>On this page, you can add CNAME records.</small>
</div>
<!-- Domain Input -->
<div class="row">
<div class="col-md-12">
<div class="box">
<!-- /.box-header -->
<div class="box-header with-border">
<h3 class="box-title">
Add a new CNAME record
</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<div class="row">
<div class="form-group col-md-6">
<label for="domain">Domain:</label>
<input id="domain" type="url" class="form-control" placeholder="Domain or comma-separated list of domains" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
</div>
<div class="form-group col-md-6">
<label for="target">Target Domain:</label>
<input id="target" type="url" class="form-control" placeholder="Associated Target Domain" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
</div>
</div>
</div>
<div class="box-footer clearfix">
<strong>Note:</strong>
<p>The target of a <code>CNAME</code> must be a domain that the Pi-hole already has in its cache or is authoritative for. This is a universal limitation of <code>CNAME</code> records.</p>
<p>The reason for this is that Pi-hole will not send additional queries upstream when serving <code>CNAME</code> replies. As consequence, if you set a target that isn't already known, the reply to the client may be incomplete. Pi-hole just returns the information it knows at the time of the query. This results in certain limitations for <code>CNAME</code> targets,
for instance, only <i>active</i> DHCP leases work as targets - mere DHCP <i>leases</i> aren't sufficient as they aren't (yet) valid DNS records.</p>
<p>Additionally, you can't <code>CNAME</code> external domains (<code>bing.com</code> to <code>google.com</code>) successfully as this could result in invalid SSL certificate errors when the target server does not serve content for the requested domain.</p>
<button type="button" id="btnAdd" class="btn btn-primary pull-right">Add</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="box" id="recent-queries">
<div class="box-header with-border">
<h3 class="box-title">
List of local CNAME records
</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="customCNAMETable" class="table table-striped table-bordered" width="100%">
<thead>
<tr>
<th>Domain</th>
<th>Target</th>
<th>Action</th>
</tr>
</thead>
</table>
<button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear Filters</button>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
<script src="<?=pihole.fileversion('scripts/pi-hole/js/customcname.js')?>"></script>
<? mg.include('scripts/pi-hole/lua/footer.lp','r')?>

View File

@@ -1,89 +0,0 @@
<?php
/*
* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license.
*/
mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
?>
<!-- Title -->
<div class="page-header">
<h1>Local DNS Records [A/AAAA]</h1>
<small>On this page, you can add domain/IP associations</small>
</div>
<!-- Domain Input -->
<div class="row">
<div class="col-md-12">
<div class="box">
<!-- /.box-header -->
<div class="box-header with-border">
<h3 class="box-title">
Add a new domain/IP combination
</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<div class="row">
<div class="form-group col-md-6">
<label for="domain">Domain:</label>
<input id="domain" type="url" class="form-control" placeholder="Domain or comma-separated list of domains" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
</div>
<div class="form-group col-md-6">
<label for="ip">IP Address:</label>
<input id="ip" type="text" class="form-control" placeholder="Associated IP address" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
</div>
</div>
</div>
<div class="box-footer clearfix">
<strong>Note:</strong>
<p>The order of locally defined DNS records is: </p>
<ol>
<li>The device's host name and <code>pi.hole</code></li>
<li>Configured in a config file in <code>/etc/dnsmasq.d/</code></li>
<li>Read from <code>/etc/hosts</code></li>
<li>Read from the "Local (custom) DNS" list (stored in <code>/etc/pihole/custom.list</code>)</li>
</ol>
<p>Only the first record will trigger an address-to-name association.</p>
<button type="button" id="btnAdd" class="btn btn-primary pull-right">Add</button>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="box" id="recent-queries">
<div class="box-header with-border">
<h3 class="box-title">
List of local DNS domains
</h3>
</div>
<!-- /.box-header -->
<div class="box-body">
<table id="customDNSTable" class="table table-striped table-bordered" width="100%">
<thead>
<tr>
<th>Domain</th>
<th>IP</th>
<th>Action</th>
</tr>
</thead>
</table>
<button type="button" id="resetButton" class="btn btn-default btn-sm text-red hidden">Clear Filters</button>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
<script src="<?=pihole.fileversion('scripts/pi-hole/js/ip-address-sorting.js')?>"></script>
<script src="<?=pihole.fileversion('scripts/pi-hole/js/customdns.js')?>"></script>
<? mg.include('scripts/pi-hole/lua/footer.lp','r')?>

View File

@@ -1,12 +1,11 @@
<?php
/*
<? --[[
* Pi-hole: A black hole for Internet advertisements
* (c) 2019 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license.
*/
--]]
mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
?>
@@ -34,8 +33,8 @@ mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
<input id="new_name" type="text" class="form-control" placeholder="Group name or space-separated group names">
</div>
<div class="form-group col-md-6">
<label for="new_desc">Description:</label>
<input id="new_desc" type="text" class="form-control" placeholder="Group description (optional)">
<label for="new_comment">Comment:</label>
<input id="new_comment" type="text" class="form-control" placeholder="Group comment (optional)">
</div>
</div>
</div>
@@ -67,7 +66,7 @@ mg.include('scripts/pi-hole/lua/header_authenticated.lp','r')
<th></th>
<th>Name</th>
<th>Status</th>
<th>Description</th>
<th>Comment</th>
<th>&nbsp;</th>
</tr>
</thead>

View File

@@ -7,17 +7,28 @@
/* global utils:false */
var table;
var token = $("#token").text();
var table, id_names = {};
function handleAjaxError(xhr, textStatus) {
if (textStatus === "timeout") {
alert("The server took too long to send the data.");
} else {
alert("An unknown error occured while loading the data.\n" + xhr.responseText);
}
table.clear();
table.draw();
}
$(function () {
$("#btnAdd").on("click", addGroup);
table = $("#groupsTable").DataTable({
ajax: {
url: "scripts/pi-hole/php/groups.php",
data: { action: "get_groups", token: token },
type: "POST",
url: "/api/groups",
error: handleAjaxError,
dataSrc: "groups",
type: "GET",
},
order: [[0, "asc"]],
columns: [
@@ -25,7 +36,7 @@ $(function () {
{ data: null, visible: true, orderable: false, width: "15px" },
{ data: "name" },
{ data: "enabled", searchable: false },
{ data: "description" },
{ data: "comment" },
{ data: null, width: "22px", orderable: false },
],
columnDefs: [
@@ -49,6 +60,7 @@ $(function () {
$('button[id^="deleteGroup_"]').on("click", deleteGroup);
},
rowCallback: function (row, data) {
id_names[data.id] = data.name;
$(row).attr("data-id", data.id);
var tooltip =
"Added: " +
@@ -66,23 +78,23 @@ $(function () {
var disabled = data.enabled === 0;
$("td:eq(2)", row).html(
'<input type="checkbox" id="status_' + data.id + '"' + (disabled ? "" : " checked") + ">"
'<input type="checkbox" id="enabled_' + data.id + '"' + (disabled ? "" : " checked") + ">"
);
var statusEl = $("#status_" + data.id, row);
statusEl.bootstrapToggle({
var enabledEl = $("#enabled_" + data.id, row);
enabledEl.bootstrapToggle({
on: "Enabled",
off: "Disabled",
size: "small",
onstyle: "success",
width: "80px",
});
statusEl.on("change", editGroup);
enabledEl.on("change", editGroup);
$("td:eq(3)", row).html('<input id="desc_' + data.id + '" class="form-control">');
var desc = data.description !== null ? data.description : "";
var descEl = $("#desc_" + data.id, row);
descEl.val(utils.unescapeHtml(desc));
descEl.on("change", editGroup);
$("td:eq(3)", row).html('<input id="comment_' + data.id + '" class="form-control">');
var comment = data.comment !== null ? data.comment : "";
var commentEl = $("#comment_" + data.id, row);
commentEl.val(utils.unescapeHtml(comment));
commentEl.on("change", editGroup);
$("td:eq(4)", row).empty();
if (data.id !== 0) {
@@ -212,52 +224,46 @@ function delItems(ids) {
// Check input validity
if (!Array.isArray(ids)) return;
var items = "";
for (var id of ids) {
// Exploit prevention: Return early for non-numeric IDs
if (typeof id !== "number") return;
// List deleted items
items += "<li><i>" + utils.escapeHtml($("#name_" + id).val()) + "</i></li>";
}
var name = id_names[ids[0]];
// Remove first element from array
ids.shift();
utils.disableAll();
var idstring = ids.join(", ");
utils.showAlert("info", "", "Deleting group(s)...", "<ul>" + items + "</ul>");
utils.showAlert("info", "", "Deleting group...", name);
$.ajax({
url: "scripts/pi-hole/php/groups.php",
method: "post",
dataType: "json",
data: { action: "delete_group", id: JSON.stringify(ids), token: token },
url: "/api/groups/" + name,
method: "delete",
})
.done(function (response) {
utils.enableAll();
if (response.success) {
utils.showAlert(
"success",
"far fa-trash-alt",
"Successfully deleted group(s): ",
"<ul>" + items + "</ul>"
);
for (var id in ids) {
if (Object.hasOwnProperty.call(ids, id)) {
table.row(id).remove().draw(false).ajax.reload(null, false);
}
}
} else {
utils.showAlert(
"error",
"",
"Error while deleting group(s): " + idstring,
response.message
"Successfully deleted group: ",
name
);
table.row(id).remove().draw(false);
if(ids.length > 0) {
// Recursively delete all remaining items
delItems(ids);
return;
}
table.ajax.reload(null, false);
// Clear selection after deletion
table.rows().deselect();
utils.changeBulkDeleteStates(table);
// Update number of groups in the sidebar
updateFtlInfo();
})
.fail(function (jqXHR, exception) {
utils.enableAll();
@@ -273,7 +279,7 @@ function delItems(ids) {
function addGroup() {
var name = utils.escapeHtml($("#new_name").val());
var desc = utils.escapeHtml($("#new_desc").val());
var comment = utils.escapeHtml($("#new_comment").val());
utils.disableAll();
utils.showAlert("info", "", "Adding group...", name);
@@ -286,22 +292,24 @@ function addGroup() {
}
$.ajax({
url: "scripts/pi-hole/php/groups.php",
url: "/api/groups",
method: "post",
dataType: "json",
data: { action: "add_group", name: name, desc: desc, token: token },
data: JSON.stringify({
name: name,
comment: comment,
enabled: true,
}),
success: function (response) {
utils.enableAll();
if (response.success) {
utils.showAlert("success", "fas fa-plus", "Successfully added group", name);
$("#new_name").val("");
$("#new_desc").val("");
$("#new_comment").val("");
table.ajax.reload();
table.rows().deselect();
$("#new_name").focus();
} else {
utils.showAlert("error", "", "Error while adding new group", response.message);
}
// Update number of groups in the sidebar
updateFtlInfo();
},
error: function (jqXHR, exception) {
utils.enableAll();
@@ -315,69 +323,57 @@ function editGroup() {
var elem = $(this).attr("id");
var tr = $(this).closest("tr");
var id = tr.attr("data-id");
var old_name = id_names[data.id];
var name = utils.escapeHtml(tr.find("#name_" + id).val());
var status = tr.find("#status_" + id).is(":checked") ? 1 : 0;
var desc = utils.escapeHtml(tr.find("#desc_" + id).val());
var enabled = tr.find("#enabled_" + id).is(":checked");
var comment = utils.escapeHtml(tr.find("#comment_" + id).val());
var done = "edited";
var notDone = "editing";
switch (elem) {
case "status_" + id:
if (status === 0) {
case "enabled_" + id:
if (enabled === false) {
done = "disabled";
notDone = "disabling";
} else if (status === 1) {
} else if (enabled === true) {
done = "enabled";
notDone = "enabling";
}
break;
case "name_" + id:
done = "edited name of";
notDone = "editing name of";
break;
case "desc_" + id:
done = "edited description of";
notDone = "editing description of";
case "comment_" + id:
done = "edited comment of";
notDone = "editing comment of";
break;
default:
alert("bad element or invalid data-id!");
alert("bad element ( " + elem + " ) or invalid data-id!");
return;
}
utils.disableAll();
utils.showAlert("info", "", "Editing group...", name);
utils.showAlert("info", "", "Editing group...", old_name);
$.ajax({
url: "scripts/pi-hole/php/groups.php",
method: "post",
url: "/api/groups/" + old_name,
method: "put",
dataType: "json",
data: {
action: "edit_group",
id: id,
data: JSON.stringify({
name: name,
desc: desc,
status: status,
token: token,
},
comment: comment,
enabled: enabled,
}),
success: function (response) {
utils.enableAll();
if (response.success) {
utils.showAlert("success", "fas fa-pencil-alt", "Successfully " + done + " group", name);
} else {
utils.showAlert(
"error",
"",
"Error while " + notDone + " group with ID " + id,
response.message
);
}
utils.showAlert("success", "fas fa-pencil-alt", "Successfully " + done + " group", old_name);
},
error: function (jqXHR, exception) {
utils.enableAll();
utils.showAlert(
"error",
"",
"Error while " + notDone + " group with ID " + id,
"Error while " + notDone + " group with name " + old_name,
jqXHR.responseText
);
console.log(exception); // eslint-disable-line no-console

View File

@@ -43,7 +43,7 @@
<!-- Group Management -->
<li class="menu-group<? if scriptname == 'groups.lp' then mg.write(" active") end ?>">
<a href="groups.lp">
<i class="fa fa-fw menu-icon fa-user-friends"></i> <span class="text-red">Groups
<i class="fa fa-fw menu-icon fa-user-friends"></i> <span class="text-green">Groups
<span class="pull-right-container">
<span class="label label-primary pull-right" id="num_groups" title="Number of defined groups"></span>
</span>