mirror of
https://github.com/pi-hole/web.git
synced 2026-02-15 07:25:39 +00:00
Merge branch 'devel' into new/nonfatal-dnsmasq-warnings
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
6
api.php
6
api.php
@@ -13,14 +13,10 @@ require_once("scripts/pi-hole/php/database.php");
|
||||
require_once("scripts/pi-hole/php/auth.php");
|
||||
check_cors();
|
||||
|
||||
$FTL_IP = "127.0.0.1";
|
||||
|
||||
$data = array();
|
||||
|
||||
// Common API functions
|
||||
if (isset($_GET['status'])) {
|
||||
$data = array_merge($data, array("status" => piholeStatusAPI()));
|
||||
} elseif (isset($_GET['enable']) && $auth) {
|
||||
if (isset($_GET['enable']) && $auth) {
|
||||
if(isset($_GET["auth"]))
|
||||
{
|
||||
if($_GET["auth"] !== $pwhash)
|
||||
|
||||
680
api_FTL.php
680
api_FTL.php
@@ -6,429 +6,355 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license */
|
||||
|
||||
|
||||
if(!isset($api))
|
||||
{
|
||||
die("Direct call to api_FTL.php is not allowed!");
|
||||
if (!isset($api)) {
|
||||
die("Direct call to api_FTL.php is not allowed!");
|
||||
}
|
||||
|
||||
// $FTL_IP is defined in api.php
|
||||
$socket = connectFTL($FTL_IP);
|
||||
|
||||
if(!is_resource($socket))
|
||||
{
|
||||
$data = array_merge($data, array("FTLnotrunning" => true));
|
||||
if (isset($_GET['type'])) {
|
||||
$data["type"] = "FTL";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isset($_GET['type'])) {
|
||||
$data["type"] = "FTL";
|
||||
}
|
||||
|
||||
if (isset($_GET['version'])) {
|
||||
$data["version"] = 3;
|
||||
}
|
||||
if (isset($_GET['version'])) {
|
||||
$data["version"] = 3;
|
||||
}
|
||||
|
||||
if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) {
|
||||
require_once("scripts/pi-hole/php/gravity.php");
|
||||
sendRequestFTL("stats");
|
||||
$return = getResponseFTL();
|
||||
if (isset($_GET['status'])) {
|
||||
$return = callFTLAPI("stats");
|
||||
|
||||
$stats = [];
|
||||
foreach($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
if (in_array("status enabled", $return)) {
|
||||
$data = array_merge($data, array("status" => "enabled"));
|
||||
} else {
|
||||
$data = array_merge($data, array("status" => "disabled"));
|
||||
}
|
||||
}
|
||||
|
||||
if($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1])) {
|
||||
// Expect string response
|
||||
$stats[$tmp[0]] = $tmp[1];
|
||||
} elseif ($tmp[0] === "status") {
|
||||
// Expect string response
|
||||
$stats[$tmp[0]] = piholeStatusAPI();
|
||||
} elseif (isset($_GET['summary'])) {
|
||||
// "summary" expects a formmated string response
|
||||
if($tmp[0] !== "ads_percentage_today") {
|
||||
$stats[$tmp[0]] = number_format($tmp[1]);
|
||||
} else {
|
||||
$stats[$tmp[0]] = number_format($tmp[1], 1, '.', '');
|
||||
}
|
||||
} else {
|
||||
// Expect float response
|
||||
$stats[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
if (isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) {
|
||||
require_once("scripts/pi-hole/php/gravity.php");
|
||||
|
||||
}
|
||||
$stats['gravity_last_updated'] = gravity_last_update(true);
|
||||
$data = array_merge($data,$stats);
|
||||
}
|
||||
$return = callFTLAPI("stats");
|
||||
|
||||
if (isset($_GET["getMaxlogage"]) && $auth) {
|
||||
sendRequestFTL("maxlogage");
|
||||
// Convert seconds to hours and rounds to one decimal place.
|
||||
$ret = round(intval(getResponseFTL()[0]) / 3600, 1);
|
||||
// Return 24h if value is 0, empty, null or non numeric.
|
||||
$ret = $ret ?: 24;
|
||||
$stats = [];
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
|
||||
$data = array_merge($data, array("maxlogage" => $ret));
|
||||
}
|
||||
if ($tmp[0] === "domains_being_blocked" && !is_numeric($tmp[1]) || $tmp[0] === "status") {
|
||||
// Expect string response
|
||||
$stats[$tmp[0]] = $tmp[1];
|
||||
} elseif (isset($_GET['summary'])) {
|
||||
// "summary" expects a formmated string response
|
||||
if ($tmp[0] !== "ads_percentage_today") {
|
||||
$stats[$tmp[0]] = number_format($tmp[1]);
|
||||
} else {
|
||||
$stats[$tmp[0]] = number_format($tmp[1], 1, '.', '');
|
||||
}
|
||||
} else {
|
||||
// Expect float response
|
||||
$stats[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeData10mins']))
|
||||
{
|
||||
sendRequestFTL("overTime");
|
||||
$return = getResponseFTL();
|
||||
}
|
||||
$stats['gravity_last_updated'] = gravity_last_update(true);
|
||||
$data = array_merge($data,$stats);
|
||||
}
|
||||
|
||||
$domains_over_time = array();
|
||||
$ads_over_time = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$domains_over_time[intval($tmp[0])] = intval($tmp[1]);
|
||||
$ads_over_time[intval($tmp[0])] = intval($tmp[2]);
|
||||
}
|
||||
$result = array('domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
if (isset($_GET["getMaxlogage"]) && $auth) {
|
||||
$return = callFTLAPI("stats");
|
||||
|
||||
if (isset($_GET['topItems']) && $auth)
|
||||
{
|
||||
if($_GET['topItems'] === "audit")
|
||||
{
|
||||
sendRequestFTL("top-domains for audit");
|
||||
}
|
||||
else if(is_numeric($_GET['topItems']))
|
||||
{
|
||||
sendRequestFTL("top-domains (".$_GET['topItems'].")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRequestFTL("top-domains");
|
||||
}
|
||||
// Convert seconds to hours and rounds to one decimal place.
|
||||
$ret = round(intval($return[0]) / 3600, 1);
|
||||
// Return 24h if value is 0, empty, null or non numeric.
|
||||
$ret = $ret ?: 24;
|
||||
|
||||
$return = getResponseFTL();
|
||||
$top_queries = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
if(count($tmp) == 2) $tmp[2]="";
|
||||
$domain = utf8_encode($tmp[2]);
|
||||
$top_queries[$domain] = intval($tmp[1]);
|
||||
}
|
||||
$data = array_merge($data, array("maxlogage" => $ret));
|
||||
}
|
||||
|
||||
if($_GET['topItems'] === "audit")
|
||||
{
|
||||
sendRequestFTL("top-ads for audit");
|
||||
}
|
||||
else if(is_numeric($_GET['topItems']))
|
||||
{
|
||||
sendRequestFTL("top-ads (".$_GET['topItems'].")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRequestFTL("top-ads");
|
||||
}
|
||||
if (isset($_GET['overTimeData10mins'])) {
|
||||
$return = callFTLAPI("overTime");
|
||||
|
||||
$return = getResponseFTL();
|
||||
$top_ads = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$domain = utf8_encode($tmp[2]);
|
||||
if(count($tmp) > 3)
|
||||
$top_ads[$domain." (".$tmp[3].")"] = intval($tmp[1]);
|
||||
else
|
||||
$top_ads[$domain] = intval($tmp[1]);
|
||||
}
|
||||
$domains_over_time = array();
|
||||
$ads_over_time = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$domains_over_time[intval($tmp[0])] = intval($tmp[1]);
|
||||
$ads_over_time[intval($tmp[0])] = intval($tmp[2]);
|
||||
}
|
||||
|
||||
$result = array('top_queries' => $top_queries,
|
||||
'top_ads' => $top_ads);
|
||||
$result = array(
|
||||
'domains_over_time' => $domains_over_time,
|
||||
'ads_over_time' => $ads_over_time
|
||||
);
|
||||
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if ((isset($_GET['topClients']) || isset($_GET['getQuerySources'])) && $auth)
|
||||
{
|
||||
if (isset($_GET['topItems']) && $auth) {
|
||||
if ($_GET['topItems'] === "audit") {
|
||||
$return = callFTLAPI("top-domains for audit");
|
||||
} elseif (is_numeric($_GET['topItems'])) {
|
||||
$return = callFTLAPI("top-domains (".$_GET['topItems'].")");
|
||||
} else {
|
||||
$return = callFTLAPI("top-domains");
|
||||
}
|
||||
|
||||
if(isset($_GET['topClients']))
|
||||
{
|
||||
$number = $_GET['topClients'];
|
||||
}
|
||||
elseif(isset($_GET['getQuerySources']))
|
||||
{
|
||||
$number = $_GET['getQuerySources'];
|
||||
}
|
||||
$top_queries = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
if (count($tmp) == 2) {
|
||||
$tmp[2]="";
|
||||
}
|
||||
$domain = utf8_encode($tmp[2]);
|
||||
$top_queries[$domain] = intval($tmp[1]);
|
||||
}
|
||||
|
||||
if(is_numeric($number))
|
||||
{
|
||||
sendRequestFTL("top-clients (".$number.")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRequestFTL("top-clients");
|
||||
}
|
||||
if ($_GET['topItems'] === "audit") {
|
||||
$return = callFTLAPI("top-ads for audit");
|
||||
} elseif (is_numeric($_GET['topItems'])) {
|
||||
$return = callFTLAPI("top-ads (".$_GET['topItems'].")");
|
||||
} else {
|
||||
$return = callFTLAPI("top-ads");
|
||||
}
|
||||
|
||||
$return = getResponseFTL();
|
||||
$top_clients = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$clientip = utf8_encode($tmp[2]);
|
||||
if(count($tmp) > 3 && strlen($tmp[3]) > 0)
|
||||
{
|
||||
$clientname = utf8_encode($tmp[3]);
|
||||
$top_clients[$clientname."|".$clientip] = intval($tmp[1]);
|
||||
}
|
||||
else
|
||||
$top_clients[$clientip] = intval($tmp[1]);
|
||||
}
|
||||
$top_ads = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$domain = utf8_encode($tmp[2]);
|
||||
if (count($tmp) > 3) {
|
||||
$top_ads[$domain." (".$tmp[3].")"] = intval($tmp[1]);
|
||||
} else {
|
||||
$top_ads[$domain] = intval($tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = array('top_sources' => $top_clients);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$result = array(
|
||||
'top_queries' => $top_queries,
|
||||
'top_ads' => $top_ads
|
||||
);
|
||||
|
||||
if (isset($_GET['topClientsBlocked']) && $auth)
|
||||
{
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if(isset($_GET['topClientsBlocked']))
|
||||
{
|
||||
$number = $_GET['topClientsBlocked'];
|
||||
}
|
||||
if ((isset($_GET['topClients']) || isset($_GET['getQuerySources'])) && $auth) {
|
||||
|
||||
if(is_numeric($number))
|
||||
{
|
||||
sendRequestFTL("top-clients blocked (".$number.")");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRequestFTL("top-clients blocked");
|
||||
}
|
||||
if (isset($_GET['topClients'])) {
|
||||
$number = $_GET['topClients'];
|
||||
} elseif (isset($_GET['getQuerySources'])) {
|
||||
$number = $_GET['getQuerySources'];
|
||||
}
|
||||
|
||||
$return = getResponseFTL();
|
||||
$top_clients = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$clientip = utf8_encode($tmp[2]);
|
||||
if(count($tmp) > 3 && strlen($tmp[3]) > 0)
|
||||
{
|
||||
$clientname = utf8_encode($tmp[3]);
|
||||
$top_clients[$clientname."|".$clientip] = intval($tmp[1]);
|
||||
}
|
||||
else
|
||||
$top_clients[$clientip] = intval($tmp[1]);
|
||||
}
|
||||
if (is_numeric($number)) {
|
||||
$return = callFTLAPI("top-clients (".$number.")");
|
||||
} else {
|
||||
$return = callFTLAPI("top-clients");
|
||||
}
|
||||
|
||||
$result = array('top_sources_blocked' => $top_clients);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$top_clients = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$clientip = utf8_encode($tmp[2]);
|
||||
if (count($tmp) > 3 && strlen($tmp[3]) > 0) {
|
||||
$clientname = utf8_encode($tmp[3]);
|
||||
$top_clients[$clientname."|".$clientip] = intval($tmp[1]);
|
||||
} else {
|
||||
$top_clients[$clientip] = intval($tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['getForwardDestinations']) && $auth)
|
||||
{
|
||||
if($_GET['getForwardDestinations'] === "unsorted")
|
||||
{
|
||||
sendRequestFTL("forward-dest unsorted");
|
||||
}
|
||||
else
|
||||
{
|
||||
sendRequestFTL("forward-dest");
|
||||
}
|
||||
$return = getResponseFTL();
|
||||
$forward_dest = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$forwardip = utf8_encode($tmp[2]);
|
||||
if(count($tmp) > 3 && strlen($tmp[3]) > 0)
|
||||
{
|
||||
$forwardname = utf8_encode($tmp[3]);
|
||||
$forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
else
|
||||
$forward_dest[$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
$result = array('top_sources' => $top_clients);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
$result = array('forward_destinations' => $forward_dest);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
if (isset($_GET['topClientsBlocked']) && $auth) {
|
||||
|
||||
if (isset($_GET['getQueryTypes']) && $auth)
|
||||
{
|
||||
sendRequestFTL("querytypes");
|
||||
$return = getResponseFTL();
|
||||
$querytypes = array();
|
||||
foreach($return as $ret)
|
||||
{
|
||||
$tmp = explode(": ",$ret);
|
||||
// Reply cannot contain non-ASCII characters
|
||||
$querytypes[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
if (isset($_GET['topClientsBlocked'])) {
|
||||
$number = $_GET['topClientsBlocked'];
|
||||
}
|
||||
|
||||
$result = array('querytypes' => $querytypes);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
if (is_numeric($number)) {
|
||||
$return = callFTLAPI("top-clients blocked (".$number.")");
|
||||
} else {
|
||||
$return = callFTLAPI("top-clients blocked");
|
||||
}
|
||||
|
||||
if (isset($_GET['getCacheInfo']) && $auth)
|
||||
{
|
||||
sendRequestFTL("cacheinfo");
|
||||
$return = getResponseFTL();
|
||||
$cacheinfo = array();
|
||||
foreach($return as $ret)
|
||||
{
|
||||
$tmp = explode(": ",$ret);
|
||||
// Reply cannot contain non-ASCII characters
|
||||
$cacheinfo[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
$top_clients = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$clientip = utf8_encode($tmp[2]);
|
||||
if (count($tmp) > 3 && strlen($tmp[3]) > 0) {
|
||||
$clientname = utf8_encode($tmp[3]);
|
||||
$top_clients[$clientname."|".$clientip] = intval($tmp[1]);
|
||||
} else {
|
||||
$top_clients[$clientip] = intval($tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = array('cacheinfo' => $cacheinfo);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$result = array('top_sources_blocked' => $top_clients);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['getAllQueries']) && $auth)
|
||||
{
|
||||
if(isset($_GET['from']) && isset($_GET['until']))
|
||||
{
|
||||
// Get limited time interval
|
||||
sendRequestFTL("getallqueries-time ".$_GET['from']." ".$_GET['until']);
|
||||
}
|
||||
else if(isset($_GET['domain']))
|
||||
{
|
||||
// Get specific domain only
|
||||
sendRequestFTL("getallqueries-domain ".$_GET['domain']);
|
||||
}
|
||||
else if(isset($_GET['client']) && (isset($_GET['type']) && $_GET['type'] === "blocked"))
|
||||
{
|
||||
// Get specific client only
|
||||
sendRequestFTL("getallqueries-client-blocked ".$_GET['client']);
|
||||
}
|
||||
else if(isset($_GET['client']))
|
||||
{
|
||||
// Get specific client only
|
||||
sendRequestFTL("getallqueries-client ".$_GET['client']);
|
||||
}
|
||||
else if(isset($_GET['querytype']))
|
||||
{
|
||||
// Get specific query type only
|
||||
sendRequestFTL("getallqueries-qtype ".$_GET['querytype']);
|
||||
}
|
||||
else if(isset($_GET['forwarddest']))
|
||||
{
|
||||
// Get specific forward destination only
|
||||
sendRequestFTL("getallqueries-forward ".$_GET['forwarddest']);
|
||||
}
|
||||
else if(is_numeric($_GET['getAllQueries']))
|
||||
{
|
||||
sendRequestFTL("getallqueries (".$_GET['getAllQueries'].")");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get all queries
|
||||
sendRequestFTL("getallqueries");
|
||||
}
|
||||
$return = getResponseFTL();
|
||||
$allQueries = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = str_getcsv($line," ");
|
||||
// UTF-8 encode domain
|
||||
$tmp[2] = utf8_encode(str_replace("~"," ",$tmp[2]));
|
||||
// UTF-8 encode client host name
|
||||
$tmp[3] = utf8_encode($tmp[3]);
|
||||
array_push($allQueries,$tmp);
|
||||
}
|
||||
if (isset($_GET['getForwardDestinations']) && $auth) {
|
||||
if ($_GET['getForwardDestinations'] === "unsorted") {
|
||||
$return = callFTLAPI("forward-dest unsorted");
|
||||
} else {
|
||||
$return = callFTLAPI("forward-dest");
|
||||
}
|
||||
|
||||
$result = array('data' => $allQueries);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$forward_dest = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$forwardip = utf8_encode($tmp[2]);
|
||||
if (count($tmp) > 3 && strlen($tmp[3]) > 0) {
|
||||
$forwardname = utf8_encode($tmp[3]);
|
||||
$forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]);
|
||||
} else {
|
||||
$forward_dest[$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_GET["recentBlocked"]) && $auth)
|
||||
{
|
||||
sendRequestFTL("recentBlocked");
|
||||
die(utf8_encode(getResponseFTL()[0]));
|
||||
unset($data);
|
||||
}
|
||||
$result = array('forward_destinations' => $forward_dest);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['getForwardDestinationNames']) && $auth)
|
||||
{
|
||||
sendRequestFTL("forward-names");
|
||||
$return = getResponseFTL();
|
||||
$forward_dest = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
$forwardip = utf8_encode($tmp[2]);
|
||||
if(count($tmp) > 3)
|
||||
{
|
||||
$forwardname = utf8_encode($tmp[3]);
|
||||
$forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$forward_dest[$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
}
|
||||
if (isset($_GET['getQueryTypes']) && $auth) {
|
||||
$return = callFTLAPI("querytypes");
|
||||
|
||||
$result = array('forward_destinations' => $forward_dest);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$querytypes = array();
|
||||
foreach ($return as $ret) {
|
||||
$tmp = explode(": ",$ret);
|
||||
// Reply cannot contain non-ASCII characters
|
||||
$querytypes[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeDataQueryTypes']) && $auth)
|
||||
{
|
||||
sendRequestFTL("QueryTypesoverTime");
|
||||
$return = getResponseFTL();
|
||||
$over_time = array();
|
||||
$result = array('querytypes' => $querytypes);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
for ($i=0; $i < count($tmp)-1; $i++) {
|
||||
$over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]);
|
||||
}
|
||||
}
|
||||
$result = array('over_time' => $over_time);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
if (isset($_GET['getCacheInfo']) && $auth) {
|
||||
$return = callFTLAPI("cacheinfo");
|
||||
$cacheinfo = array();
|
||||
foreach ($return as $ret) {
|
||||
$tmp = explode(": ",$ret);
|
||||
// Reply cannot contain non-ASCII characters
|
||||
$cacheinfo[$tmp[0]] = floatval($tmp[1]);
|
||||
}
|
||||
|
||||
if (isset($_GET['getClientNames']) && $auth)
|
||||
{
|
||||
sendRequestFTL("client-names");
|
||||
$return = getResponseFTL();
|
||||
$client_names = array();
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ", $line);
|
||||
$client_names[] = array(
|
||||
"name" => utf8_encode($tmp[0]),
|
||||
"ip" => utf8_encode($tmp[1])
|
||||
);
|
||||
}
|
||||
$result = array('cacheinfo' => $cacheinfo);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
$result = array('clients' => $client_names);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
if (isset($_GET['getAllQueries']) && $auth) {
|
||||
if (isset($_GET['from']) && isset($_GET['until'])) {
|
||||
// Get limited time interval
|
||||
$return = callFTLAPI("getallqueries-time ".$_GET['from']." ".$_GET['until']);
|
||||
} elseif (isset($_GET['domain'])) {
|
||||
// Get specific domain only
|
||||
$return = callFTLAPI("getallqueries-domain ".$_GET['domain']);
|
||||
} elseif (isset($_GET['client']) && (isset($_GET['type']) && $_GET['type'] === "blocked")) {
|
||||
// Get specific client only
|
||||
$return = callFTLAPI("getallqueries-client-blocked ".$_GET['client']);
|
||||
} elseif (isset($_GET['client'])) {
|
||||
// Get specific client only
|
||||
$return = callFTLAPI("getallqueries-client ".$_GET['client']);
|
||||
} elseif (isset($_GET['querytype'])) {
|
||||
// Get specific query type only
|
||||
$return = callFTLAPI("getallqueries-qtype ".$_GET['querytype']);
|
||||
} elseif (isset($_GET['forwarddest'])) {
|
||||
// Get specific forward destination only
|
||||
$return = callFTLAPI("getallqueries-forward ".$_GET['forwarddest']);
|
||||
} elseif (is_numeric($_GET['getAllQueries'])) {
|
||||
$return = callFTLAPI("getallqueries (".$_GET['getAllQueries'].")");
|
||||
} else {
|
||||
// Get all queries
|
||||
$return = callFTLAPI("getallqueries");
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeDataClients']) && $auth)
|
||||
{
|
||||
sendRequestFTL("ClientsoverTime");
|
||||
$return = getResponseFTL();
|
||||
$over_time = array();
|
||||
$allQueries = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = str_getcsv($line," ");
|
||||
// UTF-8 encode domain
|
||||
$tmp[2] = utf8_encode(str_replace("~"," ",$tmp[2]));
|
||||
// UTF-8 encode client host name
|
||||
$tmp[3] = utf8_encode($tmp[3]);
|
||||
array_push($allQueries,$tmp);
|
||||
}
|
||||
|
||||
foreach($return as $line)
|
||||
{
|
||||
$tmp = explode(" ",$line);
|
||||
for ($i=0; $i < count($tmp)-1; $i++) {
|
||||
$over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]);
|
||||
}
|
||||
}
|
||||
$result = array('over_time' => $over_time);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
$result = array('data' => $allQueries);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['delete_lease']) && $auth)
|
||||
{
|
||||
sendRequestFTL("delete-lease ".$_GET['delete_lease']);
|
||||
$return = getResponseFTL();
|
||||
$data["delete_lease"] = $return[0];
|
||||
}
|
||||
if (isset($_GET["recentBlocked"]) && $auth) {
|
||||
die(utf8_encode(callFTLAPI("recentBlocked")[0]));
|
||||
unset($data);
|
||||
}
|
||||
|
||||
disconnectFTL();
|
||||
if (isset($_GET['getForwardDestinationNames']) && $auth) {
|
||||
$return = callFTLAPI("forward-names");
|
||||
|
||||
$forward_dest = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
$forwardip = utf8_encode($tmp[2]);
|
||||
if (count($tmp) > 3) {
|
||||
$forwardname = utf8_encode($tmp[3]);
|
||||
$forward_dest[$forwardname."|".$forwardip] = floatval($tmp[1]);
|
||||
} else {
|
||||
$forward_dest[$forwardip] = floatval($tmp[1]);
|
||||
}
|
||||
}
|
||||
|
||||
$result = array('forward_destinations' => $forward_dest);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeDataQueryTypes']) && $auth) {
|
||||
$return = callFTLAPI("QueryTypesoverTime");
|
||||
$over_time = array();
|
||||
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
for ($i=0; $i < count($tmp)-1; $i++) {
|
||||
$over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]);
|
||||
}
|
||||
}
|
||||
$result = array('over_time' => $over_time);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['getClientNames']) && $auth) {
|
||||
$return = callFTLAPI("client-names");
|
||||
$client_names = array();
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ", $line);
|
||||
$client_names[] = array(
|
||||
"name" => utf8_encode($tmp[0]),
|
||||
"ip" => utf8_encode($tmp[1])
|
||||
);
|
||||
}
|
||||
|
||||
$result = array('clients' => $client_names);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['overTimeDataClients']) && $auth) {
|
||||
$return = callFTLAPI("ClientsoverTime");
|
||||
$over_time = array();
|
||||
|
||||
foreach ($return as $line) {
|
||||
$tmp = explode(" ",$line);
|
||||
for ($i=0; $i < count($tmp)-1; $i++) {
|
||||
$over_time[intval($tmp[0])][$i] = floatval($tmp[$i+1]);
|
||||
}
|
||||
}
|
||||
$result = array('over_time' => $over_time);
|
||||
$data = array_merge($data, $result);
|
||||
}
|
||||
|
||||
if (isset($_GET['delete_lease']) && $auth) {
|
||||
$return = callFTLAPI("delete-lease ".$_GET['delete_lease']);
|
||||
$data["delete_lease"] = $return[0];
|
||||
}
|
||||
|
||||
if (isset($_GET['dns-port']) && $auth) {
|
||||
$return = callFTLAPI("dns-port");
|
||||
$data["dns-port"] = $return[0];
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -319,7 +319,7 @@ if (isset($_GET['getGraphData']) && $auth)
|
||||
if(isset($_GET["interval"]))
|
||||
{
|
||||
$q = intval($_GET["interval"]);
|
||||
if($q > 10)
|
||||
if($q >= 10)
|
||||
$interval = $q;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/auditlog.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -94,7 +94,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/customcname.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
</div>
|
||||
|
||||
<script src="scripts/vendor/daterangepicker.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/db_graph.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -146,7 +146,6 @@ else
|
||||
</div>
|
||||
|
||||
<script src="scripts/vendor/daterangepicker.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/db_lists.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
<!-- /.row -->
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/daterangepicker.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/db_queries.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -98,7 +98,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/customdns.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
|
||||
<script src="scripts/vendor/bootstrap-select.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/bootstrap-toggle.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/groups-adlists.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -88,7 +88,6 @@
|
||||
<script src="scripts/vendor/bootstrap-select.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/bootstrap-toggle.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/groups-clients.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -140,7 +140,6 @@
|
||||
|
||||
<script src="scripts/vendor/bootstrap-select.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/bootstrap-toggle.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/groups-domains.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -78,7 +78,6 @@
|
||||
|
||||
<script src="scripts/vendor/bootstrap-select.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/bootstrap-toggle.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/groups.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -290,7 +290,6 @@ else
|
||||
<!-- /.row -->
|
||||
<?php } ?>
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/index.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th> </th>
|
||||
<th>Time</th>
|
||||
<th>Type</th>
|
||||
<th>Message</th>
|
||||
@@ -31,7 +32,7 @@
|
||||
<th>Data3</th>
|
||||
<th>Data4</th>
|
||||
<th>Data5</th>
|
||||
<th>Action</th>
|
||||
<th> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
@@ -43,7 +44,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/messages.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -64,7 +64,6 @@
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/network.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
|
||||
68
package-lock.json
generated
68
package-lock.json
generated
@@ -282,48 +282,48 @@
|
||||
}
|
||||
},
|
||||
"autoprefixer": {
|
||||
"version": "10.4.2",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.2.tgz",
|
||||
"integrity": "sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==",
|
||||
"version": "10.4.4",
|
||||
"resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.4.tgz",
|
||||
"integrity": "sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"browserslist": "^4.19.1",
|
||||
"caniuse-lite": "^1.0.30001297",
|
||||
"fraction.js": "^4.1.2",
|
||||
"browserslist": "^4.20.2",
|
||||
"caniuse-lite": "^1.0.30001317",
|
||||
"fraction.js": "^4.2.0",
|
||||
"normalize-range": "^0.1.2",
|
||||
"picocolors": "^1.0.0",
|
||||
"postcss-value-parser": "^4.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"browserslist": {
|
||||
"version": "4.19.1",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz",
|
||||
"integrity": "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==",
|
||||
"version": "4.20.2",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz",
|
||||
"integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"caniuse-lite": "^1.0.30001286",
|
||||
"electron-to-chromium": "^1.4.17",
|
||||
"caniuse-lite": "^1.0.30001317",
|
||||
"electron-to-chromium": "^1.4.84",
|
||||
"escalade": "^3.1.1",
|
||||
"node-releases": "^2.0.1",
|
||||
"node-releases": "^2.0.2",
|
||||
"picocolors": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"caniuse-lite": {
|
||||
"version": "1.0.30001298",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001298.tgz",
|
||||
"integrity": "sha512-AcKqikjMLlvghZL/vfTHorlQsLDhGRalYf1+GmWCf5SCMziSGjRYQW/JEksj14NaYHIR6KIhrFAy0HV5C25UzQ==",
|
||||
"version": "1.0.30001319",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001319.tgz",
|
||||
"integrity": "sha512-xjlIAFHucBRSMUo1kb5D4LYgcN1M45qdKP++lhqowDpwJwGkpIRTt5qQqnhxjj1vHcI7nrJxWhCC1ATrCEBTcw==",
|
||||
"dev": true
|
||||
},
|
||||
"electron-to-chromium": {
|
||||
"version": "1.4.38",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.38.tgz",
|
||||
"integrity": "sha512-WhHt3sZazKj0KK/UpgsbGQnUUoFeAHVishzHFExMxagpZgjiGYSC9S0ZlbhCfSH2L2i+2A1yyqOIliTctMx7KQ==",
|
||||
"version": "1.4.88",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.88.tgz",
|
||||
"integrity": "sha512-oA7mzccefkvTNi9u7DXmT0LqvhnOiN2BhSrKerta7HeUC1cLoIwtbf2wL+Ah2ozh5KQd3/1njrGrwDBXx6d14Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node-releases": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz",
|
||||
"integrity": "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==",
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz",
|
||||
"integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
@@ -1516,9 +1516,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"fraction.js": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
|
||||
"integrity": "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==",
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz",
|
||||
"integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==",
|
||||
"dev": true
|
||||
},
|
||||
"fs-extra": {
|
||||
@@ -2477,9 +2477,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz",
|
||||
"integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==",
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz",
|
||||
"integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==",
|
||||
"dev": true
|
||||
},
|
||||
"natural-compare": {
|
||||
@@ -2757,12 +2757,12 @@
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
"version": "8.4.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.6.tgz",
|
||||
"integrity": "sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==",
|
||||
"version": "8.4.12",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz",
|
||||
"integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"nanoid": "^3.2.0",
|
||||
"nanoid": "^3.3.1",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
}
|
||||
@@ -2825,9 +2825,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
|
||||
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz",
|
||||
"integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier-linter-helpers": {
|
||||
|
||||
@@ -24,11 +24,11 @@
|
||||
"testpr": "npm run prettier:fix && git diff --ws-error-highlight=all --color=always --exit-code && npm run xo"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.2",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"eslint-plugin-compat": "^4.0.2",
|
||||
"postcss": "^8.4.6",
|
||||
"postcss": "^8.4.12",
|
||||
"postcss-cli": "^9.1.0",
|
||||
"prettier": "2.5.1",
|
||||
"prettier": "2.6.0",
|
||||
"xo": "^0.48.0"
|
||||
},
|
||||
"browserslist": [
|
||||
@@ -52,7 +52,7 @@
|
||||
"plugin:compat/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 5,
|
||||
"ecmaVersion": "latest",
|
||||
"sourceType": "script"
|
||||
},
|
||||
"prettier": true,
|
||||
|
||||
15
queries.php
15
queries.php
@@ -46,7 +46,19 @@ if(isset($_GET["all"]))
|
||||
}
|
||||
else if(isset($_GET["client"]))
|
||||
{
|
||||
$showing .= " queries for client ".htmlentities($_GET["client"]);
|
||||
// Add switch between showing all queries and blocked only
|
||||
if (isset($_GET["type"]) && $_GET["type"] === "blocked")
|
||||
{
|
||||
// Show blocked queries for this client + link to all
|
||||
$showing .= " blocked queries for client ".htmlentities($_GET["client"]);
|
||||
$showing .= ", <a href=\"?client=".htmlentities($_GET["client"])."\">show all</a>";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show All queries for this client + link to show only blocked
|
||||
$showing .= " all queries for client ".htmlentities($_GET["client"]);
|
||||
$showing .= ", <a href=\"?client=".htmlentities($_GET["client"])."&type=blocked\">show blocked only</a>";
|
||||
}
|
||||
}
|
||||
else if(isset($_GET["forwarddest"]))
|
||||
{
|
||||
@@ -164,7 +176,6 @@ if(strlen($showing) > 0)
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<script src="scripts/pi-hole/js/ip-address-sorting.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/queries.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
<pre id="output" style="width: 100%; height: 100%;" hidden></pre>
|
||||
|
||||
<script src="scripts/pi-hole/js/queryads.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
require "scripts/pi-hole/php/footer.php";
|
||||
?>
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
/* global utils:false, Chart:false, moment:false */
|
||||
|
||||
var start__ = moment().subtract(7, "days");
|
||||
var from = moment(start__).utc().valueOf() / 1000;
|
||||
var from = Math.round(moment(start__).utc().valueOf() / 1000);
|
||||
var end__ = moment();
|
||||
var until = moment(end__).utc().valueOf() / 1000;
|
||||
var until = Math.round(moment(end__).utc().valueOf() / 1000);
|
||||
var interval = 0;
|
||||
|
||||
var dateformat = "MMMM Do YYYY, HH:mm";
|
||||
@@ -51,8 +51,8 @@ $(function () {
|
||||
autoUpdateInput: false,
|
||||
},
|
||||
function (startt, endt) {
|
||||
from = moment(startt).utc().valueOf() / 1000;
|
||||
until = moment(endt).utc().valueOf() / 1000;
|
||||
from = Math.round(moment(startt).utc().valueOf() / 1000);
|
||||
until = Math.round(moment(endt).utc().valueOf() / 1000);
|
||||
}
|
||||
);
|
||||
});
|
||||
@@ -63,32 +63,80 @@ function compareNumbers(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
function computeInterval(from, until) {
|
||||
// Compute interval to obtain about 200 values
|
||||
var num = 200;
|
||||
// humanly understandable intervals (in seconds)
|
||||
var intervals = [
|
||||
10,
|
||||
20,
|
||||
30,
|
||||
60,
|
||||
120,
|
||||
180,
|
||||
300,
|
||||
600,
|
||||
900,
|
||||
1200,
|
||||
1800,
|
||||
3600,
|
||||
3600 * 2,
|
||||
3600 * 3,
|
||||
3600 * 4,
|
||||
3600 * 6,
|
||||
3600 * 8,
|
||||
3600 * 12,
|
||||
3600 * 24,
|
||||
3600 * 24 * 7,
|
||||
3600 * 24 * 30,
|
||||
];
|
||||
|
||||
var duration = until - from;
|
||||
if (duration / (num * intervals[0]) < 1) {
|
||||
return intervals[0];
|
||||
}
|
||||
|
||||
var preverr = Number.MAX_VALUE,
|
||||
err;
|
||||
for (var i = 0; i < intervals.length; i++) {
|
||||
err = Math.abs(1 - duration / (num * intervals[i]));
|
||||
// pick the interval with least deviation
|
||||
// from selected duration
|
||||
if (preverr < err) {
|
||||
return intervals[i - 1];
|
||||
}
|
||||
|
||||
preverr = err;
|
||||
}
|
||||
|
||||
return intervals[intervals.length - 1];
|
||||
}
|
||||
|
||||
function updateQueriesOverTime() {
|
||||
var timeoutWarning = $("#timeoutWarning");
|
||||
|
||||
$("#queries-over-time .overlay").show();
|
||||
timeoutWarning.show();
|
||||
|
||||
// Compute interval to obtain about 200 values
|
||||
var num = 200;
|
||||
interval = (until - from) / num;
|
||||
interval = computeInterval(from, until);
|
||||
// Default displaying axis scaling
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "hour";
|
||||
|
||||
var duration = until - from;
|
||||
// Xaxis scaling based on selected daterange
|
||||
if (num * interval > 4 * 365 * 24 * 60 * 60) {
|
||||
if (duration > 4 * 365 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 4 years, set ticks interval to year
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "year";
|
||||
} else if (num * interval >= 366 * 24 * 60 * 60) {
|
||||
} else if (duration >= 366 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 1 year, set ticks interval to quarter
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "quarter";
|
||||
} else if (num * interval >= 92 * 24 * 60 * 60) {
|
||||
} else if (duration >= 92 * 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";
|
||||
} else if (num * interval >= 31 * 24 * 60 * 60) {
|
||||
} else if (duration >= 31 * 24 * 60 * 60) {
|
||||
// If the requested data is 1 month or more, set ticks interval to weeks
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "week";
|
||||
} else if (num * interval > 3 * 24 * 60 * 60) {
|
||||
} else if (duration > 3 * 24 * 60 * 60) {
|
||||
// If the requested data is more than 3 days (72 hours), set ticks interval to days
|
||||
timeLineChart.options.scales.xAxes[0].time.unit = "day";
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ function eventsource() {
|
||||
"message",
|
||||
function (e) {
|
||||
ta.append(e.data);
|
||||
// scroll page to the bottom (to the last received data)
|
||||
$("html, body").scrollTop($(document).height());
|
||||
},
|
||||
false
|
||||
);
|
||||
@@ -49,6 +51,7 @@ function eventsource() {
|
||||
"error",
|
||||
function () {
|
||||
source.close();
|
||||
$("#output").removeClass("loading");
|
||||
},
|
||||
false
|
||||
);
|
||||
@@ -57,5 +60,6 @@ function eventsource() {
|
||||
$("#debugBtn").on("click", function () {
|
||||
$("#debugBtn").prop("disabled", true);
|
||||
$("#upload").prop("disabled", true);
|
||||
$("#output").addClass("loading");
|
||||
eventsource();
|
||||
});
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
/* global utils:false */
|
||||
//The following functions allow us to display time until pi-hole is enabled after disabling.
|
||||
//Works between all pages
|
||||
|
||||
@@ -30,7 +31,7 @@ function piholeChanged(action) {
|
||||
break;
|
||||
|
||||
case "disabled":
|
||||
status.html("<i class='fa fa-circle text-red'></i> Offline");
|
||||
status.html("<i class='fa fa-circle text-red'></i> Blocking disabled");
|
||||
ena.show();
|
||||
dis.hide();
|
||||
break;
|
||||
@@ -101,28 +102,6 @@ function piholeChange(action, duration) {
|
||||
}
|
||||
}
|
||||
|
||||
function checkMessages() {
|
||||
var ignoreNonfatal = localStorage
|
||||
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
|
||||
: false;
|
||||
$.getJSON("api_db.php?status" + (ignoreNonfatal ? "&ignore=DNSMASQ_WARN" : ""), function (data) {
|
||||
if ("message_count" in data && data.message_count > 0) {
|
||||
var title =
|
||||
data.message_count > 1
|
||||
? "There are " + data.message_count + " warnings. Click for further details."
|
||||
: "There is one warning. Click for further details.";
|
||||
|
||||
$("#pihole-diagnosis").prop("title", title);
|
||||
$("#pihole-diagnosis-count").text(data.message_count);
|
||||
$("#pihole-diagnosis").removeClass("hidden");
|
||||
} else {
|
||||
$("#pihole-diagnosis").prop("title", "");
|
||||
$("#pihole-diagnosis-count").text(0);
|
||||
$("#pihole-diagnosis").addClass("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testCookies() {
|
||||
if (navigator.cookieEnabled) {
|
||||
return true;
|
||||
@@ -242,9 +221,9 @@ $(function () {
|
||||
initCPUtemp();
|
||||
|
||||
// Run check immediately after page loading ...
|
||||
checkMessages();
|
||||
utils.checkMessages();
|
||||
// ... and once again with five seconds delay
|
||||
setTimeout(checkMessages, 5000);
|
||||
setTimeout(utils.checkMessages, 5000);
|
||||
});
|
||||
|
||||
// Handle Enable/Disable
|
||||
|
||||
@@ -145,6 +145,7 @@ $(function () {
|
||||
order: [[0, "asc"]],
|
||||
columns: [
|
||||
{ data: "id", visible: false },
|
||||
{ data: null, visible: true, width: "15px" },
|
||||
{ data: "timestamp", width: "8%", render: renderTimestamp },
|
||||
{ data: "type", width: "8%" },
|
||||
{ data: "message", orderable: false, render: renderMessage },
|
||||
@@ -153,9 +154,17 @@ $(function () {
|
||||
{ data: "blob3", visible: false },
|
||||
{ data: "blob4", visible: false },
|
||||
{ data: "blob5", visible: false },
|
||||
{ data: null, width: "80px", orderable: false },
|
||||
{ data: null, width: "22px", orderable: false },
|
||||
],
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 1,
|
||||
orderable: false,
|
||||
className: "select-checkbox",
|
||||
render: function () {
|
||||
return "";
|
||||
},
|
||||
},
|
||||
{
|
||||
targets: "_all",
|
||||
render: $.fn.dataTable.render.text(),
|
||||
@@ -163,6 +172,11 @@ $(function () {
|
||||
],
|
||||
drawCallback: function () {
|
||||
$('button[id^="deleteMessage_"]').on("click", deleteMessage);
|
||||
|
||||
// Hide buttons if all messages were deleted
|
||||
var hasRows = this.api().rows({ filter: "applied" }).data().length > 0;
|
||||
$(".datatable-bt").css("visibility", hasRows ? "visible" : "hidden");
|
||||
|
||||
// Remove visible dropdown to prevent orphaning
|
||||
$("body > .bootstrap-select.dropdown").remove();
|
||||
},
|
||||
@@ -171,16 +185,63 @@ $(function () {
|
||||
var button =
|
||||
'<button type="button" class="btn btn-danger btn-xs" id="deleteMessage_' +
|
||||
data.id +
|
||||
'" data-del-id="' +
|
||||
data.id +
|
||||
'">' +
|
||||
'<span class="far fa-trash-alt"></span>' +
|
||||
"</button>";
|
||||
$("td:eq(3)", row).html(button);
|
||||
$("td:eq(4)", row).html(button);
|
||||
},
|
||||
select: {
|
||||
style: "multi",
|
||||
selector: "td:not(:last-child)",
|
||||
info: false,
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: '<span class="far fa-square"></span>',
|
||||
titleAttr: "Select All",
|
||||
className: "btn-sm datatable-bt selectAll",
|
||||
action: function () {
|
||||
table.rows({ page: "current" }).select();
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '<span class="far fa-plus-square"></span>',
|
||||
titleAttr: "Select All",
|
||||
className: "btn-sm datatable-bt selectMore",
|
||||
action: function () {
|
||||
table.rows({ page: "current" }).select();
|
||||
},
|
||||
},
|
||||
{
|
||||
extend: "selectNone",
|
||||
text: '<span class="far fa-check-square"></span>',
|
||||
titleAttr: "Deselect All",
|
||||
className: "btn-sm datatable-bt removeAll",
|
||||
},
|
||||
{
|
||||
text: '<span class="far fa-trash-alt"></span>',
|
||||
titleAttr: "Delete Selected",
|
||||
className: "btn-sm datatable-bt deleteSelected",
|
||||
action: function () {
|
||||
// For each ".selected" row ...
|
||||
var ids = [];
|
||||
$("tr.selected").each(function () {
|
||||
// ... add the row identified by "data-id".
|
||||
ids.push(parseInt($(this).attr("data-id"), 10));
|
||||
});
|
||||
// Delete all selected rows at once
|
||||
delMsg(ids);
|
||||
},
|
||||
},
|
||||
],
|
||||
dom:
|
||||
"<'row'<'col-sm-12'f>>" +
|
||||
"<'row'<'col-sm-4'l><'col-sm-8'p>>" +
|
||||
"<'row'<'col-sm-6'l><'col-sm-6'f>>" +
|
||||
"<'row'<'col-sm-3'B><'col-sm-9'p>>" +
|
||||
"<'row'<'col-sm-12'<'table-responsive'tr>>>" +
|
||||
"<'row'<'col-sm-5'i><'col-sm-7'p>>",
|
||||
"<'row'<'col-sm-3'B><'col-sm-9'p>>" +
|
||||
"<'row'<'col-sm-12'i>>",
|
||||
lengthMenu: [
|
||||
[10, 25, 50, 100, -1],
|
||||
[10, 25, 50, 100, "All"],
|
||||
@@ -201,7 +262,7 @@ $(function () {
|
||||
}
|
||||
|
||||
// Reset visibility of ID and blob columns
|
||||
var hiddenCols = [0, 4, 5, 6, 7, 8];
|
||||
var hiddenCols = [0, 5, 6, 7, 8, 9];
|
||||
for (var key in hiddenCols) {
|
||||
if (Object.prototype.hasOwnProperty.call(hiddenCols, key)) {
|
||||
data.columns[hiddenCols[key]].visible = false;
|
||||
@@ -212,42 +273,94 @@ $(function () {
|
||||
return data;
|
||||
},
|
||||
});
|
||||
table.on("init select deselect", function () {
|
||||
changeButtonStates();
|
||||
});
|
||||
});
|
||||
|
||||
// Show only the appropriate buttons
|
||||
function changeButtonStates() {
|
||||
var allRows = table.rows({ filter: "applied" }).data().length;
|
||||
var pageLength = table.page.len();
|
||||
var selectedRows = table.rows(".selected").data().length;
|
||||
|
||||
if (selectedRows === 0) {
|
||||
// Nothing selected
|
||||
$(".selectAll").removeClass("hidden");
|
||||
$(".selectMore").addClass("hidden");
|
||||
$(".removeAll").addClass("hidden");
|
||||
$(".deleteSelected").addClass("hidden");
|
||||
} else if (selectedRows >= pageLength || selectedRows === allRows) {
|
||||
// Whole page is selected (or all available messages were selected)
|
||||
$(".selectAll").addClass("hidden");
|
||||
$(".selectMore").addClass("hidden");
|
||||
$(".removeAll").removeClass("hidden");
|
||||
$(".deleteSelected").removeClass("hidden");
|
||||
} else {
|
||||
// Some rows are selected, but not all
|
||||
$(".selectAll").addClass("hidden");
|
||||
$(".selectMore").removeClass("hidden");
|
||||
$(".removeAll").addClass("hidden");
|
||||
$(".deleteSelected").removeClass("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
// Remove 'bnt-group' class from container, to avoid grouping
|
||||
$.fn.dataTable.Buttons.defaults.dom.container.className = "dt-buttons";
|
||||
|
||||
function deleteMessage() {
|
||||
var tr = $(this).closest("tr");
|
||||
var id = tr.attr("data-id");
|
||||
// Passes the button data-del-id attribute as ID
|
||||
var ids = [parseInt($(this).attr("data-del-id"), 10)];
|
||||
delMsg(ids);
|
||||
}
|
||||
|
||||
function delMsg(ids) {
|
||||
// Check input validity
|
||||
if (!Array.isArray(ids)) return;
|
||||
|
||||
// Exploit prevention: Return early for non-numeric IDs
|
||||
for (var id in ids) {
|
||||
if (Object.hasOwnProperty.call(ids, id) && typeof ids[id] !== "number") return;
|
||||
}
|
||||
|
||||
utils.disableAll();
|
||||
utils.showAlert("info", "", "Deleting message with ID " + parseInt(id, 10), "...");
|
||||
var idstring = ids.join(", ");
|
||||
utils.showAlert("info", "", "Deleting messages: " + idstring, "...");
|
||||
|
||||
$.ajax({
|
||||
url: "scripts/pi-hole/php/message.php",
|
||||
method: "post",
|
||||
dataType: "json",
|
||||
data: { action: "delete_message", id: id, token: token },
|
||||
success: function (response) {
|
||||
data: { action: "delete_message", id: JSON.stringify(ids), token: token },
|
||||
})
|
||||
.done(function (response) {
|
||||
utils.enableAll();
|
||||
if (response.success) {
|
||||
utils.showAlert("success", "far fa-trash-alt", "Successfully deleted message # ", id);
|
||||
table.row(tr).remove().draw(false).ajax.reload(null, false);
|
||||
} else {
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting message with ID " + id,
|
||||
response.message
|
||||
"success",
|
||||
"far fa-trash-alt",
|
||||
"Successfully deleted messages: " + idstring,
|
||||
""
|
||||
);
|
||||
for (var id in ids) {
|
||||
if (Object.hasOwnProperty.call(ids, id)) {
|
||||
table.row(id).remove().draw(false).ajax.reload(null, false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
utils.showAlert("error", "", "Error while deleting message: " + idstring, response.message);
|
||||
}
|
||||
},
|
||||
error: function (jqXHR, exception) {
|
||||
|
||||
// Clear selection after deletion
|
||||
table.rows().deselect();
|
||||
changeButtonStates();
|
||||
})
|
||||
.done(
|
||||
utils.checkMessages // Update icon warnings count
|
||||
)
|
||||
.fail(function (jqXHR, exception) {
|
||||
utils.enableAll();
|
||||
utils.showAlert(
|
||||
"error",
|
||||
"",
|
||||
"Error while deleting message with ID " + id,
|
||||
jqXHR.responseText
|
||||
);
|
||||
utils.showAlert("error", "", "Error while deleting message: " + idstring, jqXHR.responseText);
|
||||
console.log(exception); // eslint-disable-line no-console
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -450,7 +450,7 @@ $(function () {
|
||||
|
||||
$("#all-queries tbody").on("click", "button", function () {
|
||||
var data = tableApi.row($(this).parents("tr")).data();
|
||||
if (data[4] === "2" || data[4] === "3") {
|
||||
if (data[4] === "2" || data[4] === "3" || data[4] === "14") {
|
||||
utils.addFromQueryLog(data[2], "black");
|
||||
} else {
|
||||
utils.addFromQueryLog(data[2], "white");
|
||||
|
||||
@@ -360,6 +360,26 @@ function colorBar(percentage, total, cssClass) {
|
||||
return '<div class="progress progress-sm" title="' + title + '"> ' + bar + " </div>";
|
||||
}
|
||||
|
||||
function checkMessages() {
|
||||
var ignoreNonfatal = localStorage
|
||||
? localStorage.getItem("hideNonfatalDnsmasqWarnings_chkbox") === "true"
|
||||
: false;
|
||||
$.getJSON("api_db.php?status" + (ignoreNonfatal ? "&ignore=DNSMASQ_WARN" : ""), function (data) {
|
||||
if ("message_count" in data && data.message_count > 0) {
|
||||
var title =
|
||||
data.message_count > 1
|
||||
? "There are " + data.message_count + " warnings. Click for further details."
|
||||
: "There is one warning. Click for further details.";
|
||||
|
||||
$("#pihole-diagnosis").prop("title", title);
|
||||
$("#pihole-diagnosis-count").text(data.message_count);
|
||||
$("#pihole-diagnosis").removeClass("hidden");
|
||||
} else {
|
||||
$("#pihole-diagnosis").addClass("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
window.utils = (function () {
|
||||
return {
|
||||
escapeHtml: escapeHtml,
|
||||
@@ -382,5 +402,6 @@ window.utils = (function () {
|
||||
addFromQueryLog: addFromQueryLog,
|
||||
addTD: addTD,
|
||||
colorBar: colorBar,
|
||||
checkMessages: checkMessages,
|
||||
};
|
||||
})();
|
||||
|
||||
@@ -6,88 +6,93 @@
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
$piholeFTLConfFile = "/etc/pihole/pihole-FTL.conf";
|
||||
const DEFAULT_FTLCONFFILE = "/etc/pihole/pihole-FTL.conf";
|
||||
const DEFAULT_FTL_IP = "127.0.0.1";
|
||||
const DEFAULT_FTL_PORT = 4711;
|
||||
|
||||
function piholeFTLConfig()
|
||||
{
|
||||
static $piholeFTLConfig;
|
||||
global $piholeFTLConfFile;
|
||||
function piholeFTLConfig($piholeFTLConfFile = DEFAULT_FTLCONFFILE, $force = false) {
|
||||
static $piholeFTLConfig;
|
||||
|
||||
if(isset($piholeFTLConfig))
|
||||
{
|
||||
return $piholeFTLConfig;
|
||||
}
|
||||
if (isset($piholeFTLConfig) && !$force) {
|
||||
return $piholeFTLConfig;
|
||||
}
|
||||
|
||||
if(is_readable($piholeFTLConfFile))
|
||||
{
|
||||
$piholeFTLConfig = parse_ini_file($piholeFTLConfFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
$piholeFTLConfig = array();
|
||||
}
|
||||
if (is_readable($piholeFTLConfFile)) {
|
||||
$piholeFTLConfig = parse_ini_file($piholeFTLConfFile);
|
||||
} else {
|
||||
$piholeFTLConfig = array();
|
||||
}
|
||||
|
||||
return $piholeFTLConfig;
|
||||
return $piholeFTLConfig;
|
||||
}
|
||||
|
||||
function connectFTL($address, $port=4711)
|
||||
{
|
||||
if($address == "127.0.0.1")
|
||||
{
|
||||
$config = piholeFTLConfig();
|
||||
// Read port
|
||||
$portfileName = isset($config['PORTFILE']) ? $config['PORTFILE'] : '';
|
||||
if ($portfileName != '')
|
||||
{
|
||||
$portfileContents = file_get_contents($portfileName);
|
||||
if(is_numeric($portfileContents))
|
||||
$port = intval($portfileContents);
|
||||
}
|
||||
}
|
||||
function connectFTL($address, $port) {
|
||||
if ($address == DEFAULT_FTL_IP) {
|
||||
$config = piholeFTLConfig();
|
||||
// Read port
|
||||
$portfileName = isset($config['PORTFILE']) ? $config['PORTFILE'] : '';
|
||||
if ($portfileName != '') {
|
||||
$portfileContents = file_get_contents($portfileName);
|
||||
if (is_numeric($portfileContents)) {
|
||||
$port = intval($portfileContents);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Open Internet socket connection
|
||||
$socket = @fsockopen($address, $port, $errno, $errstr, 1.0);
|
||||
// Open Internet socket connection
|
||||
$socket = @fsockopen($address, $port, $errno, $errstr, 1.0);
|
||||
|
||||
return $socket;
|
||||
return $socket;
|
||||
}
|
||||
|
||||
function sendRequestFTL($requestin)
|
||||
{
|
||||
global $socket;
|
||||
|
||||
$request = ">".$requestin;
|
||||
fwrite($socket, $request) or die('{"error":"Could not send data to server"}');
|
||||
function sendRequestFTL($requestin, $socket) {
|
||||
$request = ">".$requestin;
|
||||
fwrite($socket, $request) or die('{"error":"Could not send data to server"}');
|
||||
}
|
||||
|
||||
function getResponseFTL()
|
||||
{
|
||||
global $socket;
|
||||
function getResponseFTL($socket) {
|
||||
$response = [];
|
||||
|
||||
$response = [];
|
||||
$errCount = 0;
|
||||
while (true) {
|
||||
$out = fgets($socket);
|
||||
if ($out == "") {
|
||||
$errCount++;
|
||||
}
|
||||
|
||||
$errCount = 0;
|
||||
while(true)
|
||||
{
|
||||
$out = fgets($socket);
|
||||
if ($out == "") $errCount++;
|
||||
if ($errCount > 100) {
|
||||
// Tried 100 times, but never got proper reply, fail to prevent busy loop
|
||||
die('{"error":"Tried 100 times to connect to FTL server, but never got proper reply. Please check Port and logs!"}');
|
||||
}
|
||||
if(strrpos($out,"---EOM---") !== false)
|
||||
break;
|
||||
if ($errCount > 100) {
|
||||
// Tried 100 times, but never got proper reply, fail to prevent busy loop
|
||||
die('{"error":"Tried 100 times to connect to FTL server, but never got proper reply. Please check Port and logs!"}');
|
||||
}
|
||||
|
||||
$out = rtrim($out);
|
||||
if(strlen($out) > 0)
|
||||
$response[] = $out;
|
||||
}
|
||||
if (strrpos($out,"---EOM---") !== false) {
|
||||
break;
|
||||
}
|
||||
|
||||
return $response;
|
||||
$out = rtrim($out);
|
||||
if (strlen($out) > 0) {
|
||||
$response[] = $out;
|
||||
}
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
function disconnectFTL()
|
||||
{
|
||||
global $socket;
|
||||
fclose($socket);
|
||||
function disconnectFTL($socket) {
|
||||
fclose($socket);
|
||||
}
|
||||
|
||||
function callFTLAPI($request, $FTL_IP = DEFAULT_FTL_IP, $port = DEFAULT_FTL_PORT) {
|
||||
$socket = connectFTL($FTL_IP, $port);
|
||||
|
||||
if (!is_resource($socket)) {
|
||||
$data = array("FTLnotrunning" => true);
|
||||
} else {
|
||||
sendRequestFTL($request, $socket);
|
||||
$data = getResponseFTL($socket);
|
||||
}
|
||||
disconnectFTL($socket);
|
||||
|
||||
return $data;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
<?php
|
||||
require "auth.php";
|
||||
require "password.php";
|
||||
check_cors();
|
||||
?>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
@@ -24,10 +30,6 @@ body {
|
||||
</head>
|
||||
<body>
|
||||
<?php
|
||||
require "auth.php";
|
||||
require "password.php";
|
||||
check_cors();
|
||||
|
||||
if($auth) {
|
||||
if(strlen($pwhash) > 0) {
|
||||
echo '<div class="qrcode">';
|
||||
|
||||
@@ -8,7 +8,7 @@ header('Cache-Control: no-cache');
|
||||
require "password.php";
|
||||
require "auth.php";
|
||||
|
||||
if(!$auth) {
|
||||
if (!$auth) {
|
||||
die("Unauthorized");
|
||||
}
|
||||
|
||||
@@ -18,22 +18,43 @@ $token = isset($_GET["token"]) ? $_GET["token"] : "";
|
||||
check_csrf($token);
|
||||
|
||||
function echoEvent($datatext) {
|
||||
$data = htmlspecialchars($datatext);
|
||||
$ANSIcolors = array(
|
||||
chr(27)."[1;91m" => '<span class="log-red">',
|
||||
chr(27)."[1;32m" => '<span class="log-green">',
|
||||
chr(27)."[1;33m" => '<span class="log-yellow">',
|
||||
chr(27)."[1;34m" => '<span class="log-blue">',
|
||||
chr(27)."[1;35m" => '<span class="log-purple">',
|
||||
chr(27)."[1;36m" => '<span class="log-cyan">',
|
||||
|
||||
if(!isset($_GET["IE"]))
|
||||
echo "data: ".implode("\ndata: ", explode("\n", $data))."\n\n";
|
||||
else
|
||||
echo $data;
|
||||
chr(27)."[90m" => '<span class="log-gray">',
|
||||
chr(27)."[91m" => '<span class="log-red">',
|
||||
chr(27)."[32m" => '<span class="log-green">',
|
||||
chr(27)."[33m" => '<span class="log-yellow">',
|
||||
chr(27)."[94m" => '<span class="log-blue">',
|
||||
chr(27)."[95m" => '<span class="log-purple">',
|
||||
chr(27)."[96m" => '<span class="log-cyan">',
|
||||
|
||||
chr(27)."[1m" => '<span class="text-bold">',
|
||||
chr(27)."[4m" => '<span class="text-underline">',
|
||||
|
||||
chr(27)."[0m" => '</span>',
|
||||
);
|
||||
|
||||
$data = str_replace(array_keys($ANSIcolors), $ANSIcolors, htmlspecialchars($datatext));
|
||||
|
||||
if (!isset($_GET["IE"])) {
|
||||
echo "data: ".implode("\ndata: ", explode("\n", $data))."\n\n";
|
||||
} else {
|
||||
echo $data;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_GET["upload"]))
|
||||
{
|
||||
$proc = popen("sudo pihole -d -a -w", "r");
|
||||
}
|
||||
else
|
||||
{
|
||||
$proc = popen("sudo pihole -d -w", "r");
|
||||
if (isset($_GET["upload"])) {
|
||||
$proc = popen("sudo pihole -d -a -w", "r");
|
||||
} else {
|
||||
$proc = popen("sudo pihole -d -w", "r");
|
||||
}
|
||||
|
||||
while (!feof($proc)) {
|
||||
echoEvent(fread($proc, 4096));
|
||||
}
|
||||
|
||||
@@ -484,30 +484,33 @@ function getQueryTypeStr($querytype)
|
||||
}
|
||||
|
||||
// Returns an integer representing pihole blocking status
|
||||
function piholeStatus()
|
||||
{
|
||||
// Receive the return of "pihole status web"
|
||||
$pistatus = pihole_execute('status web');
|
||||
return isset($pistatus[0]) ? intval($pistatus[0]) : -2;
|
||||
}
|
||||
function piholeStatus() {
|
||||
// Retrieve DNS Port calling FTL API directly
|
||||
$port = callFTLAPI("dns-port");
|
||||
|
||||
// Returns pihole status, using only valid API responses (enabled/disabled)
|
||||
function piholeStatusAPI()
|
||||
{
|
||||
// Receive the return of "pihole status web"
|
||||
$pistatus = piholeStatus();
|
||||
// Retrieve FTL status
|
||||
$FTLstats = callFTLAPI("stats");
|
||||
|
||||
switch ($pistatus) {
|
||||
case -2: // Unkown
|
||||
case -1: // DNS service not running"
|
||||
case 0: // Offline
|
||||
$response = "disabled";
|
||||
break;
|
||||
|
||||
default:
|
||||
// DNS service running on port $returncode
|
||||
$response = "enabled";
|
||||
if (array_key_exists("FTLnotrunning", $port) || array_key_exists("FTLnotrunning", $FTLstats)){
|
||||
// FTL is not running
|
||||
$ret = -1;
|
||||
} elseif (in_array("status enabled", $FTLstats)) {
|
||||
// FTL is enabled
|
||||
if (intval($port[0]) <= 0) {
|
||||
// Port=0; FTL is not listening
|
||||
$ret = -1;
|
||||
} else {
|
||||
// FTL is running on this port
|
||||
$ret = intval($port[0]);
|
||||
}
|
||||
} elseif (in_array("status disabled", $FTLstats)) {
|
||||
// FTL is disabled
|
||||
$ret = 0;
|
||||
} else {
|
||||
// Unknown (unexpected) response
|
||||
$ret = -2;
|
||||
}
|
||||
return $response;
|
||||
|
||||
return $ret;
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -204,6 +204,7 @@
|
||||
<link rel="stylesheet" href="style/vendor/SourceSansPro/SourceSansPro.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/bootstrap/css/bootstrap.min.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/datatables.min.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/datatables_extensions.min.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/daterangepicker.min.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/AdminLTE.min.css?v=<?=$cacheVer?>">
|
||||
<link rel="stylesheet" href="style/vendor/select2.min.css?v=<?=$cacheVer?>">
|
||||
@@ -223,9 +224,12 @@
|
||||
<script src="scripts/vendor/bootstrap-notify.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/select2.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/datatables.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/datatables.select.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/datatables.buttons.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/moment.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/vendor/Chart.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="style/vendor/font-awesome/js/all.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
</head>
|
||||
<body class="hold-transition sidebar-mini <?php if($boxedlayout){ ?>layout-boxed<?php } ?>">
|
||||
<noscript>
|
||||
@@ -338,7 +342,7 @@ if($auth) {
|
||||
if ($pistatus == 53) {
|
||||
echo '<span id="status"><i class="fa fa-w fa-circle text-green-light"></i> Active</span>';
|
||||
} elseif ($pistatus == 0) {
|
||||
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> Offline</span>';
|
||||
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> Blocking disabled</span>';
|
||||
} elseif ($pistatus == -1) {
|
||||
echo '<span id="status"><i class="fa fa-w fa-circle text-red"></i> DNS service not running</span>';
|
||||
} elseif ($pistatus == -2) {
|
||||
@@ -642,7 +646,7 @@ if($auth) {
|
||||
<!-- Donate -->
|
||||
<li>
|
||||
<a href="https://pi-hole.net/donate/" rel="noopener" target="_blank">
|
||||
<i class="fab fa-fw menu-icon fa-paypal"></i> <span>Donate</span>
|
||||
<i class="fas fa-fw menu-icon fa-donate"></i> <span>Donate</span>
|
||||
</a>
|
||||
</li>
|
||||
<!-- Docs -->
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<div class="text-center">
|
||||
<img src="img/logo.svg" alt="Pi-hole logo" style="width: <?php if ($boxedlayout) { ?>50%<?php } else { ?>30%<?php } ?>;">
|
||||
<img src="img/logo.svg" alt="Pi-hole logo" class="loginpage-logo">
|
||||
</div>
|
||||
<br>
|
||||
|
||||
@@ -26,31 +26,24 @@
|
||||
|
||||
<div class="panel-body">
|
||||
<form action="" id="loginform" method="post">
|
||||
<div class="form-group has-feedback <?php if ($wrongpassword) { ?>has-error<?php } ?>">
|
||||
<input type="password" id="loginpw" name="pw" class="form-control" placeholder="Password" autocomplete="current-password" autofocus>
|
||||
<span class="fa fa-key form-control-feedback"></span>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-12">
|
||||
<button type="submit" class="btn btn-primary form-control"><i class="fas fa-sign-in-alt"></i> Log in</button>
|
||||
<div class="form-group login-options has-feedback<?php if ($wrongpassword) { ?> has-error<?php } ?>">
|
||||
<div class="pwd-field">
|
||||
<input type="password" id="loginpw" name="pw" class="form-control" placeholder="Password" autocomplete="current-password" autofocus>
|
||||
<span class="fa fa-key form-control-feedback"></span>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="logincookie" name="persistentlogin">
|
||||
<label for="logincookie">Remember me for 7 days</label>
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col-xs-8 hidden-xs hidden-sm">
|
||||
<ul>
|
||||
<li><kbd>Return</kbd> → Log in and go to requested page (<?php echo $scriptname; ?>)</li>
|
||||
<li><kbd>Ctrl</kbd>+<kbd>Return</kbd> → Log in and go to Settings page</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-4">
|
||||
<div>
|
||||
<input type="checkbox" id="logincookie" name="persistentlogin">
|
||||
<label for="logincookie">Remember me for 7 days</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<button type="submit" class="btn btn-primary form-control"><i class="fas fa-sign-in-alt"></i> Log in</button>
|
||||
</div>
|
||||
<br>
|
||||
<div class="box login-help hidden-xs">
|
||||
<p><kbd>Return</kbd> ➜ Log in and go to requested page (<?php echo $scriptname; ?>)</p>
|
||||
<p><kbd>Ctrl</kbd> + <kbd>Return</kbd> ➜ Log in and go to Settings page</p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12">
|
||||
<div class="box box-<?php if (!$wrongpassword) { ?>info collapsed-box<?php } else { ?>danger<?php }?>">
|
||||
|
||||
@@ -42,23 +42,23 @@ function JSON_error($message = null)
|
||||
echo json_encode($response);
|
||||
}
|
||||
|
||||
// Delete message identified by IDs
|
||||
if ($_POST['action'] == 'delete_message' && isset($_POST['id'])) {
|
||||
// Delete message identified by ID
|
||||
try {
|
||||
|
||||
$stmt = $db->prepare('DELETE FROM message WHERE id=:id');
|
||||
if (!$stmt) {
|
||||
$ids = json_decode($_POST['id']);
|
||||
if(!is_array($ids))
|
||||
throw new Exception('Invalid payload: id is not an array');
|
||||
// Explot prevention: Ensure all entries in the ID array are integers
|
||||
foreach($ids as $value) {
|
||||
if (!is_numeric($value))
|
||||
throw new Exception('Invalid payload: id contains non-numeric entries');
|
||||
}
|
||||
$stmt = $db->prepare('DELETE FROM message WHERE id IN ('.implode(",",$ids).')');
|
||||
if (!$stmt)
|
||||
throw new Exception('While preparing message statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
|
||||
throw new Exception('While binding id to message statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
if (!$stmt->execute()) {
|
||||
if (!$stmt->execute())
|
||||
throw new Exception('While executing message statement: ' . $db->lastErrorMsg());
|
||||
}
|
||||
|
||||
|
||||
$reload = true;
|
||||
JSON_success();
|
||||
|
||||
@@ -352,6 +352,13 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
|
||||
}
|
||||
pihole_execute("-a -i ".$DNSinterface." -web");
|
||||
|
||||
// Add rate-limiting settings
|
||||
if(isset($_POST["rate_limit_count"]) && isset($_POST["rate_limit_interval"]))
|
||||
{
|
||||
// Restart of FTL is delayed
|
||||
pihole_execute("-a ratelimit " . intval($_POST["rate_limit_count"]) . " " . intval($_POST["rate_limit_interval"]) . " false");
|
||||
}
|
||||
|
||||
// If there has been no error we can save the new DNS server IPs
|
||||
if(!strlen($error))
|
||||
{
|
||||
|
||||
51
scripts/vendor/datatables.buttons.min.js
vendored
Normal file
51
scripts/vendor/datatables.buttons.min.js
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
/*!
|
||||
Buttons for DataTables 1.7.1
|
||||
©2016-2021 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(e){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(y){return e(y,window,document)}):"object"===typeof exports?module.exports=function(y,w){y||(y=window);w&&w.fn.dataTable||(w=require("datatables.net")(y,w).$);return e(w,y,y.document)}:e(jQuery,window,document)})(function(e,y,w,r){function B(a,b,c){e.fn.animate?a.stop().fadeIn(b,c):(a.css("display","block"),c&&c.call(a))}function C(a,b,c){e.fn.animate?a.stop().fadeOut(b,c):(a.css("display","none"),c&&c.call(a))}
|
||||
function E(a,b){a=new q.Api(a);b=b?b:a.init().buttons||q.defaults.buttons;return(new t(a,b)).container()}var q=e.fn.dataTable,I=0,J=0,x=q.ext.buttons,t=function(a,b){if(!(this instanceof t))return function(c){return(new t(c,a)).container()};"undefined"===typeof b&&(b={});!0===b&&(b={});Array.isArray(b)&&(b={buttons:b});this.c=e.extend(!0,{},t.defaults,b);b.buttons&&(this.c.buttons=b.buttons);this.s={dt:new q.Api(a),buttons:[],listenKeys:"",namespace:"dtb"+I++};this.dom={container:e("<"+this.c.dom.container.tag+
|
||||
"/>").addClass(this.c.dom.container.className)};this._constructor()};e.extend(t.prototype,{action:function(a,b){a=this._nodeToButton(a);if(b===r)return a.conf.action;a.conf.action=b;return this},active:function(a,b){var c=this._nodeToButton(a);a=this.c.dom.button.active;c=e(c.node);if(b===r)return c.hasClass(a);c.toggleClass(a,b===r?!0:b);return this},add:function(a,b){var c=this.s.buttons;if("string"===typeof b){b=b.split("-");var d=this.s;c=0;for(var f=b.length-1;c<f;c++)d=d.buttons[1*b[c]];c=d.buttons;
|
||||
b=1*b[b.length-1]}this._expandButton(c,a,d!==r,b);this._draw();return this},container:function(){return this.dom.container},disable:function(a){a=this._nodeToButton(a);e(a.node).addClass(this.c.dom.button.disabled).attr("disabled",!0);return this},destroy:function(){e("body").off("keyup."+this.s.namespace);var a=this.s.buttons.slice(),b;var c=0;for(b=a.length;c<b;c++)this.remove(a[c].node);this.dom.container.remove();a=this.s.dt.settings()[0];c=0;for(b=a.length;c<b;c++)if(a.inst===this){a.splice(c,
|
||||
1);break}return this},enable:function(a,b){if(!1===b)return this.disable(a);a=this._nodeToButton(a);e(a.node).removeClass(this.c.dom.button.disabled).removeAttr("disabled");return this},name:function(){return this.c.name},node:function(a){if(!a)return this.dom.container;a=this._nodeToButton(a);return e(a.node)},processing:function(a,b){var c=this.s.dt,d=this._nodeToButton(a);if(b===r)return e(d.node).hasClass("processing");e(d.node).toggleClass("processing",b);e(c.table().node()).triggerHandler("buttons-processing.dt",
|
||||
[b,c.button(a),c,e(a),d.conf]);return this},remove:function(a){var b=this._nodeToButton(a),c=this._nodeToHost(a),d=this.s.dt;if(b.buttons.length)for(var f=b.buttons.length-1;0<=f;f--)this.remove(b.buttons[f].node);b.conf.destroy&&b.conf.destroy.call(d.button(a),d,e(a),b.conf);this._removeKey(b.conf);e(b.node).remove();a=e.inArray(b,c);c.splice(a,1);return this},text:function(a,b){var c=this._nodeToButton(a);a=this.c.dom.collection.buttonLiner;a=c.inCollection&&a&&a.tag?a.tag:this.c.dom.buttonLiner.tag;
|
||||
var d=this.s.dt,f=e(c.node),h=function(m){return"function"===typeof m?m(d,f,c.conf):m};if(b===r)return h(c.conf.text);c.conf.text=b;a?f.children(a).html(h(b)):f.html(h(b));return this},_constructor:function(){var a=this,b=this.s.dt,c=b.settings()[0],d=this.c.buttons;c._buttons||(c._buttons=[]);c._buttons.push({inst:this,name:this.c.name});for(var f=0,h=d.length;f<h;f++)this.add(d[f]);b.on("destroy",function(m,g){g===c&&a.destroy()});e("body").on("keyup."+this.s.namespace,function(m){if(!w.activeElement||
|
||||
w.activeElement===w.body){var g=String.fromCharCode(m.keyCode).toLowerCase();-1!==a.s.listenKeys.toLowerCase().indexOf(g)&&a._keypress(g,m)}})},_addKey:function(a){a.key&&(this.s.listenKeys+=e.isPlainObject(a.key)?a.key.key:a.key)},_draw:function(a,b){a||(a=this.dom.container,b=this.s.buttons);a.children().detach();for(var c=0,d=b.length;c<d;c++)a.append(b[c].inserter),a.append(" "),b[c].buttons&&b[c].buttons.length&&this._draw(b[c].collection,b[c].buttons)},_expandButton:function(a,b,c,d){var f=
|
||||
this.s.dt,h=0;b=Array.isArray(b)?b:[b];for(var m=0,g=b.length;m<g;m++){var n=this._resolveExtends(b[m]);if(n)if(Array.isArray(n))this._expandButton(a,n,c,d);else{var k=this._buildButton(n,c);k&&(d!==r&&null!==d?(a.splice(d,0,k),d++):a.push(k),k.conf.buttons&&(k.collection=e("<"+this.c.dom.collection.tag+"/>"),k.conf._collection=k.collection,this._expandButton(k.buttons,k.conf.buttons,!0,d)),n.init&&n.init.call(f.button(k.node),f,e(k.node),n),h++)}}},_buildButton:function(a,b){var c=this.c.dom.button,
|
||||
d=this.c.dom.buttonLiner,f=this.c.dom.collection,h=this.s.dt,m=function(p){return"function"===typeof p?p(h,k,a):p};b&&f.button&&(c=f.button);b&&f.buttonLiner&&(d=f.buttonLiner);if(a.available&&!a.available(h,a))return!1;var g=function(p,l,v,u){u.action.call(l.button(v),p,l,v,u);e(l.table().node()).triggerHandler("buttons-action.dt",[l.button(v),l,v,u])};f=a.tag||c.tag;var n=a.clickBlurs===r?!0:a.clickBlurs,k=e("<"+f+"/>").addClass(c.className).attr("tabindex",this.s.dt.settings()[0].iTabIndex).attr("aria-controls",
|
||||
this.s.dt.table().node().id).on("click.dtb",function(p){p.preventDefault();!k.hasClass(c.disabled)&&a.action&&g(p,h,k,a);n&&k.trigger("blur")}).on("keyup.dtb",function(p){13===p.keyCode&&!k.hasClass(c.disabled)&&a.action&&g(p,h,k,a)});"a"===f.toLowerCase()&&k.attr("href","#");"button"===f.toLowerCase()&&k.attr("type","button");d.tag?(f=e("<"+d.tag+"/>").html(m(a.text)).addClass(d.className),"a"===d.tag.toLowerCase()&&f.attr("href","#"),k.append(f)):k.html(m(a.text));!1===a.enabled&&k.addClass(c.disabled);
|
||||
a.className&&k.addClass(a.className);a.titleAttr&&k.attr("title",m(a.titleAttr));a.attr&&k.attr(a.attr);a.namespace||(a.namespace=".dt-button-"+J++);d=(d=this.c.dom.buttonContainer)&&d.tag?e("<"+d.tag+"/>").addClass(d.className).append(k):k;this._addKey(a);this.c.buttonCreated&&(d=this.c.buttonCreated(a,d));return{conf:a,node:k.get(0),inserter:d,buttons:[],inCollection:b,collection:null}},_nodeToButton:function(a,b){b||(b=this.s.buttons);for(var c=0,d=b.length;c<d;c++){if(b[c].node===a)return b[c];
|
||||
if(b[c].buttons.length){var f=this._nodeToButton(a,b[c].buttons);if(f)return f}}},_nodeToHost:function(a,b){b||(b=this.s.buttons);for(var c=0,d=b.length;c<d;c++){if(b[c].node===a)return b;if(b[c].buttons.length){var f=this._nodeToHost(a,b[c].buttons);if(f)return f}}},_keypress:function(a,b){if(!b._buttonsHandled){var c=function(d){for(var f=0,h=d.length;f<h;f++){var m=d[f].conf,g=d[f].node;m.key&&(m.key===a?(b._buttonsHandled=!0,e(g).click()):!e.isPlainObject(m.key)||m.key.key!==a||m.key.shiftKey&&
|
||||
!b.shiftKey||m.key.altKey&&!b.altKey||m.key.ctrlKey&&!b.ctrlKey||m.key.metaKey&&!b.metaKey||(b._buttonsHandled=!0,e(g).click()));d[f].buttons.length&&c(d[f].buttons)}};c(this.s.buttons)}},_removeKey:function(a){if(a.key){var b=e.isPlainObject(a.key)?a.key.key:a.key;a=this.s.listenKeys.split("");b=e.inArray(b,a);a.splice(b,1);this.s.listenKeys=a.join("")}},_resolveExtends:function(a){var b=this.s.dt,c,d=function(g){for(var n=0;!e.isPlainObject(g)&&!Array.isArray(g);){if(g===r)return;if("function"===
|
||||
typeof g){if(g=g(b,a),!g)return!1}else if("string"===typeof g){if(!x[g])throw"Unknown button type: "+g;g=x[g]}n++;if(30<n)throw"Buttons: Too many iterations";}return Array.isArray(g)?g:e.extend({},g)};for(a=d(a);a&&a.extend;){if(!x[a.extend])throw"Cannot extend unknown button type: "+a.extend;var f=d(x[a.extend]);if(Array.isArray(f))return f;if(!f)return!1;var h=f.className;a=e.extend({},f,a);h&&a.className!==h&&(a.className=h+" "+a.className);var m=a.postfixButtons;if(m){a.buttons||(a.buttons=[]);
|
||||
h=0;for(c=m.length;h<c;h++)a.buttons.push(m[h]);a.postfixButtons=null}if(m=a.prefixButtons){a.buttons||(a.buttons=[]);h=0;for(c=m.length;h<c;h++)a.buttons.splice(h,0,m[h]);a.prefixButtons=null}a.extend=f.extend}return a},_popover:function(a,b,c){var d=this.c,f=e.extend({align:"button-left",autoClose:!1,background:!0,backgroundClassName:"dt-button-background",contentClassName:d.dom.collection.className,collectionLayout:"",collectionTitle:"",dropup:!1,fade:400,rightAlignClassName:"dt-button-right",
|
||||
tag:d.dom.collection.tag},c),h=b.node(),m=function(){C(e(".dt-button-collection"),f.fade,function(){e(this).detach()});e(b.buttons('[aria-haspopup="true"][aria-expanded="true"]').nodes()).attr("aria-expanded","false");e("div.dt-button-background").off("click.dtb-collection");t.background(!1,f.backgroundClassName,f.fade,h);e("body").off(".dtb-collection");b.off("buttons-action.b-internal")};!1===a&&m();c=e(b.buttons('[aria-haspopup="true"][aria-expanded="true"]').nodes());c.length&&(h=c.eq(0),m());
|
||||
c=e("<div/>").addClass("dt-button-collection").addClass(f.collectionLayout).css("display","none");a=e(a).addClass(f.contentClassName).attr("role","menu").appendTo(c);h.attr("aria-expanded","true");h.parents("body")[0]!==w.body&&(h=w.body.lastChild);f.collectionTitle&&c.prepend('<div class="dt-button-collection-title">'+f.collectionTitle+"</div>");B(c.insertAfter(h),f.fade);d=e(b.table().container());var g=c.css("position");"dt-container"===f.align&&(h=h.parent(),c.css("width",d.width()));if("absolute"===
|
||||
g){var n=h.position();g=e(b.node()).position();c.css({top:g.top+h.outerHeight(),left:n.left});n=c.outerHeight();var k=d.offset().top+d.height();k=g.top+h.outerHeight()+n-k;var p=g.top-n,l=d.offset().top;g=g.top-n-5;(k>l-p||f.dropup)&&-g<l&&c.css("top",g);g=d.offset().left;d=d.width();d=g+d;n=c.offset().left;k=c.width();k=n+k;p=h.offset().left;l=h.outerWidth();var v=p+l;c.hasClass(f.rightAlignClassName)||c.hasClass(f.leftAlignClassName)||"dt-container"===f.align?(l=0,c.hasClass(f.rightAlignClassName)?
|
||||
(l=v-k,g>n+l&&(g-=n+l,d-=k+l,l=g>d?l+d:l+g)):(l=g-n,d<k+l&&(g-=n+l,d-=k+l,l=g>d?l+d:l+g))):(d=h.offset().top,l=0,l="button-right"===f.align?v-k:p-n);c.css("left",c.position().left+l)}else d=c.height()/2,d>e(y).height()/2&&(d=e(y).height()/2),c.css("marginTop",-1*d);f.background&&t.background(!0,f.backgroundClassName,f.fade,h);e("div.dt-button-background").on("click.dtb-collection",function(){});e("body").on("click.dtb-collection",function(u){var z=e.fn.addBack?"addBack":"andSelf",F=e(u.target).parent()[0];
|
||||
(!e(u.target).parents()[z]().filter(a).length&&!e(F).hasClass("dt-buttons")||e(u.target).hasClass("dt-button-background"))&&m()}).on("keyup.dtb-collection",function(u){27===u.keyCode&&m()});f.autoClose&&setTimeout(function(){b.on("buttons-action.b-internal",function(u,z,F,K){K[0]!==h[0]&&m()})},0);e(c).trigger("buttons-popover.dt")}});t.background=function(a,b,c,d){c===r&&(c=400);d||(d=w.body);a?B(e("<div/>").addClass(b).css("display","none").insertAfter(d),c):C(e("div."+b),c,function(){e(this).removeClass(b).remove()})};
|
||||
t.instanceSelector=function(a,b){if(a===r||null===a)return e.map(b,function(h){return h.inst});var c=[],d=e.map(b,function(h){return h.name}),f=function(h){if(Array.isArray(h))for(var m=0,g=h.length;m<g;m++)f(h[m]);else"string"===typeof h?-1!==h.indexOf(",")?f(h.split(",")):(h=e.inArray(h.trim(),d),-1!==h&&c.push(b[h].inst)):"number"===typeof h&&c.push(b[h].inst)};f(a);return c};t.buttonSelector=function(a,b){for(var c=[],d=function(g,n,k){for(var p,l,v=0,u=n.length;v<u;v++)if(p=n[v])l=k!==r?k+v:
|
||||
v+"",g.push({node:p.node,name:p.conf.name,idx:l}),p.buttons&&d(g,p.buttons,l+"-")},f=function(g,n){var k,p=[];d(p,n.s.buttons);var l=e.map(p,function(v){return v.node});if(Array.isArray(g)||g instanceof e)for(l=0,k=g.length;l<k;l++)f(g[l],n);else if(null===g||g===r||"*"===g)for(l=0,k=p.length;l<k;l++)c.push({inst:n,node:p[l].node});else if("number"===typeof g)c.push({inst:n,node:n.s.buttons[g].node});else if("string"===typeof g)if(-1!==g.indexOf(","))for(p=g.split(","),l=0,k=p.length;l<k;l++)f(p[l].trim(),
|
||||
n);else if(g.match(/^\d+(\-\d+)*$/))l=e.map(p,function(v){return v.idx}),c.push({inst:n,node:p[e.inArray(g,l)].node});else if(-1!==g.indexOf(":name"))for(g=g.replace(":name",""),l=0,k=p.length;l<k;l++)p[l].name===g&&c.push({inst:n,node:p[l].node});else e(l).filter(g).each(function(){c.push({inst:n,node:this})});else"object"===typeof g&&g.nodeName&&(p=e.inArray(g,l),-1!==p&&c.push({inst:n,node:l[p]}))},h=0,m=a.length;h<m;h++)f(b,a[h]);return c};t.stripData=function(a,b){if("string"!==typeof a)return a;
|
||||
a=a.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"");a=a.replace(/<!\-\-.*?\-\->/g,"");if(!b||b.stripHtml)a=a.replace(/<[^>]*>/g,"");if(!b||b.trim)a=a.replace(/^\s+|\s+$/g,"");if(!b||b.stripNewlines)a=a.replace(/\n/g," ");if(!b||b.decodeEntities)G.innerHTML=a,a=G.value;return a};t.defaults={buttons:["copy","excel","csv","pdf","print"],name:"main",tabIndex:0,dom:{container:{tag:"div",className:"dt-buttons"},collection:{tag:"div",className:""},button:{tag:"button",className:"dt-button",
|
||||
active:"active",disabled:"disabled"},buttonLiner:{tag:"span",className:""}}};t.version="1.7.1";e.extend(x,{collection:{text:function(a){return a.i18n("buttons.collection","Collection")},className:"buttons-collection",init:function(a,b,c){b.attr("aria-expanded",!1)},action:function(a,b,c,d){a.stopPropagation();d._collection.parents("body").length?this.popover(!1,d):this.popover(d._collection,d)},attr:{"aria-haspopup":!0}},copy:function(a,b){if(x.copyHtml5)return"copyHtml5"},csv:function(a,b){if(x.csvHtml5&&
|
||||
x.csvHtml5.available(a,b))return"csvHtml5"},excel:function(a,b){if(x.excelHtml5&&x.excelHtml5.available(a,b))return"excelHtml5"},pdf:function(a,b){if(x.pdfHtml5&&x.pdfHtml5.available(a,b))return"pdfHtml5"},pageLength:function(a){a=a.settings()[0].aLengthMenu;var b=[],c=[];if(Array.isArray(a[0]))b=a[0],c=a[1];else for(var d=0;d<a.length;d++){var f=a[d];e.isPlainObject(f)?(b.push(f.value),c.push(f.label)):(b.push(f),c.push(f))}return{extend:"collection",text:function(h){return h.i18n("buttons.pageLength",
|
||||
{"-1":"Show all rows",_:"Show %d rows"},h.page.len())},className:"buttons-page-length",autoClose:!0,buttons:e.map(b,function(h,m){return{text:c[m],className:"button-page-length",action:function(g,n){n.page.len(h).draw()},init:function(g,n,k){var p=this;n=function(){p.active(g.page.len()===h)};g.on("length.dt"+k.namespace,n);n()},destroy:function(g,n,k){g.off("length.dt"+k.namespace)}}}),init:function(h,m,g){var n=this;h.on("length.dt"+g.namespace,function(){n.text(g.text)})},destroy:function(h,m,
|
||||
g){h.off("length.dt"+g.namespace)}}}});q.Api.register("buttons()",function(a,b){b===r&&(b=a,a=r);this.selector.buttonGroup=a;var c=this.iterator(!0,"table",function(d){if(d._buttons)return t.buttonSelector(t.instanceSelector(a,d._buttons),b)},!0);c._groupSelector=a;return c});q.Api.register("button()",function(a,b){a=this.buttons(a,b);1<a.length&&a.splice(1,a.length);return a});q.Api.registerPlural("buttons().active()","button().active()",function(a){return a===r?this.map(function(b){return b.inst.active(b.node)}):
|
||||
this.each(function(b){b.inst.active(b.node,a)})});q.Api.registerPlural("buttons().action()","button().action()",function(a){return a===r?this.map(function(b){return b.inst.action(b.node)}):this.each(function(b){b.inst.action(b.node,a)})});q.Api.register(["buttons().enable()","button().enable()"],function(a){return this.each(function(b){b.inst.enable(b.node,a)})});q.Api.register(["buttons().disable()","button().disable()"],function(){return this.each(function(a){a.inst.disable(a.node)})});q.Api.registerPlural("buttons().nodes()",
|
||||
"button().node()",function(){var a=e();e(this.each(function(b){a=a.add(b.inst.node(b.node))}));return a});q.Api.registerPlural("buttons().processing()","button().processing()",function(a){return a===r?this.map(function(b){return b.inst.processing(b.node)}):this.each(function(b){b.inst.processing(b.node,a)})});q.Api.registerPlural("buttons().text()","button().text()",function(a){return a===r?this.map(function(b){return b.inst.text(b.node)}):this.each(function(b){b.inst.text(b.node,a)})});q.Api.registerPlural("buttons().trigger()",
|
||||
"button().trigger()",function(){return this.each(function(a){a.inst.node(a.node).trigger("click")})});q.Api.register("button().popover()",function(a,b){return this.map(function(c){return c.inst._popover(a,this.button(this[0].node),b)})});q.Api.register("buttons().containers()",function(){var a=e(),b=this._groupSelector;this.iterator(!0,"table",function(c){if(c._buttons){c=t.instanceSelector(b,c._buttons);for(var d=0,f=c.length;d<f;d++)a=a.add(c[d].container())}});return a});q.Api.register("buttons().container()",
|
||||
function(){return this.containers().eq(0)});q.Api.register("button().add()",function(a,b){var c=this.context;c.length&&(c=t.instanceSelector(this._groupSelector,c[0]._buttons),c.length&&c[0].add(b,a));return this.button(this._groupSelector,a)});q.Api.register("buttons().destroy()",function(){this.pluck("inst").unique().each(function(a){a.destroy()});return this});q.Api.registerPlural("buttons().remove()","buttons().remove()",function(){this.each(function(a){a.inst.remove(a.node)});return this});var A;
|
||||
q.Api.register("buttons.info()",function(a,b,c){var d=this;if(!1===a)return this.off("destroy.btn-info"),C(e("#datatables_buttons_info"),400,function(){e(this).remove()}),clearTimeout(A),A=null,this;A&&clearTimeout(A);e("#datatables_buttons_info").length&&e("#datatables_buttons_info").remove();a=a?"<h2>"+a+"</h2>":"";B(e('<div id="datatables_buttons_info" class="dt-button-info"/>').html(a).append(e("<div/>")["string"===typeof b?"html":"append"](b)).css("display","none").appendTo("body"));c!==r&&0!==
|
||||
c&&(A=setTimeout(function(){d.buttons.info(!1)},c));this.on("destroy.btn-info",function(){d.buttons.info(!1)});return this});q.Api.register("buttons.exportData()",function(a){if(this.context.length)return L(new q.Api(this.context[0]),a)});q.Api.register("buttons.exportInfo()",function(a){a||(a={});var b=a;var c="*"===b.filename&&"*"!==b.title&&b.title!==r&&null!==b.title&&""!==b.title?b.title:b.filename;"function"===typeof c&&(c=c());c===r||null===c?c=null:(-1!==c.indexOf("*")&&(c=c.replace("*",e("head > title").text()).trim()),
|
||||
c=c.replace(/[^a-zA-Z0-9_\u00A1-\uFFFF\.,\-_ !\(\)]/g,""),(b=D(b.extension))||(b=""),c+=b);b=D(a.title);b=null===b?null:-1!==b.indexOf("*")?b.replace("*",e("head > title").text()||"Exported data"):b;return{filename:c,title:b,messageTop:H(this,a.message||a.messageTop,"top"),messageBottom:H(this,a.messageBottom,"bottom")}});var D=function(a){return null===a||a===r?null:"function"===typeof a?a():a},H=function(a,b,c){b=D(b);if(null===b)return null;a=e("caption",a.table().container()).eq(0);return"*"===
|
||||
b?a.css("caption-side")!==c?null:a.length?a.text():"":b},G=e("<textarea/>")[0],L=function(a,b){var c=e.extend(!0,{},{rows:null,columns:"",modifier:{search:"applied",order:"applied"},orthogonal:"display",stripHtml:!0,stripNewlines:!0,decodeEntities:!0,trim:!0,format:{header:function(u){return t.stripData(u,c)},footer:function(u){return t.stripData(u,c)},body:function(u){return t.stripData(u,c)}},customizeData:null},b);b=a.columns(c.columns).indexes().map(function(u){var z=a.column(u).header();return c.format.header(z.innerHTML,
|
||||
u,z)}).toArray();var d=a.table().footer()?a.columns(c.columns).indexes().map(function(u){var z=a.column(u).footer();return c.format.footer(z?z.innerHTML:"",u,z)}).toArray():null,f=e.extend({},c.modifier);a.select&&"function"===typeof a.select.info&&f.selected===r&&a.rows(c.rows,e.extend({selected:!0},f)).any()&&e.extend(f,{selected:!0});f=a.rows(c.rows,f).indexes().toArray();var h=a.cells(f,c.columns);f=h.render(c.orthogonal).toArray();h=h.nodes().toArray();for(var m=b.length,g=[],n=0,k=0,p=0<m?f.length/
|
||||
m:0;k<p;k++){for(var l=[m],v=0;v<m;v++)l[v]=c.format.body(f[n],k,v,h[n]),n++;g[k]=l}b={header:b,footer:d,body:g};c.customizeData&&c.customizeData(b);return b};e.fn.dataTable.Buttons=t;e.fn.DataTable.Buttons=t;e(w).on("init.dt plugin-init.dt",function(a,b){"dt"===a.namespace&&(a=b.oInit.buttons||q.defaults.buttons)&&!b._buttons&&(new t(b,a)).container()});q.ext.feature.push({fnInit:E,cFeature:"B"});q.ext.features&&q.ext.features.register("buttons",E);return t});
|
||||
|
||||
|
||||
/*!
|
||||
Bootstrap integration for DataTables' Buttons
|
||||
©2016 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-buttons"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net-bs")(a,b).$);b.fn.dataTable.Buttons||require("datatables.net-buttons")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,e){a=c.fn.dataTable;c.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group"},
|
||||
button:{className:"btn btn-default"},collection:{tag:"ul",className:"dropdown-menu",button:{tag:"li",className:"dt-button",active:"active",disabled:"disabled"},buttonLiner:{tag:"a",className:""}}}});a.ext.buttons.collection.text=function(d){return d.i18n("buttons.collection",'Collection <span class="caret"/>')};return a.Buttons});
|
||||
45
scripts/vendor/datatables.select.min.js
vendored
Normal file
45
scripts/vendor/datatables.select.min.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*!
|
||||
Copyright 2015-2019 SpryMedia Ltd.
|
||||
|
||||
This source file is free software, available under the following license:
|
||||
MIT license - http://datatables.net/license/mit
|
||||
|
||||
This source file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
|
||||
|
||||
For details please refer to: http://www.datatables.net/extensions/select
|
||||
Select for DataTables 1.3.1
|
||||
2015-2019 SpryMedia Ltd - datatables.net/license/mit
|
||||
*/
|
||||
(function(f){"function"===typeof define&&define.amd?define(["jquery","datatables.net"],function(k){return f(k,window,document)}):"object"===typeof exports?module.exports=function(k,p){k||(k=window);p&&p.fn.dataTable||(p=require("datatables.net")(k,p).$);return f(p,k,k.document)}:f(jQuery,window,document)})(function(f,k,p,h){function z(a,b,c){var d=function(c,b){if(c>b){var d=b;b=c;c=d}var e=!1;return a.columns(":visible").indexes().filter(function(a){a===c&&(e=!0);return a===b?(e=!1,!0):e})};var e=
|
||||
function(c,b){var d=a.rows({search:"applied"}).indexes();if(d.indexOf(c)>d.indexOf(b)){var e=b;b=c;c=e}var f=!1;return d.filter(function(a){a===c&&(f=!0);return a===b?(f=!1,!0):f})};a.cells({selected:!0}).any()||c?(d=d(c.column,b.column),c=e(c.row,b.row)):(d=d(0,b.column),c=e(0,b.row));c=a.cells(c,d).flatten();a.cells(b,{selected:!0}).any()?a.cells(c).deselect():a.cells(c).select()}function v(a){var b=a.settings()[0]._select.selector;f(a.table().container()).off("mousedown.dtSelect",b).off("mouseup.dtSelect",
|
||||
b).off("click.dtSelect",b);f("body").off("click.dtSelect"+a.table().node().id.replace(/[^a-zA-Z0-9\-_]/g,"-"))}function A(a){var b=f(a.table().container()),c=a.settings()[0],d=c._select.selector,e;b.on("mousedown.dtSelect",d,function(a){if(a.shiftKey||a.metaKey||a.ctrlKey)b.css("-moz-user-select","none").one("selectstart.dtSelect",d,function(){return!1});k.getSelection&&(e=k.getSelection())}).on("mouseup.dtSelect",d,function(){b.css("-moz-user-select","")}).on("click.dtSelect",d,function(c){var b=
|
||||
a.select.items();if(e){var d=k.getSelection();if((!d.anchorNode||f(d.anchorNode).closest("table")[0]===a.table().node())&&d!==e)return}d=a.settings()[0];var l=f.trim(a.settings()[0].oClasses.sWrapper).replace(/ +/g,".");if(f(c.target).closest("div."+l)[0]==a.table().container()&&(l=a.cell(f(c.target).closest("td, th")),l.any())){var g=f.Event("user-select.dt");m(a,g,[b,l,c]);g.isDefaultPrevented()||(g=l.index(),"row"===b?(b=g.row,w(c,a,d,"row",b)):"column"===b?(b=l.index().column,w(c,a,d,"column",
|
||||
b)):"cell"===b&&(b=l.index(),w(c,a,d,"cell",b)),d._select_lastCell=g)}});f("body").on("click.dtSelect"+a.table().node().id.replace(/[^a-zA-Z0-9\-_]/g,"-"),function(b){!c._select.blurable||f(b.target).parents().filter(a.table().container()).length||0===f(b.target).parents("html").length||f(b.target).parents("div.DTE").length||r(c,!0)})}function m(a,b,c,d){if(!d||a.flatten().length)"string"===typeof b&&(b+=".dt"),c.unshift(a),f(a.table().node()).trigger(b,c)}function B(a){var b=a.settings()[0];if(b._select.info&&
|
||||
b.aanFeatures.i&&"api"!==a.select.style()){var c=a.rows({selected:!0}).flatten().length,d=a.columns({selected:!0}).flatten().length,e=a.cells({selected:!0}).flatten().length,l=function(b,c,d){b.append(f('<span class="select-item"/>').append(a.i18n("select."+c+"s",{_:"%d "+c+"s selected",0:"",1:"1 "+c+" selected"},d)))};f.each(b.aanFeatures.i,function(b,a){a=f(a);b=f('<span class="select-info"/>');l(b,"row",c);l(b,"column",d);l(b,"cell",e);var g=a.children("span.select-info");g.length&&g.remove();
|
||||
""!==b.text()&&a.append(b)})}}function D(a){var b=new g.Api(a);a.aoRowCreatedCallback.push({fn:function(b,d,e){d=a.aoData[e];d._select_selected&&f(b).addClass(a._select.className);b=0;for(e=a.aoColumns.length;b<e;b++)(a.aoColumns[b]._select_selected||d._selected_cells&&d._selected_cells[b])&&f(d.anCells[b]).addClass(a._select.className)},sName:"select-deferRender"});b.on("preXhr.dt.dtSelect",function(){var a=b.rows({selected:!0}).ids(!0).filter(function(b){return b!==h}),d=b.cells({selected:!0}).eq(0).map(function(a){var c=
|
||||
b.row(a.row).id(!0);return c?{row:c,column:a.column}:h}).filter(function(b){return b!==h});b.one("draw.dt.dtSelect",function(){b.rows(a).select();d.any()&&d.each(function(a){b.cells(a.row,a.column).select()})})});b.on("draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt",function(){B(b)});b.on("destroy.dtSelect",function(){v(b);b.off(".dtSelect")})}function C(a,b,c,d){var e=a[b+"s"]({search:"applied"}).indexes();d=f.inArray(d,e);var g=f.inArray(c,e);if(a[b+"s"]({selected:!0}).any()||
|
||||
-1!==d){if(d>g){var u=g;g=d;d=u}e.splice(g+1,e.length);e.splice(0,d)}else e.splice(f.inArray(c,e)+1,e.length);a[b](c,{selected:!0}).any()?(e.splice(f.inArray(c,e),1),a[b+"s"](e).deselect()):a[b+"s"](e).select()}function r(a,b){if(b||"single"===a._select.style)a=new g.Api(a),a.rows({selected:!0}).deselect(),a.columns({selected:!0}).deselect(),a.cells({selected:!0}).deselect()}function w(a,b,c,d,e){var f=b.select.style(),g=b.select.toggleable(),h=b[d](e,{selected:!0}).any();if(!h||g)"os"===f?a.ctrlKey||
|
||||
a.metaKey?b[d](e).select(!h):a.shiftKey?"cell"===d?z(b,e,c._select_lastCell||null):C(b,d,e,c._select_lastCell?c._select_lastCell[d]:null):(a=b[d+"s"]({selected:!0}),h&&1===a.flatten().length?b[d](e).deselect():(a.deselect(),b[d](e).select())):"multi+shift"==f?a.shiftKey?"cell"===d?z(b,e,c._select_lastCell||null):C(b,d,e,c._select_lastCell?c._select_lastCell[d]:null):b[d](e).select(!h):b[d](e).select(!h)}function t(a,b){return function(c){return c.i18n("buttons."+a,b)}}function x(a){a=a._eventNamespace;
|
||||
return"draw.dt.DT"+a+" select.dt.DT"+a+" deselect.dt.DT"+a}function E(a,b){return-1!==f.inArray("rows",b.limitTo)&&a.rows({selected:!0}).any()||-1!==f.inArray("columns",b.limitTo)&&a.columns({selected:!0}).any()||-1!==f.inArray("cells",b.limitTo)&&a.cells({selected:!0}).any()?!0:!1}var g=f.fn.dataTable;g.select={};g.select.version="1.3.1";g.select.init=function(a){var b=a.settings()[0],c=b.oInit.select,d=g.defaults.select;c=c===h?d:c;d="row";var e="api",l=!1,u=!0,k=!0,m="td, th",p="selected",n=!1;
|
||||
b._select={};!0===c?(e="os",n=!0):"string"===typeof c?(e=c,n=!0):f.isPlainObject(c)&&(c.blurable!==h&&(l=c.blurable),c.toggleable!==h&&(u=c.toggleable),c.info!==h&&(k=c.info),c.items!==h&&(d=c.items),e=c.style!==h?c.style:"os",n=!0,c.selector!==h&&(m=c.selector),c.className!==h&&(p=c.className));a.select.selector(m);a.select.items(d);a.select.style(e);a.select.blurable(l);a.select.toggleable(u);a.select.info(k);b._select.className=p;f.fn.dataTable.ext.order["select-checkbox"]=function(b,a){return this.api().column(a,
|
||||
{order:"index"}).nodes().map(function(a){return"row"===b._select.items?f(a).parent().hasClass(b._select.className):"cell"===b._select.items?f(a).hasClass(b._select.className):!1})};!n&&f(a.table().node()).hasClass("selectable")&&a.select.style("os")};f.each([{type:"row",prop:"aoData"},{type:"column",prop:"aoColumns"}],function(a,b){g.ext.selector[b.type].push(function(a,d,e){d=d.selected;var c=[];if(!0!==d&&!1!==d)return e;for(var f=0,g=e.length;f<g;f++){var h=a[b.prop][e[f]];(!0===d&&!0===h._select_selected||
|
||||
!1===d&&!h._select_selected)&&c.push(e[f])}return c})});g.ext.selector.cell.push(function(a,b,c){b=b.selected;var d=[];if(b===h)return c;for(var e=0,f=c.length;e<f;e++){var g=a.aoData[c[e].row];(!0===b&&g._selected_cells&&!0===g._selected_cells[c[e].column]||!(!1!==b||g._selected_cells&&g._selected_cells[c[e].column]))&&d.push(c[e])}return d});var n=g.Api.register,q=g.Api.registerPlural;n("select()",function(){return this.iterator("table",function(a){g.select.init(new g.Api(a))})});n("select.blurable()",
|
||||
function(a){return a===h?this.context[0]._select.blurable:this.iterator("table",function(b){b._select.blurable=a})});n("select.toggleable()",function(a){return a===h?this.context[0]._select.toggleable:this.iterator("table",function(b){b._select.toggleable=a})});n("select.info()",function(a){return B===h?this.context[0]._select.info:this.iterator("table",function(b){b._select.info=a})});n("select.items()",function(a){return a===h?this.context[0]._select.items:this.iterator("table",function(b){b._select.items=
|
||||
a;m(new g.Api(b),"selectItems",[a])})});n("select.style()",function(a){return a===h?this.context[0]._select.style:this.iterator("table",function(b){b._select.style=a;b._select_init||D(b);var c=new g.Api(b);v(c);"api"!==a&&A(c);m(new g.Api(b),"selectStyle",[a])})});n("select.selector()",function(a){return a===h?this.context[0]._select.selector:this.iterator("table",function(b){v(new g.Api(b));b._select.selector=a;"api"!==b._select.style&&A(new g.Api(b))})});q("rows().select()","row().select()",function(a){var b=
|
||||
this;if(!1===a)return this.deselect();this.iterator("row",function(b,a){r(b);b.aoData[a]._select_selected=!0;f(b.aoData[a].nTr).addClass(b._select.className)});this.iterator("table",function(a,d){m(b,"select",["row",b[d]],!0)});return this});q("columns().select()","column().select()",function(a){var b=this;if(!1===a)return this.deselect();this.iterator("column",function(b,a){r(b);b.aoColumns[a]._select_selected=!0;a=(new g.Api(b)).column(a);f(a.header()).addClass(b._select.className);f(a.footer()).addClass(b._select.className);
|
||||
a.nodes().to$().addClass(b._select.className)});this.iterator("table",function(a,d){m(b,"select",["column",b[d]],!0)});return this});q("cells().select()","cell().select()",function(a){var b=this;if(!1===a)return this.deselect();this.iterator("cell",function(b,a,e){r(b);a=b.aoData[a];a._selected_cells===h&&(a._selected_cells=[]);a._selected_cells[e]=!0;a.anCells&&f(a.anCells[e]).addClass(b._select.className)});this.iterator("table",function(a,d){m(b,"select",["cell",b[d]],!0)});return this});q("rows().deselect()",
|
||||
"row().deselect()",function(){var a=this;this.iterator("row",function(a,c){a.aoData[c]._select_selected=!1;f(a.aoData[c].nTr).removeClass(a._select.className)});this.iterator("table",function(b,c){m(a,"deselect",["row",a[c]],!0)});return this});q("columns().deselect()","column().deselect()",function(){var a=this;this.iterator("column",function(a,c){a.aoColumns[c]._select_selected=!1;var b=new g.Api(a),e=b.column(c);f(e.header()).removeClass(a._select.className);f(e.footer()).removeClass(a._select.className);
|
||||
b.cells(null,c).indexes().each(function(b){var c=a.aoData[b.row],d=c._selected_cells;!c.anCells||d&&d[b.column]||f(c.anCells[b.column]).removeClass(a._select.className)})});this.iterator("table",function(b,c){m(a,"deselect",["column",a[c]],!0)});return this});q("cells().deselect()","cell().deselect()",function(){var a=this;this.iterator("cell",function(a,c,d){c=a.aoData[c];c._selected_cells[d]=!1;c.anCells&&!a.aoColumns[d]._select_selected&&f(c.anCells[d]).removeClass(a._select.className)});this.iterator("table",
|
||||
function(b,c){m(a,"deselect",["cell",a[c]],!0)});return this});var y=0;f.extend(g.ext.buttons,{selected:{text:t("selected","Selected"),className:"buttons-selected",limitTo:["rows","columns","cells"],init:function(a,b,c){var d=this;c._eventNamespace=".select"+y++;a.on(x(c),function(){d.enable(E(a,c))});this.disable()},destroy:function(a,b,c){a.off(c._eventNamespace)}},selectedSingle:{text:t("selectedSingle","Selected single"),className:"buttons-selected-single",init:function(a,b,c){var d=this;c._eventNamespace=
|
||||
".select"+y++;a.on(x(c),function(){var b=a.rows({selected:!0}).flatten().length+a.columns({selected:!0}).flatten().length+a.cells({selected:!0}).flatten().length;d.enable(1===b)});this.disable()},destroy:function(a,b,c){a.off(c._eventNamespace)}},selectAll:{text:t("selectAll","Select all"),className:"buttons-select-all",action:function(){this[this.select.items()+"s"]().select()}},selectNone:{text:t("selectNone","Deselect all"),className:"buttons-select-none",action:function(){r(this.settings()[0],
|
||||
!0)},init:function(a,b,c){var d=this;c._eventNamespace=".select"+y++;a.on(x(c),function(){var b=a.rows({selected:!0}).flatten().length+a.columns({selected:!0}).flatten().length+a.cells({selected:!0}).flatten().length;d.enable(0<b)});this.disable()},destroy:function(a,b,c){a.off(c._eventNamespace)}}});f.each(["Row","Column","Cell"],function(a,b){var c=b.toLowerCase();g.ext.buttons["select"+b+"s"]={text:t("select"+b+"s","Select "+c+"s"),className:"buttons-select-"+c+"s",action:function(){this.select.items(c)},
|
||||
init:function(a){var b=this;a.on("selectItems.dt.DT",function(a,d,e){b.active(e===c)})}}});f(p).on("preInit.dt.dtSelect",function(a,b){"dt"===a.namespace&&g.select.init(new g.Api(b))});return g.select});
|
||||
|
||||
/*!
|
||||
Bootstrap 3 styling wrapper for Select
|
||||
©2018 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
(function(c){"function"===typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-select"],function(a){return c(a,window,document)}):"object"===typeof exports?module.exports=function(a,b){a||(a=window);b&&b.fn.dataTable||(b=require("datatables.net-bs")(a,b).$);b.fn.dataTable.select||require("datatables.net-select")(a,b);return c(b,a,a.document)}:c(jQuery,window,document)})(function(c,a,b,d){return c.fn.dataTable});
|
||||
|
||||
31
settings.php
31
settings.php
@@ -10,7 +10,7 @@ require "scripts/pi-hole/php/savesettings.php";
|
||||
require_once "scripts/pi-hole/php/FTL.php";
|
||||
// Reread ini file as things might have been changed
|
||||
$setupVars = parse_ini_file("/etc/pihole/setupVars.conf");
|
||||
$piholeFTLConf = piholeFTLConfig();
|
||||
$piholeFTLConf = piholeFTLConfig(true);
|
||||
|
||||
// Handling of PHP internal errors
|
||||
$last_error = error_get_last();
|
||||
@@ -718,6 +718,19 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
|
||||
</form>
|
||||
</div>
|
||||
<!-- ######################################################### DNS ######################################################### -->
|
||||
<?php
|
||||
// Use default
|
||||
$rate_limit_count = 1000;
|
||||
$rate_limit_interval = 60;
|
||||
// Get rate limit from piholeFTL config array
|
||||
if (isset($piholeFTLConf["RATE_LIMIT"])) {
|
||||
$rl = explode("/", $piholeFTLConf["RATE_LIMIT"]);
|
||||
if(count($rl) == 2) {
|
||||
$rate_limit_count = intval($rl[0]);
|
||||
$rate_limit_interval = intval($rl[1]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div id="dns" class="tab-pane fade<?php if($tab === "dns"){ ?> in active<?php } ?>">
|
||||
<form role="form" method="post">
|
||||
<div class="row">
|
||||
@@ -934,6 +947,21 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
|
||||
<a href="https://dnssec.vs.uni-due.de/" rel="noopener" target="_blank">here</a>.</p>
|
||||
</div>
|
||||
<br>
|
||||
<h4><a id="ratelimit"></a>Rate-limiting</h4>
|
||||
<p>Block clients making more than <input type="number" name="rate_limit_count" value="<?=$rate_limit_count?>" min="0" step="10" style="width: 5em;"> queries within
|
||||
<input type="number" name="rate_limit_interval" value="<?=$rate_limit_interval?>" min="0" step="10" style="width: 4em;"> seconds.</p>
|
||||
<p>When a client makes too many queries in too short time, it
|
||||
gets rate-limited. Rate-limited queries are answered with a
|
||||
<code>REFUSED</code> reply and not further processed by FTL
|
||||
and prevent Pi-holes getting overwhelmed by rogue clients.
|
||||
It is important to note that rate-limiting is happening on a
|
||||
per-client basis. Other clients can continue to use FTL while
|
||||
rate-limited clients are short-circuited at the same time.</p>
|
||||
<p>Rate-limiting may be disabled altogether by setting both
|
||||
values to zero. See
|
||||
<a href="https://docs.pi-hole.net/ftldns/configfile/#rate_limit" target="_blank">our documentation</a>
|
||||
for further details.</p>
|
||||
<br>
|
||||
<h4>Conditional forwarding</h4>
|
||||
<p>If not configured as your DHCP server, Pi-hole typically won't be able to
|
||||
determine the names of devices on your local network. As a
|
||||
@@ -1452,7 +1480,6 @@ if (isset($_GET['tab']) && in_array($_GET['tab'], array("sysadmin", "dns", "piho
|
||||
</div>
|
||||
|
||||
<script src="scripts/vendor/jquery.confirm.min.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/utils.js?v=<?=$cacheVer?>"></script>
|
||||
<script src="scripts/pi-hole/js/settings.js?v=<?=$cacheVer?>"></script>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -495,11 +495,64 @@ td.details-control {
|
||||
}
|
||||
}
|
||||
|
||||
/* Fix the icon position (login password field) */
|
||||
/*** Login form ***/
|
||||
.form-control-feedback {
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.loginpage-logo {
|
||||
width: 30%;
|
||||
}
|
||||
.layout-boxed .loginpage-logo {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
.login-options {
|
||||
display: flex;
|
||||
margin: 0 0 15px -15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.login-options div {
|
||||
position: relative;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.login-options div:last-child {
|
||||
margin-right: 2px;
|
||||
margin-bottom: 0 !important;
|
||||
flex: 0 1 auto;
|
||||
font-size: 95%;
|
||||
}
|
||||
|
||||
.pwd-field {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.login-help {
|
||||
padding: 6px;
|
||||
background: rgba(127, 127, 127, 0.05);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-help p {
|
||||
margin: 0;
|
||||
font-size: clamp(11px, (100vw - 400px) / 45, 15px);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 768px) {
|
||||
.layout-boxed:not(.sidebar-collapse) .login-help p {
|
||||
font-size: clamp(11px, (min(100vw, 1250px) - 380px) / 47, 15px);
|
||||
}
|
||||
}
|
||||
|
||||
/*** Accessibility - Add focus for checkboxes and radio buttons (icheck) ***/
|
||||
[class*="icheck-"] > input:first-child:focus + label::before {
|
||||
outline: 1px #3c8dbc solid;
|
||||
border-color: #3c8dbc;
|
||||
}
|
||||
|
||||
/* Fix some datatables layout on small screens */
|
||||
@media screen and (max-width: 660px), screen and (min-width: 767px) and (max-width: 960px) {
|
||||
#domainsTable_wrapper .table-responsive {
|
||||
@@ -645,3 +698,91 @@ td.details-control {
|
||||
.menu-icon {
|
||||
margin-right: 0.5em;
|
||||
}
|
||||
|
||||
/* Datatables Select - bgcolor */
|
||||
:root {
|
||||
--datatable-bgcolor: #e0e8ee;
|
||||
}
|
||||
|
||||
div.dt-buttons {
|
||||
margin: 2px 0 5px;
|
||||
}
|
||||
@media screen and (max-width: 767px) {
|
||||
div.dt-buttons {
|
||||
margin-bottom: 5px;
|
||||
float: none;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* Datatables Select - checkbox outline */
|
||||
table.dataTable tbody td.select-checkbox::before,
|
||||
table.dataTable tbody th.select-checkbox::before {
|
||||
border-color: currentColor;
|
||||
border-radius: 2px;
|
||||
border-width: 2px;
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
|
||||
table.dataTable tr.selected td.select-checkbox::after,
|
||||
table.dataTable tr.selected th.select-checkbox::after {
|
||||
color: currentColor;
|
||||
content: "";
|
||||
text-shadow: none;
|
||||
border-bottom: 2px solid currentColor;
|
||||
border-right: 2px solid currentColor;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
transform: rotate(45deg) translate(7px, 3px);
|
||||
}
|
||||
|
||||
.datatable-bt {
|
||||
padding: 3px 8px;
|
||||
}
|
||||
|
||||
.datatable-bt span {
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
/* Datatables Select - selected row bgcolor */
|
||||
table.dataTable tbody > tr.selected,
|
||||
table.dataTable tbody > tr > .selected {
|
||||
background: none;
|
||||
background-image: linear-gradient(var(--datatable-bgcolor), var(--datatable-bgcolor));
|
||||
}
|
||||
|
||||
#messagesTable pre {
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
#output {
|
||||
position: relative;
|
||||
margin: 5px 0;
|
||||
min-height: 36px;
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.loading::before {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
padding: 1em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
line-height: 1;
|
||||
background: rgba(35, 60, 85, 0.8);
|
||||
box-shadow: 0 0 6px -3px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.loading::after {
|
||||
content: "\1F553\FE0E Loading...";
|
||||
position: absolute;
|
||||
padding: 1em;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
color: #fff;
|
||||
line-height: 1;
|
||||
animation: 2s infinite Pulse steps(20);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
* The colors used in this theme has been inspired by
|
||||
* https://github.com/anvyst/adminlte-skin-midnight */
|
||||
|
||||
:root {
|
||||
--datatable-bgcolor: rgba(64, 76, 88, 0.8);
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #353c42;
|
||||
color: #bec5cb;
|
||||
@@ -410,6 +414,34 @@ td.highlight {
|
||||
border: 1px solid #353c42;
|
||||
}
|
||||
|
||||
/* Used in debug log page */
|
||||
.log-red {
|
||||
color: #ff4038;
|
||||
}
|
||||
.log-green {
|
||||
color: #4c4;
|
||||
}
|
||||
.log-yellow {
|
||||
color: #fb0;
|
||||
}
|
||||
.log-blue {
|
||||
color: #48f;
|
||||
}
|
||||
.log-purple {
|
||||
color: #b8e;
|
||||
}
|
||||
.log-cyan {
|
||||
color: #0df;
|
||||
}
|
||||
.log-gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
#output {
|
||||
border-color: #505458;
|
||||
background: #272c30;
|
||||
}
|
||||
|
||||
/* Used by the long-term pages */
|
||||
.daterangepicker {
|
||||
background-color: #3e464c;
|
||||
@@ -558,3 +590,16 @@ input[type="password"]::-webkit-caps-lock-indicator {
|
||||
.close {
|
||||
color: #383838;
|
||||
}
|
||||
|
||||
/*** Fix login input visual misalignment ***/
|
||||
#loginform,
|
||||
#loginform input {
|
||||
color: rgb(120, 127, 133);
|
||||
}
|
||||
|
||||
.login-options input,
|
||||
.login-options [class*="icheck-"] > input:first-child + input[type="hidden"] + label::before,
|
||||
.login-options [class*="icheck-"] > input:first-child + label::before {
|
||||
background: none;
|
||||
border-color: rgb(120, 127, 133);
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ select:-webkit-autofill {
|
||||
--darkreader-neutral-text: #d8d4cf;
|
||||
--darkreader-selection-background: #004daa;
|
||||
--darkreader-selection-text: #e8e6e3;
|
||||
--datatable-bgcolor: rgb(35, 47, 52);
|
||||
}
|
||||
|
||||
/* Modified CSS */
|
||||
@@ -1022,7 +1023,6 @@ fieldset[disabled] .btn-link:hover {
|
||||
background-color: rgb(39, 42, 44);
|
||||
}
|
||||
.dropdown-menu > li > a {
|
||||
color: rgb(200, 195, 188);
|
||||
color: rgb(157, 148, 136);
|
||||
}
|
||||
.dropdown-menu > li > a:focus,
|
||||
@@ -5059,7 +5059,6 @@ fieldset[disabled] .btn-yahoo.focus {
|
||||
color: rgb(76, 188, 255) !important;
|
||||
}
|
||||
.text-black {
|
||||
color: rgb(221, 218, 214) !important;
|
||||
color: rgb(232, 230, 227) !important;
|
||||
}
|
||||
.text-light-blue {
|
||||
@@ -5962,3 +5961,26 @@ td.highlight {
|
||||
border-color: #d8b013 !important;
|
||||
color: #f3e8c8 !important;
|
||||
}
|
||||
|
||||
/* Used in debug log page */
|
||||
.log-red {
|
||||
color: #e22;
|
||||
}
|
||||
.log-green {
|
||||
color: #0b0;
|
||||
}
|
||||
.log-yellow {
|
||||
color: #fb0;
|
||||
}
|
||||
.log-blue {
|
||||
color: #08c;
|
||||
}
|
||||
.log-purple {
|
||||
color: #c6f;
|
||||
}
|
||||
.log-cyan {
|
||||
color: #0df;
|
||||
}
|
||||
.log-gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
}
|
||||
.main-header .navbar .sidebar-toggle:hover {
|
||||
color: #f6f6f6;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
background-color: #367fa9;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
@@ -213,6 +212,29 @@
|
||||
color: #36f !important;
|
||||
}
|
||||
|
||||
/* Used in debug log page */
|
||||
.log-red {
|
||||
color: #e00;
|
||||
}
|
||||
.log-green {
|
||||
color: #093;
|
||||
}
|
||||
.log-yellow {
|
||||
color: #f69600;
|
||||
}
|
||||
.log-blue {
|
||||
color: #04d;
|
||||
}
|
||||
.log-purple {
|
||||
color: #a0c;
|
||||
}
|
||||
.log-cyan {
|
||||
color: #0ab;
|
||||
}
|
||||
.log-gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
td.highlight {
|
||||
background-color: rgba(255, 204, 0, 0.333);
|
||||
}
|
||||
@@ -239,3 +261,19 @@ td.highlight {
|
||||
.iradio_minimal-blue {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.datatable-bt,
|
||||
.datatable-bt:active,
|
||||
.datatable-bt:active:focus,
|
||||
.datatable-bt:focus {
|
||||
background: #fff;
|
||||
border-color: #ddd;
|
||||
color: #345;
|
||||
}
|
||||
|
||||
.datatable-bt:hover,
|
||||
.datatable-bt:active:hover {
|
||||
background: #337ab7;
|
||||
border-color: #337ab7;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
--net-recent-color: #055;
|
||||
--net-old-color: #125;
|
||||
--net-older-color: #1c2228;
|
||||
--datatable-bgcolor: var(--net-old-color);
|
||||
}
|
||||
|
||||
.sidebar-collapse {
|
||||
@@ -117,6 +118,8 @@ pre {
|
||||
#output {
|
||||
padding: 10px 3px;
|
||||
border-radius: 12px;
|
||||
background: #181818;
|
||||
color: #9ab;
|
||||
}
|
||||
|
||||
td code {
|
||||
@@ -380,6 +383,10 @@ p.login-box-msg,
|
||||
background: #f00;
|
||||
}
|
||||
|
||||
.login-help p {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.input-group .input-group-addon {
|
||||
border-radius: 8px 0 0 8px;
|
||||
border-right: none;
|
||||
@@ -1226,7 +1233,6 @@ table.dataTable thead .sorting_desc_disabled:after {
|
||||
#ad-frequency table td:last-child,
|
||||
#ad-frequency table th:last-child {
|
||||
width: 130px !important;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
#domain-frequency table td:first-child,
|
||||
@@ -1768,6 +1774,22 @@ table.dataTable {
|
||||
border: none;
|
||||
}
|
||||
|
||||
/*** datatables Select: row, checkbox and button ***/
|
||||
table.dataTable tbody > tr.selected td,
|
||||
table.dataTable tbody > tr > .selected td {
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.select-checkbox {
|
||||
min-width: 8px;
|
||||
}
|
||||
|
||||
.datatable-bt {
|
||||
border-radius: 6px;
|
||||
padding: 3px 10px;
|
||||
}
|
||||
|
||||
/*** icheckbox ***/
|
||||
.icheckbox_minimal-blue {
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -1868,6 +1890,29 @@ input[type="password"]::-webkit-caps-lock-indicator {
|
||||
color: #36f !important;
|
||||
}
|
||||
|
||||
/* Used in debug log page */
|
||||
.log-red {
|
||||
color: #e22;
|
||||
}
|
||||
.log-green {
|
||||
color: #0b0;
|
||||
}
|
||||
.log-yellow {
|
||||
color: #fb0;
|
||||
}
|
||||
.log-blue {
|
||||
color: #08c;
|
||||
}
|
||||
.log-purple {
|
||||
color: #c6f;
|
||||
}
|
||||
.log-cyan {
|
||||
color: #0df;
|
||||
}
|
||||
.log-gray {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
div.dataTables_wrapper div.dataTables_paginate ul.pagination {
|
||||
margin: 10px 0;
|
||||
text-transform: uppercase;
|
||||
|
||||
15
style/vendor/datatables_extensions.min.css
vendored
Normal file
15
style/vendor/datatables_extensions.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user