mirror of
https://github.com/pi-hole/web.git
synced 2026-02-15 07:25:39 +00:00
Pi-hole web v5.17 (#2430)
This commit is contained in:
2
.github/workflows/phpstan.yml
vendored
2
.github/workflows/phpstan.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
run: composer validate
|
||||
- name: Cache Composer packages
|
||||
id: composer-cache
|
||||
uses: actions/cache@v3.0.10
|
||||
uses: actions/cache@v3.0.11
|
||||
with:
|
||||
path: vendor
|
||||
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
uses: actions/checkout@v3.1.0
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@v3.5.0
|
||||
uses: actions/setup-node@v3.5.1
|
||||
with:
|
||||
node-version: "16.x"
|
||||
cache: npm
|
||||
|
||||
@@ -192,7 +192,7 @@ if (isset($_GET['topDomains']) && $auth) {
|
||||
$limit = ' AND timestamp <= :until';
|
||||
}
|
||||
// Select top permitted domains only
|
||||
$stmt = $db->prepare('SELECT domain,count(domain) FROM queries WHERE status IN (2,3,12,13,14)'.$limit.' GROUP by domain order by count(domain) desc limit 20');
|
||||
$stmt = $db->prepare('SELECT domain,count(domain) FROM queries WHERE status IN (2,3,12,13,14,17)'.$limit.' GROUP by domain order by count(domain) desc limit 20');
|
||||
$stmt->bindValue(':from', intval($_GET['from']), SQLITE3_INTEGER);
|
||||
$stmt->bindValue(':until', intval($_GET['until']), SQLITE3_INTEGER);
|
||||
$results = $stmt->execute();
|
||||
|
||||
@@ -32,7 +32,7 @@ require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="domain">Domain:</label>
|
||||
<input id="domain" type="url" class="form-control" placeholder="Add a domain (example.com or sub.example.com)" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
<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>
|
||||
|
||||
@@ -49,6 +49,7 @@ require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
<div class="col-md-3">
|
||||
<div><input type="checkbox" id="type_forwarded" checked><label for="type_forwarded">Permitted: forwarded</label><br></div>
|
||||
<div><input type="checkbox" id="type_cached" checked><label for="type_cached">Permitted: cached</label></div>
|
||||
<div><input type="checkbox" id="type_cached_stale" checked><label for="type_cached_stale">Permitted: stale cache</label></div>
|
||||
<div><input type="checkbox" id="type_retried" checked><label for="type_retried">Permitted: retried</label></div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
|
||||
@@ -32,7 +32,7 @@ require 'scripts/pi-hole/php/header_authenticated.php';
|
||||
<div class="row">
|
||||
<div class="form-group col-md-6">
|
||||
<label for="domain">Domain:</label>
|
||||
<input id="domain" type="url" class="form-control" placeholder="Add a domain (example.com or sub.example.com)" autocomplete="off" spellcheck="false" autocapitalize="none" autocorrect="off">
|
||||
<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>
|
||||
|
||||
@@ -42,7 +42,7 @@ require 'scripts/pi-hole/php/header.php';
|
||||
<form action="" id="loginform" method="post">
|
||||
<div class="form-group login-options has-feedback<?php if ($wrongpassword) { ?> has-error<?php } ?>">
|
||||
<div class="pwd-field">
|
||||
<input type="password" id="loginpw" name="pw" class="form-control" placeholder="Password" autocomplete="current-password" autofocus>
|
||||
<input type="password" id="loginpw" name="pw" class="form-control" placeholder="Password" spellcheck="false" autocomplete="current-password" autofocus>
|
||||
<span class="fa fa-key form-control-feedback"></span>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
32
package-lock.json
generated
32
package-lock.json
generated
@@ -281,13 +281,13 @@
|
||||
}
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.4.12",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz",
|
||||
"integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==",
|
||||
"version": "10.4.13",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz",
|
||||
"integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browserslist": "^4.21.4",
|
||||
"caniuse-lite": "^1.0.30001407",
|
||||
"caniuse-lite": "^1.0.30001426",
|
||||
"fraction.js": "^4.2.0",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
@@ -307,15 +307,15 @@
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001410",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001410.tgz",
|
||||
"integrity": "sha512-QoblBnuE+rG0lc3Ur9ltP5q47lbguipa/ncNMyyGuqPk44FxbScWAeEO+k5fSQ8WekdAK4mWqNs1rADDAiN5xQ==",
|
||||
"version": "1.0.30001426",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001426.tgz",
|
||||
"integrity": "sha512-n7cosrHLl8AWt0wwZw/PJZgUg3lV0gk9LMI7ikGJwhyhgsd2Nb65vKvmSexCqq/J7rbH3mFG6yZZiPR5dLPW5A==",
|
||||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.261",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.261.tgz",
|
||||
"integrity": "sha512-fVXliNUGJ7XUVJSAasPseBbVgJIeyw5M1xIkgXdTSRjlmCqBbiSTsEdLOCJS31Fc8B7CaloQ/BFAg8By3ODLdg==",
|
||||
"version": "1.4.284",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz",
|
||||
"integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==",
|
||||
"dev": true
|
||||
},
|
||||
"node-releases": {
|
||||
@@ -2737,9 +2737,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.17",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz",
|
||||
"integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==",
|
||||
"version": "8.4.19",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.19.tgz",
|
||||
"integrity": "sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nanoid": "^3.3.4",
|
||||
@@ -3371,9 +3371,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"update-browserslist-db": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz",
|
||||
"integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==",
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz",
|
||||
"integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"escalade": "^3.1.1",
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.12",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"eslint-plugin-compat": "^4.0.2",
|
||||
"postcss": "^8.4.17",
|
||||
"postcss": "^8.4.19",
|
||||
"postcss-cli": "^10.0.0",
|
||||
"prettier": "2.7.1",
|
||||
"xo": "^0.52.4"
|
||||
|
||||
@@ -236,12 +236,15 @@ $(function () {
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
interaction: {
|
||||
mode: "nearest",
|
||||
axis: "x",
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
yAlign: "bottom",
|
||||
intersect: false,
|
||||
mode: "x",
|
||||
itemSort: function (a, b) {
|
||||
return b.datasetIndex - a.datasetIndex;
|
||||
},
|
||||
@@ -390,7 +393,7 @@ $("#querytime").on("apply.daterangepicker", function (ev, picker) {
|
||||
updateQueriesOverTime();
|
||||
});
|
||||
|
||||
$("#queryOverTimeChart").click(function (evt) {
|
||||
$("#queryOverTimeChart").on("click", function (evt) {
|
||||
var activePoints = timeLineChart.getElementsAtEventForMode(
|
||||
evt,
|
||||
"nearest",
|
||||
|
||||
@@ -167,6 +167,10 @@ function excludeStatusTypes() {
|
||||
statusType.push(16);
|
||||
}
|
||||
|
||||
if ($("#type_cached_stale").prop("checked") === false) {
|
||||
statusType.push(17);
|
||||
}
|
||||
|
||||
return statusType.join(",");
|
||||
}
|
||||
|
||||
@@ -176,7 +180,7 @@ var reloadCallback = function () {
|
||||
var data = tableApi.rows().data();
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
statistics[0]++; // TOTAL query
|
||||
if (data[i][4] === 1 || (data[i][4] > 4 && ![10, 12, 13, 14].includes(data[i][4]))) {
|
||||
if (data[i][4] === 1 || (data[i][4] > 4 && ![10, 12, 13, 14, 17].includes(data[i][4]))) {
|
||||
statistics[2]++; // EXACT blocked
|
||||
} else if (data[i][4] === 3) {
|
||||
statistics[1]++; // CACHE query
|
||||
@@ -349,6 +353,13 @@ $(function () {
|
||||
"<span class='text-orange'>Blocked <br class='hidden-lg'>(special domain)</span>";
|
||||
blocked = true;
|
||||
break;
|
||||
case 17:
|
||||
fieldtext =
|
||||
"<span class='text-orange'>OK</span> <br class='hidden-lg'>(stale cache)" +
|
||||
dnssecStatus;
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
default:
|
||||
fieldtext = "Unknown (" + parseInt(data[4], 10) + ")";
|
||||
}
|
||||
@@ -464,12 +475,12 @@ $("#querytime").on("apply.daterangepicker", function (ev, picker) {
|
||||
refreshTableData();
|
||||
});
|
||||
|
||||
$("input[id^=type]").change(function () {
|
||||
$("input[id^=type]").on("change", function () {
|
||||
if (datepickerManuallySelected) {
|
||||
reloadBox.show();
|
||||
}
|
||||
});
|
||||
|
||||
$(".bt-reload").click(function () {
|
||||
$(".bt-reload").on("click", function () {
|
||||
refreshTableData();
|
||||
});
|
||||
|
||||
@@ -150,7 +150,7 @@ function initCheckboxRadioStyle() {
|
||||
var iCheckStyle = $("#iCheckStyle");
|
||||
if (iCheckStyle !== null) {
|
||||
iCheckStyle.val(chkboxStyle);
|
||||
iCheckStyle.change(function () {
|
||||
iCheckStyle.on("change", function () {
|
||||
var themename = $(this).val();
|
||||
localStorage.setItem("theme_icheck", themename);
|
||||
applyCheckboxRadioStyle(themename);
|
||||
@@ -197,7 +197,7 @@ function initCPUtemp() {
|
||||
var tempunitSelector = $("#tempunit-selector");
|
||||
if (tempunitSelector !== null) {
|
||||
tempunitSelector.val(tempunit);
|
||||
tempunitSelector.change(function () {
|
||||
tempunitSelector.on("change", function () {
|
||||
tempunit = $(this).val();
|
||||
setCPUtemp(tempunit);
|
||||
});
|
||||
@@ -256,7 +256,7 @@ $("#pihole-disable-custom").on("click", function (e) {
|
||||
});
|
||||
|
||||
// Handle Ctrl + Enter button on Login page
|
||||
$(document).keypress(function (e) {
|
||||
$(document).on("keypress", function (e) {
|
||||
if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey && $("#loginpw").is(":focus")) {
|
||||
$("#loginform").attr("action", "settings.php");
|
||||
$("#loginform").submit();
|
||||
|
||||
@@ -69,7 +69,7 @@ function showSuggestDomains(value) {
|
||||
// Purposefully omit 'btn' class to save space on padding
|
||||
return $('<button type="button" class="btn-link btn-block text-right">')
|
||||
.append($("<i>").text(hostname))
|
||||
.click(function () {
|
||||
.on("click", function () {
|
||||
hideSuggestDomains();
|
||||
newDomainEl.val(hostname);
|
||||
});
|
||||
|
||||
@@ -724,17 +724,26 @@ function updateSummaryData(runOnce) {
|
||||
}
|
||||
|
||||
function doughnutTooltip(tooltipLabel) {
|
||||
var percentageTotalShown = tooltipLabel.chart._metasets[0].total.toFixed(2);
|
||||
var label = " " + tooltipLabel.label;
|
||||
var percentageTotalShown = tooltipLabel.chart._metasets[0].total.toFixed(1);
|
||||
// tooltipLabel.chart._metasets[0].total returns the total percentage of the shown slices
|
||||
// to compensate rounding errors we round to one decimal
|
||||
|
||||
if (percentageTotalShown >= 100) {
|
||||
var label = " " + tooltipLabel.label;
|
||||
// in case the item share is really small it could be rounded to 0.0
|
||||
// we compensate for this
|
||||
var itemPercentage =
|
||||
tooltipLabel.parsed.toFixed(1) === 0 ? "< 0.1" : tooltipLabel.parsed.toFixed(1);
|
||||
|
||||
// even if no doughnut slice is hidden, sometimes percentageTotalShown is slightly less then 100
|
||||
// we therefore use 99.9 to decide if slices are hidden (we only show with 0.1 precision)
|
||||
if (percentageTotalShown > 99.9) {
|
||||
// All items shown
|
||||
return label + ": " + tooltipLabel.parsed.toFixed(1) + "%";
|
||||
return label + ": " + itemPercentage + "%";
|
||||
} else {
|
||||
return (
|
||||
label +
|
||||
":<br>• " +
|
||||
tooltipLabel.parsed.toFixed(1) +
|
||||
itemPercentage +
|
||||
"% of all queries<br>• " +
|
||||
((tooltipLabel.parsed * 100) / percentageTotalShown).toFixed(1) +
|
||||
"% of shown items"
|
||||
@@ -855,6 +864,10 @@ $(function () {
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: "nearest",
|
||||
axis: "x",
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
@@ -862,7 +875,6 @@ $(function () {
|
||||
tooltip: {
|
||||
enabled: true,
|
||||
intersect: false,
|
||||
mode: "x",
|
||||
yAlign: "bottom",
|
||||
itemSort: function (a, b) {
|
||||
return b.datasetIndex - a.datasetIndex;
|
||||
@@ -963,6 +975,10 @@ $(function () {
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
mode: "nearest",
|
||||
axis: "x",
|
||||
},
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
@@ -971,7 +987,6 @@ $(function () {
|
||||
// Disable the on-canvas tooltip
|
||||
enabled: false,
|
||||
intersect: false,
|
||||
mode: "x",
|
||||
external: customTooltips,
|
||||
yAlign: "top",
|
||||
itemSort: function (a, b) {
|
||||
@@ -1056,7 +1071,7 @@ $(function () {
|
||||
updateTopClientsChart();
|
||||
}
|
||||
|
||||
$("#queryOverTimeChart").click(function (evt) {
|
||||
$("#queryOverTimeChart").on("click", function (evt) {
|
||||
var activePoints = timeLineChart.getElementsAtEventForMode(
|
||||
evt,
|
||||
"nearest",
|
||||
@@ -1078,7 +1093,7 @@ $(function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
$("#clientsChart").click(function (evt) {
|
||||
$("#clientsChart").on("click", function (evt) {
|
||||
var activePoints = clientsChart.getElementsAtEventForMode(
|
||||
evt,
|
||||
"nearest",
|
||||
|
||||
@@ -178,7 +178,7 @@ $(function () {
|
||||
}
|
||||
|
||||
$("td:eq(3)", row).html(names.join("<br>"));
|
||||
$("td:eq(3)", row).hover(function () {
|
||||
$("td:eq(3)", row).on("hover", function () {
|
||||
this.title = allnames.join("\n");
|
||||
});
|
||||
}
|
||||
@@ -201,7 +201,7 @@ $(function () {
|
||||
}
|
||||
|
||||
$("td:eq(0)", row).html(ips.join("<br>"));
|
||||
$("td:eq(0)", row).hover(function () {
|
||||
$("td:eq(0)", row).on("hover", function () {
|
||||
this.title = data.ip.join("\n");
|
||||
});
|
||||
|
||||
|
||||
@@ -219,6 +219,13 @@ $(function () {
|
||||
"<span class='text-orange'>Blocked <br class='hidden-lg'>(special domain)</span>";
|
||||
blocked = true;
|
||||
break;
|
||||
case "17":
|
||||
fieldtext =
|
||||
"<span class='text-orange'>OK</span> <br class='hidden-lg'>(stale cache)" +
|
||||
dnssecStatus;
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
default:
|
||||
fieldtext = "Unknown (" + parseInt(data[4], 10) + ")";
|
||||
}
|
||||
@@ -240,17 +247,18 @@ $(function () {
|
||||
$("td:eq(6)", row).html(buttontext);
|
||||
|
||||
if (DomainlistLink) {
|
||||
$("td:eq(4)", row).hover(
|
||||
function () {
|
||||
$("td:eq(4)", row).on(
|
||||
"hover",
|
||||
(function () {
|
||||
this.title = "Click to show matching blacklist/whitelist domain";
|
||||
this.style.color = "#72afd2";
|
||||
},
|
||||
function () {
|
||||
this.style.color = "";
|
||||
}
|
||||
})
|
||||
);
|
||||
$("td:eq(4)", row).off(); // Release any possible previous onClick event handlers
|
||||
$("td:eq(4)", row).click(function () {
|
||||
$("td:eq(4)", row).on("click", function () {
|
||||
var newTab = window.open("groups-domains.php?domainid=" + data[9], "_blank");
|
||||
if (newTab) {
|
||||
newTab.focus();
|
||||
@@ -366,80 +374,85 @@ $(function () {
|
||||
// Query type IPv4 / IPv6
|
||||
api
|
||||
.$("td:eq(1)")
|
||||
.click(function (event) {
|
||||
.on("click", function (event) {
|
||||
addColumnFilter(event, 1, this.textContent);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
.on(
|
||||
"hover",
|
||||
(function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(1, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Domain
|
||||
api
|
||||
.$("td:eq(2)")
|
||||
.click(function (event) {
|
||||
.on("click", function (event) {
|
||||
addColumnFilter(event, 2, this.textContent.split("\n")[0]);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
.on(
|
||||
"hover",
|
||||
(function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(2, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Client
|
||||
api
|
||||
.$("td:eq(3)")
|
||||
.click(function (event) {
|
||||
.on("click", function (event) {
|
||||
addColumnFilter(event, 3, this.textContent);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
.on(
|
||||
"hover",
|
||||
(function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(3, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Status
|
||||
api
|
||||
.$("td:eq(4)")
|
||||
.click(function (event) {
|
||||
.on("click", function (event) {
|
||||
var id = this.children.id.value;
|
||||
var text = this.textContent;
|
||||
addColumnFilter(event, 4, id + "#" + text);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
.on(
|
||||
"hover",
|
||||
(function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(4, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Reply type
|
||||
api
|
||||
.$("td:eq(5)")
|
||||
.click(function (event) {
|
||||
.on("click", function (event) {
|
||||
var id = this.children.id.value;
|
||||
var text = this.textContent.split(" ")[0];
|
||||
addColumnFilter(event, 5, id + "#" + text);
|
||||
})
|
||||
.hover(
|
||||
function () {
|
||||
.on(
|
||||
"hover",
|
||||
(function () {
|
||||
$(this).addClass("pointer").attr("title", tooltipText(5, this.textContent));
|
||||
},
|
||||
function () {
|
||||
$(this).removeClass("pointer");
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
// Disable autocorrect in the search box
|
||||
@@ -458,14 +471,14 @@ $(function () {
|
||||
|
||||
$("#all-queries tbody").on("click", "button", function () {
|
||||
var data = tableApi.row($(this).parents("tr")).data();
|
||||
if (data[4] === "2" || data[4] === "3" || data[4] === "14") {
|
||||
if (data[4] === "2" || data[4] === "3" || data[4] === "14" || data[4] === "17") {
|
||||
utils.addFromQueryLog(data[2], "black");
|
||||
} else {
|
||||
utils.addFromQueryLog(data[2], "white");
|
||||
}
|
||||
});
|
||||
|
||||
$("#resetButton").click(function () {
|
||||
$("#resetButton").on("click", function () {
|
||||
tableApi.search("");
|
||||
resetColumnsFilters();
|
||||
});
|
||||
|
||||
@@ -87,7 +87,7 @@ function eventsource() {
|
||||
}
|
||||
|
||||
// Handle enter key
|
||||
$("#domain").keypress(function (e) {
|
||||
$("#domain").on("keypress", function (e) {
|
||||
if (e.which === 13) {
|
||||
// Enter was pressed, and the input has focus
|
||||
exact = "";
|
||||
|
||||
@@ -59,7 +59,7 @@ $(function () {
|
||||
});
|
||||
|
||||
// display selected import file on button's adjacent textfield
|
||||
$("#zip_file").change(function () {
|
||||
$("#zip_file").on("change", function () {
|
||||
var fileName = $(this)[0].files.length === 1 ? $(this)[0].files[0].name : "";
|
||||
$("#zip_filename").val(fileName);
|
||||
});
|
||||
@@ -194,7 +194,7 @@ $("#apiTokenModal").on("show.bs.modal", function () {
|
||||
$('iframe[name="apiToken_iframe"]').contents().find("table").css(qrCodeStyle);
|
||||
});
|
||||
|
||||
$("#DHCPchk").click(function () {
|
||||
$("#DHCPchk").on("click", function () {
|
||||
$("input.DHCPgroup").prop("disabled", !this.checked);
|
||||
$("#dhcpnotice").prop("hidden", !this.checked).addClass("lookatme");
|
||||
});
|
||||
@@ -347,7 +347,7 @@ $(function () {
|
||||
|
||||
// En-/disable conditional forwarding input fields based
|
||||
// on the checkbox state
|
||||
$('input[name="rev_server"]').click(function () {
|
||||
$('input[name="rev_server"]').on("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);
|
||||
@@ -377,7 +377,7 @@ $(function () {
|
||||
}
|
||||
}
|
||||
|
||||
bargraphs.click(function () {
|
||||
bargraphs.on("click", function () {
|
||||
localStorage.setItem("barchart_chkbox", bargraphs.prop("checked"));
|
||||
});
|
||||
});
|
||||
@@ -397,7 +397,7 @@ $(function () {
|
||||
}
|
||||
}
|
||||
|
||||
colorfulQueryLog.click(function () {
|
||||
colorfulQueryLog.on("click", function () {
|
||||
localStorage.setItem("colorfulQueryLog_chkbox", colorfulQueryLog.prop("checked"));
|
||||
});
|
||||
});
|
||||
@@ -463,7 +463,7 @@ $(function () {
|
||||
}
|
||||
}
|
||||
|
||||
nonfatalwarnigns.click(function () {
|
||||
nonfatalwarnigns.on("click", function () {
|
||||
localStorage.setItem("hideNonfatalDnsmasqWarnings_chkbox", nonfatalwarnigns.prop("checked"));
|
||||
// Call check messages to make new setting effective
|
||||
checkMessages();
|
||||
|
||||
@@ -39,11 +39,11 @@ $(function () {
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").click(function () {
|
||||
$("#chk1").on("click", function () {
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").click(function () {
|
||||
$("#chk2").on("click", function () {
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
|
||||
@@ -39,11 +39,11 @@ $(function () {
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").click(function () {
|
||||
$("#chk1").on("click", function () {
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").click(function () {
|
||||
$("#chk2").on("click", function () {
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
|
||||
@@ -196,6 +196,7 @@ function getCustomDNSEntries()
|
||||
$data = new \stdClass();
|
||||
$data->ip = $explodedLine[0];
|
||||
$data->domain = $explodedLine[1];
|
||||
$data->domains = array_slice($explodedLine, 0, -1);
|
||||
$entries[] = $data;
|
||||
}
|
||||
|
||||
@@ -234,22 +235,39 @@ function addCustomDNSEntry($ip = '', $domain = '', $reload = '', $json = true)
|
||||
return returnError('Domain must be set', $json);
|
||||
}
|
||||
|
||||
if (!validDomain($domain)) {
|
||||
return returnError('Domain must be valid', $json);
|
||||
$num = 0;
|
||||
// Check if each submitted domain is valid
|
||||
$domains = array_map('trim', explode(',', $domain));
|
||||
foreach ($domains as $d) {
|
||||
if (!validDomain($d)) {
|
||||
return returnError("Domain '{$d}' is not valid", $json);
|
||||
}
|
||||
++$num;
|
||||
}
|
||||
|
||||
// Only check for duplicates if adding new records from the web UI (not through Teleporter)
|
||||
if (isset($_REQUEST['ip']) || isset($_REQUEST['domain'])) {
|
||||
$existingEntries = getCustomDNSEntries();
|
||||
foreach ($existingEntries as $entry) {
|
||||
if ($entry->domain == $domain && get_ip_type($entry->ip) == $ipType) {
|
||||
return returnError('This domain already has a custom DNS entry for an IPv'.$ipType, $json);
|
||||
foreach ($domains as $d) {
|
||||
if ($entry->domain == $d && get_ip_type($entry->ip) == $ipType) {
|
||||
return returnError("The domain {$d} already has a custom DNS entry for an IPv".$ipType, $json);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add record
|
||||
pihole_execute('-a addcustomdns '.$ip.' '.$domain.' '.$reload);
|
||||
// if $reload is not set and more then one domain is supplied, restart FTL only once after all entries were added
|
||||
if (($num > 0) && (empty($reload))) {
|
||||
$reload = 'false';
|
||||
}
|
||||
// Add records
|
||||
foreach ($domains as $domain) {
|
||||
pihole_execute('-a addcustomdns '.$ip.' '.$domain.' '.$reload);
|
||||
}
|
||||
if ($num > 0) {
|
||||
pihole_execute('restartdns');
|
||||
}
|
||||
|
||||
return returnSuccess('', $json);
|
||||
} catch (\Exception $ex) {
|
||||
@@ -392,12 +410,20 @@ function addCustomCNAMEEntry($domain = '', $target = '', $reload = '', $json = t
|
||||
return returnError('Target must be valid', $json);
|
||||
}
|
||||
|
||||
// Check if each submitted domain is valid
|
||||
$num = 0;
|
||||
$domains = array_map('trim', explode(',', $domain));
|
||||
foreach ($domains as $d) {
|
||||
// Check if each submitted domain is valid
|
||||
if (!validDomain($d)) {
|
||||
return returnError("Domain '{$d}' is not valid", $json);
|
||||
}
|
||||
|
||||
// Check if each submitted domain is different than the target to avoid loops
|
||||
if (strtolower($d) === strtolower($target)) {
|
||||
return returnError('Domain and target cannot be the same', $json);
|
||||
}
|
||||
|
||||
++$num;
|
||||
}
|
||||
|
||||
$existingEntries = getCustomCNAMEEntries();
|
||||
@@ -411,7 +437,18 @@ function addCustomCNAMEEntry($domain = '', $target = '', $reload = '', $json = t
|
||||
}
|
||||
}
|
||||
|
||||
pihole_execute('-a addcustomcname '.$domain.' '.$target.' '.$reload);
|
||||
// if $reload is not set and more then one domain is supplied, restart FTL only once after all entries were added
|
||||
if (($num > 0) && (empty($reload))) {
|
||||
$reload = 'false';
|
||||
}
|
||||
// add records
|
||||
foreach ($domains as $d) {
|
||||
pihole_execute('-a addcustomcname '.$d.' '.$target.' '.$reload);
|
||||
}
|
||||
|
||||
if ($num > 0) {
|
||||
pihole_execute('restartdns');
|
||||
}
|
||||
|
||||
return returnSuccess('', $json);
|
||||
} catch (\Exception $ex) {
|
||||
|
||||
@@ -1,77 +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.
|
||||
*/
|
||||
?>
|
||||
|
||||
<div class="mainbox col-md-6 col-md-offset-3 col-sm-8 col-sm-offset-2" style="float:none">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="text-center">
|
||||
<img src="img/logo.svg" alt="Pi-hole logo" class="loginpage-logo">
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="panel-title text-center"><span class="logo-lg" style="font-size: 25px;">Pi-<b>hole</b></span></div>
|
||||
<p class="login-box-msg">Sign in to start your session</p>
|
||||
<div id="cookieInfo" class="panel-title text-center text-red" style="font-size: 150%" hidden>Verify that cookies are allowed for <code><?php echo $_SERVER['HTTP_HOST']; ?></code></div>
|
||||
|
||||
<?php if ($wrongpassword) { ?>
|
||||
<div class="form-group has-error login-box-msg">
|
||||
<label class="control-label"><i class="fa fa-times-circle"></i> Wrong password!</label>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<div class="panel-body">
|
||||
<form action="" id="loginform" method="post">
|
||||
<div class="form-group login-options has-feedback<?php if ($wrongpassword) { ?> has-error<?php } ?>">
|
||||
<div class="pwd-field">
|
||||
<input type="password" id="loginpw" name="pw" class="form-control" placeholder="Password" autocomplete="current-password" autofocus>
|
||||
<span class="fa fa-key form-control-feedback"></span>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="logincookie" name="persistentlogin">
|
||||
<label for="logincookie">Remember me for 7 days</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary form-control"><i class="fas fa-sign-in-alt"></i> Log in</button>
|
||||
</div>
|
||||
<div class="box login-help hidden-xs">
|
||||
<p><kbd>Return</kbd> ➜ Log in and go to requested page (<?php echo $scriptname; ?>)</p>
|
||||
<p><kbd>Ctrl</kbd> + <kbd>Return</kbd> ➜ Log in and go to Settings page</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box box-<?php if (!$wrongpassword) { ?>info collapsed-box<?php } else { ?>danger<?php }?>">
|
||||
<div class="box-header with-border pointer no-user-select" data-widget="collapse">
|
||||
<h3 class="box-title">Forgot password?</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool"><i class="fa <?php if ($wrongpassword) { ?>fa-minus<?php } else { ?>fa-plus<?php } ?>"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body">
|
||||
<p>
|
||||
After installing Pi-hole for the first time, a password is generated and displayed to the user. The
|
||||
password cannot be retrieved later on, but it is possible to set a new password (or explicitly disable
|
||||
the password by setting an empty password) using the command
|
||||
</p>
|
||||
<pre>sudo pihole -a -p</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
require 'scripts/pi-hole/php/footer.php';
|
||||
?>
|
||||
@@ -43,6 +43,12 @@ if (!$file) {
|
||||
if (isset($_GET['offset'])) {
|
||||
$offset = intval($_GET['offset']);
|
||||
if ($offset > 0) {
|
||||
// If offset is grater then current file end it means the file was truncated (log rotation)
|
||||
fseek($file, 0, SEEK_END);
|
||||
if ($offset > ftell($file)) {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
// Seeks on the file pointer where we want to continue reading is known
|
||||
fseek($file, $offset);
|
||||
|
||||
|
||||
@@ -126,7 +126,11 @@ if (isset($FTL_commit)) {
|
||||
}
|
||||
|
||||
if ($docker_current) {
|
||||
$dockerVersionStr = '<a href="'.$dockerUrl.'/'.rawurlencode($docker_current).'" rel="noopener" target="_blank">'.htmlentities($docker_current).'</a>';
|
||||
if ($docker_current == 'dev' || $docker_current == 'nightly') {
|
||||
$dockerVersionStr = htmlentities($docker_current);
|
||||
} else {
|
||||
$dockerVersionStr = '<a href="'.$dockerUrl.'/'.rawurlencode($docker_current).'" rel="noopener" target="_blank">'.htmlentities($docker_current).'</a>';
|
||||
}
|
||||
} else {
|
||||
$dockerVersionStr = '';
|
||||
}
|
||||
|
||||
5
scripts/vendor/jquery.confirm.min.js
vendored
5
scripts/vendor/jquery.confirm.min.js
vendored
@@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* jquery.confirm
|
||||
*
|
||||
* @version 2.3.1
|
||||
* @version 2.7.0
|
||||
*
|
||||
* @author My C-Labs
|
||||
* @author Matthieu Napoli <matthieu@mnapoli.fr>
|
||||
@@ -10,5 +10,4 @@
|
||||
*
|
||||
* @license MIT
|
||||
* @url https://myclabs.github.io/jquery.confirm/
|
||||
*/
|
||||
(function(a){a.fn.confirm=function(b){if(typeof b==="undefined"){b={}}this.click(function(c){c.preventDefault();var d=a.extend({button:a(this)},b);a.confirm(d,c)});return this};a.confirm=function(k,g){if(typeof k=="undefined"){console.error("No options given.");return}if(a(".confirmation-modal").length>0){return}var j={};if(k.button){var c={title:"title",text:"text","confirm-button":"confirmButton","submit-form":"submitForm","cancel-button":"cancelButton","confirm-button-class":"confirmButtonClass","cancel-button-class":"cancelButtonClass","dialog-class":"dialogClass","modal-options-backdrop":"modalOptionsBackdrop","modal-options-keyboard":"modalOptionsKeyboard"};a.each(c,function(e,l){var m=k.button.data(e);if(typeof m!="undefined"){j[l]=m}})}var d=a.extend({},a.confirm.options,{confirm:function(){if(j.submitForm||(typeof j.submitForm=="undefined"&&k.submitForm)||(typeof j.submitForm=="undefined"&&typeof k.submitForm=="undefined"&&a.confirm.options.submitForm)){g.target.closest("form").submit()}else{var e=g&&(("string"===typeof g&&g)||(g.currentTarget&&g.currentTarget.attributes.href.value));if(e){if(k.post){var l=a('<form method="post" class="hide" action="'+e+'"></form>');a("body").append(l);l.submit()}else{window.location=e}}}},cancel:function(e){},button:null},k,j);var b="";if(d.title!==""){b='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title">'+d.title+"</h4></div>"}var h="";if(d.cancelButton){h='<button class="cancel btn '+d.cancelButtonClass+'" type="button" data-dismiss="modal">'+d.cancelButton+"</button>"}var f='<div class="confirmation-modal modal fade" tabindex="-1" role="dialog"><div class="'+d.dialogClass+'"><div class="modal-content">'+b+'<div class="modal-body">'+d.text+'</div><div class="modal-footer"><button class="confirm btn '+d.confirmButtonClass+'" type="button" data-dismiss="modal">'+d.confirmButton+"</button>"+h+"</div></div></div></div>";var i=a(f);if(typeof d.modalOptionsBackdrop!="undefined"||typeof d.modalOptionsKeyboard!="undefined"){i.modal({backdrop:d.modalOptionsBackdrop,keyboard:d.modalOptionsKeyboard})}i.on("shown.bs.modal",function(){i.find(".btn-primary:first").focus()});i.on("hidden.bs.modal",function(){i.remove()});i.find(".confirm").click(function(){d.confirm(d.button)});i.find(".cancel").click(function(){d.cancel(d.button)});a("body").append(i);i.modal("show")};a.confirm.options={text:"Are you sure?",title:"",confirmButton:"Yes",cancelButton:"Cancel",post:false,submitForm:false,confirmButtonClass:"btn-primary",cancelButtonClass:"btn-default",dialogClass:"modal-dialog",modalOptionsBackdrop:true,modalOptionsKeyboard:true}})(jQuery);
|
||||
*/ !function(o){o.fn.confirm=function(t){return void 0===t&&(t={}),this.click(function(n){n.preventDefault();var i=o.extend({button:o(this)},t);o.confirm(i,n)}),this},o.confirm=function(t,n){if(void 0===t){console.error("No options given.");return}if(!(o(".confirmation-modal").length>0)){var i={};t.button&&o.each({title:"title",text:"text","confirm-button":"confirmButton","submit-form":"submitForm","cancel-button":"cancelButton","confirm-button-class":"confirmButtonClass","cancel-button-class":"cancelButtonClass","dialog-class":"dialogClass","modal-options-backdrop":"modalOptionsBackdrop","modal-options-keyboard":"modalOptionsKeyboard"},function(o,n){var a=t.button.data(o);void 0!==a&&(i[n]=a)});var a=o.extend({},o.confirm.options,{confirm:function(){if(i.submitForm||void 0===i.submitForm&&t.submitForm||void 0===i.submitForm&&void 0===t.submitForm&&o.confirm.options.submitForm)n.target.closest("form").submit();else{var a=n&&("string"==typeof n&&n||n.currentTarget&&n.currentTarget.attributes.href.value);if(a){if(t.post){var s=o('<form method="post" class="hide" action="'+a+'"></form>');o("body").append(s),s.submit()}else window.location=a}}},cancel:function(o){},button:null},t,i),s="";""!==a.title&&(s='<div class="modal-header"><button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button><h4 class="modal-title">'+a.title+"</h4></div>");var c="";a.cancelButton&&(c='<button class="cancel btn '+a.cancelButtonClass+'" type="button" data-dismiss="modal">'+a.cancelButton+"</button>");var d=o('<div class="confirmation-modal modal fade" tabindex="-1" role="dialog"><div class="'+a.dialogClass+'"><div class="modal-content">'+s+'<div class="modal-body">'+a.text+'</div><div class="modal-footer"><button class="confirm btn '+a.confirmButtonClass+'" type="button" data-dismiss="modal">'+a.confirmButton+"</button>"+c+"</div></div></div></div>");(void 0!==a.modalOptionsBackdrop||void 0!==a.modalOptionsKeyboard)&&d.modal({backdrop:a.modalOptionsBackdrop,keyboard:a.modalOptionsKeyboard}),d.on("shown.bs.modal",function(){d.find(".btn-primary:first").focus()}),d.on("hidden.bs.modal",function(){d.remove()}),d.find(".confirm").click(function(){a.confirm(a.button)}),d.find(".cancel").click(function(){a.cancel(a.button)}),o("body").append(d),d.modal("show")}},o.confirm.options={text:"Are you sure?",title:"",confirmButton:"Yes",cancelButton:"Cancel",post:!1,submitForm:!1,confirmButtonClass:"btn-primary",cancelButtonClass:"btn-default",dialogClass:"modal-dialog",modalOptionsBackdrop:!0,modalOptionsKeyboard:!0}}(jQuery);
|
||||
|
||||
4
scripts/vendor/jquery.min.js
vendored
4
scripts/vendor/jquery.min.js
vendored
File diff suppressed because one or more lines are too long
2
scripts/vendor/moment.min.js
vendored
2
scripts/vendor/moment.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -504,7 +504,7 @@ p.login-box-msg,
|
||||
}
|
||||
|
||||
.dropdown-toggle {
|
||||
z-index: 2000;
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
.main-header li.user-header {
|
||||
|
||||
Reference in New Issue
Block a user