mirror of
https://github.com/pi-hole/web.git
synced 2024-12-06 19:36:21 +01:00
+125
-103
@@ -1,12 +1,13 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
// Define global variables
|
||||
var auditList = [], auditTimeout;
|
||||
var auditList = [],
|
||||
auditTimeout;
|
||||
|
||||
// Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406
|
||||
function escapeHtml(text) {
|
||||
@@ -14,123 +15,144 @@ function escapeHtml(text) {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"\"": """,
|
||||
'"': """,
|
||||
"'": "'"
|
||||
};
|
||||
|
||||
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
||||
return text.replace(/[&<>"']/g, function(m) {
|
||||
return map[m];
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopLists() {
|
||||
$.getJSON("api.php?topItems=audit", function(data) {
|
||||
$.getJSON("api.php?topItems=audit", function(data) {
|
||||
if ("FTLnotrunning" in data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if("FTLnotrunning" in data)
|
||||
{
|
||||
return;
|
||||
// Clear tables before filling them with data
|
||||
$("#domain-frequency td")
|
||||
.parent()
|
||||
.remove();
|
||||
$("#ad-frequency td")
|
||||
.parent()
|
||||
.remove();
|
||||
var domaintable = $("#domain-frequency").find("tbody:last");
|
||||
var adtable = $("#ad-frequency").find("tbody:last");
|
||||
var url, domain;
|
||||
for (domain in data.top_queries) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_queries, domain)) {
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
url = '<a href="queries.php?domain=' + domain + '">' + domain + "</a>";
|
||||
domaintable.append(
|
||||
"<tr> <td>" +
|
||||
url +
|
||||
"</td> <td>" +
|
||||
data.top_queries[domain] +
|
||||
'</td> <td> <button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button> <button class="btn btn-default btn-sm text-orange"><i class="fa fa-balance-scale"></i> Audit</button> </td> </tr> '
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (domain in data.top_ads) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads, domain)) {
|
||||
var input = domain.split(" ");
|
||||
// Sanitize domain
|
||||
var printdomain = escapeHtml(input[0]);
|
||||
if (input.length > 1) {
|
||||
url =
|
||||
'<a href="queries.php?domain=' +
|
||||
printdomain +
|
||||
'">' +
|
||||
printdomain +
|
||||
"</a> (wildcard blocked)";
|
||||
adtable.append(
|
||||
"<tr> <td>" +
|
||||
url +
|
||||
"</td> <td>" +
|
||||
data.top_ads[domain] +
|
||||
'</td> <td> <button type="button" class="btn btn-default btn-sm text-orange"><i class="fa fa-balance-scale"></i> Audit</button> </td> </tr> '
|
||||
);
|
||||
} else {
|
||||
url = '<a href="queries.php?domain=' + printdomain + '">' + printdomain + "</a>";
|
||||
adtable.append(
|
||||
"<tr> <td>" +
|
||||
url +
|
||||
"</td> <td>" +
|
||||
data.top_ads[domain] +
|
||||
'</td> <td> <button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button> <button class="btn btn-default btn-sm text-orange"><i class="fa fa-balance-scale"></i> Audit</button> </td> </tr> '
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#domain-frequency td").parent().remove();
|
||||
$("#ad-frequency td").parent().remove();
|
||||
var domaintable = $("#domain-frequency").find("tbody:last");
|
||||
var adtable = $("#ad-frequency").find("tbody:last");
|
||||
var url, domain;
|
||||
for (domain in data.top_queries) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_queries,domain)){
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
url = "<a href=\"queries.php?domain="+domain+"\">"+domain+"</a>";
|
||||
domaintable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_queries[domain] + "</td> <td> <button type=\"button\" class=\"btn btn-default btn-sm text-red\"><i class=\"fa fa-ban\"></i> Blacklist</button> <button class=\"btn btn-default btn-sm text-orange\"><i class=\"fa fa-balance-scale\"></i> Audit</button> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
|
||||
for (domain in data.top_ads) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads,domain)){
|
||||
var input = domain.split(" ");
|
||||
// Sanitize domain
|
||||
var printdomain = escapeHtml(input[0]);
|
||||
if(input.length > 1)
|
||||
{
|
||||
url = "<a href=\"queries.php?domain="+printdomain+"\">"+printdomain+"</a> (wildcard blocked)";
|
||||
adtable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_ads[domain] + "</td> <td> <button type=\"button\" class=\"btn btn-default btn-sm text-orange\"><i class=\"fa fa-balance-scale\"></i> Audit</button> </td> </tr> ");
|
||||
}
|
||||
else
|
||||
{
|
||||
url = "<a href=\"queries.php?domain="+printdomain+"\">"+printdomain+"</a>";
|
||||
adtable.append("<tr> <td>" + url +
|
||||
"</td> <td>" + data.top_ads[domain] + "</td> <td> <button type=\"button\" class=\"btn btn-default btn-sm text-green\"><i class=\"fas fa-check\"></i> Whitelist</button> <button class=\"btn btn-default btn-sm text-orange\"><i class=\"fa fa-balance-scale\"></i> Audit</button> </td> </tr> ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$("#domain-frequency .overlay").hide();
|
||||
$("#ad-frequency .overlay").hide();
|
||||
// Update top lists data every second
|
||||
setTimeout(updateTopLists, 1000);
|
||||
});
|
||||
$("#domain-frequency .overlay").hide();
|
||||
$("#ad-frequency .overlay").hide();
|
||||
// Update top lists data every second
|
||||
setTimeout(updateTopLists, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
function add(domain,list) {
|
||||
var token = $("#token").text();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain, "list":list, "token":token}
|
||||
});
|
||||
function add(domain, list) {
|
||||
var token = $("#token").text();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: { domain: domain, list: list, token: token }
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Pull in data via AJAX
|
||||
updateTopLists();
|
||||
|
||||
// Pull in data via AJAX
|
||||
updateTopLists();
|
||||
$("#domain-frequency tbody").on("click", "button", function() {
|
||||
var url = $(this)
|
||||
.parents("tr")[0]
|
||||
.textContent.split(" ")[0];
|
||||
if ($(this).context.textContent === " Blacklist") {
|
||||
add(url, "audit");
|
||||
add(url, "black");
|
||||
$("#gravityBtn").prop("disabled", false);
|
||||
} else {
|
||||
auditUrl(url);
|
||||
}
|
||||
});
|
||||
|
||||
$("#domain-frequency tbody").on( "click", "button", function () {
|
||||
var url = ($(this).parents("tr"))[0].textContent.split(" ")[0];
|
||||
if($(this).context.textContent === " Blacklist")
|
||||
{
|
||||
add(url,"audit");
|
||||
add(url,"black");
|
||||
$("#gravityBtn").prop("disabled", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
auditUrl(url);
|
||||
}
|
||||
});
|
||||
|
||||
$("#ad-frequency tbody").on( "click", "button", function () {
|
||||
var url = ($(this).parents("tr"))[0].textContent.split(" ")[0].split(" ")[0];
|
||||
if($(this).context.textContent === " Whitelist")
|
||||
{
|
||||
add(url,"audit");
|
||||
add(url,"white");
|
||||
$("#gravityBtn").prop("disabled", false);
|
||||
}
|
||||
else
|
||||
{
|
||||
auditUrl(url);
|
||||
}
|
||||
});
|
||||
$("#ad-frequency tbody").on("click", "button", function() {
|
||||
var url = $(this)
|
||||
.parents("tr")[0]
|
||||
.textContent.split(" ")[0]
|
||||
.split(" ")[0];
|
||||
if ($(this).context.textContent === " Whitelist") {
|
||||
add(url, "audit");
|
||||
add(url, "white");
|
||||
$("#gravityBtn").prop("disabled", false);
|
||||
} else {
|
||||
auditUrl(url);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function auditUrl(url) {
|
||||
if (auditList.indexOf(url) > -1) {
|
||||
return;
|
||||
}
|
||||
if (auditTimeout) {
|
||||
clearTimeout(auditTimeout);
|
||||
}
|
||||
auditList.push(url);
|
||||
// wait 3 seconds to see if more domains need auditing
|
||||
// and batch them all into a single request
|
||||
auditTimeout = setTimeout(function() {
|
||||
add(auditList.join(' '), "audit");
|
||||
auditList = [];
|
||||
}, 3000);
|
||||
if (auditList.indexOf(url) > -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (auditTimeout) {
|
||||
clearTimeout(auditTimeout);
|
||||
}
|
||||
|
||||
auditList.push(url);
|
||||
// wait 3 seconds to see if more domains need auditing
|
||||
// and batch them all into a single request
|
||||
auditTimeout = setTimeout(function() {
|
||||
add(auditList.join(" "), "audit");
|
||||
auditList = [];
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
$("#gravityBtn").on("click", function() {
|
||||
window.location.replace("gravity.php?go");
|
||||
window.location.replace("gravity.php?go");
|
||||
});
|
||||
|
||||
@@ -1,105 +1,110 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
var table;
|
||||
|
||||
function showAlert(type, message)
|
||||
{
|
||||
var alertElement = null;
|
||||
var messageElement = null;
|
||||
function showAlert(type, message) {
|
||||
var alertElement = null;
|
||||
var messageElement = null;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case 'info': alertElement = $('#alInfo'); break;
|
||||
case 'success': alertElement = $('#alSuccess'); break;
|
||||
case 'warning': alertElement = $('#alWarning'); messageElement = $('#warn'); break;
|
||||
case 'error': alertElement = $('#alFailure'); messageElement = $('#err'); break;
|
||||
default: return;
|
||||
}
|
||||
switch (type) {
|
||||
case "info":
|
||||
alertElement = $("#alInfo");
|
||||
break;
|
||||
case "success":
|
||||
alertElement = $("#alSuccess");
|
||||
break;
|
||||
case "warning":
|
||||
alertElement = $("#alWarning");
|
||||
messageElement = $("#warn");
|
||||
break;
|
||||
case "error":
|
||||
alertElement = $("#alFailure");
|
||||
messageElement = $("#err");
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
if (messageElement != null)
|
||||
messageElement.html(message);
|
||||
if (messageElement != null) messageElement.html(message);
|
||||
|
||||
alertElement.fadeIn(200);
|
||||
alertElement.delay(8000).fadeOut(2000);
|
||||
alertElement.fadeIn(200);
|
||||
alertElement.delay(8000).fadeOut(2000);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#btnAdd").on("click", addCustomDNS);
|
||||
|
||||
$('#btnAdd').on('click', addCustomDNS);
|
||||
|
||||
table = $("#customDNSTable").DataTable( {
|
||||
"ajax": "scripts/pi-hole/php/customdns.php?action=get",
|
||||
columns: [
|
||||
{},
|
||||
{},
|
||||
{orderable: false, searchable: false}
|
||||
],
|
||||
"columnDefs": [ {
|
||||
"targets": 2,
|
||||
"render": function ( data, type, row ) {
|
||||
return "<button class=\"btn btn-danger btn-xs deleteCustomDNS\" type=\"button\" data-domain='"+row[0]+"' data-ip='"+row[1]+"'>" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span>" +
|
||||
"</button>";
|
||||
}
|
||||
} ],
|
||||
"drawCallback": function() {
|
||||
$('.deleteCustomDNS').on('click', deleteCustomDNS);
|
||||
table = $("#customDNSTable").DataTable({
|
||||
ajax: "scripts/pi-hole/php/customdns.php?action=get",
|
||||
columns: [{}, {}, { orderable: false, searchable: false }],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 2,
|
||||
render: function(data, type, row) {
|
||||
return (
|
||||
'<button class="btn btn-danger btn-xs deleteCustomDNS" type="button" data-domain=\'' +
|
||||
row[0] +
|
||||
"' data-ip='" +
|
||||
row[1] +
|
||||
"'>" +
|
||||
'<span class="glyphicon glyphicon-trash"></span>' +
|
||||
"</button>"
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
],
|
||||
drawCallback: function() {
|
||||
$(".deleteCustomDNS").on("click", deleteCustomDNS);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function addCustomDNS()
|
||||
{
|
||||
var ip = $('#ip').val();
|
||||
var domain = $('#domain').val();
|
||||
function addCustomDNS() {
|
||||
var ip = $("#ip").val();
|
||||
var domain = $("#domain").val();
|
||||
|
||||
showAlert('info');
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: 'json',
|
||||
data: {"action":"add", "ip" : ip, "domain": domain},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert('success');
|
||||
table.ajax.reload();
|
||||
}
|
||||
else
|
||||
showAlert('error', response.message);
|
||||
},
|
||||
error: function() {
|
||||
showAlert('error', "Error while adding this custom DNS entry");
|
||||
}
|
||||
});
|
||||
showAlert("info");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "add", ip: ip, domain: domain },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert("success");
|
||||
table.ajax.reload();
|
||||
} else showAlert("error", response.message);
|
||||
},
|
||||
error: function() {
|
||||
showAlert("error", "Error while adding this custom DNS entry");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function deleteCustomDNS()
|
||||
{
|
||||
var ip = $(this).attr("data-ip");
|
||||
var domain = $(this).attr("data-domain");
|
||||
function deleteCustomDNS() {
|
||||
var ip = $(this).attr("data-ip");
|
||||
var domain = $(this).attr("data-domain");
|
||||
|
||||
showAlert('info');
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: 'json',
|
||||
data: {"action":"delete", "domain": domain, "ip": ip},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert('success');
|
||||
table.ajax.reload();
|
||||
}
|
||||
else
|
||||
showAlert('error', response.message);
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert('error', "Error while deleting this custom DNS entry");
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
showAlert("info");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/customdns.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "delete", domain: domain, ip: ip },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert("success");
|
||||
table.ajax.reload();
|
||||
} else showAlert("error", response.message);
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert("error", "Error while deleting this custom DNS entry");
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+270
-230
@@ -1,66 +1,97 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global Chart:false, moment:false */
|
||||
|
||||
var start__ = moment().subtract(6, "days");
|
||||
var from = moment(start__).utc().valueOf()/1000;
|
||||
var from =
|
||||
moment(start__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
var end__ = moment();
|
||||
var until = moment(end__).utc().valueOf()/1000;
|
||||
var until =
|
||||
moment(end__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
var interval = 0;
|
||||
|
||||
var timeoutWarning = $("#timeoutWarning");
|
||||
|
||||
var dateformat = "MMMM Do YYYY, HH:mm";
|
||||
|
||||
$(function () {
|
||||
$("#querytime").daterangepicker(
|
||||
$(function() {
|
||||
$("#querytime").daterangepicker(
|
||||
{
|
||||
timePicker: true, timePickerIncrement: 15,
|
||||
timePicker: true,
|
||||
timePickerIncrement: 15,
|
||||
locale: { format: dateformat },
|
||||
startDate: start__, endDate: end__,
|
||||
startDate: start__,
|
||||
endDate: end__,
|
||||
ranges: {
|
||||
"Today": [moment().startOf("day"), moment()],
|
||||
"Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")],
|
||||
Today: [moment().startOf("day"), moment()],
|
||||
Yesterday: [
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.startOf("day"),
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.endOf("day")
|
||||
],
|
||||
"Last 7 Days": [moment().subtract(6, "days"), moment()],
|
||||
"Last 30 Days": [moment().subtract(29, "days"), moment()],
|
||||
"This Month": [moment().startOf("month"), moment()],
|
||||
"Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")],
|
||||
"Last Month": [
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.startOf("month"),
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.endOf("month")
|
||||
],
|
||||
"This Year": [moment().startOf("year"), moment()],
|
||||
"All Time": [moment(0), moment()]
|
||||
},
|
||||
"opens": "center", "showDropdowns": true,
|
||||
"autoUpdateInput": false
|
||||
opens: "center",
|
||||
showDropdowns: true,
|
||||
autoUpdateInput: false
|
||||
},
|
||||
function (startt, endt) {
|
||||
from = moment(startt).utc().valueOf()/1000;
|
||||
until = moment(endt).utc().valueOf()/1000;
|
||||
});
|
||||
|
||||
function(startt, endt) {
|
||||
from =
|
||||
moment(startt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
until =
|
||||
moment(endt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
function padNumber(num) {
|
||||
return ("00" + num).substr(-2,2);
|
||||
return ("00" + num).substr(-2, 2);
|
||||
}
|
||||
|
||||
// Helper function needed for converting the Objects to Arrays
|
||||
|
||||
function objectToArray(p){
|
||||
var keys = Object.keys(p);
|
||||
keys.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
function objectToArray(p) {
|
||||
var keys = Object.keys(p);
|
||||
keys.sort(function(a, b) {
|
||||
return a - b;
|
||||
});
|
||||
|
||||
var arr = [], idx = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
arr.push(p[keys[i]]);
|
||||
idx.push(keys[i]);
|
||||
}
|
||||
return [idx,arr];
|
||||
var arr = [],
|
||||
idx = [];
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
arr.push(p[keys[i]]);
|
||||
idx.push(keys[i]);
|
||||
}
|
||||
|
||||
return [idx, arr];
|
||||
}
|
||||
|
||||
var timeLineChart;
|
||||
@@ -70,229 +101,238 @@ function compareNumbers(a, b) {
|
||||
}
|
||||
|
||||
function updateQueriesOverTime() {
|
||||
$("#queries-over-time .overlay").show();
|
||||
timeoutWarning.show();
|
||||
$("#queries-over-time .overlay").show();
|
||||
timeoutWarning.show();
|
||||
|
||||
// Compute interval to obtain about 200 values
|
||||
var num = 200;
|
||||
interval = (until-from)/num;
|
||||
// Default displaying axis scaling
|
||||
timeLineChart.options.scales.xAxes[0].time.unit="hour"
|
||||
// Compute interval to obtain about 200 values
|
||||
var num = 200;
|
||||
interval = (until - from) / num;
|
||||
// Default displaying axis scaling
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "hour";
|
||||
|
||||
if(num*interval >= 6*29*24*60*60)
|
||||
{
|
||||
// If the requested data is more than 3 months, set ticks interval to quarterly
|
||||
timeLineChart.options.scales.xAxes[0].time.unit="quarter"
|
||||
}
|
||||
else if(num*interval >= 3*29*24*60*60)
|
||||
{
|
||||
// If the requested data is more than 3 months, set ticks interval to months
|
||||
timeLineChart.options.scales.xAxes[0].time.unit="month"
|
||||
}
|
||||
if(num*interval >= 29*24*60*60)
|
||||
{
|
||||
// If the requested data is more than 1 month, set ticks interval to weeks
|
||||
timeLineChart.options.scales.xAxes[0].time.unit="week"
|
||||
}
|
||||
else if(num*interval >= 6*24*60*60)
|
||||
{
|
||||
// If the requested data is more than 1 week, set ticks interval to days
|
||||
timeLineChart.options.scales.xAxes[0].time.unit="day"
|
||||
}
|
||||
if (num * interval >= 6 * 29 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 3 months, set ticks interval to quarterly
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "quarter";
|
||||
} else if (num * interval >= 3 * 29 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 3 months, set ticks interval to months
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "month";
|
||||
}
|
||||
|
||||
$.getJSON("api_db.php?getGraphData&from="+from+"&until="+until+"&interval="+interval, function(data) {
|
||||
if (num * interval >= 29 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 1 month, set ticks interval to weeks
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "week";
|
||||
} else if (num * interval >= 6 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 1 week, set ticks interval to days
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "day";
|
||||
}
|
||||
|
||||
// convert received objects to arrays
|
||||
data.domains_over_time = objectToArray(data.domains_over_time);
|
||||
data.ads_over_time = objectToArray(data.ads_over_time);
|
||||
// Remove possibly already existing data
|
||||
timeLineChart.data.labels = [];
|
||||
timeLineChart.data.datasets[0].data = [];
|
||||
timeLineChart.data.datasets[1].data = [];
|
||||
$.getJSON(
|
||||
"api_db.php?getGraphData&from=" + from + "&until=" + until + "&interval=" + interval,
|
||||
function(data) {
|
||||
// convert received objects to arrays
|
||||
data.domains_over_time = objectToArray(data.domains_over_time);
|
||||
data.ads_over_time = objectToArray(data.ads_over_time);
|
||||
// Remove possibly already existing data
|
||||
timeLineChart.data.labels = [];
|
||||
timeLineChart.data.datasets[0].data = [];
|
||||
timeLineChart.data.datasets[1].data = [];
|
||||
|
||||
var dates = [], hour;
|
||||
var dates = [],
|
||||
hour;
|
||||
|
||||
for (hour in data.domains_over_time[0]) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.domains_over_time[0], hour)) {
|
||||
dates.push(parseInt(data.domains_over_time[0][hour]));
|
||||
}
|
||||
for (hour in data.domains_over_time[0]) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.domains_over_time[0], hour)) {
|
||||
dates.push(parseInt(data.domains_over_time[0][hour]));
|
||||
}
|
||||
}
|
||||
|
||||
for (hour in data.ads_over_time[0]) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.ads_over_time[0], hour)) {
|
||||
if(dates.indexOf(parseInt(data.ads_over_time[0][hour])) === -1)
|
||||
{
|
||||
dates.push(parseInt(data.ads_over_time[0][hour]));
|
||||
}
|
||||
}
|
||||
for (hour in data.ads_over_time[0]) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.ads_over_time[0], hour)) {
|
||||
if (dates.indexOf(parseInt(data.ads_over_time[0][hour])) === -1) {
|
||||
dates.push(parseInt(data.ads_over_time[0][hour]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dates.sort(compareNumbers);
|
||||
dates.sort(compareNumbers);
|
||||
|
||||
// Add data for each hour that is available
|
||||
for (hour in dates) {
|
||||
if (Object.prototype.hasOwnProperty.call(dates, hour)) {
|
||||
var date, dom = 0, ads = 0;
|
||||
date = new Date(1000*dates[hour]);
|
||||
// Add data for each hour that is available
|
||||
for (hour in dates) {
|
||||
if (Object.prototype.hasOwnProperty.call(dates, hour)) {
|
||||
var date,
|
||||
dom = 0,
|
||||
ads = 0;
|
||||
date = new Date(1000 * dates[hour]);
|
||||
|
||||
var idx = data.domains_over_time[0].indexOf(dates[hour].toString());
|
||||
if (idx > -1)
|
||||
{
|
||||
dom = data.domains_over_time[1][idx];
|
||||
}
|
||||
var idx = data.domains_over_time[0].indexOf(dates[hour].toString());
|
||||
if (idx > -1) {
|
||||
dom = data.domains_over_time[1][idx];
|
||||
}
|
||||
|
||||
idx = data.ads_over_time[0].indexOf(dates[hour].toString());
|
||||
if (idx > -1)
|
||||
{
|
||||
ads = data.ads_over_time[1][idx];
|
||||
}
|
||||
idx = data.ads_over_time[0].indexOf(dates[hour].toString());
|
||||
if (idx > -1) {
|
||||
ads = data.ads_over_time[1][idx];
|
||||
}
|
||||
|
||||
timeLineChart.data.labels.push(date);
|
||||
timeLineChart.data.datasets[0].data.push(dom - ads);
|
||||
timeLineChart.data.datasets[1].data.push(ads);
|
||||
}
|
||||
timeLineChart.data.labels.push(date);
|
||||
timeLineChart.data.datasets[0].data.push(dom - ads);
|
||||
timeLineChart.data.datasets[1].data.push(ads);
|
||||
}
|
||||
}
|
||||
|
||||
timeLineChart.options.scales.xAxes[0].display=true;
|
||||
$("#queries-over-time .overlay").hide();
|
||||
timeoutWarning.hide();
|
||||
timeLineChart.update();
|
||||
});
|
||||
timeLineChart.options.scales.xAxes[0].display = true;
|
||||
$("#queries-over-time .overlay").hide();
|
||||
timeoutWarning.hide();
|
||||
timeLineChart.update();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
|
||||
timeLineChart = new Chart(ctx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: [ ],
|
||||
datasets: [
|
||||
{
|
||||
label: "Permitted DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0, 166, 90,.8)",
|
||||
borderColor: "rgba(0, 166, 90,.8)",
|
||||
pointBorderColor: "rgba(0, 166, 90,.8)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5
|
||||
},
|
||||
{
|
||||
label: "Blocked DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0,192,239,1)",
|
||||
borderColor: "rgba(0,192,239,1)",
|
||||
pointBorderColor: "rgba(0,192,239,1)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5
|
||||
}
|
||||
]
|
||||
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
|
||||
timeLineChart = new Chart(ctx, {
|
||||
type: "bar",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Permitted DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0, 166, 90,.8)",
|
||||
borderColor: "rgba(0, 166, 90,.8)",
|
||||
pointBorderColor: "rgba(0, 166, 90,.8)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5
|
||||
},
|
||||
options: {
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
mode: "x-axis",
|
||||
callbacks: {
|
||||
title: function(tooltipItem) {
|
||||
var label = tooltipItem[0].xLabel;
|
||||
var time = new Date(label);
|
||||
var from_date = time.getFullYear() +
|
||||
"-" +
|
||||
padNumber(time.getMonth()+1) +
|
||||
"-" +
|
||||
padNumber(time.getDate()) +
|
||||
" " +
|
||||
padNumber(time.getHours()) +
|
||||
":" +
|
||||
padNumber(time.getMinutes()) +
|
||||
":" +
|
||||
padNumber(time.getSeconds());
|
||||
time = new Date(time.valueOf() + 1000 * interval);
|
||||
var until_date = time.getFullYear() +
|
||||
"-" +
|
||||
padNumber(time.getMonth()+1) +
|
||||
"-" +
|
||||
padNumber(time.getDate()) +
|
||||
" " +
|
||||
padNumber(time.getHours()) +
|
||||
":" +
|
||||
padNumber(time.getMinutes()) +
|
||||
":" +
|
||||
padNumber(time.getSeconds());
|
||||
return "Queries from " + from_date + " to " + until_date;
|
||||
},
|
||||
label: function(tooltipItems, data) {
|
||||
if(tooltipItems.datasetIndex === 1)
|
||||
{
|
||||
var percentage = 0.0;
|
||||
var total = parseInt(data.datasets[0].data[tooltipItems.index]);
|
||||
var blocked = parseInt(data.datasets[1].data[tooltipItems.index]);
|
||||
if(total > 0)
|
||||
{
|
||||
percentage = 100.0*blocked/total;
|
||||
}
|
||||
return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel + " (" + percentage.toFixed(1) + "%)";
|
||||
}
|
||||
|
||||
return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel;
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [{
|
||||
type: "time",
|
||||
stacked: true,
|
||||
time: {
|
||||
unit: "hour",
|
||||
displayFormats: {
|
||||
"minute": "HH:mm",
|
||||
"hour": "HH:mm",
|
||||
"day": "MMM DD",
|
||||
"week": "MMM DD",
|
||||
"month": "MMM",
|
||||
"quarter": "MMM",
|
||||
"year": "YYYY MMM"
|
||||
}
|
||||
}
|
||||
}],
|
||||
yAxes: [{
|
||||
stacked: true,
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}]
|
||||
},
|
||||
maintainAspectRatio: false
|
||||
{
|
||||
label: "Blocked DNS Queries",
|
||||
fill: true,
|
||||
backgroundColor: "rgba(0,192,239,1)",
|
||||
borderColor: "rgba(0,192,239,1)",
|
||||
pointBorderColor: "rgba(0,192,239,1)",
|
||||
pointRadius: 1,
|
||||
pointHoverRadius: 5,
|
||||
data: [],
|
||||
pointHitRadius: 5
|
||||
}
|
||||
});
|
||||
]
|
||||
},
|
||||
options: {
|
||||
tooltips: {
|
||||
enabled: true,
|
||||
mode: "x-axis",
|
||||
callbacks: {
|
||||
title: function(tooltipItem) {
|
||||
var label = tooltipItem[0].xLabel;
|
||||
var time = new Date(label);
|
||||
var from_date =
|
||||
time.getFullYear() +
|
||||
"-" +
|
||||
padNumber(time.getMonth() + 1) +
|
||||
"-" +
|
||||
padNumber(time.getDate()) +
|
||||
" " +
|
||||
padNumber(time.getHours()) +
|
||||
":" +
|
||||
padNumber(time.getMinutes()) +
|
||||
":" +
|
||||
padNumber(time.getSeconds());
|
||||
time = new Date(time.valueOf() + 1000 * interval);
|
||||
var until_date =
|
||||
time.getFullYear() +
|
||||
"-" +
|
||||
padNumber(time.getMonth() + 1) +
|
||||
"-" +
|
||||
padNumber(time.getDate()) +
|
||||
" " +
|
||||
padNumber(time.getHours()) +
|
||||
":" +
|
||||
padNumber(time.getMinutes()) +
|
||||
":" +
|
||||
padNumber(time.getSeconds());
|
||||
return "Queries from " + from_date + " to " + until_date;
|
||||
},
|
||||
label: function(tooltipItems, data) {
|
||||
if (tooltipItems.datasetIndex === 1) {
|
||||
var percentage = 0.0;
|
||||
var total = parseInt(data.datasets[0].data[tooltipItems.index]);
|
||||
var blocked = parseInt(data.datasets[1].data[tooltipItems.index]);
|
||||
if (total > 0) {
|
||||
percentage = (100.0 * blocked) / total;
|
||||
}
|
||||
|
||||
return (
|
||||
data.datasets[tooltipItems.datasetIndex].label +
|
||||
": " +
|
||||
tooltipItems.yLabel +
|
||||
" (" +
|
||||
percentage.toFixed(1) +
|
||||
"%)"
|
||||
);
|
||||
}
|
||||
|
||||
return data.datasets[tooltipItems.datasetIndex].label + ": " + tooltipItems.yLabel;
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
display: false
|
||||
},
|
||||
scales: {
|
||||
xAxes: [
|
||||
{
|
||||
type: "time",
|
||||
stacked: true,
|
||||
time: {
|
||||
unit: "hour",
|
||||
displayFormats: {
|
||||
minute: "HH:mm",
|
||||
hour: "HH:mm",
|
||||
day: "MMM DD",
|
||||
week: "MMM DD",
|
||||
month: "MMM",
|
||||
quarter: "MMM",
|
||||
year: "YYYY MMM"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxes: [
|
||||
{
|
||||
stacked: true,
|
||||
ticks: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
maintainAspectRatio: false
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#querytime").on("apply.daterangepicker", function(ev, picker) {
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
$("#queries-over-time").show();
|
||||
updateQueriesOverTime();
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
$("#queries-over-time").show();
|
||||
updateQueriesOverTime();
|
||||
});
|
||||
|
||||
$("#queryOverTimeChart").click(function(evt){
|
||||
var activePoints = timeLineChart.getElementAtEvent(evt);
|
||||
if(activePoints.length > 0)
|
||||
{
|
||||
//get the internal index in the chart
|
||||
var clickedElementindex = activePoints[0]._index;
|
||||
$("#queryOverTimeChart").click(function(evt) {
|
||||
var activePoints = timeLineChart.getElementAtEvent(evt);
|
||||
if (activePoints.length > 0) {
|
||||
//get the internal index in the chart
|
||||
var clickedElementindex = activePoints[0]._index;
|
||||
|
||||
//get specific label by index
|
||||
var label = timeLineChart.data.labels[clickedElementindex];
|
||||
//get specific label by index
|
||||
var label = timeLineChart.data.labels[clickedElementindex];
|
||||
|
||||
//get value by index
|
||||
var from = label/1000;
|
||||
var until = label/1000 + 600;
|
||||
window.location.href = "db_queries.php?from="+from+"&until="+until;
|
||||
}
|
||||
return false;
|
||||
//get value by index
|
||||
var from = label / 1000;
|
||||
var until = label / 1000 + 600;
|
||||
window.location.href = "db_queries.php?from=" + from + "&until=" + until;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
+189
-136
@@ -1,45 +1,75 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global moment:false */
|
||||
|
||||
var start__ = moment().subtract(6, "days");
|
||||
var from = moment(start__).utc().valueOf()/1000;
|
||||
var from =
|
||||
moment(start__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
var end__ = moment();
|
||||
var until = moment(end__).utc().valueOf()/1000;
|
||||
var until =
|
||||
moment(end__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
|
||||
var timeoutWarning = $("#timeoutWarning");
|
||||
var listsStillLoading = 0;
|
||||
|
||||
var dateformat = "MMMM Do YYYY, HH:mm";
|
||||
|
||||
$(function () {
|
||||
$("#querytime").daterangepicker(
|
||||
$(function() {
|
||||
$("#querytime").daterangepicker(
|
||||
{
|
||||
timePicker: true, timePickerIncrement: 15,
|
||||
timePicker: true,
|
||||
timePickerIncrement: 15,
|
||||
locale: { format: dateformat },
|
||||
startDate: start__, endDate: end__,
|
||||
startDate: start__,
|
||||
endDate: end__,
|
||||
ranges: {
|
||||
"Today": [moment().startOf("day"), moment()],
|
||||
"Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")],
|
||||
Today: [moment().startOf("day"), moment()],
|
||||
Yesterday: [
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.startOf("day"),
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.endOf("day")
|
||||
],
|
||||
"Last 7 Days": [moment().subtract(6, "days"), moment()],
|
||||
"Last 30 Days": [moment().subtract(29, "days"), moment()],
|
||||
"This Month": [moment().startOf("month"), moment()],
|
||||
"Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")],
|
||||
"Last Month": [
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.startOf("month"),
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.endOf("month")
|
||||
],
|
||||
"This Year": [moment().startOf("year"), moment()],
|
||||
"All Time": [moment(0), moment()]
|
||||
},
|
||||
"opens": "center", "showDropdowns": true,
|
||||
"autoUpdateInput": false
|
||||
opens: "center",
|
||||
showDropdowns: true,
|
||||
autoUpdateInput: false
|
||||
},
|
||||
function (startt, endt) {
|
||||
from = moment(startt).utc().valueOf()/1000;
|
||||
until = moment(endt).utc().valueOf()/1000;
|
||||
});
|
||||
function(startt, endt) {
|
||||
from =
|
||||
moment(startt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
until =
|
||||
moment(endt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Credit: http://stackoverflow.com/questions/1787322/htmlspecialchars-equivalent-in-javascript/4835406#4835406
|
||||
@@ -48,151 +78,174 @@ function escapeHtml(text) {
|
||||
"&": "&",
|
||||
"<": "<",
|
||||
">": ">",
|
||||
"\"": """,
|
||||
'"': """,
|
||||
"'": "'"
|
||||
};
|
||||
|
||||
return text.replace(/[&<>"']/g, function(m) { return map[m]; });
|
||||
return text.replace(/[&<>"']/g, function(m) {
|
||||
return map[m];
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopClientsChart() {
|
||||
$("#client-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topClients&from="+from+"&until="+until, function(data) {
|
||||
$("#client-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topClients&from=" + from + "&until=" + until, function(data) {
|
||||
// Clear tables before filling them with data
|
||||
$("#client-frequency td")
|
||||
.parent()
|
||||
.remove();
|
||||
var clienttable = $("#client-frequency").find("tbody:last");
|
||||
var client, percentage, clientname;
|
||||
var sum = 0;
|
||||
for (client in data.top_sources) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_sources, client)) {
|
||||
sum += data.top_sources[client];
|
||||
}
|
||||
}
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#client-frequency td").parent().remove();
|
||||
var clienttable = $("#client-frequency").find("tbody:last");
|
||||
var client, percentage, clientname;
|
||||
var sum = 0;
|
||||
for (client in data.top_sources) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_sources, client)){
|
||||
sum += data.top_sources[client];
|
||||
}
|
||||
for (client in data.top_sources) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_sources, client)) {
|
||||
// Sanitize client
|
||||
client = escapeHtml(client);
|
||||
if (escapeHtml(client) !== client) {
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_sources[escapeHtml(client)] = data.top_sources[client];
|
||||
}
|
||||
|
||||
for (client in data.top_sources) {
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_sources, client)){
|
||||
// Sanitize client
|
||||
client = escapeHtml(client);
|
||||
if(escapeHtml(client) !== client)
|
||||
{
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_sources[escapeHtml(client)] = data.top_sources[client];
|
||||
}
|
||||
if(client.indexOf("|") > -1)
|
||||
{
|
||||
var idx = client.indexOf("|");
|
||||
clientname = client.substr(0, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
clientname = client;
|
||||
}
|
||||
|
||||
percentage = data.top_sources[client] / sum * 100.0;
|
||||
clienttable.append("<tr> <td>" + clientname +
|
||||
"</td> <td>" + data.top_sources[client] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"% of " + sum + "\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
|
||||
if (client.indexOf("|") > -1) {
|
||||
var idx = client.indexOf("|");
|
||||
clientname = client.substr(0, idx);
|
||||
} else {
|
||||
clientname = client;
|
||||
}
|
||||
|
||||
$("#client-frequency .overlay").hide();
|
||||
percentage = (data.top_sources[client] / sum) * 100.0;
|
||||
clienttable.append(
|
||||
"<tr> <td>" +
|
||||
clientname +
|
||||
"</td> <td>" +
|
||||
data.top_sources[client] +
|
||||
'</td> <td> <div class="progress progress-sm" title="' +
|
||||
percentage.toFixed(1) +
|
||||
"% of " +
|
||||
sum +
|
||||
'"> <div class="progress-bar progress-bar-blue" style="width: ' +
|
||||
percentage +
|
||||
'%"></div> </div> </td> </tr> '
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
listsStillLoading--;
|
||||
if(listsStillLoading === 0)
|
||||
timeoutWarning.hide();
|
||||
});
|
||||
$("#client-frequency .overlay").hide();
|
||||
|
||||
listsStillLoading--;
|
||||
if (listsStillLoading === 0) timeoutWarning.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopDomainsChart() {
|
||||
$("#domain-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topDomains&from="+from+"&until="+until, function(data) {
|
||||
$("#domain-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topDomains&from=" + from + "&until=" + until, function(data) {
|
||||
// Clear tables before filling them with data
|
||||
$("#domain-frequency td")
|
||||
.parent()
|
||||
.remove();
|
||||
var domaintable = $("#domain-frequency").find("tbody:last");
|
||||
var domain, percentage;
|
||||
var sum = 0;
|
||||
for (domain in data.top_domains) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)) {
|
||||
sum += data.top_domains[domain];
|
||||
}
|
||||
}
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#domain-frequency td").parent().remove();
|
||||
var domaintable = $("#domain-frequency").find("tbody:last");
|
||||
var domain, percentage;
|
||||
var sum = 0;
|
||||
for (domain in data.top_domains) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)){
|
||||
sum += data.top_domains[domain];
|
||||
}
|
||||
for (domain in data.top_domains) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)) {
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
if (escapeHtml(domain) !== domain) {
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_domains[escapeHtml(domain)] = data.top_domains[domain];
|
||||
}
|
||||
|
||||
for (domain in data.top_domains) {
|
||||
percentage = (data.top_domains[domain] / sum) * 100.0;
|
||||
domaintable.append(
|
||||
"<tr> <td>" +
|
||||
domain +
|
||||
"</td> <td>" +
|
||||
data.top_domains[domain] +
|
||||
'</td> <td> <div class="progress progress-sm" title="' +
|
||||
percentage.toFixed(1) +
|
||||
"% of " +
|
||||
sum +
|
||||
'"> <div class="progress-bar progress-bar-blue" style="width: ' +
|
||||
percentage +
|
||||
'%"></div> </div> </td> </tr> '
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_domains, domain)){
|
||||
// Sanitize domain
|
||||
domain = escapeHtml(domain);
|
||||
if(escapeHtml(domain) !== domain)
|
||||
{
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_domains[escapeHtml(domain)] = data.top_domains[domain];
|
||||
}
|
||||
$("#domain-frequency .overlay").hide();
|
||||
|
||||
percentage = data.top_domains[domain] / sum * 100.0;
|
||||
domaintable.append("<tr> <td>" + domain +
|
||||
"</td> <td>" + data.top_domains[domain] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"% of " + sum + "\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " +
|
||||
percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$("#domain-frequency .overlay").hide();
|
||||
|
||||
listsStillLoading--;
|
||||
if(listsStillLoading === 0)
|
||||
timeoutWarning.hide();
|
||||
});
|
||||
listsStillLoading--;
|
||||
if (listsStillLoading === 0) timeoutWarning.hide();
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopAdsChart() {
|
||||
$("#ad-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topAds&from="+from+"&until="+until, function(data) {
|
||||
$("#ad-frequency .overlay").show();
|
||||
$.getJSON("api_db.php?topAds&from=" + from + "&until=" + until, function(data) {
|
||||
// Clear tables before filling them with data
|
||||
$("#ad-frequency td")
|
||||
.parent()
|
||||
.remove();
|
||||
var adtable = $("#ad-frequency").find("tbody:last");
|
||||
var ad, percentage;
|
||||
var sum = 0;
|
||||
for (ad in data.top_ads) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)) {
|
||||
sum += data.top_ads[ad];
|
||||
}
|
||||
}
|
||||
|
||||
// Clear tables before filling them with data
|
||||
$("#ad-frequency td").parent().remove();
|
||||
var adtable = $("#ad-frequency").find("tbody:last");
|
||||
var ad, percentage;
|
||||
var sum = 0;
|
||||
for (ad in data.top_ads) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)){
|
||||
sum += data.top_ads[ad];
|
||||
}
|
||||
for (ad in data.top_ads) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)) {
|
||||
// Sanitize ad
|
||||
ad = escapeHtml(ad);
|
||||
if (escapeHtml(ad) !== ad) {
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_ads[escapeHtml(ad)] = data.top_ads[ad];
|
||||
}
|
||||
|
||||
for (ad in data.top_ads) {
|
||||
percentage = (data.top_ads[ad] / sum) * 100.0;
|
||||
adtable.append(
|
||||
"<tr> <td>" +
|
||||
ad +
|
||||
"</td> <td>" +
|
||||
data.top_ads[ad] +
|
||||
'</td> <td> <div class="progress progress-sm" title="' +
|
||||
percentage.toFixed(1) +
|
||||
"% of " +
|
||||
sum +
|
||||
'"> <div class="progress-bar progress-bar-blue" style="width: ' +
|
||||
percentage +
|
||||
'%"></div> </div> </td> </tr> '
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.top_ads, ad)){
|
||||
// Sanitize ad
|
||||
ad = escapeHtml(ad);
|
||||
if(escapeHtml(ad) !== ad)
|
||||
{
|
||||
// Make a copy with the escaped index if necessary
|
||||
data.top_ads[escapeHtml(ad)] = data.top_ads[ad];
|
||||
}
|
||||
$("#ad-frequency .overlay").hide();
|
||||
|
||||
percentage = data.top_ads[ad] / sum * 100.0;
|
||||
adtable.append("<tr> <td>" + ad + "</td> <td>" + data.top_ads[ad] + "</td> <td> <div class=\"progress progress-sm\" title=\""+percentage.toFixed(1)+"% of " + sum + "\"> <div class=\"progress-bar progress-bar-blue\" style=\"width: " + percentage + "%\"></div> </div> </td> </tr> ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$("#ad-frequency .overlay").hide();
|
||||
|
||||
listsStillLoading--;
|
||||
if(listsStillLoading === 0)
|
||||
timeoutWarning.hide();
|
||||
});
|
||||
listsStillLoading--;
|
||||
if (listsStillLoading === 0) timeoutWarning.hide();
|
||||
});
|
||||
}
|
||||
|
||||
$("#querytime").on("apply.daterangepicker", function(ev, picker) {
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
timeoutWarning.show();
|
||||
listsStillLoading = 3;
|
||||
updateTopClientsChart();
|
||||
updateTopDomainsChart();
|
||||
updateTopAdsChart();
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
timeoutWarning.show();
|
||||
listsStillLoading = 3;
|
||||
updateTopClientsChart();
|
||||
updateTopDomainsChart();
|
||||
updateTopAdsChart();
|
||||
});
|
||||
|
||||
+334
-288
@@ -1,16 +1,22 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global moment:false */
|
||||
|
||||
var start__ = moment().subtract(6, "days");
|
||||
var from = moment(start__).utc().valueOf()/1000;
|
||||
var from =
|
||||
moment(start__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
var end__ = moment();
|
||||
var until = moment(end__).utc().valueOf()/1000;
|
||||
var until =
|
||||
moment(end__)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
var instantquery = false;
|
||||
var daterange;
|
||||
|
||||
@@ -20,324 +26,364 @@ var dateformat = "MMMM Do YYYY, HH:mm";
|
||||
|
||||
// Do we want to filter queries?
|
||||
var GETDict = {};
|
||||
window.location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});
|
||||
window.location.search
|
||||
.substr(1)
|
||||
.split("&")
|
||||
.forEach(function(item) {
|
||||
GETDict[item.split("=")[0]] = item.split("=")[1];
|
||||
});
|
||||
|
||||
if("from" in GETDict && "until" in GETDict)
|
||||
{
|
||||
from = parseInt(GETDict.from);
|
||||
until = parseInt(GETDict.until);
|
||||
start__ = moment(1000*from);
|
||||
end__ = moment(1000*until);
|
||||
instantquery = true;
|
||||
if ("from" in GETDict && "until" in GETDict) {
|
||||
from = parseInt(GETDict.from);
|
||||
until = parseInt(GETDict.until);
|
||||
start__ = moment(1000 * from);
|
||||
end__ = moment(1000 * until);
|
||||
instantquery = true;
|
||||
}
|
||||
|
||||
$(function () {
|
||||
daterange = $("#querytime").daterangepicker(
|
||||
$(function() {
|
||||
daterange = $("#querytime").daterangepicker(
|
||||
{
|
||||
timePicker: true, timePickerIncrement: 15,
|
||||
timePicker: true,
|
||||
timePickerIncrement: 15,
|
||||
locale: { format: dateformat },
|
||||
startDate: start__, endDate: end__,
|
||||
startDate: start__,
|
||||
endDate: end__,
|
||||
ranges: {
|
||||
"Today": [moment().startOf("day"), moment()],
|
||||
"Yesterday": [moment().subtract(1, "days").startOf("day"), moment().subtract(1, "days").endOf("day")],
|
||||
Today: [moment().startOf("day"), moment()],
|
||||
Yesterday: [
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.startOf("day"),
|
||||
moment()
|
||||
.subtract(1, "days")
|
||||
.endOf("day")
|
||||
],
|
||||
"Last 7 Days": [moment().subtract(6, "days"), moment()],
|
||||
"Last 30 Days": [moment().subtract(29, "days"), moment()],
|
||||
"This Month": [moment().startOf("month"), moment()],
|
||||
"Last Month": [moment().subtract(1, "month").startOf("month"), moment().subtract(1, "month").endOf("month")],
|
||||
"Last Month": [
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.startOf("month"),
|
||||
moment()
|
||||
.subtract(1, "month")
|
||||
.endOf("month")
|
||||
],
|
||||
"This Year": [moment().startOf("year"), moment()],
|
||||
"All Time": [moment(0), moment()]
|
||||
},
|
||||
"opens": "center", "showDropdowns": true,
|
||||
"autoUpdateInput": false
|
||||
opens: "center",
|
||||
showDropdowns: true,
|
||||
autoUpdateInput: false
|
||||
},
|
||||
function (startt, endt) {
|
||||
from = moment(startt).utc().valueOf()/1000;
|
||||
until = moment(endt).utc().valueOf()/1000;
|
||||
});
|
||||
function(startt, endt) {
|
||||
from =
|
||||
moment(startt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
until =
|
||||
moment(endt)
|
||||
.utc()
|
||||
.valueOf() / 1000;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
var tableApi, statistics;
|
||||
|
||||
function add(domain,list) {
|
||||
var token = $("#token").text();
|
||||
var alInfo = $("#alInfo");
|
||||
var alList = $("#alList");
|
||||
var alDomain = $("#alDomain");
|
||||
alDomain.html(domain);
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var err = $("#err");
|
||||
function add(domain, list) {
|
||||
var token = $("#token").text();
|
||||
var alInfo = $("#alInfo");
|
||||
var alList = $("#alList");
|
||||
var alDomain = $("#alDomain");
|
||||
alDomain.html(domain);
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var err = $("#err");
|
||||
|
||||
if(list === "white")
|
||||
{
|
||||
alList.html("Whitelist");
|
||||
}
|
||||
else
|
||||
{
|
||||
alList.html("Blacklist");
|
||||
}
|
||||
if (list === "white") {
|
||||
alList.html("Whitelist");
|
||||
} else {
|
||||
alList.html("Blacklist");
|
||||
}
|
||||
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain, "list":list, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("not a valid argument") >= 0 || response.indexOf("is not a valid domain") >= 0)
|
||||
{
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(4000).fadeOut(2000, function() { alFailure.hide(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
alSuccess.show();
|
||||
alSuccess.delay(1000).fadeOut(2000, function() { alSuccess.hide(); });
|
||||
}
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
alFailure.show();
|
||||
err.html("");
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
function handleAjaxError( xhr, textStatus ) {
|
||||
if ( textStatus === "timeout" )
|
||||
{
|
||||
alert( "The server took too long to send the data." );
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: { domain: domain, list: list, token: token },
|
||||
success: function(response) {
|
||||
if (
|
||||
response.indexOf("not a valid argument") >= 0 ||
|
||||
response.indexOf("is not a valid domain") >= 0
|
||||
) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(4000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
}
|
||||
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
alFailure.show();
|
||||
err.html("");
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
alList.html("");
|
||||
alDomain.html("");
|
||||
});
|
||||
}
|
||||
else if(xhr.responseText.indexOf("Connection refused") >= 0)
|
||||
{
|
||||
alert( "An error occurred while loading the data: Connection refused. Is FTL running?" );
|
||||
}
|
||||
else
|
||||
{
|
||||
alert( "An unknown error occurred while loading the data.\n"+xhr.responseText );
|
||||
}
|
||||
$("#all-queries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
});
|
||||
}
|
||||
|
||||
function getQueryTypes()
|
||||
{
|
||||
var queryType = [];
|
||||
if($("#type_gravity").prop("checked"))
|
||||
{
|
||||
queryType.push(1);
|
||||
}
|
||||
if($("#type_forwarded").prop("checked"))
|
||||
{
|
||||
queryType.push(2);
|
||||
}
|
||||
if($("#type_cached").prop("checked"))
|
||||
{
|
||||
queryType.push(3);
|
||||
}
|
||||
if($("#type_regex").prop("checked"))
|
||||
{
|
||||
queryType.push(4);
|
||||
}
|
||||
if($("#type_blacklist").prop("checked"))
|
||||
{
|
||||
queryType.push(5);
|
||||
}
|
||||
if($("#type_external").prop("checked"))
|
||||
{
|
||||
// Multiple IDs correspond to this status
|
||||
// We request queries with all of them
|
||||
queryType.push([6,7,8]);
|
||||
}
|
||||
return queryType.join(",");
|
||||
function handleAjaxError(xhr, textStatus) {
|
||||
if (textStatus === "timeout") {
|
||||
alert("The server took too long to send the data.");
|
||||
} else if (xhr.responseText.indexOf("Connection refused") >= 0) {
|
||||
alert("An error occurred while loading the data: Connection refused. Is FTL running?");
|
||||
} else {
|
||||
alert("An unknown error occurred while loading the data.\n" + xhr.responseText);
|
||||
}
|
||||
|
||||
$("#all-queries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
}
|
||||
|
||||
var reloadCallback = function()
|
||||
{
|
||||
timeoutWarning.hide();
|
||||
statistics = [0,0,0,0];
|
||||
var data = tableApi.rows().data();
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
statistics[0]++;
|
||||
if(data[i][4] === 1)
|
||||
{
|
||||
statistics[2]++;
|
||||
}
|
||||
else if(data[i][4] === 3)
|
||||
{
|
||||
statistics[1]++;
|
||||
}
|
||||
else if(data[i][4] === 4)
|
||||
{
|
||||
statistics[3]++;
|
||||
}
|
||||
}
|
||||
$("h3#dns_queries").text(statistics[0].toLocaleString());
|
||||
$("h3#ads_blocked_exact").text(statistics[2].toLocaleString());
|
||||
$("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString());
|
||||
function getQueryTypes() {
|
||||
var queryType = [];
|
||||
if ($("#type_gravity").prop("checked")) {
|
||||
queryType.push(1);
|
||||
}
|
||||
|
||||
var percent = 0.0;
|
||||
if(statistics[2] + statistics[3] > 0)
|
||||
{
|
||||
percent = 100.0*(statistics[2] + statistics[3]) / statistics[0];
|
||||
if ($("#type_forwarded").prop("checked")) {
|
||||
queryType.push(2);
|
||||
}
|
||||
|
||||
if ($("#type_cached").prop("checked")) {
|
||||
queryType.push(3);
|
||||
}
|
||||
|
||||
if ($("#type_regex").prop("checked")) {
|
||||
queryType.push(4);
|
||||
}
|
||||
|
||||
if ($("#type_blacklist").prop("checked")) {
|
||||
queryType.push(5);
|
||||
}
|
||||
|
||||
if ($("#type_external").prop("checked")) {
|
||||
// Multiple IDs correspond to this status
|
||||
// We request queries with all of them
|
||||
queryType.push([6, 7, 8]);
|
||||
}
|
||||
|
||||
return queryType.join(",");
|
||||
}
|
||||
|
||||
var reloadCallback = function() {
|
||||
timeoutWarning.hide();
|
||||
statistics = [0, 0, 0, 0];
|
||||
var data = tableApi.rows().data();
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
statistics[0]++;
|
||||
if (data[i][4] === 1) {
|
||||
statistics[2]++;
|
||||
} else if (data[i][4] === 3) {
|
||||
statistics[1]++;
|
||||
} else if (data[i][4] === 4) {
|
||||
statistics[3]++;
|
||||
}
|
||||
$("h3#ads_percentage_today").text(parseFloat(percent).toFixed(1).toLocaleString()+" %");
|
||||
}
|
||||
|
||||
$("h3#dns_queries").text(statistics[0].toLocaleString());
|
||||
$("h3#ads_blocked_exact").text(statistics[2].toLocaleString());
|
||||
$("h3#ads_wildcard_blocked").text(statistics[3].toLocaleString());
|
||||
|
||||
var percent = 0.0;
|
||||
if (statistics[2] + statistics[3] > 0) {
|
||||
percent = (100.0 * (statistics[2] + statistics[3])) / statistics[0];
|
||||
}
|
||||
|
||||
$("h3#ads_percentage_today").text(
|
||||
parseFloat(percent)
|
||||
.toFixed(1)
|
||||
.toLocaleString() + " %"
|
||||
);
|
||||
};
|
||||
|
||||
function refreshTableData() {
|
||||
timeoutWarning.show();
|
||||
var APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
|
||||
// Check if query type filtering is enabled
|
||||
var queryType = getQueryTypes();
|
||||
if(queryType !== "1,2,3,4,5,6")
|
||||
{
|
||||
APIstring += "&types="+queryType;
|
||||
}
|
||||
statistics = [0,0,0];
|
||||
tableApi.ajax.url(APIstring).load(reloadCallback);
|
||||
timeoutWarning.show();
|
||||
var APIstring = "api_db.php?getAllQueries&from=" + from + "&until=" + until;
|
||||
// Check if query type filtering is enabled
|
||||
var queryType = getQueryTypes();
|
||||
if (queryType !== "1,2,3,4,5,6") {
|
||||
APIstring += "&types=" + queryType;
|
||||
}
|
||||
|
||||
statistics = [0, 0, 0];
|
||||
tableApi.ajax.url(APIstring).load(reloadCallback);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var APIstring;
|
||||
var APIstring;
|
||||
|
||||
if(instantquery)
|
||||
{
|
||||
APIstring = "api_db.php?getAllQueries&from="+from+"&until="+until;
|
||||
}
|
||||
else
|
||||
{
|
||||
APIstring = "api_db.php?getAllQueries=empty";
|
||||
}
|
||||
// Check if query type filtering is enabled
|
||||
var queryType = getQueryTypes();
|
||||
if(queryType !== 63) // 63 (0b00111111) = all possible query types are selected
|
||||
{
|
||||
APIstring += "&types="+queryType;
|
||||
}
|
||||
if (instantquery) {
|
||||
APIstring = "api_db.php?getAllQueries&from=" + from + "&until=" + until;
|
||||
} else {
|
||||
APIstring = "api_db.php?getAllQueries=empty";
|
||||
}
|
||||
|
||||
tableApi = $("#all-queries").DataTable( {
|
||||
"rowCallback": function( row, data ){
|
||||
var fieldtext, buttontext, color;
|
||||
switch (data[4])
|
||||
{
|
||||
case 1:
|
||||
color = "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:
|
||||
color = "green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(forwarded)";
|
||||
buttontext = "<button type=\"button\" class=\"btn btn-default btn-sm text-red\"><i class=\"fa fa-ban\"></i> Blacklist</button>";
|
||||
break;
|
||||
case 3:
|
||||
color = "green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(cached)";
|
||||
buttontext = "<button type=\"button\" class=\"btn btn-default btn-sm text-red\"><i class=\"fa fa-ban\"></i> Blacklist</button>";
|
||||
break;
|
||||
case 4:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex/wildcard)";
|
||||
buttontext = "<button type=\"button\" class=\"btn btn-default btn-sm text-green\"><i class=\"fas fa-check\"></i> Whitelist</button>";
|
||||
break;
|
||||
case 5:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(blacklist)";
|
||||
buttontext = "<button type=\"button\" class=\"btn btn-default btn-sm text-green\"><i class=\"fas fa-check\"></i> Whitelist</button>";
|
||||
break;
|
||||
case 6:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, IP)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case 7:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NULL)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case 8:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NXRA)";
|
||||
buttontext = "";
|
||||
break;
|
||||
default:
|
||||
color = "black";
|
||||
fieldtext = "Unknown";
|
||||
buttontext = "";
|
||||
}
|
||||
// Check if query type filtering is enabled
|
||||
var queryType = getQueryTypes();
|
||||
if (queryType !== 63) {
|
||||
// 63 (0b00111111) = all possible query types are selected
|
||||
APIstring += "&types=" + queryType;
|
||||
}
|
||||
|
||||
$(row).css("color", color);
|
||||
$("td:eq(4)", row).html(fieldtext);
|
||||
$("td:eq(5)", row).html(buttontext);
|
||||
},
|
||||
dom: "<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
"ajax": {
|
||||
"url": APIstring,
|
||||
"error": handleAjaxError,
|
||||
"dataSrc": function(data){
|
||||
var dataIndex = 0;
|
||||
return data.data.map(function(x){
|
||||
x[0] = x[0] * 1e6 + (dataIndex++);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
},
|
||||
"autoWidth" : false,
|
||||
"processing": true,
|
||||
"deferRender": true,
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "15%", "render": function (data, type) { if(type === "display"){return moment.unix(Math.floor(data/1e6)).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");}return data; }},
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "40%" },
|
||||
{ "width" : "20%" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "5%" }
|
||||
],
|
||||
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
|
||||
"columnDefs": [ {
|
||||
"targets": -1,
|
||||
"data": null,
|
||||
"defaultContent": ""
|
||||
} ],
|
||||
"initComplete": reloadCallback
|
||||
});
|
||||
$("#all-queries tbody").on( "click", "button", function () {
|
||||
var data = tableApi.row( $(this).parents("tr") ).data();
|
||||
if (data[4] === 1 || data[4] === 4 || data[5] === 5)
|
||||
{
|
||||
add(data[2],"white");
|
||||
tableApi = $("#all-queries").DataTable({
|
||||
rowCallback: function(row, data) {
|
||||
var fieldtext, buttontext, color;
|
||||
switch (data[4]) {
|
||||
case 1:
|
||||
color = "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:
|
||||
color = "green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(forwarded)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
case 3:
|
||||
color = "green";
|
||||
fieldtext = "OK <br class='hidden-lg'>(cached)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-red"><i class="fa fa-ban"></i> Blacklist</button>';
|
||||
break;
|
||||
case 4:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(regex/wildcard)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
|
||||
break;
|
||||
case 5:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(blacklist)";
|
||||
buttontext =
|
||||
'<button type="button" class="btn btn-default btn-sm text-green"><i class="fas fa-check"></i> Whitelist</button>';
|
||||
break;
|
||||
case 6:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, IP)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case 7:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NULL)";
|
||||
buttontext = "";
|
||||
break;
|
||||
case 8:
|
||||
color = "red";
|
||||
fieldtext = "Blocked <br class='hidden-lg'>(external, NXRA)";
|
||||
buttontext = "";
|
||||
break;
|
||||
default:
|
||||
color = "black";
|
||||
fieldtext = "Unknown";
|
||||
buttontext = "";
|
||||
}
|
||||
|
||||
$(row).css("color", color);
|
||||
$("td:eq(4)", row).html(fieldtext);
|
||||
$("td:eq(5)", row).html(buttontext);
|
||||
},
|
||||
dom:
|
||||
"<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
ajax: {
|
||||
url: APIstring,
|
||||
error: handleAjaxError,
|
||||
dataSrc: function(data) {
|
||||
var dataIndex = 0;
|
||||
return data.data.map(function(x) {
|
||||
x[0] = x[0] * 1e6 + dataIndex++;
|
||||
return x;
|
||||
});
|
||||
}
|
||||
},
|
||||
autoWidth: false,
|
||||
processing: true,
|
||||
deferRender: true,
|
||||
order: [[0, "desc"]],
|
||||
columns: [
|
||||
{
|
||||
width: "15%",
|
||||
render: function(data, type) {
|
||||
if (type === "display") {
|
||||
return moment
|
||||
.unix(Math.floor(data / 1e6))
|
||||
.format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
else
|
||||
{
|
||||
add(data[2],"black");
|
||||
}
|
||||
} );
|
||||
|
||||
if(instantquery)
|
||||
{
|
||||
daterange.val(start__.format(dateformat) + " - " + end__.format(dateformat));
|
||||
},
|
||||
{ width: "10%" },
|
||||
{ width: "40%" },
|
||||
{ width: "20%" },
|
||||
{ width: "10%" },
|
||||
{ width: "5%" }
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"]
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: -1,
|
||||
data: null,
|
||||
defaultContent: ""
|
||||
}
|
||||
],
|
||||
initComplete: reloadCallback
|
||||
});
|
||||
$("#all-queries tbody").on("click", "button", function() {
|
||||
var data = tableApi.row($(this).parents("tr")).data();
|
||||
if (data[4] === 1 || data[4] === 4 || data[5] === 5) {
|
||||
add(data[2], "white");
|
||||
} else {
|
||||
add(data[2], "black");
|
||||
}
|
||||
} );
|
||||
});
|
||||
|
||||
if (instantquery) {
|
||||
daterange.val(start__.format(dateformat) + " - " + end__.format(dateformat));
|
||||
}
|
||||
});
|
||||
|
||||
$("#querytime").on("apply.daterangepicker", function(ev, picker) {
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
refreshTableData();
|
||||
$(this).val(picker.startDate.format(dateformat) + " to " + picker.endDate.format(dateformat));
|
||||
refreshTableData();
|
||||
});
|
||||
|
||||
+57
-54
@@ -1,74 +1,77 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global ActiveXObject: false */
|
||||
|
||||
// Credit: http://stackoverflow.com/a/10642418/2087442
|
||||
function httpGet(ta,theUrl)
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{
|
||||
function httpGet(ta, theUrl) {
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest) {
|
||||
// code for IE7+
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
} else {
|
||||
// code for IE6, IE5
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
|
||||
ta.show();
|
||||
ta.empty();
|
||||
ta.append(xmlhttp.responseText);
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState === 4 && xmlhttp.status === 200)
|
||||
{
|
||||
ta.show();
|
||||
ta.empty();
|
||||
ta.append(xmlhttp.responseText);
|
||||
}
|
||||
};
|
||||
xmlhttp.open("GET", theUrl, false);
|
||||
xmlhttp.send();
|
||||
};
|
||||
|
||||
xmlhttp.open("GET", theUrl, false);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function eventsource() {
|
||||
var ta = $("#output");
|
||||
var upload = $( "#upload" );
|
||||
var checked = "";
|
||||
var token = encodeURIComponent($("#token").text());
|
||||
var ta = $("#output");
|
||||
var upload = $("#upload");
|
||||
var checked = "";
|
||||
var token = encodeURIComponent($("#token").text());
|
||||
|
||||
if(upload.prop("checked"))
|
||||
{
|
||||
checked = "upload";
|
||||
}
|
||||
if (upload.prop("checked")) {
|
||||
checked = "upload";
|
||||
}
|
||||
|
||||
// IE does not support EventSource - load whole content at once
|
||||
if (typeof EventSource !== "function") {
|
||||
httpGet(ta,"scripts/pi-hole/php/debug.php?IE&token="+token+"&"+checked);
|
||||
return;
|
||||
}
|
||||
// IE does not support EventSource - load whole content at once
|
||||
if (typeof EventSource !== "function") {
|
||||
httpGet(ta, "scripts/pi-hole/php/debug.php?IE&token=" + token + "&" + checked);
|
||||
return;
|
||||
}
|
||||
|
||||
var source = new EventSource("scripts/pi-hole/php/debug.php?&token="+token+"&"+checked);
|
||||
var source = new EventSource("scripts/pi-hole/php/debug.php?&token=" + token + "&" + checked);
|
||||
|
||||
// Reset and show field
|
||||
ta.empty();
|
||||
ta.show();
|
||||
// Reset and show field
|
||||
ta.empty();
|
||||
ta.show();
|
||||
|
||||
source.addEventListener("message", function(e) {
|
||||
ta.append(e.data);
|
||||
}, false);
|
||||
source.addEventListener(
|
||||
"message",
|
||||
function(e) {
|
||||
ta.append(e.data);
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener("error", function() {
|
||||
source.close();
|
||||
}, false);
|
||||
// Will be called when script has finished
|
||||
source.addEventListener(
|
||||
"error",
|
||||
function() {
|
||||
source.close();
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
$("#debugBtn").on("click", function(){
|
||||
$("#debugBtn").attr("disabled", true);
|
||||
$("#upload").attr("disabled", true);
|
||||
eventsource();
|
||||
$("#debugBtn").on("click", function() {
|
||||
$("#debugBtn").attr("disabled", true);
|
||||
$("#upload").attr("disabled", true);
|
||||
eventsource();
|
||||
});
|
||||
|
||||
+140
-154
@@ -1,135 +1,128 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
//The following functions allow us to display time until pi-hole is enabled after disabling.
|
||||
//Works between all pages
|
||||
|
||||
function secondsTimeSpanToHMS(s) {
|
||||
var h = Math.floor(s/3600); //Get whole hours
|
||||
s -= h*3600;
|
||||
var m = Math.floor(s/60); //Get remaining minutes
|
||||
s -= m*60;
|
||||
return h+":"+(m < 10 ? "0"+m : m)+":"+(s < 10 ? "0"+s : s); //zero padding on minutes and seconds
|
||||
var h = Math.floor(s / 3600); //Get whole hours
|
||||
s -= h * 3600;
|
||||
var m = Math.floor(s / 60); //Get remaining minutes
|
||||
s -= m * 60;
|
||||
return h + ":" + (m < 10 ? "0" + m : m) + ":" + (s < 10 ? "0" + s : s); //zero padding on minutes and seconds
|
||||
}
|
||||
|
||||
function piholeChanged(action)
|
||||
{
|
||||
var status = $("#status");
|
||||
var ena = $("#pihole-enable");
|
||||
var dis = $("#pihole-disable");
|
||||
function piholeChanged(action) {
|
||||
var status = $("#status");
|
||||
var ena = $("#pihole-enable");
|
||||
var dis = $("#pihole-disable");
|
||||
|
||||
switch(action) {
|
||||
case "enabled":
|
||||
status.html("<i class='fa fa-circle text-green-light'></i> Active");
|
||||
ena.hide();
|
||||
dis.show();
|
||||
dis.removeClass("active");
|
||||
break;
|
||||
|
||||
case "disabled":
|
||||
status.html("<i class='fa fa-circle text-red'></i> Offline");
|
||||
ena.show();
|
||||
dis.hide();
|
||||
break;
|
||||
}
|
||||
switch (action) {
|
||||
case "enabled":
|
||||
status.html("<i class='fa fa-circle text-green-light'></i> Active");
|
||||
ena.hide();
|
||||
dis.show();
|
||||
dis.removeClass("active");
|
||||
break;
|
||||
|
||||
case "disabled":
|
||||
status.html("<i class='fa fa-circle text-red'></i> Offline");
|
||||
ena.show();
|
||||
dis.hide();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function countDown(){
|
||||
var ena = $("#enableLabel");
|
||||
var enaT = $("#enableTimer");
|
||||
var target = new Date(parseInt(enaT.html()));
|
||||
var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000);
|
||||
function countDown() {
|
||||
var ena = $("#enableLabel");
|
||||
var enaT = $("#enableTimer");
|
||||
var target = new Date(parseInt(enaT.html()));
|
||||
var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000);
|
||||
|
||||
if(seconds > 0){
|
||||
setTimeout(countDown,1000);
|
||||
ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")");
|
||||
}
|
||||
else
|
||||
{
|
||||
ena.text("Enable");
|
||||
piholeChanged("enabled");
|
||||
localStorage.removeItem("countDownTarget");
|
||||
}
|
||||
if (seconds > 0) {
|
||||
setTimeout(countDown, 1000);
|
||||
ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")");
|
||||
} else {
|
||||
ena.text("Enable");
|
||||
piholeChanged("enabled");
|
||||
localStorage.removeItem("countDownTarget");
|
||||
}
|
||||
}
|
||||
|
||||
function piholeChange(action, duration)
|
||||
{
|
||||
var token = encodeURIComponent($("#token").text());
|
||||
var enaT = $("#enableTimer");
|
||||
var btnStatus;
|
||||
function piholeChange(action, duration) {
|
||||
var token = encodeURIComponent($("#token").text());
|
||||
var enaT = $("#enableTimer");
|
||||
var btnStatus;
|
||||
|
||||
switch(action) {
|
||||
case "enable":
|
||||
btnStatus = $("#flip-status-enable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?enable&token=" + token, function(data) {
|
||||
if(data.status === "enabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("enabled");
|
||||
}
|
||||
});
|
||||
break;
|
||||
switch (action) {
|
||||
case "enable":
|
||||
btnStatus = $("#flip-status-enable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?enable&token=" + token, function(data) {
|
||||
if (data.status === "enabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("enabled");
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
||||
case "disable":
|
||||
btnStatus = $("#flip-status-disable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?disable=" + duration + "&token=" + token, function(data) {
|
||||
if(data.status === "disabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("disabled");
|
||||
if(duration > 0)
|
||||
{
|
||||
enaT.html(new Date().getTime() + duration * 1000);
|
||||
setTimeout(countDown,100);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "disable":
|
||||
btnStatus = $("#flip-status-disable");
|
||||
btnStatus.html("<i class='fa fa-spinner'> </i>");
|
||||
$.getJSON("api.php?disable=" + duration + "&token=" + token, function(data) {
|
||||
if (data.status === "disabled") {
|
||||
btnStatus.html("");
|
||||
piholeChanged("disabled");
|
||||
if (duration > 0) {
|
||||
enaT.html(new Date().getTime() + duration * 1000);
|
||||
setTimeout(countDown, 100);
|
||||
}
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$( document ).ready(function() {
|
||||
var enaT = $("#enableTimer");
|
||||
var target = new Date(parseInt(enaT.html()));
|
||||
var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000);
|
||||
if (seconds > 0)
|
||||
{
|
||||
setTimeout(countDown,100);
|
||||
}
|
||||
$(document).ready(function() {
|
||||
var enaT = $("#enableTimer");
|
||||
var target = new Date(parseInt(enaT.html()));
|
||||
var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000);
|
||||
if (seconds > 0) {
|
||||
setTimeout(countDown, 100);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Enable/Disable
|
||||
$("#pihole-enable").on("click", function(e){
|
||||
e.preventDefault();
|
||||
localStorage.removeItem("countDownTarget");
|
||||
piholeChange("enable","");
|
||||
$("#pihole-enable").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
localStorage.removeItem("countDownTarget");
|
||||
piholeChange("enable", "");
|
||||
});
|
||||
$("#pihole-disable-permanently").on("click", function(e){
|
||||
e.preventDefault();
|
||||
piholeChange("disable","0");
|
||||
$("#pihole-disable-permanently").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
piholeChange("disable", "0");
|
||||
});
|
||||
$("#pihole-disable-10s").on("click", function(e){
|
||||
e.preventDefault();
|
||||
piholeChange("disable","10");
|
||||
$("#pihole-disable-10s").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
piholeChange("disable", "10");
|
||||
});
|
||||
$("#pihole-disable-30s").on("click", function(e){
|
||||
e.preventDefault();
|
||||
piholeChange("disable","30");
|
||||
$("#pihole-disable-30s").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
piholeChange("disable", "30");
|
||||
});
|
||||
$("#pihole-disable-5m").on("click", function(e){
|
||||
e.preventDefault();
|
||||
piholeChange("disable","300");
|
||||
$("#pihole-disable-5m").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
piholeChange("disable", "300");
|
||||
});
|
||||
$("#pihole-disable-custom").on("click", function(e){
|
||||
e.preventDefault();
|
||||
var custVal = $("#customTimeout").val();
|
||||
custVal = $("#btnMins").hasClass("active") ? custVal * 60 : custVal;
|
||||
piholeChange("disable",custVal);
|
||||
$("#pihole-disable-custom").on("click", function(e) {
|
||||
e.preventDefault();
|
||||
var custVal = $("#customTimeout").val();
|
||||
custVal = $("#btnMins").hasClass("active") ? custVal * 60 : custVal;
|
||||
piholeChange("disable", custVal);
|
||||
});
|
||||
|
||||
// Session timer
|
||||
@@ -137,70 +130,63 @@ var sessionTimerCounter = document.getElementById("sessiontimercounter");
|
||||
var sessionvalidity = parseInt(sessionTimerCounter.textContent);
|
||||
var start = new Date();
|
||||
|
||||
function updateSessionTimer()
|
||||
{
|
||||
start = new Date();
|
||||
start.setSeconds(start.getSeconds() + sessionvalidity);
|
||||
function updateSessionTimer() {
|
||||
start = new Date();
|
||||
start.setSeconds(start.getSeconds() + sessionvalidity);
|
||||
}
|
||||
|
||||
if(sessionvalidity > 0)
|
||||
{
|
||||
// setSeconds will correctly handle wrap-around cases
|
||||
updateSessionTimer();
|
||||
if (sessionvalidity > 0) {
|
||||
// setSeconds will correctly handle wrap-around cases
|
||||
updateSessionTimer();
|
||||
|
||||
setInterval(function() {
|
||||
var current = new Date();
|
||||
var totalseconds = (start - current) / 1000;
|
||||
var minutes = Math.floor(totalseconds / 60);
|
||||
if(minutes < 10){ minutes = "0" + minutes; }
|
||||
setInterval(function() {
|
||||
var current = new Date();
|
||||
var totalseconds = (start - current) / 1000;
|
||||
var minutes = Math.floor(totalseconds / 60);
|
||||
if (minutes < 10) {
|
||||
minutes = "0" + minutes;
|
||||
}
|
||||
|
||||
var seconds = Math.floor(totalseconds % 60);
|
||||
if(seconds < 10){ seconds = "0" + seconds; }
|
||||
var seconds = Math.floor(totalseconds % 60);
|
||||
if (seconds < 10) {
|
||||
seconds = "0" + seconds;
|
||||
}
|
||||
|
||||
if(totalseconds > 0)
|
||||
{
|
||||
sessionTimerCounter.textContent = minutes + ":" + seconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
sessionTimerCounter.textContent = "-- : --";
|
||||
}
|
||||
|
||||
}, 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
document.getElementById("sessiontimer").style.display = "none";
|
||||
if (totalseconds > 0) {
|
||||
sessionTimerCounter.textContent = minutes + ":" + seconds;
|
||||
} else {
|
||||
sessionTimerCounter.textContent = "-- : --";
|
||||
}
|
||||
}, 1000);
|
||||
} else {
|
||||
document.getElementById("sessiontimer").style.display = "none";
|
||||
}
|
||||
|
||||
// Handle Strg + Enter button on Login page
|
||||
$(document).keypress(function(e) {
|
||||
if((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey && $("#loginpw").is(":focus")) {
|
||||
$("#loginform").attr("action", "settings.php");
|
||||
$("#loginform").submit();
|
||||
}
|
||||
if ((e.keyCode === 10 || e.keyCode === 13) && e.ctrlKey && $("#loginpw").is(":focus")) {
|
||||
$("#loginform").attr("action", "settings.php");
|
||||
$("#loginform").submit();
|
||||
}
|
||||
});
|
||||
|
||||
function testCookies()
|
||||
{
|
||||
if (navigator.cookieEnabled)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
function testCookies() {
|
||||
if (navigator.cookieEnabled) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// set and read cookie
|
||||
document.cookie = "cookietest=1";
|
||||
var ret = document.cookie.indexOf("cookietest=") !== -1;
|
||||
// set and read cookie
|
||||
document.cookie = "cookietest=1";
|
||||
var ret = document.cookie.indexOf("cookietest=") !== -1;
|
||||
|
||||
// delete cookie
|
||||
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
|
||||
// delete cookie
|
||||
document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
|
||||
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
$(function() {
|
||||
if(!testCookies() && $("#cookieInfo").length)
|
||||
{
|
||||
$("#cookieInfo").show();
|
||||
}
|
||||
if (!testCookies() && $("#cookieInfo").length) {
|
||||
$("#cookieInfo").show();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,73 +1,80 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
function eventsource() {
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var ta = $("#output");
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var ta = $("#output");
|
||||
|
||||
// IE does not support EventSource - exit early
|
||||
if (typeof EventSource !== "function") {
|
||||
ta.show();
|
||||
ta.html("Updating lists of ad-serving domains is not supported with this browser!");
|
||||
return;
|
||||
}
|
||||
var source = new EventSource("scripts/pi-hole/php/gravity.sh.php");
|
||||
|
||||
ta.html("");
|
||||
// IE does not support EventSource - exit early
|
||||
if (typeof EventSource !== "function") {
|
||||
ta.show();
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
ta.html("Updating lists of ad-serving domains is not supported with this browser!");
|
||||
return;
|
||||
}
|
||||
|
||||
source.addEventListener("message", function(e) {
|
||||
if(e.data.indexOf("Pi-hole blocking is") !== -1)
|
||||
{
|
||||
alSuccess.show();
|
||||
}
|
||||
var source = new EventSource("scripts/pi-hole/php/gravity.sh.php");
|
||||
|
||||
// Detect ${OVER}
|
||||
if(e.data.indexOf("<------") !== -1)
|
||||
{
|
||||
ta.text(ta.text().substring(0, ta.text().lastIndexOf("\n")) + "\n");
|
||||
var new_string = e.data.replace("<------", "");
|
||||
ta.append(new_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
ta.append(e.data);
|
||||
}
|
||||
ta.html("");
|
||||
ta.show();
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
|
||||
}, false);
|
||||
source.addEventListener(
|
||||
"message",
|
||||
function(e) {
|
||||
if (e.data.indexOf("Pi-hole blocking is") !== -1) {
|
||||
alSuccess.show();
|
||||
}
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener("error", function() {
|
||||
alInfo.delay(1000).fadeOut(2000, function() { alInfo.hide(); });
|
||||
source.close();
|
||||
$("#gravityBtn").removeAttr("disabled");
|
||||
}, false);
|
||||
// Detect ${OVER}
|
||||
if (e.data.indexOf("<------") !== -1) {
|
||||
ta.text(ta.text().substring(0, ta.text().lastIndexOf("\n")) + "\n");
|
||||
var new_string = e.data.replace("<------", "");
|
||||
ta.append(new_string);
|
||||
} else {
|
||||
ta.append(e.data);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener(
|
||||
"error",
|
||||
function() {
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
source.close();
|
||||
$("#gravityBtn").removeAttr("disabled");
|
||||
},
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
$("#gravityBtn").on("click", function(){
|
||||
$("#gravityBtn").attr("disabled", true);
|
||||
eventsource();
|
||||
$("#gravityBtn").on("click", function() {
|
||||
$("#gravityBtn").attr("disabled", true);
|
||||
eventsource();
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
$(function() {
|
||||
$("[data-hide]").on("click", function() {
|
||||
$(this)
|
||||
.closest("." + $(this).attr("data-hide"))
|
||||
.hide();
|
||||
});
|
||||
|
||||
// Do we want to start updating immediately?
|
||||
// gravity.php?go
|
||||
var searchString = window.location.search.substring(1);
|
||||
if(searchString.indexOf("go") !== -1)
|
||||
{
|
||||
$("#gravityBtn").attr("disabled", true);
|
||||
eventsource();
|
||||
}
|
||||
// Do we want to start updating immediately?
|
||||
// gravity.php?go
|
||||
var searchString = window.location.search.substring(1);
|
||||
if (searchString.indexOf("go") !== -1) {
|
||||
$("#gravityBtn").attr("disabled", true);
|
||||
eventsource();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "warning":
|
||||
opts = {
|
||||
@@ -48,6 +49,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "error":
|
||||
opts = {
|
||||
@@ -61,9 +63,9 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,10 +92,7 @@ $(document).ready(function() {
|
||||
|
||||
$("#select").on("change", function() {
|
||||
$("#ip-custom").val("");
|
||||
$("#ip-custom").prop(
|
||||
"disabled",
|
||||
$("#select option:selected").val() !== "custom"
|
||||
);
|
||||
$("#ip-custom").prop("disabled", $("#select option:selected").val() !== "custom");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -130,9 +129,7 @@ function initTable() {
|
||||
|
||||
var disabled = data.enabled === 0;
|
||||
$("td:eq(1)", row).html(
|
||||
'<input type="checkbox" id="status"' +
|
||||
(disabled ? "" : " checked") +
|
||||
">"
|
||||
'<input type="checkbox" id="status"' + (disabled ? "" : " checked") + ">"
|
||||
);
|
||||
var status = $("#status", row);
|
||||
status.bootstrapToggle({
|
||||
@@ -154,9 +151,7 @@ function initTable() {
|
||||
comment.on("change", editAdlist);
|
||||
|
||||
$("td:eq(3)", row).empty();
|
||||
$("td:eq(3)", row).append(
|
||||
'<select id="multiselect" multiple="multiple"></select>'
|
||||
);
|
||||
$("td:eq(3)", row).append('<select id="multiselect" multiple="multiple"></select>');
|
||||
var sel = $("#multiselect", row);
|
||||
// Add all known groups
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
@@ -164,12 +159,14 @@ function initTable() {
|
||||
if (!groups[i].enabled) {
|
||||
extra = " (disabled)";
|
||||
}
|
||||
|
||||
sel.append(
|
||||
$("<option />")
|
||||
.val(groups[i].id)
|
||||
.text(groups[i].name + extra)
|
||||
);
|
||||
}
|
||||
|
||||
// Select assigned groups
|
||||
sel.val(data.groups);
|
||||
// Initialize multiselect
|
||||
@@ -200,6 +197,7 @@ function initTable() {
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
@@ -249,31 +247,16 @@ function addAdlist() {
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-plus",
|
||||
"Successfully added adlist",
|
||||
address
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-plus", "Successfully added adlist", address);
|
||||
$("#new_address").val("");
|
||||
$("#new_comment").val("");
|
||||
table.ajax.reload();
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new adlist: ",
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "", "Error while adding new adlist: ", response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new adlist: ",
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while adding new adlist: ", jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
@@ -331,7 +314,7 @@ function editAdlist() {
|
||||
"error",
|
||||
"",
|
||||
"Error while " + not_done + " adlist with ID " + id,
|
||||
+response.message
|
||||
Number(response.message)
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -360,31 +343,15 @@ function deleteAdlist() {
|
||||
data: { action: "delete_adlist", id: id, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-trash",
|
||||
"Successfully deleted adlist ",
|
||||
address
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-trash", "Successfully deleted adlist ", address);
|
||||
table
|
||||
.row(tr)
|
||||
.remove()
|
||||
.draw(false);
|
||||
} else
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting adlist with ID " + id,
|
||||
response.message
|
||||
);
|
||||
} else showAlert("error", "", "Error while deleting adlist with ID " + id, response.message);
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting adlist with ID " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while deleting adlist with ID " + id, jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "warning":
|
||||
opts = {
|
||||
@@ -48,6 +49,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "error":
|
||||
opts = {
|
||||
@@ -61,9 +63,9 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,16 +80,19 @@ function reload_client_suggestions() {
|
||||
if (!data.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var text = key;
|
||||
if (data[key].length > 0) {
|
||||
text += " (" + data[key] + ")";
|
||||
}
|
||||
|
||||
sel.append(
|
||||
$("<option />")
|
||||
.val(key)
|
||||
.text(text)
|
||||
);
|
||||
}
|
||||
|
||||
sel.append(
|
||||
$("<option />")
|
||||
.val("custom")
|
||||
@@ -118,10 +123,7 @@ $(document).ready(function() {
|
||||
|
||||
$("#select").on("change", function() {
|
||||
$("#ip-custom").val("");
|
||||
$("#ip-custom").prop(
|
||||
"disabled",
|
||||
$("#select option:selected").val() !== "custom"
|
||||
);
|
||||
$("#ip-custom").prop("disabled", $("#select option:selected").val() !== "custom");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -153,18 +155,11 @@ function initTable() {
|
||||
data.id +
|
||||
'">';
|
||||
if (data.name !== null && data.name.length > 0)
|
||||
ip_name +=
|
||||
'<br><code id="name" title="' +
|
||||
tooltip +
|
||||
'">' +
|
||||
data.name +
|
||||
"</code>";
|
||||
ip_name += '<br><code id="name" title="' + tooltip + '">' + data.name + "</code>";
|
||||
$("td:eq(0)", row).html(ip_name);
|
||||
|
||||
$("td:eq(1)", row).empty();
|
||||
$("td:eq(1)", row).append(
|
||||
'<select id="multiselect" multiple="multiple"></select>'
|
||||
);
|
||||
$("td:eq(1)", row).append('<select id="multiselect" multiple="multiple"></select>');
|
||||
var sel = $("#multiselect", row);
|
||||
// Add all known groups
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
@@ -172,12 +167,14 @@ function initTable() {
|
||||
if (!groups[i].enabled) {
|
||||
extra = " (disabled)";
|
||||
}
|
||||
|
||||
sel.append(
|
||||
$("<option />")
|
||||
.val(groups[i].id)
|
||||
.text(groups[i].name + extra)
|
||||
);
|
||||
}
|
||||
|
||||
// Select assigned groups
|
||||
sel.val(data.groups);
|
||||
// Initialize multiselect
|
||||
@@ -208,6 +205,7 @@ function initTable() {
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
@@ -254,30 +252,15 @@ function addClient() {
|
||||
data: { action: "add_client", ip: ip, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-plus",
|
||||
"Successfully added client",
|
||||
ip
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-plus", "Successfully added client", ip);
|
||||
reload_client_suggestions();
|
||||
table.ajax.reload();
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new client",
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "", "Error while adding new client", response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new client",
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while adding new client", jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
@@ -318,11 +301,7 @@ function editClient() {
|
||||
ip_name
|
||||
);
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"Error while " + not_done + " client with ID " + id,
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "Error while " + not_done + " client with ID " + id, response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
@@ -347,6 +326,7 @@ function deleteClient() {
|
||||
if (name.length > 0) {
|
||||
ip_name += " (" + name + ")";
|
||||
}
|
||||
|
||||
showAlert("info", "", "Deleting client...", ip_name);
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/groups.php",
|
||||
@@ -355,33 +335,18 @@ function deleteClient() {
|
||||
data: { action: "delete_client", id: id, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-trash",
|
||||
"Successfully deleted client ",
|
||||
ip_name
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-trash", "Successfully deleted client ", ip_name);
|
||||
table
|
||||
.row(tr)
|
||||
.remove()
|
||||
.draw(false);
|
||||
reload_client_suggestions();
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting client with ID " + id,
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "", "Error while deleting client with ID " + id, response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting client with ID " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while deleting client with ID " + id, jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -35,6 +35,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "warning":
|
||||
opts = {
|
||||
@@ -48,6 +49,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "error":
|
||||
opts = {
|
||||
@@ -61,9 +63,9 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,10 +92,7 @@ $(document).ready(function() {
|
||||
|
||||
$("#select").on("change", function() {
|
||||
$("#ip-custom").val("");
|
||||
$("#ip-custom").prop(
|
||||
"disabled",
|
||||
$("#select option:selected").val() !== "custom"
|
||||
);
|
||||
$("#ip-custom").prop("disabled", $("#select option:selected").val() !== "custom");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -149,9 +148,7 @@ function initTable() {
|
||||
|
||||
var disabled = data.enabled === 0;
|
||||
$("td:eq(2)", row).html(
|
||||
'<input type="checkbox" id="status"' +
|
||||
(disabled ? "" : " checked") +
|
||||
">"
|
||||
'<input type="checkbox" id="status"' + (disabled ? "" : " checked") + ">"
|
||||
);
|
||||
$("#status", row).bootstrapToggle({
|
||||
on: "Enabled",
|
||||
@@ -171,9 +168,7 @@ function initTable() {
|
||||
$("#comment", row).on("change", editDomain);
|
||||
|
||||
$("td:eq(4)", row).empty();
|
||||
$("td:eq(4)", row).append(
|
||||
'<select id="multiselect" multiple="multiple"></select>'
|
||||
);
|
||||
$("td:eq(4)", row).append('<select id="multiselect" multiple="multiple"></select>');
|
||||
var sel = $("#multiselect", row);
|
||||
// Add all known groups
|
||||
for (var i = 0; i < groups.length; i++) {
|
||||
@@ -181,12 +176,14 @@ function initTable() {
|
||||
if (!groups[i].enabled) {
|
||||
extra = " (disabled)";
|
||||
}
|
||||
|
||||
sel.append(
|
||||
$("<option />")
|
||||
.val(groups[i].id)
|
||||
.text(groups[i].name + extra)
|
||||
);
|
||||
}
|
||||
|
||||
// Select assigned groups
|
||||
sel.val(data.groups);
|
||||
// Initialize multiselect
|
||||
@@ -217,6 +214,7 @@ function initTable() {
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
@@ -268,30 +266,14 @@ function addDomain() {
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-plus",
|
||||
"Successfully added domain",
|
||||
domain
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-plus", "Successfully added domain", domain);
|
||||
$("#new_domain").val("");
|
||||
$("#new_comment").val("");
|
||||
table.ajax.reload();
|
||||
} else
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new domain",
|
||||
response.message
|
||||
);
|
||||
} else showAlert("error", "", "Error while adding new domain", response.message);
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new domain",
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while adding new domain", jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
@@ -384,31 +366,15 @@ function deleteDomain() {
|
||||
data: { action: "delete_domain", id: id, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-trash",
|
||||
"Successfully deleted domain",
|
||||
domain
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-trash", "Successfully deleted domain", domain);
|
||||
table
|
||||
.row(tr)
|
||||
.remove()
|
||||
.draw(false);
|
||||
} else
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting domain with ID " + id,
|
||||
response.message
|
||||
);
|
||||
} else showAlert("error", "", "Error while deleting domain with ID " + id, response.message);
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting domain with ID " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while deleting domain with ID " + id, jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -34,6 +34,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "warning":
|
||||
opts = {
|
||||
@@ -47,6 +48,7 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
case "error":
|
||||
opts = {
|
||||
@@ -60,9 +62,9 @@ function showAlert(type, icon, title, message) {
|
||||
} else {
|
||||
$.notify(opts);
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,9 +113,7 @@ $(document).ready(function() {
|
||||
|
||||
var disabled = data.enabled === 0;
|
||||
$("td:eq(1)", row).html(
|
||||
'<input type="checkbox" id="status"' +
|
||||
(disabled ? "" : " checked") +
|
||||
">"
|
||||
'<input type="checkbox" id="status"' + (disabled ? "" : " checked") + ">"
|
||||
);
|
||||
var status = $("#status", row);
|
||||
status.bootstrapToggle({
|
||||
@@ -158,6 +158,7 @@ $(document).ready(function() {
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
@@ -202,31 +203,16 @@ function addGroup() {
|
||||
data: { action: "add_group", name: name, desc: desc, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-plus",
|
||||
"Successfully added group",
|
||||
name
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-plus", "Successfully added group", name);
|
||||
$("#new_name").val("");
|
||||
$("#new_desc").val("");
|
||||
table.ajax.reload();
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new group",
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "", "Error while adding new group", response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while adding new group",
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while adding new group", jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
@@ -271,12 +257,7 @@ function editGroup() {
|
||||
},
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-pencil",
|
||||
"Successfully " + done + " group",
|
||||
name
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-pencil", "Successfully " + done + " group", name);
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
@@ -311,32 +292,17 @@ function deleteGroup() {
|
||||
data: { action: "delete_group", id: id, token: token },
|
||||
success: function(response) {
|
||||
if (response.success) {
|
||||
showAlert(
|
||||
"success",
|
||||
"glyphicon glyphicon-trash",
|
||||
"Successfully deleted group ",
|
||||
name
|
||||
);
|
||||
showAlert("success", "glyphicon glyphicon-trash", "Successfully deleted group ", name);
|
||||
table
|
||||
.row(tr)
|
||||
.remove()
|
||||
.draw(false);
|
||||
} else {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting group with ID " + id,
|
||||
response.message
|
||||
);
|
||||
showAlert("error", "", "Error while deleting group with ID " + id, response.message);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting group with ID " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
showAlert("error", "", "Error while deleting group with ID " + id, jqXHR.responseText);
|
||||
console.log(exception);
|
||||
}
|
||||
});
|
||||
|
||||
+923
-869
File diff suppressed because it is too large
Load Diff
@@ -1,113 +1,88 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
// This code has been taken from
|
||||
// https://datatables.net/plug-ins/sorting/ip-address
|
||||
jQuery.extend( jQuery.fn.dataTableExt.oSort,
|
||||
{
|
||||
"ip-address-pre": function ( a )
|
||||
{
|
||||
if (!a) { return 0; }
|
||||
var i, item;
|
||||
var m = a.split("."),
|
||||
n = a.split(":"),
|
||||
x = "",
|
||||
xa = "";
|
||||
if (m.length === 4)
|
||||
{
|
||||
// IPV4
|
||||
for(i = 0; i < m.length; i++)
|
||||
{
|
||||
item = m[i];
|
||||
|
||||
if(item.length === 1)
|
||||
{
|
||||
x += "00" + item;
|
||||
}
|
||||
else if(item.length === 2)
|
||||
{
|
||||
x += "0" + item;
|
||||
}
|
||||
else
|
||||
{
|
||||
x += item;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (n.length > 0)
|
||||
{
|
||||
// IPV6
|
||||
var count = 0;
|
||||
for(i = 0; i < n.length; i++)
|
||||
{
|
||||
item = n[i];
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
xa += ":";
|
||||
}
|
||||
|
||||
if(item.length === 0)
|
||||
{
|
||||
count += 0;
|
||||
}
|
||||
else if(item.length === 1)
|
||||
{
|
||||
xa += "000" + item;
|
||||
count += 4;
|
||||
}
|
||||
else if(item.length === 2)
|
||||
{
|
||||
xa += "00" + item;
|
||||
count += 4;
|
||||
}
|
||||
else if(item.length === 3)
|
||||
{
|
||||
xa += "0" + item;
|
||||
count += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
xa += item;
|
||||
count += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Padding the ::
|
||||
n = xa.split(":");
|
||||
var paddDone = 0;
|
||||
|
||||
for (i = 0; i < n.length; i++)
|
||||
{
|
||||
item = n[i];
|
||||
if (item.length === 0 && paddDone === 0)
|
||||
{
|
||||
for(var padding = 0; padding < (32-count); padding++)
|
||||
{
|
||||
x += "0";
|
||||
paddDone = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x += item;
|
||||
}
|
||||
}
|
||||
}
|
||||
return x;
|
||||
},
|
||||
|
||||
"ip-address-asc": function ( a, b )
|
||||
{
|
||||
return ((a < b) ? -1 : ((a > b) ? 1 : 0));
|
||||
},
|
||||
|
||||
"ip-address-desc": function ( a, b )
|
||||
{
|
||||
return ((a < b) ? 1 : ((a > b) ? -1 : 0));
|
||||
jQuery.extend(jQuery.fn.dataTableExt.oSort, {
|
||||
"ip-address-pre": function(a) {
|
||||
if (!a) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var i, item;
|
||||
var m = a.split("."),
|
||||
n = a.split(":"),
|
||||
x = "",
|
||||
xa = "";
|
||||
if (m.length === 4) {
|
||||
// IPV4
|
||||
for (i = 0; i < m.length; i++) {
|
||||
item = m[i];
|
||||
|
||||
if (item.length === 1) {
|
||||
x += "00" + item;
|
||||
} else if (item.length === 2) {
|
||||
x += "0" + item;
|
||||
} else {
|
||||
x += item;
|
||||
}
|
||||
}
|
||||
} else if (n.length > 0) {
|
||||
// IPV6
|
||||
var count = 0;
|
||||
for (i = 0; i < n.length; i++) {
|
||||
item = n[i];
|
||||
|
||||
if (i > 0) {
|
||||
xa += ":";
|
||||
}
|
||||
|
||||
if (item.length === 0) {
|
||||
count += 0;
|
||||
} else if (item.length === 1) {
|
||||
xa += "000" + item;
|
||||
count += 4;
|
||||
} else if (item.length === 2) {
|
||||
xa += "00" + item;
|
||||
count += 4;
|
||||
} else if (item.length === 3) {
|
||||
xa += "0" + item;
|
||||
count += 4;
|
||||
} else {
|
||||
xa += item;
|
||||
count += 4;
|
||||
}
|
||||
}
|
||||
|
||||
// Padding the ::
|
||||
n = xa.split(":");
|
||||
var paddDone = 0;
|
||||
|
||||
for (i = 0; i < n.length; i++) {
|
||||
item = n[i];
|
||||
if (item.length === 0 && paddDone === 0) {
|
||||
for (var padding = 0; padding < 32 - count; padding++) {
|
||||
x += "0";
|
||||
paddDone = 1;
|
||||
}
|
||||
} else {
|
||||
x += item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return x;
|
||||
},
|
||||
|
||||
"ip-address-asc": function(a, b) {
|
||||
return a < b ? -1 : a > b ? 1 : 0;
|
||||
},
|
||||
|
||||
"ip-address-desc": function(a, b) {
|
||||
return a < b ? 1 : a > b ? -1 : 0;
|
||||
}
|
||||
});
|
||||
|
||||
+235
-223
@@ -1,275 +1,287 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
// IE likes to cache too much :P
|
||||
$.ajaxSetup({cache: false});
|
||||
$.ajaxSetup({ cache: false });
|
||||
|
||||
// Get PHP info
|
||||
var token = $("#token").text();
|
||||
var listType = $("#list-type").html();
|
||||
var fullName = listType === "white" ? "Whitelist" : "Blacklist";
|
||||
|
||||
function addListEntry(entry, index, list, button, type)
|
||||
{
|
||||
var disabled = [];
|
||||
if(entry.enabled === "0")
|
||||
disabled.push("individual");
|
||||
// For entry.group_enabled we either get "0" (= disabled by a group),
|
||||
// "1" (= enabled by a group), or "" (= not managed by a group)
|
||||
if(entry.group_enabled === "0")
|
||||
disabled.push("group");
|
||||
function addListEntry(entry, index, list, button, type) {
|
||||
var disabled = [];
|
||||
if (entry.enabled === "0") disabled.push("individual");
|
||||
// For entry.group_enabled we either get "0" (= disabled by a group),
|
||||
// "1" (= enabled by a group), or "" (= not managed by a group)
|
||||
if (entry.group_enabled === "0") disabled.push("group");
|
||||
|
||||
var used = disabled.length === 0 ? "used" : "not-used";
|
||||
var comment = entry.comment.length > 0 ? " - " + entry.comment : "";
|
||||
var disabled_message = disabled.length > 0 ? " - disabled due to " + disabled.join(" + ") + " setting" : "";
|
||||
var date_added = new Date(parseInt(entry.date_added)*1000);
|
||||
var date_modified = new Date(parseInt(entry.date_modified)*1000);
|
||||
var tooltip = "Added: " + date_added.toLocaleString() +
|
||||
"\nModified: " + date_modified.toLocaleString();
|
||||
list.append(
|
||||
"<li id=\"" + index + "\" class=\"list-group-item " + used + " clearfix\">" +
|
||||
"<span title=\"" + tooltip + "\" data-toggle=\"tooltip\" data-placement=\"right\">" +
|
||||
entry.domain + comment + disabled_message + "</span>" +
|
||||
"<button class=\"btn btn-danger btn-xs pull-right\" type=\"button\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></button></li>"
|
||||
);
|
||||
// Handle button
|
||||
$(button+" #"+index).on("click", "button", function() {
|
||||
sub(index, entry.domain, type);
|
||||
});
|
||||
var used = disabled.length === 0 ? "used" : "not-used";
|
||||
var comment = entry.comment.length > 0 ? " - " + entry.comment : "";
|
||||
var disabled_message =
|
||||
disabled.length > 0 ? " - disabled due to " + disabled.join(" + ") + " setting" : "";
|
||||
var date_added = new Date(parseInt(entry.date_added) * 1000);
|
||||
var date_modified = new Date(parseInt(entry.date_modified) * 1000);
|
||||
var tooltip =
|
||||
"Added: " + date_added.toLocaleString() + "\nModified: " + date_modified.toLocaleString();
|
||||
list.append(
|
||||
'<li id="' +
|
||||
index +
|
||||
'" class="list-group-item ' +
|
||||
used +
|
||||
' clearfix">' +
|
||||
'<span title="' +
|
||||
tooltip +
|
||||
'" data-toggle="tooltip" data-placement="right">' +
|
||||
entry.domain +
|
||||
comment +
|
||||
disabled_message +
|
||||
"</span>" +
|
||||
'<button class="btn btn-danger btn-xs pull-right" type="button">' +
|
||||
'<span class="glyphicon glyphicon-trash"></span></button></li>'
|
||||
);
|
||||
// Handle button
|
||||
$(button + " #" + index).on("click", "button", function() {
|
||||
sub(index, entry.domain, type);
|
||||
});
|
||||
}
|
||||
|
||||
function refresh(fade) {
|
||||
var list = $("#list");
|
||||
var listw = $("#list-regex");
|
||||
if(fade) {
|
||||
list.fadeOut(100);
|
||||
listw.fadeOut(100);
|
||||
}
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/get.php",
|
||||
method: "get",
|
||||
data: {"list":listType},
|
||||
success: function(response) {
|
||||
list.html("");
|
||||
listw.html("");
|
||||
var list = $("#list");
|
||||
var listw = $("#list-regex");
|
||||
if (fade) {
|
||||
list.fadeOut(100);
|
||||
listw.fadeOut(100);
|
||||
}
|
||||
|
||||
if((listType === "black" &&
|
||||
response.blacklist.length === 0 &&
|
||||
response.regex_blacklist.length === 0) ||
|
||||
(listType === "white" &&
|
||||
response.whitelist.length === 0 &&
|
||||
response.regex_whitelist.length === 0))
|
||||
{
|
||||
$("h3").hide();
|
||||
list.html("<div class=\"alert alert-info\" role=\"alert\">Your " + fullName + " is empty!</div>");
|
||||
}
|
||||
else
|
||||
{
|
||||
var data, data2;
|
||||
if(listType === "white")
|
||||
{
|
||||
data = response.whitelist.sort();
|
||||
data2 = response.regex_whitelist.sort();
|
||||
}
|
||||
else if(listType === "black")
|
||||
{
|
||||
data = response.blacklist.sort();
|
||||
data2 = response.regex_blacklist.sort();
|
||||
}
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/get.php",
|
||||
method: "get",
|
||||
data: { list: listType },
|
||||
success: function(response) {
|
||||
list.html("");
|
||||
listw.html("");
|
||||
|
||||
if(data.length > 0)
|
||||
{
|
||||
$("#h3-exact").fadeIn(100);
|
||||
}
|
||||
if(data2.length > 0)
|
||||
{
|
||||
$("#h3-regex").fadeIn(100);
|
||||
}
|
||||
|
||||
data.forEach(function (entry, index)
|
||||
{
|
||||
addListEntry(entry, index, list, "#list", "exact");
|
||||
});
|
||||
data2.forEach(function (entry, index)
|
||||
{
|
||||
addListEntry(entry, index, listw, "#list-regex", listType+"_regex");
|
||||
});
|
||||
}
|
||||
list.fadeIn(100);
|
||||
listw.fadeIn(100);
|
||||
},
|
||||
error: function() {
|
||||
$("#alFailure").show();
|
||||
if (
|
||||
(listType === "black" &&
|
||||
response.blacklist.length === 0 &&
|
||||
response.regex_blacklist.length === 0) ||
|
||||
(listType === "white" &&
|
||||
response.whitelist.length === 0 &&
|
||||
response.regex_whitelist.length === 0)
|
||||
) {
|
||||
$("h3").hide();
|
||||
list.html(
|
||||
'<div class="alert alert-info" role="alert">Your ' + fullName + " is empty!</div>"
|
||||
);
|
||||
} else {
|
||||
var data, data2;
|
||||
if (listType === "white") {
|
||||
data = response.whitelist.sort();
|
||||
data2 = response.regex_whitelist.sort();
|
||||
} else if (listType === "black") {
|
||||
data = response.blacklist.sort();
|
||||
data2 = response.regex_blacklist.sort();
|
||||
}
|
||||
});
|
||||
|
||||
if (data.length > 0) {
|
||||
$("#h3-exact").fadeIn(100);
|
||||
}
|
||||
|
||||
if (data2.length > 0) {
|
||||
$("#h3-regex").fadeIn(100);
|
||||
}
|
||||
|
||||
data.forEach(function(entry, index) {
|
||||
addListEntry(entry, index, list, "#list", "exact");
|
||||
});
|
||||
data2.forEach(function(entry, index) {
|
||||
addListEntry(entry, index, listw, "#list-regex", listType + "_regex");
|
||||
});
|
||||
}
|
||||
|
||||
list.fadeIn(100);
|
||||
listw.fadeIn(100);
|
||||
},
|
||||
error: function() {
|
||||
$("#alFailure").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.addEventListener('load', refresh(false));
|
||||
window.addEventListener("load", refresh(false));
|
||||
|
||||
function sub(index, entry, arg) {
|
||||
var list = "#list";
|
||||
var heading = "#h3-exact";
|
||||
var locallistType = listType;
|
||||
if(arg === "black_regex" || arg === "white_regex")
|
||||
{
|
||||
list = "#list-regex";
|
||||
heading = "#h3-regex";
|
||||
locallistType = arg;
|
||||
}
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var err = $("#err");
|
||||
var msg = $("#success-message");
|
||||
var list = "#list";
|
||||
var heading = "#h3-exact";
|
||||
var locallistType = listType;
|
||||
if (arg === "black_regex" || arg === "white_regex") {
|
||||
list = "#list-regex";
|
||||
heading = "#h3-regex";
|
||||
locallistType = arg;
|
||||
}
|
||||
|
||||
var domain = $(list+" #"+index);
|
||||
domain.hide("highlight");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/sub.php",
|
||||
method: "post",
|
||||
data: {"domain":entry, "list":locallistType, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("Success") === -1) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(8000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(8000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
msg.html(response);
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.remove();
|
||||
if($(list+" li").length === 0)
|
||||
{
|
||||
$(heading).fadeOut(100);
|
||||
}
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert("Failed to remove the domain!");
|
||||
domain.show({queue:true});
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var err = $("#err");
|
||||
var msg = $("#success-message");
|
||||
|
||||
var domain = $(list + " #" + index);
|
||||
domain.hide("highlight");
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/sub.php",
|
||||
method: "post",
|
||||
data: { domain: entry, list: locallistType, token: token },
|
||||
success: function(response) {
|
||||
if (response.indexOf("Success") === -1) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(8000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(8000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
msg.html(response);
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.remove();
|
||||
if ($(list + " li").length === 0) {
|
||||
$(heading).fadeOut(100);
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert("Failed to remove the domain!");
|
||||
domain.show({ queue: true });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function add(type) {
|
||||
var domain = $("#domain");
|
||||
if(domain.val().length === 0){
|
||||
return;
|
||||
var domain = $("#domain");
|
||||
if (domain.val().length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var comment = $("#comment");
|
||||
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var alWarning = $("#alWarning");
|
||||
var err = $("#err");
|
||||
var msg = $("#success-message");
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
alWarning.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: { domain: domain.val().trim(), comment: comment.val(), list: type, token: token },
|
||||
success: function(response) {
|
||||
if (response.indexOf("Success") === -1) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(8000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(8000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
msg.html(response);
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.val("");
|
||||
comment.val("");
|
||||
refresh(true);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alFailure.show();
|
||||
err.html("");
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
}
|
||||
|
||||
var comment = $("#comment");
|
||||
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
var alWarning = $("#alWarning");
|
||||
var err = $("#err");
|
||||
var msg = $("#success-message");
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
alWarning.hide();
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain.val().trim(),"comment":comment.val(), "list":type, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("Success") === -1) {
|
||||
alFailure.show();
|
||||
err.html(response);
|
||||
alFailure.delay(8000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(8000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
msg.html(response);
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.val("");
|
||||
comment.val("");
|
||||
refresh(true);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alFailure.show();
|
||||
err.html("");
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Handle enter button for adding domains
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#domain,#comment").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
add(listType);
|
||||
}
|
||||
if (e.which === 13 && $("#domain,#comment").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
add(listType);
|
||||
}
|
||||
});
|
||||
|
||||
// Handle buttons
|
||||
$("#btnAdd").on("click", function() {
|
||||
add(listType);
|
||||
add(listType);
|
||||
});
|
||||
|
||||
$("#btnAddWildcard").on("click", function() {
|
||||
add(listType+"_wild");
|
||||
add(listType + "_wild");
|
||||
});
|
||||
|
||||
$("#btnAddRegex").on("click", function() {
|
||||
add(listType+"_regex");
|
||||
add(listType + "_regex");
|
||||
});
|
||||
|
||||
$("#btnRefresh").on("click", function() {
|
||||
refresh(true);
|
||||
refresh(true);
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
$(function() {
|
||||
$("[data-hide]").on("click", function() {
|
||||
$(this)
|
||||
.closest("." + $(this).attr("data-hide"))
|
||||
.hide();
|
||||
});
|
||||
});
|
||||
|
||||
// Wrap form-group's buttons to next line when viewed on a small screen
|
||||
$(window).on("resize",function() {
|
||||
if ($(window).width() < 991) {
|
||||
$(".form-group.input-group").removeClass("input-group").addClass("input-group-block");
|
||||
$(".form-group.input-group-block > input").css("margin-bottom", "5px");
|
||||
$(".form-group.input-group-block > .input-group-btn").removeClass("input-group-btn").addClass("btn-block text-center");
|
||||
}
|
||||
else {
|
||||
$(".form-group.input-group-block").removeClass("input-group-block").addClass( "input-group" );
|
||||
$(".form-group.input-group > input").css("margin-bottom","");
|
||||
$(".form-group.input-group > .btn-block.text-center").removeClass("btn-block text-center").addClass("input-group-btn");
|
||||
}
|
||||
$(window).on("resize", function() {
|
||||
if ($(window).width() < 991) {
|
||||
$(".form-group.input-group")
|
||||
.removeClass("input-group")
|
||||
.addClass("input-group-block");
|
||||
$(".form-group.input-group-block > input").css("margin-bottom", "5px");
|
||||
$(".form-group.input-group-block > .input-group-btn")
|
||||
.removeClass("input-group-btn")
|
||||
.addClass("btn-block text-center");
|
||||
} else {
|
||||
$(".form-group.input-group-block")
|
||||
.removeClass("input-group-block")
|
||||
.addClass("input-group");
|
||||
$(".form-group.input-group > input").css("margin-bottom", "");
|
||||
$(".form-group.input-group > .btn-block.text-center")
|
||||
.removeClass("btn-block text-center")
|
||||
.addClass("input-group-btn");
|
||||
}
|
||||
});
|
||||
$(document).ready(function() {
|
||||
$(window).trigger("resize");
|
||||
$(window).trigger("resize");
|
||||
});
|
||||
|
||||
+160
-140
@@ -1,9 +1,9 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global moment:false */
|
||||
|
||||
@@ -15,159 +15,179 @@ var APIstring = "api_db.php?network";
|
||||
var MAXIPDISPLAY = 3;
|
||||
|
||||
function handleAjaxError(xhr, textStatus) {
|
||||
if ( textStatus === "timeout" )
|
||||
{
|
||||
alert( "The server took too long to send the data." );
|
||||
}
|
||||
else if(xhr.responseText.indexOf("Connection refused") >= 0)
|
||||
{
|
||||
alert( "An error occured while loading the data: Connection refused. Is FTL running?" );
|
||||
}
|
||||
else
|
||||
{
|
||||
alert( "An unknown error occured while loading the data.\n"+xhr.responseText );
|
||||
}
|
||||
$("#network-entries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
if (textStatus === "timeout") {
|
||||
alert("The server took too long to send the data.");
|
||||
} else if (xhr.responseText.indexOf("Connection refused") >= 0) {
|
||||
alert("An error occured while loading the data: Connection refused. Is FTL running?");
|
||||
} else {
|
||||
alert("An unknown error occured while loading the data.\n" + xhr.responseText);
|
||||
}
|
||||
|
||||
$("#network-entries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
}
|
||||
|
||||
function getTimestamp(){
|
||||
if (!Date.now)
|
||||
{
|
||||
Date.now = function() { return new Date().getTime(); };
|
||||
function getTimestamp() {
|
||||
if (!Date.now) {
|
||||
Date.now = function() {
|
||||
return new Date().getTime();
|
||||
};
|
||||
}
|
||||
|
||||
return Math.floor(Date.now() / 1000);
|
||||
}
|
||||
|
||||
function valueToHex(c) {
|
||||
var hex = Math.round(c).toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
var hex = Math.round(c).toString(16);
|
||||
return hex.length === 1 ? "0" + hex : hex;
|
||||
}
|
||||
|
||||
function rgbToHex(values) {
|
||||
return "#" + valueToHex(values[0]) +
|
||||
valueToHex(values[1]) +
|
||||
valueToHex(values[2]);
|
||||
return "#" + valueToHex(values[0]) + valueToHex(values[1]) + valueToHex(values[2]);
|
||||
}
|
||||
|
||||
function mixColors(ratio, rgb1, rgb2)
|
||||
{
|
||||
return [(1.0-ratio)*rgb1[0]+ratio*rgb2[0],
|
||||
(1.0-ratio)*rgb1[1]+ratio*rgb2[1],
|
||||
(1.0-ratio)*rgb1[2]+ratio*rgb2[2]];
|
||||
function mixColors(ratio, rgb1, rgb2) {
|
||||
return [
|
||||
(1.0 - ratio) * rgb1[0] + ratio * rgb2[0],
|
||||
(1.0 - ratio) * rgb1[1] + ratio * rgb2[1],
|
||||
(1.0 - ratio) * rgb1[2] + ratio * rgb2[2]
|
||||
];
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
tableApi = $("#network-entries").DataTable( {
|
||||
"rowCallback": function( row, data )
|
||||
{
|
||||
var color, mark, lastQuery = parseInt(data.lastQuery);
|
||||
if(lastQuery > 0)
|
||||
{
|
||||
var diff = getTimestamp()-lastQuery;
|
||||
if(diff <= 86400)
|
||||
{
|
||||
// Last query came in within the last 24 hours (24*60*60 = 86400)
|
||||
// Color: light-green to light-yellow
|
||||
var ratio = Number(diff)/86400;
|
||||
var lightgreen = [0xE7, 0xFF, 0xDE];
|
||||
var lightyellow = [0xFF, 0xFF, 0xDF];
|
||||
color = rgbToHex(mixColors(ratio, lightgreen, lightyellow));
|
||||
mark = "✔";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Last query was longer than 24 hours ago
|
||||
// Color: light-orange
|
||||
color = "#ffedd9";
|
||||
mark = "<strong>?</strong>";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This client has never sent a query to Pi-hole, color light-red
|
||||
color = "#ffbfaa";
|
||||
mark = "✘";
|
||||
}
|
||||
// Set determined background color
|
||||
$(row).css("background-color", color);
|
||||
$("td:eq(7)", row).html(mark);
|
||||
tableApi = $("#network-entries").DataTable({
|
||||
rowCallback: function(row, data) {
|
||||
var color,
|
||||
mark,
|
||||
lastQuery = parseInt(data.lastQuery);
|
||||
if (lastQuery > 0) {
|
||||
var diff = getTimestamp() - lastQuery;
|
||||
if (diff <= 86400) {
|
||||
// Last query came in within the last 24 hours (24*60*60 = 86400)
|
||||
// Color: light-green to light-yellow
|
||||
var ratio = Number(diff) / 86400;
|
||||
var lightgreen = [0xe7, 0xff, 0xde];
|
||||
var lightyellow = [0xff, 0xff, 0xdf];
|
||||
color = rgbToHex(mixColors(ratio, lightgreen, lightyellow));
|
||||
mark = "✔";
|
||||
} else {
|
||||
// Last query was longer than 24 hours ago
|
||||
// Color: light-orange
|
||||
color = "#ffedd9";
|
||||
mark = "<strong>?</strong>";
|
||||
}
|
||||
} else {
|
||||
// This client has never sent a query to Pi-hole, color light-red
|
||||
color = "#ffbfaa";
|
||||
mark = "✘";
|
||||
}
|
||||
|
||||
// Insert "Never" into Last Query field when we have
|
||||
// never seen a query from this device
|
||||
if(data.lastQuery === 0)
|
||||
{
|
||||
$("td:eq(5)", row).html("Never");
|
||||
}
|
||||
// Set determined background color
|
||||
$(row).css("background-color", color);
|
||||
$("td:eq(7)", row).html(mark);
|
||||
|
||||
// Set hostname to "N/A" if not available
|
||||
if(!data.name || data.name.length === 0)
|
||||
{
|
||||
$("td:eq(3)", row).html("N/A");
|
||||
}
|
||||
// Insert "Never" into Last Query field when we have
|
||||
// never seen a query from this device
|
||||
if (data.lastQuery === 0) {
|
||||
$("td:eq(5)", row).html("Never");
|
||||
}
|
||||
|
||||
// Set number of queries to localized string (add thousand separators)
|
||||
$("td:eq(6)", row).html(data.numQueries.toLocaleString());
|
||||
// Set hostname to "N/A" if not available
|
||||
if (!data.name || data.name.length === 0) {
|
||||
$("td:eq(3)", row).html("N/A");
|
||||
}
|
||||
|
||||
var ips = data.ip;
|
||||
var shortips = ips;
|
||||
if(ips.length > MAXIPDISPLAY)
|
||||
{
|
||||
shortips = ips.slice(0,MAXIPDISPLAY-1);
|
||||
shortips.push("...");
|
||||
}
|
||||
$("td:eq(0)", row).html(shortips.join("<br>"));
|
||||
$("td:eq(0)", row).hover(function () { this.title=ips.join("\n");});
|
||||
// Set number of queries to localized string (add thousand separators)
|
||||
$("td:eq(6)", row).html(data.numQueries.toLocaleString());
|
||||
|
||||
// MAC + Vendor field if available
|
||||
if(data.macVendor && data.macVendor.length > 0)
|
||||
{
|
||||
$("td:eq(1)", row).html(data.hwaddr+"<br/>"+data.macVendor);
|
||||
}
|
||||
var ips = data.ip;
|
||||
var shortips = ips;
|
||||
if (ips.length > MAXIPDISPLAY) {
|
||||
shortips = ips.slice(0, MAXIPDISPLAY - 1);
|
||||
shortips.push("...");
|
||||
}
|
||||
|
||||
},
|
||||
dom: "<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
"ajax": {"url": APIstring, "error": handleAjaxError, "dataSrc": "network" },
|
||||
"autoWidth" : false,
|
||||
"processing": true,
|
||||
"order" : [[5, "desc"]],
|
||||
"columns": [
|
||||
{data: "ip", "type": "ip-address", "width" : "10%", "render": $.fn.dataTable.render.text() },
|
||||
{data: "hwaddr", "width" : "10%", "render": $.fn.dataTable.render.text() },
|
||||
{data: "interface", "width" : "4%", "render": $.fn.dataTable.render.text() },
|
||||
{data: "name", "width" : "15%", "render": $.fn.dataTable.render.text() },
|
||||
{data: "firstSeen", "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 data; }},
|
||||
{data: "lastQuery", "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 data; }},
|
||||
{data: "numQueries", "width" : "9%", "render": $.fn.dataTable.render.text() },
|
||||
{data: "", "width" : "6%", "orderable" : false }
|
||||
],
|
||||
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
|
||||
"stateSave": true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// Store current state in client's local storage area
|
||||
localStorage.setItem("network_table", JSON.stringify(data));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// Receive previous state from client's local storage area
|
||||
var data = localStorage.getItem("network_table");
|
||||
// Return if not available
|
||||
if(data === null){ return null; }
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page
|
||||
data.start = 0;
|
||||
// Always start with empty search field
|
||||
data.search.search = "";
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
"columnDefs": [ {
|
||||
"targets": -1,
|
||||
"data": null,
|
||||
"defaultContent": ""
|
||||
} ]
|
||||
});
|
||||
} );
|
||||
$("td:eq(0)", row).html(shortips.join("<br>"));
|
||||
$("td:eq(0)", row).hover(function() {
|
||||
this.title = ips.join("\n");
|
||||
});
|
||||
|
||||
// MAC + Vendor field if available
|
||||
if (data.macVendor && data.macVendor.length > 0) {
|
||||
$("td:eq(1)", row).html(data.hwaddr + "<br/>" + data.macVendor);
|
||||
}
|
||||
},
|
||||
dom:
|
||||
"<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
ajax: { url: APIstring, error: handleAjaxError, dataSrc: "network" },
|
||||
autoWidth: false,
|
||||
processing: true,
|
||||
order: [[5, "desc"]],
|
||||
columns: [
|
||||
{ data: "ip", type: "ip-address", width: "10%", render: $.fn.dataTable.render.text() },
|
||||
{ data: "hwaddr", width: "10%", render: $.fn.dataTable.render.text() },
|
||||
{ data: "interface", width: "4%", render: $.fn.dataTable.render.text() },
|
||||
{ data: "name", width: "15%", render: $.fn.dataTable.render.text() },
|
||||
{
|
||||
data: "firstSeen",
|
||||
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 data;
|
||||
}
|
||||
},
|
||||
{
|
||||
data: "lastQuery",
|
||||
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 data;
|
||||
}
|
||||
},
|
||||
{ data: "numQueries", width: "9%", render: $.fn.dataTable.render.text() },
|
||||
{ data: "", width: "6%", orderable: false }
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"]
|
||||
],
|
||||
stateSave: true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// Store current state in client's local storage area
|
||||
localStorage.setItem("network_table", JSON.stringify(data));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// Receive previous state from client's local storage area
|
||||
var data = localStorage.getItem("network_table");
|
||||
// Return if not available
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page
|
||||
data.start = 0;
|
||||
// Always start with empty search field
|
||||
data.search.search = "";
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: -1,
|
||||
data: null,
|
||||
defaultContent: ""
|
||||
}
|
||||
]
|
||||
});
|
||||
});
|
||||
|
||||
+421
-377
@@ -1,398 +1,442 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global moment:false */
|
||||
|
||||
var tableApi;
|
||||
|
||||
function add(domain,list) {
|
||||
var token = $("#token").text();
|
||||
var alertModal = $("#alertModal");
|
||||
var alProcessing = alertModal.find(".alProcessing");
|
||||
var alSuccess = alertModal.find(".alSuccess");
|
||||
var alFailure = alertModal.find(".alFailure");
|
||||
var alNetworkErr = alertModal.find(".alFailure #alNetErr");
|
||||
var alCustomErr = alertModal.find(".alFailure #alCustomErr");
|
||||
var alList = "#alList";
|
||||
var alDomain = "#alDomain";
|
||||
function add(domain, list) {
|
||||
var token = $("#token").text();
|
||||
var alertModal = $("#alertModal");
|
||||
var alProcessing = alertModal.find(".alProcessing");
|
||||
var alSuccess = alertModal.find(".alSuccess");
|
||||
var alFailure = alertModal.find(".alFailure");
|
||||
var alNetworkErr = alertModal.find(".alFailure #alNetErr");
|
||||
var alCustomErr = alertModal.find(".alFailure #alCustomErr");
|
||||
var alList = "#alList";
|
||||
var alDomain = "#alDomain";
|
||||
|
||||
// Exit the function here if the Modal is already shown (multiple running interlock)
|
||||
if (alertModal.css("display") !== "none") {
|
||||
return;
|
||||
}
|
||||
// Exit the function here if the Modal is already shown (multiple running interlock)
|
||||
if (alertModal.css("display") !== "none") {
|
||||
return;
|
||||
}
|
||||
|
||||
var listtype;
|
||||
if (list === "white") {
|
||||
listtype = "Whitelist";
|
||||
} else {
|
||||
listtype = "Blacklist";
|
||||
}
|
||||
alProcessing.children(alDomain).html(domain);
|
||||
alProcessing.children(alList).html(listtype);
|
||||
alertModal.modal("show");
|
||||
var listtype;
|
||||
if (list === "white") {
|
||||
listtype = "Whitelist";
|
||||
} else {
|
||||
listtype = "Blacklist";
|
||||
}
|
||||
|
||||
// add Domain to List after Modal has faded in
|
||||
alertModal.one("shown.bs.modal", function() {
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain, "list":list, "token":token},
|
||||
success: function(response) {
|
||||
alProcessing.hide();
|
||||
if (response.indexOf("not a valid argument") >= 0 ||
|
||||
response.indexOf("is not a valid domain") >= 0 ||
|
||||
response.indexOf("Wrong token") >= 0)
|
||||
{
|
||||
// Failure
|
||||
alNetworkErr.hide();
|
||||
alCustomErr.html(response.replace("[✗]", ""));
|
||||
alFailure.fadeIn(1000);
|
||||
setTimeout(function() { alertModal.modal("hide"); }, 3000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Success
|
||||
alSuccess.children(alDomain).html(domain);
|
||||
alSuccess.children(alList).html(listtype);
|
||||
alSuccess.fadeIn(1000);
|
||||
setTimeout(function() { alertModal.modal("hide"); }, 2000);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// Network Error
|
||||
alProcessing.hide();
|
||||
alNetworkErr.show();
|
||||
alFailure.fadeIn(1000);
|
||||
setTimeout(function() { alertModal.modal("hide"); }, 3000);
|
||||
}
|
||||
});
|
||||
alProcessing.children(alDomain).html(domain);
|
||||
alProcessing.children(alList).html(listtype);
|
||||
alertModal.modal("show");
|
||||
|
||||
// add Domain to List after Modal has faded in
|
||||
alertModal.one("shown.bs.modal", function() {
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/add.php",
|
||||
method: "post",
|
||||
data: { domain: domain, list: list, token: token },
|
||||
success: function(response) {
|
||||
alProcessing.hide();
|
||||
if (
|
||||
response.indexOf("not a valid argument") >= 0 ||
|
||||
response.indexOf("is not a valid domain") >= 0 ||
|
||||
response.indexOf("Wrong token") >= 0
|
||||
) {
|
||||
// Failure
|
||||
alNetworkErr.hide();
|
||||
alCustomErr.html(response.replace("[✗]", ""));
|
||||
alFailure.fadeIn(1000);
|
||||
setTimeout(function() {
|
||||
alertModal.modal("hide");
|
||||
}, 3000);
|
||||
} else {
|
||||
// Success
|
||||
alSuccess.children(alDomain).html(domain);
|
||||
alSuccess.children(alList).html(listtype);
|
||||
alSuccess.fadeIn(1000);
|
||||
setTimeout(function() {
|
||||
alertModal.modal("hide");
|
||||
}, 2000);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
// Network Error
|
||||
alProcessing.hide();
|
||||
alNetworkErr.show();
|
||||
alFailure.fadeIn(1000);
|
||||
setTimeout(function() {
|
||||
alertModal.modal("hide");
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Reset Modal after it has faded out
|
||||
alertModal.one("hidden.bs.modal", function() {
|
||||
alProcessing.show();
|
||||
alSuccess.add(alFailure).hide();
|
||||
alProcessing.add(alSuccess).children(alDomain).html("").end().children(alList).html("");
|
||||
alCustomErr.html("");
|
||||
});
|
||||
// Reset Modal after it has faded out
|
||||
alertModal.one("hidden.bs.modal", function() {
|
||||
alProcessing.show();
|
||||
alSuccess.add(alFailure).hide();
|
||||
alProcessing
|
||||
.add(alSuccess)
|
||||
.children(alDomain)
|
||||
.html("")
|
||||
.end()
|
||||
.children(alList)
|
||||
.html("");
|
||||
alCustomErr.html("");
|
||||
});
|
||||
}
|
||||
|
||||
function handleAjaxError( xhr, textStatus ) {
|
||||
if ( textStatus === "timeout" )
|
||||
{
|
||||
alert( "The server took too long to send the data." );
|
||||
}
|
||||
else if(xhr.responseText.indexOf("Connection refused") >= 0)
|
||||
{
|
||||
alert( "An error occured while loading the data: Connection refused. Is FTL running?" );
|
||||
}
|
||||
else
|
||||
{
|
||||
alert( "An unknown error occured while loading the data.\n"+xhr.responseText );
|
||||
}
|
||||
$("#all-queries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
function handleAjaxError(xhr, textStatus) {
|
||||
if (textStatus === "timeout") {
|
||||
alert("The server took too long to send the data.");
|
||||
} else if (xhr.responseText.indexOf("Connection refused") >= 0) {
|
||||
alert("An error occured while loading the data: Connection refused. Is FTL running?");
|
||||
} else {
|
||||
alert("An unknown error occured while loading the data.\n" + xhr.responseText);
|
||||
}
|
||||
|
||||
$("#all-queries_processing").hide();
|
||||
tableApi.clear();
|
||||
tableApi.draw();
|
||||
}
|
||||
|
||||
function autofilter(){
|
||||
return document.getElementById("autofilter").checked;
|
||||
function autofilter() {
|
||||
return document.getElementById("autofilter").checked;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
// Do we want to filter queries?
|
||||
var GETDict = {};
|
||||
window.location.search.substr(1).split("&").forEach(function(item) {GETDict[item.split("=")[0]] = item.split("=")[1];});
|
||||
|
||||
var APIstring = "api.php?getAllQueries";
|
||||
|
||||
if("from" in GETDict && "until" in GETDict)
|
||||
{
|
||||
APIstring += "&from="+GETDict.from;
|
||||
APIstring += "&until="+GETDict.until;
|
||||
}
|
||||
else if("client" in GETDict)
|
||||
{
|
||||
APIstring += "&client="+GETDict.client;
|
||||
}
|
||||
else if("domain" in GETDict)
|
||||
{
|
||||
APIstring += "&domain="+GETDict.domain;
|
||||
}
|
||||
else if("querytype" in GETDict)
|
||||
{
|
||||
APIstring += "&querytype="+GETDict.querytype;
|
||||
}
|
||||
else if("forwarddest" in GETDict)
|
||||
{
|
||||
APIstring += "&forwarddest="+GETDict.forwarddest;
|
||||
}
|
||||
// If we don't ask filtering and also not for all queries, just request the most recent 100 queries
|
||||
else if(!("all" in GETDict))
|
||||
{
|
||||
APIstring += "=100";
|
||||
}
|
||||
|
||||
tableApi = $("#all-queries").DataTable( {
|
||||
"rowCallback": function( row, data ){
|
||||
// DNSSEC status
|
||||
var dnssec_status;
|
||||
switch (data[5])
|
||||
{
|
||||
case "1":
|
||||
dnssec_status = "<br><span class=\"text-green\">SECURE</span>";
|
||||
break;
|
||||
case "2":
|
||||
dnssec_status = "<br><span class=\"text-orange\">INSECURE</span>";
|
||||
break;
|
||||
case "3":
|
||||
dnssec_status = "<br><span class=\"text-red\">BOGUS</span>";
|
||||
break;
|
||||
case "4":
|
||||
dnssec_status = "<br><span class=\"text-red\">ABANDONED</span>";
|
||||
break;
|
||||
case "5":
|
||||
dnssec_status = "<br><span class=\"text-orange\">UNKNOWN</span>";
|
||||
break;
|
||||
default: // No DNSSEC
|
||||
dnssec_status = "";
|
||||
}
|
||||
|
||||
// Query status
|
||||
var blocked, fieldtext, buttontext, colorClass;
|
||||
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)"+dnssec_status;
|
||||
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)"+dnssec_status;
|
||||
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/wildcard)";
|
||||
buttontext = "<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'>(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;
|
||||
default:
|
||||
blocked = false;
|
||||
colorClass = "text-black";
|
||||
fieldtext = "Unknown ("+parseInt(data[4])+")";
|
||||
buttontext = "";
|
||||
}
|
||||
$(row).addClass(colorClass);
|
||||
$("td:eq(4)", row).html(fieldtext);
|
||||
$("td:eq(6)", row).html(buttontext);
|
||||
|
||||
// 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])+")";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
replytext = "-";
|
||||
}
|
||||
$("td:eq(5)", row).addClass("text-black");
|
||||
$("td:eq(5)", row).html(replytext);
|
||||
|
||||
if(data.length > 7 && data[7] > 0)
|
||||
{
|
||||
var content = $("td:eq(5)", row).html();
|
||||
$("td:eq(5)", row).html(content + " (" + (0.1*data[7]).toFixed(1)+"ms)");
|
||||
}
|
||||
|
||||
},
|
||||
dom: "<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
"ajax": {
|
||||
"url": APIstring,
|
||||
"error": handleAjaxError,
|
||||
"dataSrc": function(data){
|
||||
var dataIndex = 0;
|
||||
return data.data.map(function(x){
|
||||
x[0] = x[0] * 1e6 + (dataIndex++);
|
||||
return x;
|
||||
});
|
||||
}
|
||||
},
|
||||
"autoWidth" : false,
|
||||
"processing": true,
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "15%", "render": function (data, type) { if(type === "display"){return moment.unix(Math.floor(data/1e6)).format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");}return data; }},
|
||||
{ "width" : "4%" },
|
||||
{ "width" : "36%", "render": $.fn.dataTable.render.text() },
|
||||
{ "width" : "8%", "render": $.fn.dataTable.render.text() },
|
||||
{ "width" : "14%", "orderData": 4 },
|
||||
{ "width" : "8%", "orderData": 6 },
|
||||
{ "width" : "10%", "orderData": 4 }
|
||||
],
|
||||
"lengthMenu": [[10, 25, 50, 100, -1], [10, 25, 50, 100, "All"]],
|
||||
"stateSave": true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// Store current state in client's local storage area
|
||||
localStorage.setItem("query_log_table", JSON.stringify(data));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// Receive previous state from client's local storage area
|
||||
var data = localStorage.getItem("query_log_table");
|
||||
// Return if not available
|
||||
if(data === null){ return null; }
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
// Always start with empty search field
|
||||
data.search.search = "";
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
"columnDefs": [ {
|
||||
"targets": -1,
|
||||
"data": null,
|
||||
"defaultContent": ""
|
||||
} ],
|
||||
"initComplete": function () {
|
||||
var api = this.api();
|
||||
// Query type IPv4 / IPv6
|
||||
api.$("td:eq(1)").click( function () { if(autofilter()){ api.search( this.textContent ).draw(); $("#resetButton").show(); }});
|
||||
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 = "";
|
||||
}
|
||||
},
|
||||
function () { this.style.color=""; }
|
||||
);
|
||||
api.$("td:eq(1)").css("cursor","pointer");
|
||||
// Domain
|
||||
api.$("td:eq(2)").click( function () { if(autofilter()){ api.search( this.textContent ).draw(); $("#resetButton").show(); }});
|
||||
api.$("td:eq(2)").hover(
|
||||
function () {
|
||||
if(autofilter()) {
|
||||
this.title = "Click to show only queries with domain " + this.textContent;
|
||||
this.style.color = "#72afd2";
|
||||
} else {
|
||||
this.title = "";
|
||||
this.style.color = "";
|
||||
}
|
||||
},
|
||||
function () { this.style.color=""; }
|
||||
);
|
||||
api.$("td:eq(2)").css("cursor","pointer");
|
||||
// Client
|
||||
api.$("td:eq(3)").click( function () { if(autofilter()){ api.search( this.textContent ).draw(); $("#resetButton").show(); }});
|
||||
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 = "";
|
||||
}
|
||||
},
|
||||
function () { this.style.color=""; }
|
||||
);
|
||||
api.$("td:eq(3)").css("cursor","pointer");
|
||||
}
|
||||
// Do we want to filter queries?
|
||||
var GETDict = {};
|
||||
window.location.search
|
||||
.substr(1)
|
||||
.split("&")
|
||||
.forEach(function(item) {
|
||||
GETDict[item.split("=")[0]] = item.split("=")[1];
|
||||
});
|
||||
|
||||
$("#all-queries tbody").on( "click", "button", function () {
|
||||
var data = tableApi.row( $(this).parents("tr") ).data();
|
||||
if (data[4] === "1" || data[4] === "4" || data[4] === "5")
|
||||
{
|
||||
add(data[2],"white");
|
||||
}
|
||||
else
|
||||
{
|
||||
add(data[2],"black");
|
||||
}
|
||||
} );
|
||||
var APIstring = "api.php?getAllQueries";
|
||||
|
||||
$("#resetButton").click( function () { tableApi.search("").draw(); $("#resetButton").hide(); } );
|
||||
} );
|
||||
if ("from" in GETDict && "until" in GETDict) {
|
||||
APIstring += "&from=" + GETDict.from;
|
||||
APIstring += "&until=" + GETDict.until;
|
||||
} else if ("client" in GETDict) {
|
||||
APIstring += "&client=" + GETDict.client;
|
||||
} else if ("domain" in GETDict) {
|
||||
APIstring += "&domain=" + GETDict.domain;
|
||||
} else if ("querytype" in GETDict) {
|
||||
APIstring += "&querytype=" + GETDict.querytype;
|
||||
} else if ("forwarddest" in GETDict) {
|
||||
APIstring += "&forwarddest=" + GETDict.forwarddest;
|
||||
}
|
||||
// If we don't ask filtering and also not for all queries, just request the most recent 100 queries
|
||||
else if (!("all" in GETDict)) {
|
||||
APIstring += "=100";
|
||||
}
|
||||
|
||||
tableApi = $("#all-queries").DataTable({
|
||||
rowCallback: function(row, data) {
|
||||
// DNSSEC status
|
||||
var dnssec_status;
|
||||
switch (data[5]) {
|
||||
case "1":
|
||||
dnssec_status = '<br><span class="text-green">SECURE</span>';
|
||||
break;
|
||||
case "2":
|
||||
dnssec_status = '<br><span class="text-orange">INSECURE</span>';
|
||||
break;
|
||||
case "3":
|
||||
dnssec_status = '<br><span class="text-red">BOGUS</span>';
|
||||
break;
|
||||
case "4":
|
||||
dnssec_status = '<br><span class="text-red">ABANDONED</span>';
|
||||
break;
|
||||
case "5":
|
||||
dnssec_status = '<br><span class="text-orange">UNKNOWN</span>';
|
||||
break;
|
||||
default:
|
||||
// No DNSSEC
|
||||
dnssec_status = "";
|
||||
}
|
||||
|
||||
// Query status
|
||||
var blocked, fieldtext, buttontext, colorClass;
|
||||
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)" + dnssec_status;
|
||||
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)" + dnssec_status;
|
||||
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/wildcard)";
|
||||
buttontext =
|
||||
'<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'>(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;
|
||||
default:
|
||||
blocked = false;
|
||||
colorClass = "text-black";
|
||||
fieldtext = "Unknown (" + parseInt(data[4]) + ")";
|
||||
buttontext = "";
|
||||
}
|
||||
|
||||
$(row).addClass(colorClass);
|
||||
$("td:eq(4)", row).html(fieldtext);
|
||||
$("td:eq(6)", row).html(buttontext);
|
||||
|
||||
// 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]) + ")";
|
||||
}
|
||||
} else {
|
||||
replytext = "-";
|
||||
}
|
||||
|
||||
$("td:eq(5)", row).addClass("text-black");
|
||||
$("td:eq(5)", row).html(replytext);
|
||||
|
||||
if (data.length > 7 && data[7] > 0) {
|
||||
var content = $("td:eq(5)", row).html();
|
||||
$("td:eq(5)", row).html(content + " (" + (0.1 * data[7]).toFixed(1) + "ms)");
|
||||
}
|
||||
},
|
||||
dom:
|
||||
"<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
ajax: {
|
||||
url: APIstring,
|
||||
error: handleAjaxError,
|
||||
dataSrc: function(data) {
|
||||
var dataIndex = 0;
|
||||
return data.data.map(function(x) {
|
||||
x[0] = x[0] * 1e6 + dataIndex++;
|
||||
return x;
|
||||
});
|
||||
}
|
||||
},
|
||||
autoWidth: false,
|
||||
processing: true,
|
||||
order: [[0, "desc"]],
|
||||
columns: [
|
||||
{
|
||||
width: "15%",
|
||||
render: function(data, type) {
|
||||
if (type === "display") {
|
||||
return moment
|
||||
.unix(Math.floor(data / 1e6))
|
||||
.format("Y-MM-DD [<br class='hidden-lg'>]HH:mm:ss z");
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
},
|
||||
{ width: "4%" },
|
||||
{ width: "36%", render: $.fn.dataTable.render.text() },
|
||||
{ width: "8%", render: $.fn.dataTable.render.text() },
|
||||
{ width: "14%", orderData: 4 },
|
||||
{ width: "8%", orderData: 6 },
|
||||
{ width: "10%", orderData: 4 }
|
||||
],
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"]
|
||||
],
|
||||
stateSave: true,
|
||||
stateSaveCallback: function(settings, data) {
|
||||
// Store current state in client's local storage area
|
||||
localStorage.setItem("query_log_table", JSON.stringify(data));
|
||||
},
|
||||
stateLoadCallback: function() {
|
||||
// Receive previous state from client's local storage area
|
||||
var data = localStorage.getItem("query_log_table");
|
||||
// Return if not available
|
||||
if (data === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data = JSON.parse(data);
|
||||
// Always start on the first page to show most recent queries
|
||||
data.start = 0;
|
||||
// Always start with empty search field
|
||||
data.search.search = "";
|
||||
// Apply loaded state to table
|
||||
return data;
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: -1,
|
||||
data: null,
|
||||
defaultContent: ""
|
||||
}
|
||||
],
|
||||
initComplete: function() {
|
||||
var api = this.api();
|
||||
// Query type IPv4 / IPv6
|
||||
api.$("td:eq(1)").click(function() {
|
||||
if (autofilter()) {
|
||||
api.search(this.textContent).draw();
|
||||
$("#resetButton").show();
|
||||
}
|
||||
});
|
||||
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 = "";
|
||||
}
|
||||
},
|
||||
function() {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(1)").css("cursor", "pointer");
|
||||
// Domain
|
||||
api.$("td:eq(2)").click(function() {
|
||||
if (autofilter()) {
|
||||
api.search(this.textContent).draw();
|
||||
$("#resetButton").show();
|
||||
}
|
||||
});
|
||||
api.$("td:eq(2)").hover(
|
||||
function() {
|
||||
if (autofilter()) {
|
||||
this.title = "Click to show only queries with domain " + this.textContent;
|
||||
this.style.color = "#72afd2";
|
||||
} else {
|
||||
this.title = "";
|
||||
this.style.color = "";
|
||||
}
|
||||
},
|
||||
function() {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(2)").css("cursor", "pointer");
|
||||
// Client
|
||||
api.$("td:eq(3)").click(function() {
|
||||
if (autofilter()) {
|
||||
api.search(this.textContent).draw();
|
||||
$("#resetButton").show();
|
||||
}
|
||||
});
|
||||
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 = "";
|
||||
}
|
||||
},
|
||||
function() {
|
||||
this.style.color = "";
|
||||
}
|
||||
);
|
||||
api.$("td:eq(3)").css("cursor", "pointer");
|
||||
}
|
||||
});
|
||||
|
||||
$("#all-queries tbody").on("click", "button", function() {
|
||||
var data = tableApi.row($(this).parents("tr")).data();
|
||||
if (data[4] === "1" || data[4] === "4" || data[4] === "5") {
|
||||
add(data[2], "white");
|
||||
} else {
|
||||
add(data[2], "black");
|
||||
}
|
||||
});
|
||||
|
||||
$("#resetButton").click(function() {
|
||||
tableApi.search("").draw();
|
||||
$("#resetButton").hide();
|
||||
});
|
||||
});
|
||||
|
||||
+112
-104
@@ -1,144 +1,152 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
/* global ActiveXObject: false */
|
||||
|
||||
var exact = "";
|
||||
|
||||
function quietfilter(ta,data)
|
||||
{
|
||||
var lines = data.split("\n");
|
||||
for(var i = 0; i<lines.length; i++)
|
||||
{
|
||||
if(lines[i].indexOf("results") !== -1 && lines[i].indexOf("0 results") === -1)
|
||||
{
|
||||
var shortstring = lines[i].replace("::: /etc/pihole/","");
|
||||
// Remove "(x results)"
|
||||
shortstring = shortstring.replace(/\(.*/,"");
|
||||
ta.append(shortstring+"\n");
|
||||
}
|
||||
function quietfilter(ta, data) {
|
||||
var lines = data.split("\n");
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
if (lines[i].indexOf("results") !== -1 && lines[i].indexOf("0 results") === -1) {
|
||||
var shortstring = lines[i].replace("::: /etc/pihole/", "");
|
||||
// Remove "(x results)"
|
||||
shortstring = shortstring.replace(/\(.*/, "");
|
||||
ta.append(shortstring + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Credit: http://stackoverflow.com/a/10642418/2087442
|
||||
function httpGet(ta,quiet,theUrl)
|
||||
{
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest)
|
||||
{
|
||||
function httpGet(ta, quiet, theUrl) {
|
||||
var xmlhttp;
|
||||
if (window.XMLHttpRequest) {
|
||||
// code for IE7+
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
}
|
||||
else
|
||||
{
|
||||
xmlhttp = new XMLHttpRequest();
|
||||
} else {
|
||||
// code for IE6, IE5
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
|
||||
xmlhttp.onreadystatechange = function() {
|
||||
if (xmlhttp.readyState === 4 && xmlhttp.status === 200) {
|
||||
ta.show();
|
||||
ta.empty();
|
||||
if (!quiet) {
|
||||
ta.append(xmlhttp.responseText);
|
||||
} else {
|
||||
quietfilter(ta, xmlhttp.responseText);
|
||||
}
|
||||
}
|
||||
xmlhttp.onreadystatechange=function()
|
||||
{
|
||||
if (xmlhttp.readyState === 4 && xmlhttp.status === 200)
|
||||
{
|
||||
ta.show();
|
||||
ta.empty();
|
||||
if(!quiet)
|
||||
{
|
||||
ta.append(xmlhttp.responseText);
|
||||
}
|
||||
else
|
||||
{
|
||||
quietfilter(ta,xmlhttp.responseText);
|
||||
}
|
||||
}
|
||||
};
|
||||
xmlhttp.open("GET", theUrl, false);
|
||||
xmlhttp.send();
|
||||
};
|
||||
|
||||
xmlhttp.open("GET", theUrl, false);
|
||||
xmlhttp.send();
|
||||
}
|
||||
|
||||
function eventsource() {
|
||||
var ta = $("#output");
|
||||
var domain = $("#domain").val().trim();
|
||||
var q = $("#quiet");
|
||||
var ta = $("#output");
|
||||
var domain = $("#domain")
|
||||
.val()
|
||||
.trim();
|
||||
var q = $("#quiet");
|
||||
|
||||
if(domain.length === 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (domain.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
var quiet = false;
|
||||
if(q.val() === "yes")
|
||||
{
|
||||
quiet = true;
|
||||
exact = "exact";
|
||||
}
|
||||
var quiet = false;
|
||||
if (q.val() === "yes") {
|
||||
quiet = true;
|
||||
exact = "exact";
|
||||
}
|
||||
|
||||
// IE does not support EventSource - load whole content at once
|
||||
if (typeof EventSource !== "function") {
|
||||
httpGet(ta,quiet,"scripts/pi-hole/php/queryads.php?domain="+domain.toLowerCase()+exact+"&IE");
|
||||
return;
|
||||
}
|
||||
// IE does not support EventSource - load whole content at once
|
||||
if (typeof EventSource !== "function") {
|
||||
httpGet(
|
||||
ta,
|
||||
quiet,
|
||||
"scripts/pi-hole/php/queryads.php?domain=" + domain.toLowerCase() + exact + "&IE"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var source = new EventSource("scripts/pi-hole/php/queryads.php?domain="+domain.toLowerCase()+"&"+exact);
|
||||
var source = new EventSource(
|
||||
"scripts/pi-hole/php/queryads.php?domain=" + domain.toLowerCase() + "&" + exact
|
||||
);
|
||||
|
||||
// Reset and show field
|
||||
ta.empty();
|
||||
ta.show();
|
||||
// Reset and show field
|
||||
ta.empty();
|
||||
ta.show();
|
||||
|
||||
source.addEventListener("message", function(e) {
|
||||
if(!quiet)
|
||||
{
|
||||
ta.append(e.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
quietfilter(ta,e.data);
|
||||
}
|
||||
}, false);
|
||||
source.addEventListener(
|
||||
"message",
|
||||
function(e) {
|
||||
if (!quiet) {
|
||||
ta.append(e.data);
|
||||
} else {
|
||||
quietfilter(ta, e.data);
|
||||
}
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Will be called when script has finished
|
||||
source.addEventListener("error", function() {
|
||||
source.close();
|
||||
}, false);
|
||||
// Will be called when script has finished
|
||||
source.addEventListener(
|
||||
"error",
|
||||
function() {
|
||||
source.close();
|
||||
},
|
||||
false
|
||||
);
|
||||
|
||||
// Reset exact variable
|
||||
exact = "";
|
||||
// Reset exact variable
|
||||
exact = "";
|
||||
}
|
||||
|
||||
// Handle enter button
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#domain").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
exact = "";
|
||||
eventsource();
|
||||
}
|
||||
if (e.which === 13 && $("#domain").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
exact = "";
|
||||
eventsource();
|
||||
}
|
||||
});
|
||||
// Handle button
|
||||
$("#btnSearch").on("click", function() {
|
||||
exact = "";
|
||||
eventsource();
|
||||
exact = "";
|
||||
eventsource();
|
||||
});
|
||||
// Handle exact button
|
||||
$("#btnSearchExact").on("click", function() {
|
||||
exact = "exact";
|
||||
eventsource();
|
||||
exact = "exact";
|
||||
eventsource();
|
||||
});
|
||||
|
||||
// Wrap form-group's buttons to next line when viewed on a small screen
|
||||
$(window).on("resize",function() {
|
||||
if ($(window).width() < 991) {
|
||||
$(".form-group.input-group").removeClass("input-group").addClass("input-group-block");
|
||||
$(".form-group.input-group-block > input").css("margin-bottom", "5px");
|
||||
$(".form-group.input-group-block > .input-group-btn").removeClass("input-group-btn").addClass("btn-block text-center");
|
||||
}
|
||||
else {
|
||||
$(".form-group.input-group-block").removeClass("input-group-block").addClass( "input-group" );
|
||||
$(".form-group.input-group > input").css("margin-bottom","");
|
||||
$(".form-group.input-group > .btn-block.text-center").removeClass("btn-block text-center").addClass("input-group-btn");
|
||||
}
|
||||
$(window).on("resize", function() {
|
||||
if ($(window).width() < 991) {
|
||||
$(".form-group.input-group")
|
||||
.removeClass("input-group")
|
||||
.addClass("input-group-block");
|
||||
$(".form-group.input-group-block > input").css("margin-bottom", "5px");
|
||||
$(".form-group.input-group-block > .input-group-btn")
|
||||
.removeClass("input-group-btn")
|
||||
.addClass("btn-block text-center");
|
||||
} else {
|
||||
$(".form-group.input-group-block")
|
||||
.removeClass("input-group-block")
|
||||
.addClass("input-group");
|
||||
$(".form-group.input-group > input").css("margin-bottom", "");
|
||||
$(".form-group.input-group > .btn-block.text-center")
|
||||
.removeClass("btn-block text-center")
|
||||
.addClass("input-group-btn");
|
||||
}
|
||||
});
|
||||
$(document).ready(function() {
|
||||
$(window).trigger("resize");
|
||||
$(window).trigger("resize");
|
||||
});
|
||||
|
||||
+208
-201
@@ -1,254 +1,261 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
$(function () {
|
||||
$("[data-static]").on("click", function(){
|
||||
var row = $(this).closest("tr");
|
||||
var mac = row.find("#MAC").text();
|
||||
var ip = row.find("#IP").text();
|
||||
var host = row.find("#HOST").text();
|
||||
$("input[name=\"AddHostname\"]").val(host);
|
||||
$("input[name=\"AddIP\"]").val(ip);
|
||||
$("input[name=\"AddMAC\"]").val(mac);
|
||||
});
|
||||
$(function() {
|
||||
$("[data-static]").on("click", function() {
|
||||
var row = $(this).closest("tr");
|
||||
var mac = row.find("#MAC").text();
|
||||
var ip = row.find("#IP").text();
|
||||
var host = row.find("#HOST").text();
|
||||
$('input[name="AddHostname"]').val(host);
|
||||
$('input[name="AddIP"]').val(ip);
|
||||
$('input[name="AddMAC"]').val(mac);
|
||||
});
|
||||
});
|
||||
$(".confirm-poweroff").confirm({
|
||||
text: "Are you sure you want to send a poweroff command to your Pi-Hole?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#poweroffform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, poweroff",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
|
||||
text: "Are you sure you want to send a poweroff command to your Pi-Hole?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#poweroffform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, poweroff",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
|
||||
});
|
||||
$(".confirm-reboot").confirm({
|
||||
text: "Are you sure you want to send a reboot command to your Pi-Hole?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#rebootform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, reboot",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
|
||||
text: "Are you sure you want to send a reboot command to your Pi-Hole?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#rebootform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, reboot",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg" // Bootstrap classes for mid-size modal
|
||||
});
|
||||
|
||||
$(".confirm-restartdns").confirm({
|
||||
text: "Are you sure you want to send a restart command to your DNS server?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#restartdnsform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, restart DNS",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
text: "Are you sure you want to send a restart command to your DNS server?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#restartdnsform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, restart DNS",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$(".confirm-flushlogs").confirm({
|
||||
text: "Are you sure you want to flush your logs?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#flushlogsform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, flush logs",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
text: "Are you sure you want to flush your logs?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#flushlogsform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, flush logs",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$(".confirm-flusharp").confirm({
|
||||
text: "Are you sure you want to flush your network table?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#flusharpform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, flush my network table",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-warning",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
text: "Are you sure you want to flush your network table?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#flusharpform").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, flush my network table",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-warning",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$(".confirm-disablelogging-noflush").confirm({
|
||||
text: "Are you sure you want to disable logging?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#disablelogsform-noflush").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, disable logs",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-warning",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
text: "Are you sure you want to disable logging?",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
$("#disablelogsform-noflush").submit();
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, disable logs",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-warning",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$(".api-token").confirm({
|
||||
text: "Make sure that nobody else can scan this code around you. They will have full access to the API without having to know the password. Note that the generation of the QR code will take some time.",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
window.open("scripts/pi-hole/php/api_token.php");
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, show API token",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
text:
|
||||
"Make sure that nobody else can scan this code around you. They will have full access to the API without having to know the password. Note that the generation of the QR code will take some time.",
|
||||
title: "Confirmation required",
|
||||
confirm: function() {
|
||||
window.open("scripts/pi-hole/php/api_token.php");
|
||||
},
|
||||
cancel: function() {
|
||||
// nothing to do
|
||||
},
|
||||
confirmButton: "Yes, show API token",
|
||||
cancelButton: "No, go back",
|
||||
post: true,
|
||||
confirmButtonClass: "btn-danger",
|
||||
cancelButtonClass: "btn-success",
|
||||
dialogClass: "modal-dialog modal-mg"
|
||||
});
|
||||
|
||||
$("#DHCPchk").click(function() {
|
||||
$("input.DHCPgroup").prop("disabled", !this.checked);
|
||||
$("#dhcpnotice").prop("hidden", !this.checked).addClass("lookatme");
|
||||
$("input.DHCPgroup").prop("disabled", !this.checked);
|
||||
$("#dhcpnotice")
|
||||
.prop("hidden", !this.checked)
|
||||
.addClass("lookatme");
|
||||
});
|
||||
|
||||
function loadCacheInfo()
|
||||
{
|
||||
$.getJSON("api.php?getCacheInfo", function(data) {
|
||||
if("FTLnotrunning" in data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
function loadCacheInfo() {
|
||||
$.getJSON("api.php?getCacheInfo", function(data) {
|
||||
if ("FTLnotrunning" in data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill table with obtained values
|
||||
$("#cache-size").text(parseInt(data.cacheinfo["cache-size"]));
|
||||
$("#cache-inserted").text(parseInt(data.cacheinfo["cache-inserted"]));
|
||||
// Fill table with obtained values
|
||||
$("#cache-size").text(parseInt(data.cacheinfo["cache-size"]));
|
||||
$("#cache-inserted").text(parseInt(data.cacheinfo["cache-inserted"]));
|
||||
|
||||
// Highlight early cache removals when present
|
||||
var cachelivefreed = parseInt(data.cacheinfo["cache-live-freed"]);
|
||||
$("#cache-live-freed").text(cachelivefreed);
|
||||
if(cachelivefreed > 0)
|
||||
{
|
||||
$("#cache-live-freed").parent("tr").addClass("lookatme");
|
||||
}
|
||||
else
|
||||
{
|
||||
$("#cache-live-freed").parent("tr").removeClass("lookatme");
|
||||
}
|
||||
// Highlight early cache removals when present
|
||||
var cachelivefreed = parseInt(data.cacheinfo["cache-live-freed"]);
|
||||
$("#cache-live-freed").text(cachelivefreed);
|
||||
if (cachelivefreed > 0) {
|
||||
$("#cache-live-freed")
|
||||
.parent("tr")
|
||||
.addClass("lookatme");
|
||||
} else {
|
||||
$("#cache-live-freed")
|
||||
.parent("tr")
|
||||
.removeClass("lookatme");
|
||||
}
|
||||
|
||||
// Update cache info every 10 seconds
|
||||
setTimeout(loadCacheInfo, 10000);
|
||||
});
|
||||
// Update cache info every 10 seconds
|
||||
setTimeout(loadCacheInfo, 10000);
|
||||
});
|
||||
}
|
||||
|
||||
var leasetable, staticleasetable;
|
||||
$(document).ready(function() {
|
||||
if(document.getElementById("DHCPLeasesTable"))
|
||||
{
|
||||
leasetable = $("#DHCPLeasesTable").DataTable({
|
||||
dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-6'i><'col-sm-6'f>>",
|
||||
"columnDefs": [ { "bSortable": false, "orderable": false, targets: -1} ],
|
||||
"paging": false,
|
||||
"scrollCollapse": true,
|
||||
"scrollY": "200px",
|
||||
"scrollX" : true
|
||||
});
|
||||
}
|
||||
if(document.getElementById("DHCPStaticLeasesTable"))
|
||||
{
|
||||
staticleasetable = $("#DHCPStaticLeasesTable").DataTable({
|
||||
dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-12'i>>",
|
||||
"columnDefs": [ { "bSortable": false, "orderable": false, targets: -1} ],
|
||||
"paging": false,
|
||||
"scrollCollapse": true,
|
||||
"scrollY": "200px",
|
||||
"scrollX" : true
|
||||
});
|
||||
}
|
||||
//call draw() on each table... they don't render properly with scrollX and scrollY set... ¯\_(ツ)_/¯
|
||||
$("a[data-toggle=\"tab\"]").on("shown.bs.tab", function () {
|
||||
leasetable.draw();
|
||||
staticleasetable.draw();
|
||||
if (document.getElementById("DHCPLeasesTable")) {
|
||||
leasetable = $("#DHCPLeasesTable").DataTable({
|
||||
dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-6'i><'col-sm-6'f>>",
|
||||
columnDefs: [{ bSortable: false, orderable: false, targets: -1 }],
|
||||
paging: false,
|
||||
scrollCollapse: true,
|
||||
scrollY: "200px",
|
||||
scrollX: true
|
||||
});
|
||||
}
|
||||
|
||||
loadCacheInfo();
|
||||
if (document.getElementById("DHCPStaticLeasesTable")) {
|
||||
staticleasetable = $("#DHCPStaticLeasesTable").DataTable({
|
||||
dom: "<'row'<'col-sm-12'tr>><'row'<'col-sm-12'i>>",
|
||||
columnDefs: [{ bSortable: false, orderable: false, targets: -1 }],
|
||||
paging: false,
|
||||
scrollCollapse: true,
|
||||
scrollY: "200px",
|
||||
scrollX: true
|
||||
});
|
||||
}
|
||||
|
||||
} );
|
||||
//call draw() on each table... they don't render properly with scrollX and scrollY set... ¯\_(ツ)_/¯
|
||||
$('a[data-toggle="tab"]').on("shown.bs.tab", function() {
|
||||
leasetable.draw();
|
||||
staticleasetable.draw();
|
||||
});
|
||||
|
||||
loadCacheInfo();
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
$(function() {
|
||||
$("[data-hide]").on("click", function() {
|
||||
$(this)
|
||||
.closest("." + $(this).attr("data-hide"))
|
||||
.hide();
|
||||
});
|
||||
});
|
||||
|
||||
// DHCP leases tooltips
|
||||
$(document).ready(function(){
|
||||
$("[data-toggle=\"tooltip\"]").tooltip({"html": true, container : "body"});
|
||||
$(document).ready(function() {
|
||||
$('[data-toggle="tooltip"]').tooltip({ html: true, container: "body" });
|
||||
});
|
||||
|
||||
// Handle list deletion
|
||||
$("button[id^='adlist-btn-']").on("click", function (e) {
|
||||
var id = parseInt($(this).context.id.replace(/[^0-9.]/g, ""), 10);
|
||||
e.preventDefault();
|
||||
$("button[id^='adlist-btn-']").on("click", function(e) {
|
||||
var id = parseInt($(this).context.id.replace(/[^0-9.]/g, ""), 10);
|
||||
e.preventDefault();
|
||||
|
||||
var status = $("input[name=\"adlist-del-"+id+"\"]").is(":checked");
|
||||
var textType = status ? "none" : "line-through";
|
||||
|
||||
// Check hidden delete box (or reset)
|
||||
$("input[name=\"adlist-del-"+id+"\"]").prop("checked", !status);
|
||||
// Untick and disable check box (or reset)
|
||||
$("input[name=\"adlist-enable-"+id+"\"]").prop("checked", status).prop("disabled", !status);
|
||||
// Strike through text (or reset)
|
||||
$("a[id=\"adlist-text-"+id+"\"]").css("text-decoration", textType);
|
||||
// Highlight that the button has to be clicked in order to make the change live
|
||||
$("button[id=\"blockinglistsaveupdate\"]").addClass("btn-danger").css("font-weight", "bold");
|
||||
var status = $('input[name="adlist-del-' + id + '"]').is(":checked");
|
||||
var textType = status ? "none" : "line-through";
|
||||
|
||||
// Check hidden delete box (or reset)
|
||||
$('input[name="adlist-del-' + id + '"]').prop("checked", !status);
|
||||
// Untick and disable check box (or reset)
|
||||
$('input[name="adlist-enable-' + id + '"]')
|
||||
.prop("checked", status)
|
||||
.prop("disabled", !status);
|
||||
// Strike through text (or reset)
|
||||
$('a[id="adlist-text-' + id + '"]').css("text-decoration", textType);
|
||||
// Highlight that the button has to be clicked in order to make the change live
|
||||
$('button[id="blockinglistsaveupdate"]')
|
||||
.addClass("btn-danger")
|
||||
.css("font-weight", "bold");
|
||||
});
|
||||
|
||||
// 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);
|
||||
$(".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
|
||||
$(document).ready(function(){
|
||||
var alInfo = $("#alInfo");
|
||||
if(alInfo.length)
|
||||
{
|
||||
alInfo.delay(3000).fadeOut(2000, function() { alInfo.hide(); });
|
||||
}
|
||||
$(document).ready(function() {
|
||||
var alInfo = $("#alInfo");
|
||||
if (alInfo.length) {
|
||||
alInfo.delay(3000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
var offset, timer, pre, scrolling = true;
|
||||
var offset,
|
||||
timer,
|
||||
pre,
|
||||
scrolling = true;
|
||||
|
||||
// Check every 200msec for fresh data
|
||||
var interval = 200;
|
||||
|
||||
// Function that asks the API for new data
|
||||
function reloadData(){
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL&offset="+offset, function (data)
|
||||
{
|
||||
pre.append(data.lines);
|
||||
function reloadData() {
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL&offset=" + offset, function(data) {
|
||||
pre.append(data.lines);
|
||||
|
||||
if(scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
if (scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
|
||||
offset = data.offset;
|
||||
});
|
||||
offset = data.offset;
|
||||
});
|
||||
|
||||
timer = setTimeout(reloadData, interval);
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
$(function(){
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL", function (data)
|
||||
{
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
$(function() {
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?FTL", function(data) {
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").click(function() {
|
||||
$("#chk2").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").click(function() {
|
||||
$("#chk1").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
|
||||
@@ -1,48 +1,49 @@
|
||||
/* 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. */
|
||||
* (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. */
|
||||
|
||||
var offset, timer, pre, scrolling = true;
|
||||
var offset,
|
||||
timer,
|
||||
pre,
|
||||
scrolling = true;
|
||||
|
||||
// Check every 200msec for fresh data
|
||||
var interval = 200;
|
||||
|
||||
// Function that asks the API for new data
|
||||
function reloadData(){
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?offset="+offset, function (data)
|
||||
{
|
||||
pre.append(data.lines);
|
||||
function reloadData() {
|
||||
clearTimeout(timer);
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php?offset=" + offset, function(data) {
|
||||
pre.append(data.lines);
|
||||
|
||||
if(scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
if (scrolling && offset !== data.offset) {
|
||||
pre.scrollTop(pre[0].scrollHeight);
|
||||
}
|
||||
|
||||
offset = data.offset;
|
||||
});
|
||||
offset = data.offset;
|
||||
});
|
||||
|
||||
timer = setTimeout(reloadData, interval);
|
||||
timer = setTimeout(reloadData, interval);
|
||||
}
|
||||
|
||||
$(function(){
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php", function (data)
|
||||
{
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
$(function() {
|
||||
// Get offset at first loading of page
|
||||
$.getJSON("scripts/pi-hole/php/tailLog.php", function(data) {
|
||||
offset = data.offset;
|
||||
});
|
||||
pre = $("#output");
|
||||
// Trigger function that looks for new data
|
||||
reloadData();
|
||||
});
|
||||
|
||||
$("#chk1").click(function() {
|
||||
$("#chk2").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
$("#chk2").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
$("#chk2").click(function() {
|
||||
$("#chk1").prop("checked",this.checked);
|
||||
scrolling = this.checked;
|
||||
$("#chk1").prop("checked", this.checked);
|
||||
scrolling = this.checked;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user