diff --git a/scripts/pi-hole/js/db_graph.js b/scripts/pi-hole/js/db_graph.js
index ab859122..590788d0 100644
--- a/scripts/pi-hole/js/db_graph.js
+++ b/scripts/pi-hole/js/db_graph.js
@@ -160,23 +160,23 @@ function updateQueriesOverTime() {
for (hour in dates) {
if (Object.prototype.hasOwnProperty.call(dates, hour)) {
var date,
- dom = 0,
- ads = 0;
+ total = 0,
+ blocked = 0;
date = new Date(1000 * dates[hour]);
var idx = data.domains_over_time[0].indexOf(dates[hour].toString());
if (idx > -1) {
- dom = data.domains_over_time[1][idx];
+ total = data.domains_over_time[1][idx];
}
idx = data.ads_over_time[0].indexOf(dates[hour].toString());
if (idx > -1) {
- ads = data.ads_over_time[1][idx];
+ blocked = data.ads_over_time[1][idx];
}
timeLineChart.data.labels.push(date);
- timeLineChart.data.datasets[0].data.push(dom - ads);
- timeLineChart.data.datasets[1].data.push(ads);
+ timeLineChart.data.datasets[0].data.push(blocked);
+ timeLineChart.data.datasets[1].data.push(total - blocked);
}
}
@@ -190,28 +190,30 @@ function updateQueriesOverTime() {
$(document).ready(function() {
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
+ var blockedColor = "#999";
+ var permittedColor = "#00a65a";
timeLineChart = new Chart(ctx, {
type: "bar",
data: {
labels: [],
datasets: [
{
- label: "Permitted DNS Queries",
+ label: "Blocked DNS Queries",
fill: true,
- backgroundColor: "rgba(0, 166, 90,.8)",
- borderColor: "rgba(0, 166, 90,.8)",
- pointBorderColor: "rgba(0, 166, 90,.8)",
+ backgroundColor: blockedColor,
+ borderColor: blockedColor,
+ pointBorderColor: blockedColor,
pointRadius: 1,
pointHoverRadius: 5,
data: [],
pointHitRadius: 5
},
{
- label: "Blocked DNS Queries",
+ label: "Permitted DNS Queries",
fill: true,
- backgroundColor: "rgba(0,192,239,1)",
- borderColor: "rgba(0,192,239,1)",
- pointBorderColor: "rgba(0,192,239,1)",
+ backgroundColor: permittedColor,
+ borderColor: permittedColor,
+ pointBorderColor: permittedColor,
pointRadius: 1,
pointHoverRadius: 5,
data: [],
@@ -222,6 +224,9 @@ $(document).ready(function() {
options: {
tooltips: {
enabled: true,
+ itemSort: function(a, b) {
+ return b.datasetIndex - a.datasetIndex;
+ },
mode: "x-axis",
callbacks: {
title: function(tooltipItem) {
@@ -232,8 +237,8 @@ $(document).ready(function() {
"-" +
padNumber(time.getMonth() + 1) +
"-" +
- padNumber(time.getDate()) +
- " " +
+ padNumber(time.getDate());
+ var from_time =
padNumber(time.getHours()) +
":" +
padNumber(time.getMinutes()) +
@@ -245,22 +250,50 @@ $(document).ready(function() {
"-" +
padNumber(time.getMonth() + 1) +
"-" +
- padNumber(time.getDate()) +
- " " +
+ padNumber(time.getDate());
+ var until_time =
padNumber(time.getHours()) +
":" +
padNumber(time.getMinutes()) +
":" +
padNumber(time.getSeconds());
- return "Queries from " + from_date + " to " + until_date;
+
+ if (from_date === until_date) {
+ // Abbreviated form for intervals on the same day
+ // We split title in two lines on small screens
+ if ($(window).width() < 992) {
+ until_time += "\n";
+ }
+
+ return ("Queries from " + from_time + " to " + until_time + " on " + from_date).split(
+ "\n "
+ );
+ }
+
+ // Full tooltip for intervals spanning more than one day
+ // We split title in two lines on small screens
+ if ($(window).width() < 992) {
+ from_date += "\n";
+ }
+
+ return (
+ "Queries from " +
+ from_date +
+ " " +
+ from_time +
+ " to " +
+ until_date +
+ " " +
+ until_time
+ ).split("\n ");
},
label: function(tooltipItems, data) {
- if (tooltipItems.datasetIndex === 1) {
+ if (tooltipItems.datasetIndex === 0) {
var percentage = 0.0;
- var total = parseInt(data.datasets[0].data[tooltipItems.index]);
- var blocked = parseInt(data.datasets[1].data[tooltipItems.index]);
- if (total > 0) {
- percentage = (100.0 * blocked) / total;
+ var permitted = parseInt(data.datasets[1].data[tooltipItems.index]);
+ var blocked = parseInt(data.datasets[0].data[tooltipItems.index]);
+ if (permitted + blocked > 0) {
+ percentage = (100.0 * blocked) / (permitted + blocked);
}
return (
diff --git a/scripts/pi-hole/js/index.js b/scripts/pi-hole/js/index.js
index 952c93bd..5fffa248 100644
--- a/scripts/pi-hole/js/index.js
+++ b/scripts/pi-hole/js/index.js
@@ -250,8 +250,8 @@ function updateQueriesOverTime() {
timeLineChart.data.labels.push(d);
var blocked = data.ads_over_time[1][hour];
var permitted = data.domains_over_time[1][hour] - blocked;
- timeLineChart.data.datasets[0].data.push(permitted);
- timeLineChart.data.datasets[1].data.push(blocked);
+ timeLineChart.data.datasets[0].data.push(blocked);
+ timeLineChart.data.datasets[1].data.push(permitted);
}
}
@@ -835,6 +835,9 @@ $(document).ready(function() {
// Pull in data via AJAX
updateSummaryData();
+ var blockedColor = "#999";
+ var permittedColor = "#00a65a";
+
var ctx = document.getElementById("queryOverTimeChart").getContext("2d");
timeLineChart = new Chart(ctx, {
type: "bar",
@@ -842,22 +845,22 @@ $(document).ready(function() {
labels: [],
datasets: [
{
- label: "Permitted DNS Queries",
+ label: "Blocked DNS Queries",
fill: true,
- backgroundColor: "rgba(0, 166, 90,.8)",
- borderColor: "rgba(0, 166, 90,.8)",
- pointBorderColor: "rgba(0, 166, 90,.8)",
+ backgroundColor: blockedColor,
+ borderColor: blockedColor,
+ pointBorderColor: blockedColor,
pointRadius: 1,
pointHoverRadius: 5,
data: [],
pointHitRadius: 5
},
{
- label: "Blocked DNS Queries",
+ label: "Permitted DNS Queries",
fill: true,
- backgroundColor: "rgba(0,192,239,1)",
- borderColor: "rgba(0,192,239,1)",
- pointBorderColor: "rgba(0,192,239,1)",
+ backgroundColor: permittedColor,
+ borderColor: permittedColor,
+ pointBorderColor: permittedColor,
pointRadius: 1,
pointHoverRadius: 5,
data: [],
@@ -869,6 +872,9 @@ $(document).ready(function() {
tooltips: {
enabled: true,
mode: "x-axis",
+ itemSort: function(a, b) {
+ return b.datasetIndex - a.datasetIndex;
+ },
callbacks: {
title: function(tooltipItem) {
var label = tooltipItem[0].xLabel;
@@ -877,13 +883,13 @@ $(document).ready(function() {
var m = parseInt(time[2], 10) || 0;
var from = padNumber(h) + ":" + padNumber(m - 5) + ":00";
var to = padNumber(h) + ":" + padNumber(m + 4) + ":59";
- return "Upstreams from " + from + " to " + to;
+ return "Queries from " + from + " to " + to;
},
label: function(tooltipItems, data) {
- if (tooltipItems.datasetIndex === 1) {
+ if (tooltipItems.datasetIndex === 0) {
var percentage = 0.0;
- var permitted = parseInt(data.datasets[0].data[tooltipItems.index]);
- var blocked = parseInt(data.datasets[1].data[tooltipItems.index]);
+ var permitted = parseInt(data.datasets[1].data[tooltipItems.index]);
+ var blocked = parseInt(data.datasets[0].data[tooltipItems.index]);
var total = permitted + blocked;
if (total > 0) {
percentage = (100.0 * blocked) / total;
diff --git a/scripts/pi-hole/php/groups.php b/scripts/pi-hole/php/groups.php
index 6f1dfdd2..1346b153 100644
--- a/scripts/pi-hole/php/groups.php
+++ b/scripts/pi-hole/php/groups.php
@@ -401,11 +401,31 @@ if ($_POST['action'] == 'get_groups') {
if (extension_loaded("intl") &&
($res['type'] === ListType::whitelist ||
$res['type'] === ListType::blacklist) ) {
- $utf8_domain = idn_to_utf8($res['domain']);
+
+ // Try to convert possible IDNA domain to Unicode, we try the UTS #46 standard first
+ // as this is the new default, see https://sourceforge.net/p/icu/mailman/message/32980778/
+ // We know that this fails for some Google domains violating the standard
+ // see https://github.com/pi-hole/AdminLTE/issues/1223
+ $utf8_domain = false;
+ if (defined("INTL_IDNA_VARIANT_UTS46")) {
+ // We have to use the option IDNA_NONTRANSITIONAL_TO_ASCII here
+ // to ensure sparkasse-gießen.de is not converted into
+ // sparkass-giessen.de but into xn--sparkasse-gieen-2ib.de
+ // as mandated by the UTS #46 standard
+ $utf8_domain = idn_to_utf8($res['domain'], IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
+ }
+
+ // If conversion failed, try with the (deprecated!) IDNA 2003 variant
+ // We have to check for its existance as support of this variant is
+ // scheduled for removal with PHP 8.0
+ // see https://wiki.php.net/rfc/deprecate-and-remove-intl_idna_variant_2003
+ if ($utf8_domain === false && defined("INTL_IDNA_VARIANT_2003")) {
+ $utf8_domain = idn_to_utf8($res['domain'], IDNA_DEFAULT, INTL_IDNA_VARIANT_2003);
+ }
+
// Convert domain name to international form
// if applicable and extension is available
- if($res['domain'] !== $utf8_domain)
- {
+ if ($utf8_domain !== false && $res['domain'] !== $utf8_domain) {
$res['domain'] = $utf8_domain.' ('.$res['domain'].')';
}
}
@@ -440,9 +460,21 @@ if ($_POST['action'] == 'get_groups') {
foreach ($domains as $domain) {
$input = $domain;
- // Convert domain name to IDNA ASCII form for international domains if intl package is available
- if (extension_loaded("intl"))
- $domain = idn_to_ascii($domain);
+ // Convert domain name to IDNA ASCII form for international domains
+ if (extension_loaded("intl")) {
+ // Be prepared that this may fail and see our comments above
+ // (search for "idn_to_utf8)
+ $idn_domain = false;
+ if (defined("INTL_IDNA_VARIANT_UTS46")) {
+ $idn_domain = idn_to_ascii($domain, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
+ }
+ if ($idn_domain === false && defined("INTL_IDNA_VARIANT_2003")) {
+ $idn_domain = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_2003);
+ }
+ if($idn_domain !== false) {
+ $domain = $idn_domain;
+ }
+ }
if(strlen($_POST['type']) === 2 && $_POST['type'][1] === 'W')
{
@@ -463,7 +495,7 @@ if ($_POST['action'] == 'get_groups') {
$errormsg = 'Domain ' . htmlentities($input) . ' is not a valid domain.';
else
$errormsg = 'Domain ' . htmlentities(utf8_encode($domain)) . ' is not a valid domain.';
- throw new Exception($errormsg . '
'. 'Added ' . $added . " out of ". $total . " domains");
+ throw new Exception($errormsg . '
Added ' . $added . " out of ". $total . " domains");
}
}