mirror of
https://github.com/pi-hole/web.git
synced 2024-12-06 19:36:21 +01:00
@@ -47,6 +47,18 @@
|
||||
$data = array_merge($data, getAllQueries());
|
||||
}
|
||||
|
||||
|
||||
function filterArray(&$a) {
|
||||
$sanArray = array();
|
||||
foreach ($a as $k=>$v) {
|
||||
if (is_array($v)) {
|
||||
$sanArray[htmlspecialchars($k)] = filterArray($v);
|
||||
} else {
|
||||
$sanArray[htmlspecialchars($k)] = htmlspecialchars($v);
|
||||
}
|
||||
}
|
||||
return $sanArray;
|
||||
}
|
||||
|
||||
$data = filterArray($data);
|
||||
echo json_encode($data);
|
||||
?>
|
||||
|
||||
File diff suppressed because one or more lines are too long
+19
-2
@@ -1,4 +1,4 @@
|
||||
/* Made by Verpz https://github.com/Verpz/ Licensed Under Apache License 2.0 Details On GitHub */
|
||||
/* Made by Verpz https://github.com/Verpz/ Licensed Under MIT License Details On GitHub */
|
||||
.js-warn {
|
||||
background: #EEE;
|
||||
color: #555;
|
||||
@@ -10,7 +10,7 @@
|
||||
margin-left: auto;
|
||||
margin-top: 50px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0px 10px 70px;
|
||||
box-shadow: 0 10px 70px;
|
||||
text-align: center;
|
||||
position: fixed;
|
||||
font-family: sans-serif, serif;
|
||||
@@ -23,6 +23,7 @@
|
||||
padding: 10px 10px 0 10px;
|
||||
}
|
||||
.js-warn p {
|
||||
font-family: sans-serif, serif;
|
||||
padding: 0 10px 10px 10px;
|
||||
}
|
||||
.js-warn a {
|
||||
@@ -52,3 +53,19 @@
|
||||
border-radius: 3px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 700px) {
|
||||
.js-warn {
|
||||
width: 60%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 400px) {
|
||||
.js-warn {
|
||||
width: 80%;
|
||||
}
|
||||
.js-warn h1 {
|
||||
font-size: large;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
<?php
|
||||
$log = array();
|
||||
$ipv6 = file_exists("/etc/pihole/.useIPv6");
|
||||
$hosts = file_exists("/etc/hosts") ? file("/etc/hosts") : array();
|
||||
|
||||
|
||||
/******* Public Members ********/
|
||||
function getSummaryData() {
|
||||
global $ipv6;
|
||||
global $ipv6;
|
||||
$log = readInLog();
|
||||
$domains_being_blocked = gravityCount() / ($ipv6 ? 2 : 1);
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
);
|
||||
}
|
||||
|
||||
function getOverTimeData() {
|
||||
function getOverTimeData() {
|
||||
$log = readInLog();
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$ads_blocked = getBlockedQueries($log);
|
||||
@@ -37,7 +37,7 @@
|
||||
);
|
||||
}
|
||||
|
||||
function getTopItems() {
|
||||
function getTopItems() {
|
||||
$log = readInLog();
|
||||
$dns_queries = getDnsQueries($log);
|
||||
$ads_blocked = getBlockedQueries($log);
|
||||
@@ -112,7 +112,7 @@
|
||||
}
|
||||
}
|
||||
arsort($sources);
|
||||
array_slice($sources, 0, 10);
|
||||
$sources = array_slice($sources, 0, 10);
|
||||
return Array(
|
||||
'top_sources' => $sources
|
||||
);
|
||||
@@ -127,7 +127,7 @@
|
||||
$time = date_create(substr($query, 0, 16));
|
||||
$exploded = explode(" ", trim($query));
|
||||
$tmp = $exploded[count($exploded)-4];
|
||||
|
||||
|
||||
if (substr($tmp, 0, 5) == "query"){
|
||||
$type = substr($exploded[count($exploded)-4], 6, -1);
|
||||
$domain = $exploded[count($exploded)-3];
|
||||
@@ -140,7 +140,7 @@
|
||||
elseif (substr($tmp, strlen($tmp) - 12, 12) == "gravity.list" && $exploded[count($exploded)-5] != "read"){
|
||||
$status="Pi-holed";
|
||||
}
|
||||
|
||||
|
||||
if ( $status != ""){
|
||||
array_push($allQueries['data'], array(
|
||||
$time->format('Y-m-d\TH:i:s'),
|
||||
@@ -148,10 +148,10 @@
|
||||
$domain,
|
||||
hasHostName($client),
|
||||
$status,
|
||||
));
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
return $allQueries;
|
||||
}
|
||||
@@ -164,11 +164,11 @@
|
||||
$NGC4889 = fopen($gravity, "r");
|
||||
while ($stars = fread($NGC4889, 1024000)) {
|
||||
$swallowed += substr_count($stars, "\n");
|
||||
}
|
||||
}
|
||||
fclose($NGC4889);
|
||||
|
||||
|
||||
return $swallowed;
|
||||
|
||||
|
||||
}
|
||||
function readInLog() {
|
||||
global $log;
|
||||
@@ -226,7 +226,7 @@
|
||||
function alignTimeArrays(&$times1, &$times2) {
|
||||
$max = max(array(max(array_keys($times1)), max(array_keys($times2))));
|
||||
$min = min(array(min(array_keys($times1)), min(array_keys($times2))));
|
||||
|
||||
|
||||
for ($i = $min; $i <= $max; $i++) {
|
||||
if (!isset($times2[$i])) {
|
||||
$times2[$i] = 0;
|
||||
@@ -258,7 +258,7 @@
|
||||
function findQueriesAll($var) {
|
||||
return strpos($var, ": query[") || strpos($var, "gravity.list") || strpos($var, ": forwarded") !== false;
|
||||
}
|
||||
|
||||
|
||||
function findQueries($var) {
|
||||
return strpos($var, ": query[") !== false;
|
||||
}
|
||||
@@ -274,15 +274,15 @@
|
||||
function findForwards($var) {
|
||||
return strpos($var, ": forwarded") !== false;
|
||||
}
|
||||
|
||||
|
||||
function hasHostName($var){
|
||||
global $hosts;
|
||||
foreach ($hosts as $host){
|
||||
$x = explode("\t", $host);
|
||||
$x = preg_split('/\s+/', $host);
|
||||
if ( $var == $x[0] ){
|
||||
$var = $x[1] . "($var)";
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
+15
-9
@@ -4,21 +4,27 @@
|
||||
<!-- /.content-wrapper -->
|
||||
<footer class="main-footer">
|
||||
<div class="pull-right hidden-xs">
|
||||
<b>Pi-hole Version </b> <?php echo exec("cd /etc/.pihole/ && git describe --tags --abbrev=0"); ?>
|
||||
<b>Web Interface Version </b> <?php echo exec("cd /var/www/html/admin/ && git describe --tags --abbrev=0"); ?>
|
||||
<?php
|
||||
$piholeVersion = exec("cd /etc/.pihole/ && git describe --tags --abbrev=0");
|
||||
$webVersion = exec("cd /var/www/html/admin/ && git describe --tags --abbrev=0");
|
||||
?>
|
||||
<b>Pi-hole Version </b> <div id="piholeVersion" style="display: inline"><?php echo $piholeVersion; ?></div>
|
||||
<b>Web Interface Version </b> <div id="webVersion" style="display: inline"><?php echo $webVersion; ?></div>
|
||||
</div>
|
||||
<i class="fa fa-github"></i> <strong><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">Donate</a></strong> if you found this useful.
|
||||
</footer>
|
||||
</div>
|
||||
<!-- ./wrapper -->
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/jquery-ui.min.js"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/app.min.js" type="text/javascript"></script>
|
||||
<script src="js/other/jquery.min.js"></script>
|
||||
<script src="js/other/jquery-ui.min.js"></script>
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
<script src="js/other/app.min.js"></script>
|
||||
|
||||
<script src="js/jquery.dataTables.min.js" type="text/javascript"></script>
|
||||
<script src="js/dataTables.bootstrap.min.js" type="text/javascript"></script>
|
||||
<script src="js/Chart.min.js"></script>
|
||||
<script src="js/other/jquery.dataTables.min.js"></script>
|
||||
<script src="js/other/dataTables.bootstrap.min.js"></script>
|
||||
<script src="js/other/Chart.min.js"></script>
|
||||
|
||||
<script src="js/pihole/footer.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+25
-11
@@ -2,6 +2,7 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' https://api.github.com; script-src 'self' 'unsafe-eval'; style-src 'self' 'unsafe-inline'">
|
||||
<title>Pi-hole Admin Console</title>
|
||||
<!-- Tell the browser to be responsive to screen width -->
|
||||
<meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
|
||||
@@ -27,11 +28,20 @@
|
||||
</style>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="js/html5shiv.min.js"></script>
|
||||
<script src="js/respond.min.js"></script>
|
||||
<script src="js/other/html5shiv.min.js"></script>
|
||||
<script src="js/other/respond.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body class="skin-blue sidebar-mini">
|
||||
<!-- JS Warning -->
|
||||
<div>
|
||||
<link rel="stylesheet" type="text/css" href="css/js-warn.css">
|
||||
<input type="checkbox" id="js-hide" />
|
||||
<div class="js-warn" id="js-warn-exit"><h1>Javascript Is Disabled</h1><p>Javascript seems to be disabled. This will break some site features.</p>
|
||||
<p>To enable Javascript click <a href="http://www.enable-javascript.com/" target="_blank">here</a></p><label for="js-hide">Close</label></div>
|
||||
</div>
|
||||
<!-- /JS Warning -->
|
||||
<script src="js/pihole/header.js"></script>
|
||||
<div class="wrapper">
|
||||
<header class="main-header">
|
||||
<!-- Logo -->
|
||||
@@ -50,8 +60,8 @@
|
||||
<div class="navbar-custom-menu">
|
||||
<ul class="nav navbar-nav">
|
||||
<!-- User Account: style can be found in dropdown.less -->
|
||||
<li class="dropdown user user-menu">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<li id="dropdown-menu" class="dropdown user user-menu">
|
||||
<a href="#" class="dropdown-toggle">
|
||||
<img src="img/pihole-160x160.jpg" class="user-image" alt="Pi-hole logo" />
|
||||
<span class="hidden-xs">Pi-hole</span>
|
||||
</a>
|
||||
@@ -76,14 +86,22 @@
|
||||
<a href="https://github.com/pi-hole/pi-hole/releases">Updates</a>
|
||||
</div>
|
||||
</li>
|
||||
<!-- Menu Footer-->
|
||||
<!-- Menu Footer -->
|
||||
<li class="user-footer">
|
||||
<!-- Update alerts -->
|
||||
<div id="alPiholeUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
||||
<a class="alert-link" href="https://github.com/pi-hole/pi-hole/releases">There's an update available for this Pi-hole!</a>
|
||||
</div>
|
||||
<div id="alWebUpdate" class="alert alert-info alert-dismissible fade in" role="alert" hidden>
|
||||
<a class="alert-link" href="https://github.com/pi-hole/AdminLTE/releases">There's an update available for this Web Interface!</a>
|
||||
</div>
|
||||
|
||||
<!-- PayPal -->
|
||||
<div>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="3J2L3Z4DHW9UY">
|
||||
<input style="display: block; margin: 0 auto;" type="image" src="img/donate.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
</div>
|
||||
</li>
|
||||
@@ -130,21 +148,17 @@
|
||||
</a>
|
||||
</li>
|
||||
<!-- Whitelist -->
|
||||
<!--
|
||||
<li>
|
||||
<a href="list.php?l=white">
|
||||
<i class="fa fa-pencil-square-o"></i> <span>Whitelist</span>
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
<!-- Blacklist -->
|
||||
<!--
|
||||
<li>
|
||||
<a href="list.php?l=black">
|
||||
<i class="fa fa-pencil-square-o"></i> <span>Blacklist</span>
|
||||
<i class="fa fa-ban"></i> <span>Blacklist</span>
|
||||
</a>
|
||||
</li>
|
||||
-->
|
||||
<!-- Donate -->
|
||||
<li>
|
||||
<a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3J2L3Z4DHW9UY">
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
<?php
|
||||
require "header.html";
|
||||
?>
|
||||
<!-- JS Warning -->
|
||||
<div>
|
||||
<link rel="stylesheet" type="text/css" href="css/js-warn.css">
|
||||
<input type="checkbox" id="js-hide" />
|
||||
<div class="js-warn" id="js-warn-exit"><h1>Javascript Is Disabled</h1><p>Javascript seems to be disabled. This will break some site features.</p>
|
||||
<p>To enable Javascript click <a href="http://www.enable-javascript.com/" target="_blank">here</a></p><label for="js-hide">Close</label></div>
|
||||
<script>var jswarn = document.getElementById("js-warn-exit"); jswarn.parentNode.removeChild(jswarn);</script>
|
||||
</div>
|
||||
<!-- /JS Warning -->
|
||||
<!-- Small boxes (Stat box) -->
|
||||
<div class="row">
|
||||
<div class="col-lg-3 col-xs-6">
|
||||
@@ -199,190 +190,4 @@
|
||||
require "footer.php";
|
||||
?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
// Pull in data via AJAX
|
||||
|
||||
updateSummaryData();
|
||||
|
||||
updateQueriesOverTime();
|
||||
|
||||
updateQueryTypes();
|
||||
|
||||
updateTopClientsChart();
|
||||
|
||||
updateForwardDestinations();
|
||||
|
||||
updateTopLists();
|
||||
|
||||
// Create charts
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "All Queries",
|
||||
fillColor: "rgba(220,220,220,0.5)",
|
||||
strokeColor: "rgba(0, 166, 90,.8)",
|
||||
pointColor: "rgba(0, 166, 90,.8)"
|
||||
},
|
||||
{
|
||||
label: "Ad Queries",
|
||||
fillColor: "rgba(0,192,239,0.5)",
|
||||
strokeColor: "rgba(0,192,239,1)",
|
||||
pointColor: "rgba(0,192,239,1)"
|
||||
}
|
||||
]
|
||||
};
|
||||
var isMobile = {
|
||||
Windows: function() {
|
||||
return /IEMobile/i.test(navigator.userAgent);
|
||||
},
|
||||
Android: function() {
|
||||
return /Android/i.test(navigator.userAgent);
|
||||
},
|
||||
BlackBerry: function() {
|
||||
return /BlackBerry/i.test(navigator.userAgent);
|
||||
},
|
||||
iOS: function() {
|
||||
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
},
|
||||
any: function() {
|
||||
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
|
||||
}
|
||||
};
|
||||
var animate = false;
|
||||
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
|
||||
timeLineChart = new Chart(ctx).Line(chartData,
|
||||
{
|
||||
pointDot : false,
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
|
||||
ctx = document.getElementById("queryTypeChart").getContext("2d");
|
||||
queryTypeChart = new Chart(ctx).Doughnut([],
|
||||
{
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].strokeColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
|
||||
ctx = document.getElementById("forwardDestinationChart").getContext("2d");
|
||||
forwardDestinationChart = new Chart(ctx).Doughnut([],
|
||||
{
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].strokeColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Functions to oupdate data in page
|
||||
|
||||
function updateSummaryData(runOnce) {
|
||||
$.getJSON("api.php?summary", function LoadSummaryData(data) {
|
||||
//$("h3.statistic").addClass("glow");
|
||||
if ($("h3#ads_blocked_today").text() != data.ads_blocked_today) {
|
||||
$("h3#ads_blocked_today").addClass("glow");
|
||||
}
|
||||
if ($("h3#dns_queries_today").text() != data.dns_queries_today) {
|
||||
$("h3#dns_queries_today").addClass("glow");
|
||||
}
|
||||
if ($("h3#ads_percentage_today").text() != data.ads_percentage_today) {
|
||||
$("h3#ads_percentage_today").addClass("glow");
|
||||
}
|
||||
|
||||
window.setTimeout(function(){
|
||||
$("h3#ads_blocked_today").text(data.ads_blocked_today);
|
||||
$("h3#dns_queries_today").text(data.dns_queries_today);
|
||||
$("h3#domains_being_blocked").text(data.domains_being_blocked);
|
||||
$("h3#ads_percentage_today").text(data.ads_percentage_today + "%");
|
||||
$("h3.statistic.glow").removeClass("glow")
|
||||
}, 500);
|
||||
}).done(function() {
|
||||
if (runOnce !== true) {
|
||||
setTimeout(updateSummaryData, 10000);
|
||||
}
|
||||
}).fail(function() {
|
||||
if (runOnce !== true) {
|
||||
setTimeout(updateSummaryData, (1000 * 60 * 5));
|
||||
}
|
||||
});;
|
||||
}
|
||||
|
||||
function updateQueriesOverTime() {
|
||||
$.getJSON("api.php?overTimeData", function(data) {
|
||||
for (hour in data.ads_over_time) {
|
||||
timeLineChart.addData([data.domains_over_time[hour], data.ads_over_time[hour]], hour + ":00");
|
||||
}
|
||||
$('#queries-over-time .overlay').remove();
|
||||
//$('#queries-over-time').append(timeLineChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopClientsChart() {
|
||||
$.getJSON("api.php?summaryRaw&getQuerySources", function(data) {
|
||||
var clienttable = $('#client-frequency').find('tbody:last');
|
||||
for (domain in data.top_sources) {
|
||||
clienttable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_sources[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-blue" style="width: ' +
|
||||
data.top_sources[domain] / data.dns_queries_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
|
||||
$('#client-frequency .overlay').remove();
|
||||
});
|
||||
}
|
||||
|
||||
function updateQueryTypes() {
|
||||
$.getJSON("api.php?getQueryTypes", function(data) {
|
||||
var colors = [];
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
$.each(data, function(key , value) {
|
||||
queryTypeChart.addData({
|
||||
value: value,
|
||||
color: colors.shift(),
|
||||
label: key.substr(6,key.length - 7)
|
||||
});
|
||||
});
|
||||
$('#query-types .overlay').remove();
|
||||
//$('#query-types').append(queryTypeChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateForwardDestinations() {
|
||||
$.getJSON("api.php?getForwardDestinations", function(data) {
|
||||
var colors = [];
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
$.each(data, function(key , value) {
|
||||
forwardDestinationChart.addData({
|
||||
value: value,
|
||||
color: colors.shift(),
|
||||
label: key
|
||||
});
|
||||
});
|
||||
$('#forward-destinations .overlay').remove();
|
||||
//$('#forward-destinations').append(forwardDestinationChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopLists() {
|
||||
$.getJSON("api.php?summaryRaw&topItems", function(data) {
|
||||
var domaintable = $('#domain-frequency').find('tbody:last');
|
||||
var adtable = $('#ad-frequency').find('tbody:last');
|
||||
|
||||
for (domain in data.top_queries) {
|
||||
domaintable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_queries[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-green" style="width: ' +
|
||||
data.top_queries[domain] / data.dns_queries_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
for (domain in data.top_ads) {
|
||||
adtable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_ads[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-yellow" style="width: ' +
|
||||
data.top_ads[domain] / data.ads_blocked_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
|
||||
$('#domain-frequency .overlay').remove();
|
||||
$('#ad-frequency .overlay').remove();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script src="js/pihole/index.js"></script>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
// User menu toggle
|
||||
$("#dropdown-menu a").on("click", function(event) {
|
||||
$(this).parent().toggleClass("open");
|
||||
});
|
||||
$("body").on("click", function(event) {
|
||||
if(!$("#dropdown-menu").is(event.target) && $("#dropdown-menu").has(event.target).length === 0) {
|
||||
$("#dropdown-menu").removeClass("open");
|
||||
}
|
||||
});
|
||||
|
||||
var piholeVersion = $("#piholeVersion").html();
|
||||
var webVersion = $("#webVersion").html();
|
||||
|
||||
// Credit for following function: https://gist.github.com/alexey-bass/1115557
|
||||
function versionCompare(left, right) {
|
||||
if (typeof left + typeof right != 'stringstring')
|
||||
return false;
|
||||
|
||||
var a = left.split('.')
|
||||
, b = right.split('.')
|
||||
, i = 0, len = Math.max(a.length, b.length);
|
||||
|
||||
for (; i < len; i++) {
|
||||
if ((a[i] && !b[i] && parseInt(a[i]) > 0) || (parseInt(a[i]) > parseInt(b[i]))) {
|
||||
return 1;
|
||||
} else if ((b[i] && !a[i] && parseInt(b[i]) > 0) || (parseInt(a[i]) < parseInt(b[i]))) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Update check
|
||||
$.getJSON("https://api.github.com/repos/pi-hole/pi-hole/releases/latest", function(json) {
|
||||
if(versionCompare(piholeVersion, json.tag_name.slice(1)) < 0) {
|
||||
// Alert user
|
||||
$("#alPiholeUpdate").show();
|
||||
if(!$("#dropdown-menu").hasClass("open")) {
|
||||
$("#dropdown-menu").addClass("open");
|
||||
}
|
||||
}
|
||||
});
|
||||
$.getJSON("https://api.github.com/repos/pi-hole/AdminLTE/releases/latest", function(json) {
|
||||
if(versionCompare(webVersion, json.tag_name.slice(1)) < 0) {
|
||||
// Alert user
|
||||
$("#alWebUpdate").show();
|
||||
if(!$("#dropdown-menu").hasClass("open")) {
|
||||
$("#dropdown-menu").addClass("open");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* Make sure that Pi-hole is updated to at least v2.7, since that is needed to use the sudo
|
||||
* features of the interface
|
||||
*/
|
||||
if(versionCompare(piholeVersion, "v2.7") < 0)
|
||||
alert("Pi-hole needs to be updated to at least v2.7 before you can use features such as whitelisting/blacklisting from this web interface!")
|
||||
@@ -0,0 +1,3 @@
|
||||
// Remove JS warning
|
||||
var jswarn = document.getElementById("js-warn-exit");
|
||||
jswarn.parentNode.removeChild(jswarn);
|
||||
@@ -0,0 +1,185 @@
|
||||
$(document).ready(function() {
|
||||
// Pull in data via AJAX
|
||||
|
||||
updateSummaryData();
|
||||
|
||||
updateQueriesOverTime();
|
||||
|
||||
updateQueryTypes();
|
||||
|
||||
updateTopClientsChart();
|
||||
|
||||
updateForwardDestinations();
|
||||
|
||||
updateTopLists();
|
||||
|
||||
// Create charts
|
||||
var chartData = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "All Queries",
|
||||
fillColor: "rgba(220,220,220,0.5)",
|
||||
strokeColor: "rgba(0, 166, 90,.8)",
|
||||
pointColor: "rgba(0, 166, 90,.8)"
|
||||
},
|
||||
{
|
||||
label: "Ad Queries",
|
||||
fillColor: "rgba(0,192,239,0.5)",
|
||||
strokeColor: "rgba(0,192,239,1)",
|
||||
pointColor: "rgba(0,192,239,1)"
|
||||
}
|
||||
]
|
||||
};
|
||||
var isMobile = {
|
||||
Windows: function() {
|
||||
return /IEMobile/i.test(navigator.userAgent);
|
||||
},
|
||||
Android: function() {
|
||||
return /Android/i.test(navigator.userAgent);
|
||||
},
|
||||
BlackBerry: function() {
|
||||
return /BlackBerry/i.test(navigator.userAgent);
|
||||
},
|
||||
iOS: function() {
|
||||
return /iPhone|iPad|iPod/i.test(navigator.userAgent);
|
||||
},
|
||||
any: function() {
|
||||
return (isMobile.Android() || isMobile.BlackBerry() || isMobile.iOS() || isMobile.Windows());
|
||||
}
|
||||
};
|
||||
var animate = false;
|
||||
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
|
||||
timeLineChart = new Chart(ctx).Line(chartData,
|
||||
{
|
||||
pointDot : false,
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%><li><span style=\"background-color:<%=datasets[i].strokeColor%>\"></span><%if(datasets[i].label){%><%=datasets[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
|
||||
ctx = document.getElementById("queryTypeChart").getContext("2d");
|
||||
queryTypeChart = new Chart(ctx).Doughnut([],
|
||||
{
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].strokeColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
|
||||
ctx = document.getElementById("forwardDestinationChart").getContext("2d");
|
||||
forwardDestinationChart = new Chart(ctx).Doughnut([],
|
||||
{
|
||||
legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].strokeColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>",
|
||||
animation : animate
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
// Functions to oupdate data in page
|
||||
|
||||
function updateSummaryData(runOnce) {
|
||||
$.getJSON("api.php?summary", function LoadSummaryData(data) {
|
||||
//$("h3.statistic").addClass("glow");
|
||||
if ($("h3#ads_blocked_today").text() != data.ads_blocked_today) {
|
||||
$("h3#ads_blocked_today").addClass("glow");
|
||||
}
|
||||
if ($("h3#dns_queries_today").text() != data.dns_queries_today) {
|
||||
$("h3#dns_queries_today").addClass("glow");
|
||||
}
|
||||
if ($("h3#ads_percentage_today").text() != data.ads_percentage_today) {
|
||||
$("h3#ads_percentage_today").addClass("glow");
|
||||
}
|
||||
|
||||
window.setTimeout(function(){
|
||||
$("h3#ads_blocked_today").text(data.ads_blocked_today);
|
||||
$("h3#dns_queries_today").text(data.dns_queries_today);
|
||||
$("h3#domains_being_blocked").text(data.domains_being_blocked);
|
||||
$("h3#ads_percentage_today").text(data.ads_percentage_today + "%");
|
||||
$("h3.statistic.glow").removeClass("glow")
|
||||
}, 500);
|
||||
}).done(function() {
|
||||
if (runOnce !== true) {
|
||||
setTimeout(updateSummaryData, 10000);
|
||||
}
|
||||
}).fail(function() {
|
||||
if (runOnce !== true) {
|
||||
setTimeout(updateSummaryData, (1000 * 60 * 5));
|
||||
}
|
||||
});;
|
||||
}
|
||||
|
||||
function updateQueriesOverTime() {
|
||||
$.getJSON("api.php?overTimeData", function(data) {
|
||||
for (hour in data.ads_over_time) {
|
||||
timeLineChart.addData([data.domains_over_time[hour], data.ads_over_time[hour]], hour + ":00");
|
||||
}
|
||||
$('#queries-over-time .overlay').remove();
|
||||
//$('#queries-over-time').append(timeLineChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopClientsChart() {
|
||||
$.getJSON("api.php?summaryRaw&getQuerySources", function(data) {
|
||||
var clienttable = $('#client-frequency').find('tbody:last');
|
||||
for (domain in data.top_sources) {
|
||||
clienttable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_sources[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-blue" style="width: ' +
|
||||
data.top_sources[domain] / data.dns_queries_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
|
||||
$('#client-frequency .overlay').remove();
|
||||
});
|
||||
}
|
||||
|
||||
function updateQueryTypes() {
|
||||
$.getJSON("api.php?getQueryTypes", function(data) {
|
||||
var colors = [];
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
$.each(data, function(key , value) {
|
||||
queryTypeChart.addData({
|
||||
value: value,
|
||||
color: colors.shift(),
|
||||
label: key.substr(6,key.length - 7)
|
||||
});
|
||||
});
|
||||
$('#query-types .overlay').remove();
|
||||
//$('#query-types').append(queryTypeChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateForwardDestinations() {
|
||||
$.getJSON("api.php?getForwardDestinations", function(data) {
|
||||
var colors = [];
|
||||
$.each($.AdminLTE.options.colors, function(key, value) { colors.push(value); });
|
||||
$.each(data, function(key , value) {
|
||||
forwardDestinationChart.addData({
|
||||
value: value,
|
||||
color: colors.shift(),
|
||||
label: key
|
||||
});
|
||||
});
|
||||
$('#forward-destinations .overlay').remove();
|
||||
//$('#forward-destinations').append(forwardDestinationChart.generateLegend());
|
||||
});
|
||||
}
|
||||
|
||||
function updateTopLists() {
|
||||
$.getJSON("api.php?summaryRaw&topItems", function(data) {
|
||||
var domaintable = $('#domain-frequency').find('tbody:last');
|
||||
var adtable = $('#ad-frequency').find('tbody:last');
|
||||
|
||||
for (domain in data.top_queries) {
|
||||
domaintable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_queries[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-green" style="width: ' +
|
||||
data.top_queries[domain] / data.dns_queries_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
for (domain in data.top_ads) {
|
||||
adtable.append('<tr> <td>' + domain +
|
||||
'</td> <td>' + data.top_ads[domain] + '</td> <td> <div class="progress progress-sm"> <div class="progress-bar progress-bar-yellow" style="width: ' +
|
||||
data.top_ads[domain] / data.ads_blocked_today * 100 + '%"></div> </div> </td> </tr> ');
|
||||
}
|
||||
|
||||
$('#domain-frequency .overlay').remove();
|
||||
$('#ad-frequency .overlay').remove();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// IE likes to cache too much :P
|
||||
$.ajaxSetup({cache: false});
|
||||
|
||||
// Handle enter button for adding domains
|
||||
$(document).keypress(function(e) {
|
||||
if(e.which === 13 && $("#domain").is(":focus")) {
|
||||
// Enter was pressed, and the input has focus
|
||||
add();
|
||||
}
|
||||
});
|
||||
|
||||
// Handle buttons
|
||||
$("#btnAdd").on("click", function() {
|
||||
add();
|
||||
});
|
||||
$("#btnRefresh").on("click", function() {
|
||||
refresh(true);
|
||||
});
|
||||
|
||||
// Handle hiding of alerts
|
||||
$(function(){
|
||||
$("[data-hide]").on("click", function(){
|
||||
$(this).closest("." + $(this).attr("data-hide")).hide();
|
||||
});
|
||||
});
|
||||
|
||||
// Get PHP info
|
||||
var token = $("#token").html();
|
||||
var list_type = $("#list-type").html();
|
||||
var fullName = list_type === "white" ? "Whitelist" : "Blacklist";
|
||||
|
||||
window.onload = refresh(false);
|
||||
|
||||
function refresh(fade) {
|
||||
var list = $("#list");
|
||||
if(fade) {
|
||||
list.fadeOut(100);
|
||||
}
|
||||
$.ajax({
|
||||
url: "php/get.php",
|
||||
method: "get",
|
||||
data: {"list":list_type},
|
||||
success: function(response) {
|
||||
list.html("");
|
||||
var data = JSON.parse(response);
|
||||
|
||||
if(data.length === 0) {
|
||||
list.html('<div class="alert alert-info" role="alert">Your ' + fullName + ' is empty!</div>');
|
||||
}
|
||||
else {
|
||||
data.forEach(function (entry, index) {
|
||||
list.append(
|
||||
'<li id="' + index + '" class="list-group-item clearfix">' + entry +
|
||||
'<button class="btn btn-danger btn-xs pull-right" type="button">' +
|
||||
'<span class="glyphicon glyphicon-trash"></span></button></li>'
|
||||
);
|
||||
|
||||
// Handle button
|
||||
$("#list #"+index+"").on("click", "button", function() {
|
||||
sub(index, entry)
|
||||
});
|
||||
});
|
||||
}
|
||||
list.fadeIn("fast");
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
$("#alFailure").show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function add() {
|
||||
var domain = $("#domain");
|
||||
if(domain.val().length === 0)
|
||||
return;
|
||||
|
||||
var alInfo = $("#alInfo");
|
||||
var alSuccess = $("#alSuccess");
|
||||
var alFailure = $("#alFailure");
|
||||
alInfo.show();
|
||||
alSuccess.hide();
|
||||
alFailure.hide();
|
||||
$.ajax({
|
||||
url: "php/add.php",
|
||||
method: "post",
|
||||
data: {"domain":domain.val(), "list":list_type, "token":token},
|
||||
success: function(response) {
|
||||
if (response.indexOf("not a valid argument")>=0) {
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
} else {
|
||||
alSuccess.show();
|
||||
alSuccess.delay(1000).fadeOut(2000, function() {
|
||||
alSuccess.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
domain.val("");
|
||||
refresh(true);
|
||||
}
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
alFailure.show();
|
||||
alFailure.delay(1000).fadeOut(2000, function() {
|
||||
alFailure.hide();
|
||||
});
|
||||
alInfo.delay(1000).fadeOut(2000, function() {
|
||||
alInfo.hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function sub(index, entry) {
|
||||
var domain = $("#"+index);
|
||||
domain.hide("highlight");
|
||||
$.ajax({
|
||||
url: "php/sub.php",
|
||||
method: "post",
|
||||
data: {"domain":entry, "list":list_type, "token":token},
|
||||
success: function(response) {
|
||||
if(response.length !== 0)
|
||||
return;
|
||||
domain.remove();
|
||||
},
|
||||
error: function(jqXHR, exception) {
|
||||
alert("Failed to remove the domain!");
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
$(document).ready(function() {
|
||||
tableApi = $('#all-queries').DataTable( {
|
||||
"rowCallback": function( row, data, index ){
|
||||
if (data[4] == "Pi-holed") {
|
||||
$(row).css('color','red')
|
||||
}
|
||||
else{
|
||||
$(row).css('color','green')
|
||||
}
|
||||
|
||||
},
|
||||
"ajax": "api.php?getAllQueries",
|
||||
"autoWidth" : false,
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "20%", "type": "date" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "40%" },
|
||||
{ "width" : "15%" },
|
||||
{ "width" : "15%" }
|
||||
]
|
||||
})
|
||||
} );
|
||||
|
||||
function refreshData() {
|
||||
tableApi.ajax.url("api.php?getAllQueries").load();
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
session_start();
|
||||
require "header.html";
|
||||
|
||||
$list = $_GET['l'];
|
||||
|
||||
function getFullName() {
|
||||
global $list;
|
||||
if($list == "white")
|
||||
echo "Whitelist";
|
||||
else
|
||||
echo "Blacklist";
|
||||
}
|
||||
|
||||
// Generate CSRF token
|
||||
if(empty($_SESSION['token'])) {
|
||||
$_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32));
|
||||
}
|
||||
$token = $_SESSION['token'];
|
||||
?>
|
||||
<!-- Send PHP info to JS -->
|
||||
<div id="token" hidden><?php echo $token ?></div>
|
||||
<div id="list-type" hidden><?php echo $list ?></div>
|
||||
|
||||
<!-- Title -->
|
||||
<div class="page-header">
|
||||
<h1><?php getFullName(); ?></h1>
|
||||
</div>
|
||||
|
||||
<!-- Domain Input -->
|
||||
<div class="form-group input-group">
|
||||
<input id="domain" type="text" class="form-control" placeholder="Add a domain (example.com or sub.example.com)">
|
||||
<span class="input-group-btn">
|
||||
<button id="btnAdd" class="btn btn-default" type="button">Add</button>
|
||||
<button id="btnRefresh" class="btn btn-default" type="button">Refresh</button>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- Alerts -->
|
||||
<div id="alInfo" class="alert alert-info alert-dismissible fade in" role="alert" hidden="true">
|
||||
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
Adding to the <?php getFullName(); ?>...
|
||||
</div>
|
||||
<div id="alSuccess" class="alert alert-success alert-dismissible fade in" role="alert" hidden="true">
|
||||
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
Success! The list will refresh.
|
||||
</div>
|
||||
<div id="alFailure" class="alert alert-danger alert-dismissible fade in" role="alert" hidden="true">
|
||||
<button type="button" class="close" data-hide="alert" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||
Failure! Something went wrong.
|
||||
</div>
|
||||
|
||||
<!-- Domain List -->
|
||||
<ul class="list-group" id="list"></ul>
|
||||
|
||||
<?php
|
||||
require "footer.php";
|
||||
?>
|
||||
|
||||
<script src="js/pihole/list.js"></script>
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
if(!isset($_POST['domain'], $_POST['list'], $_POST['token']))
|
||||
die("Missing POST variables");
|
||||
|
||||
// Check CORS
|
||||
if($_SERVER['HTTP_ORIGIN'] == "http://pi.hole" || $_SERVER['HTTP_ORIGIN'] == "http://${_SERVER['SERVER_ADDR']}")
|
||||
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}");
|
||||
else if($_SERVER['HTTP_HOST'] == $_SERVER['SERVER_ADDR'] || $_SERVER['HTTP_HOST'] == "pi.hole")
|
||||
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_HOST']}");
|
||||
else
|
||||
die("Failed CORS");
|
||||
|
||||
session_start();
|
||||
|
||||
// Check CSRF token
|
||||
if(!hash_equals($_SESSION['token'], $_POST['token']))
|
||||
die("Wrong token");
|
||||
|
||||
switch($_POST['list']) {
|
||||
case "white":
|
||||
echo exec("sudo pihole -w -q ${_POST['domain']}");
|
||||
break;
|
||||
case "black":
|
||||
echo exec("sudo pihole -b -q ${_POST['domain']}");
|
||||
break;
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
if(!isset($_GET['list']))
|
||||
die();
|
||||
|
||||
$type = $_GET['list'];
|
||||
$rawList = file_get_contents("/etc/pihole/${type}list.txt");
|
||||
$list = explode("\n", $rawList);
|
||||
|
||||
// Get rid of empty lines
|
||||
for($i = sizeof($list)-1; $i >= 0; $i--) {
|
||||
if($list[$i] == "")
|
||||
unset($list[$i]);
|
||||
}
|
||||
|
||||
echo json_encode(array_values($list));
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
if(!isset($_POST['domain'], $_POST['list'], $_POST['token']))
|
||||
die("Missing POST variables");
|
||||
|
||||
// Check CORS
|
||||
if($_SERVER['HTTP_ORIGIN'] == "http://pi.hole" || $_SERVER['HTTP_ORIGIN'] == "http://${_SERVER['SERVER_ADDR']}")
|
||||
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}");
|
||||
else if($_SERVER['HTTP_HOST'] == $_SERVER['SERVER_ADDR'] || $_SERVER['HTTP_HOST'] == "pi.hole")
|
||||
header("Access-Control-Allow-Origin: ${_SERVER['HTTP_HOST']}");
|
||||
else
|
||||
die("Failed CORS");
|
||||
|
||||
session_start();
|
||||
|
||||
// Check CSRF token
|
||||
if(!hash_equals($_SESSION['token'], $_POST['token']))
|
||||
die("Wrong token");
|
||||
|
||||
switch($_POST['list']) {
|
||||
case "white":
|
||||
exec("sudo pihole -w -q -d ${_POST['domain']}");
|
||||
break;
|
||||
case "black":
|
||||
exec("sudo pihole -b -q -d ${_POST['domain']}");
|
||||
break;
|
||||
}
|
||||
+1
-29
@@ -49,32 +49,4 @@
|
||||
require "footer.php";
|
||||
?>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
tableApi = $('#all-queries').DataTable( {
|
||||
"rowCallback": function( row, data, index ){
|
||||
if (data[4] == "Pi-holed") {
|
||||
$(row).css('color','red')
|
||||
}
|
||||
else{
|
||||
$(row).css('color','green')
|
||||
}
|
||||
|
||||
},
|
||||
"ajax": "api.php?getAllQueries",
|
||||
"autoWidth" : false,
|
||||
"order" : [[0, "desc"]],
|
||||
"columns": [
|
||||
{ "width" : "20%", "type": "date" },
|
||||
{ "width" : "10%" },
|
||||
{ "width" : "40%" },
|
||||
{ "width" : "15%" },
|
||||
{ "width" : "15%" }
|
||||
]
|
||||
})
|
||||
} );
|
||||
|
||||
function refreshData() {
|
||||
tableApi.ajax.url("api.php?getAllQueries").load();
|
||||
}
|
||||
</script>
|
||||
<script src="js/pihole/queries.js"></script>
|
||||
|
||||
Reference in New Issue
Block a user