From 9765b38ec2c768c65ef71f7ea36caff48d10d4d9 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 10 Feb 2017 12:22:59 +0100 Subject: [PATCH 01/19] Added online debug log creator --- debug.php | 17 +++++++++ scripts/pi-hole/js/debug.js | 64 ++++++++++++++++++++++++++++++++++ scripts/pi-hole/php/debug.php | 19 ++++++++++ scripts/pi-hole/php/header.php | 8 ++++- 4 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 debug.php create mode 100644 scripts/pi-hole/js/debug.js create mode 100644 scripts/pi-hole/php/debug.php diff --git a/debug.php b/debug.php new file mode 100644 index 00000000..90139a0a --- /dev/null +++ b/debug.php @@ -0,0 +1,17 @@ + + + + + + + + + + + diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js new file mode 100644 index 00000000..51c7d334 --- /dev/null +++ b/scripts/pi-hole/js/debug.js @@ -0,0 +1,64 @@ +// Credit: http://stackoverflow.com/a/10642418/2087442 +function httpGet(ta,quiet,theUrl) +{ + var xmlhttp; + if (window.XMLHttpRequest) + { + // code for IE7+ + xmlhttp = new XMLHttpRequest(); + } + else + { + // code for IE6, IE5 + xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); + } + xmlhttp.onreadystatechange=function() + { + if (xmlhttp.readyState === 4 && xmlhttp.status === 200) + { + ta.show(); + ta.empty(); + if(!quiet) + { + ta.append(xmlhttp.responseText); + } + else + { + quietfilter(ta,xmlhttp.responseText); + } + } + }; + xmlhttp.open("GET", theUrl, false); + xmlhttp.send(); +} + +function eventsource() { + var ta = $("#output"); + + // IE does not support EventSource - load whole content at once + if (typeof EventSource !== "function") { + httpGet(ta,quiet,"/admin/scripts/pi-hole/php/debug.php"); + return; + } + + var host = window.location.host; + var source = new EventSource("/admin/scripts/pi-hole/php/debug.php"); + + // Reset and show field + ta.empty(); + ta.show(); + + source.addEventListener("message", function(e) { + ta.append(e.data); + }, false); + + // Will be called when script has finished + source.addEventListener("error", function(e) { + source.close(); + }, false); +} + +$("#debugBtn").on("click", function(){ + $("#debugBtn").attr("disabled", true); + eventsource(); +}); diff --git a/scripts/pi-hole/php/debug.php b/scripts/pi-hole/php/debug.php new file mode 100644 index 00000000..d57fddae --- /dev/null +++ b/scripts/pi-hole/php/debug.php @@ -0,0 +1,19 @@ + diff --git a/scripts/pi-hole/php/header.php b/scripts/pi-hole/php/header.php index 91a56f7d..85c6a276 100644 --- a/scripts/pi-hole/php/header.php +++ b/scripts/pi-hole/php/header.php @@ -405,7 +405,7 @@ Enable    -
  • active"> +
  • active"> Tools @@ -431,6 +431,12 @@ Tail pihole.log
  • + + class="active"> + + Generate debug log + + From cc13cf5e33d1cb21e96efe1ddbdb6742a9d27121 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 10 Feb 2017 12:26:20 +0100 Subject: [PATCH 02/19] Internet explorer + Windows Edge compatibility --- scripts/pi-hole/js/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index 51c7d334..15a2521b 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -37,7 +37,7 @@ function eventsource() { // IE does not support EventSource - load whole content at once if (typeof EventSource !== "function") { - httpGet(ta,quiet,"/admin/scripts/pi-hole/php/debug.php"); + httpGet(ta,quiet,"/admin/scripts/pi-hole/php/debug.php?IE"); return; } From d4fa69afaf3ae0fb84ba5d87c4d27b2fe08c3843 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 10 Feb 2017 16:42:28 +0100 Subject: [PATCH 03/19] Add notice that we are going to automatically upload the log once the user clicks on the big button --- debug.php | 1 + 1 file changed, 1 insertion(+) diff --git a/debug.php b/debug.php index 90139a0a..e148c033 100644 --- a/debug.php +++ b/debug.php @@ -6,6 +6,7 @@

    Generate debug log

    +

    Once you click this button a debug log will be generated and automatically uploaded if we detect a working internet connection

    From 4cc917dd91c62f9313fc24e34db30886aa349e6c Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 22 Feb 2017 15:07:02 +0100 Subject: [PATCH 04/19] Codacy --- scripts/pi-hole/js/debug.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index 15a2521b..dbdadb79 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -1,5 +1,5 @@ // Credit: http://stackoverflow.com/a/10642418/2087442 -function httpGet(ta,quiet,theUrl) +function httpGet(ta,theUrl) { var xmlhttp; if (window.XMLHttpRequest) @@ -18,14 +18,7 @@ function httpGet(ta,quiet,theUrl) { ta.show(); ta.empty(); - if(!quiet) - { - ta.append(xmlhttp.responseText); - } - else - { - quietfilter(ta,xmlhttp.responseText); - } + ta.append(xmlhttp.responseText); } }; xmlhttp.open("GET", theUrl, false); From e422e820d1c7281feaea676d296b670525fef06e Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 22 Feb 2017 15:44:07 +0100 Subject: [PATCH 05/19] Show disable timer across all devices --- api.php | 4 ++++ scripts/pi-hole/js/footer.js | 31 +++++++++++-------------------- scripts/pi-hole/php/header.php | 1 + 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/api.php b/api.php index 44fe3a21..5ee3f290 100644 --- a/api.php +++ b/api.php @@ -71,6 +71,7 @@ if (isset($_GET['enable'], $_GET['token']) && $auth) { check_csrf($_GET['token']); exec('sudo pihole enable'); + unlink("../custom_disable_timer"); $data = array_merge($data, Array( "status" => "enabled" )); @@ -81,11 +82,14 @@ // intval returns the integer value on success, or 0 on failure if($disable > 0) { + $timestamp = time(); exec("sudo pihole disable ".$disable."s"); + file_put_contents("../custom_disable_timer",($timestamp+$disable)*1000); } else { exec('sudo pihole disable'); + unlink("../custom_disable_timer"); } $data = array_merge($data, Array( "status" => "disabled" diff --git a/scripts/pi-hole/js/footer.js b/scripts/pi-hole/js/footer.js index 3af5b3e7..1568b0d0 100644 --- a/scripts/pi-hole/js/footer.js +++ b/scripts/pi-hole/js/footer.js @@ -40,6 +40,7 @@ function piholeChanged(action) function piholeChange(action, duration) { var token = encodeURIComponent($("#token").html()); + var enaT = $("#enableTimer"); var btnStatus; switch(action) { @@ -61,22 +62,17 @@ function piholeChange(action, duration) if(data.status === "disabled") { btnStatus.html(""); piholeChanged("disabled"); + enaT.html(new Date().getTime() + duration * 1000); + setTimeout(countDown,100); } }); break; } } -//The following three functions allow us to display time until pi-hole is enabled after disabling. +//The following functions allow us to display time until pi-hole is enabled after disabling. //Works between all pages - -function setCountdownTarget(seconds){ - var target = new Date(); - target = new Date(target.getTime() + seconds * 1000); - localStorage.setItem("countDownTarget", target); -} - function secondsTimeSpanToHMS(s) { var h = Math.floor(s/3600); //Get whole hours s -= h*3600; @@ -87,7 +83,8 @@ function secondsTimeSpanToHMS(s) { function countDown(){ var ena = $("#enableLabel"); - var target = new Date(localStorage.getItem("countDownTarget")); + var enaT = $("#enableTimer"); + var target = new Date(parseInt(enaT.html())); var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); if(seconds > 0){ @@ -103,10 +100,12 @@ function countDown(){ } $( document ).ready(function() { - var countDownTarget = localStorage.getItem("countDownTarget"); - if (countDownTarget != null) + var enaT = $("#enableTimer"); + var target = new Date(parseInt(enaT.html())); + var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); + if (seconds > 0) { - setTimeout(countDown,1000); + setTimeout(countDown,100); } }); @@ -123,28 +122,20 @@ $("#pihole-disable-permanently").on("click", function(e){ $("#pihole-disable-10s").on("click", function(e){ e.preventDefault(); piholeChange("disable","10"); - setCountdownTarget(10); - setTimeout(countDown,1000); }); $("#pihole-disable-30s").on("click", function(e){ e.preventDefault(); piholeChange("disable","30"); - setCountdownTarget(30); - setTimeout(countDown,1000); }); $("#pihole-disable-5m").on("click", function(e){ e.preventDefault(); piholeChange("disable","300"); - setCountdownTarget(300); - setTimeout(countDown,1000); }); $("#pihole-disable-custom").on("click", function(e){ e.preventDefault(); var custVal = $("#customTimeout").val(); custVal = $("#btnMins").hasClass("active") ? custVal * 60 : custVal; piholeChange("disable",custVal); - setCountdownTarget(custVal); - setTimeout(countDown,1000); }); diff --git a/scripts/pi-hole/php/header.php b/scripts/pi-hole/php/header.php index cc0abe49..ce8e6893 100644 --- a/scripts/pi-hole/php/header.php +++ b/scripts/pi-hole/php/header.php @@ -182,6 +182,7 @@ +
    From c99f23c995a12e91fc28214b6ad291afb97f2815 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 22 Feb 2017 17:35:31 +0100 Subject: [PATCH 06/19] Codacy --- scripts/pi-hole/js/footer.js | 58 ++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/scripts/pi-hole/js/footer.js b/scripts/pi-hole/js/footer.js index 1568b0d0..219ea51d 100644 --- a/scripts/pi-hole/js/footer.js +++ b/scripts/pi-hole/js/footer.js @@ -14,6 +14,35 @@ $("body").on("click", function(event) { } }); +//The following functions allow us to display time until pi-hole is enabled after disabling. +//Works between all pages + +function secondsTimeSpanToHMS(s) { + var h = Math.floor(s/3600); //Get whole hours + s -= h*3600; + var m = Math.floor(s/60); //Get remaining minutes + s -= m*60; + return h+":"+(m < 10 ? "0"+m : m)+":"+(s < 10 ? "0"+s : s); //zero padding on minutes and seconds +} + +function countDown(){ + var ena = $("#enableLabel"); + var enaT = $("#enableTimer"); + var target = new Date(parseInt(enaT.html())); + var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); + + if(seconds > 0){ + setTimeout(countDown,1000); + ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")"); + } + else + { + ena.text("Enable"); + piholeChanged("enabled"); + localStorage.removeItem("countDownTarget"); + } +} + function piholeChanged(action) { var status = $("#status"); @@ -70,35 +99,6 @@ function piholeChange(action, duration) } } -//The following functions allow us to display time until pi-hole is enabled after disabling. -//Works between all pages - -function secondsTimeSpanToHMS(s) { - var h = Math.floor(s/3600); //Get whole hours - s -= h*3600; - var m = Math.floor(s/60); //Get remaining minutes - s -= m*60; - return h+":"+(m < 10 ? "0"+m : m)+":"+(s < 10 ? "0"+s : s); //zero padding on minutes and seconds -} - -function countDown(){ - var ena = $("#enableLabel"); - var enaT = $("#enableTimer"); - var target = new Date(parseInt(enaT.html())); - var seconds = Math.round((target.getTime() - new Date().getTime()) / 1000); - - if(seconds > 0){ - setTimeout(countDown,1000); - ena.text("Enable (" + secondsTimeSpanToHMS(seconds) + ")"); - } - else - { - ena.text("Enable"); - piholeChanged("enabled"); - localStorage.removeItem("countDownTarget"); - } -} - $( document ).ready(function() { var enaT = $("#enableTimer"); var target = new Date(parseInt(enaT.html())); From 71672319af81472eb575463d2319824c8de50b39 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 22 Feb 2017 18:07:12 +0100 Subject: [PATCH 07/19] Another codacy commit --- scripts/pi-hole/js/debug.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index dbdadb79..c529f2f7 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -30,7 +30,7 @@ function eventsource() { // IE does not support EventSource - load whole content at once if (typeof EventSource !== "function") { - httpGet(ta,quiet,"/admin/scripts/pi-hole/php/debug.php?IE"); + httpGet(ta,"/admin/scripts/pi-hole/php/debug.php?IE"); return; } From 20ce214c9f06483d65a8d7ec9871efd85269f8df Mon Sep 17 00:00:00 2001 From: DL6ER Date: Wed, 22 Feb 2017 19:47:58 +0100 Subject: [PATCH 08/19] Add checkbox if the user wants his debug log to be uploaded automatically --- debug.php | 3 ++- scripts/pi-hole/js/debug.js | 11 +++++++++-- scripts/pi-hole/php/debug.php | 9 ++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/debug.php b/debug.php index e148c033..84416cff 100644 --- a/debug.php +++ b/debug.php @@ -6,7 +6,8 @@

    Generate debug log

    -

    Once you click this button a debug log will be generated and automatically uploaded if we detect a working internet connection

    +

    Upload debug log and provide token once finished

    +

    Once you click this button a debug log will be generated and can automatically be uploaded if we detect a working internet connection.

    diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index c529f2f7..6508dfbe 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -27,15 +27,22 @@ function httpGet(ta,theUrl) function eventsource() { var ta = $("#output"); + var upload = $( "#upload" ); + var checked = ""; + + if(upload.prop("checked")) + { + checked = "upload"; + } // IE does not support EventSource - load whole content at once if (typeof EventSource !== "function") { - httpGet(ta,"/admin/scripts/pi-hole/php/debug.php?IE"); + httpGet(ta,"/admin/scripts/pi-hole/php/debug.php?IE&"+checked); return; } var host = window.location.host; - var source = new EventSource("/admin/scripts/pi-hole/php/debug.php"); + var source = new EventSource("/admin/scripts/pi-hole/php/debug.php?"+checked); // Reset and show field ta.empty(); diff --git a/scripts/pi-hole/php/debug.php b/scripts/pi-hole/php/debug.php index d57fddae..996966a7 100644 --- a/scripts/pi-hole/php/debug.php +++ b/scripts/pi-hole/php/debug.php @@ -12,7 +12,14 @@ function echoEvent($datatext) { echo $datatext; } -$proc = popen("sudo pihole -d -a", "r"); +if(isset($_GET["upload"])) +{ + $proc = popen("sudo pihole -d -a", "r"); +} +else +{ + $proc = popen("sudo pihole -d", "r"); +} while (!feof($proc)) { echoEvent(fread($proc, 4096)); } From ab974f3f03475e14e7ee48b408b8d9570abc350b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 23 Feb 2017 12:22:03 +0100 Subject: [PATCH 09/19] Disable checkbox after starting generation of debug log since the action can not be changed afterwards --- scripts/pi-hole/js/debug.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/pi-hole/js/debug.js b/scripts/pi-hole/js/debug.js index 6508dfbe..c0db2ce0 100644 --- a/scripts/pi-hole/js/debug.js +++ b/scripts/pi-hole/js/debug.js @@ -60,5 +60,6 @@ function eventsource() { $("#debugBtn").on("click", function(){ $("#debugBtn").attr("disabled", true); + $("#upload").attr("disabled", true); eventsource(); }); From 616213d10b2705db87c316e7ee85e838570d04aa Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 23 Feb 2017 14:24:14 +0100 Subject: [PATCH 10/19] Improve Enable/Disable through API as often requested --- api.php | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/api.php b/api.php index 44fe3a21..8568e6b0 100644 --- a/api.php +++ b/api.php @@ -68,15 +68,31 @@ $data = array_merge($data, getAllQueries($_GET['getAllQueries'])); } - if (isset($_GET['enable'], $_GET['token']) && $auth) { - check_csrf($_GET['token']); + if (isset($_GET['enable']) && $auth) { + if(isset($_GET["auth"])) + { + if($_GET["auth"] !== $pwhash) + die("Not autorized!"); + } + else + { + // Skip token validation if explicit auth string is given + check_csrf($_GET['token']); + } exec('sudo pihole enable'); - $data = array_merge($data, Array( - "status" => "enabled" - )); + $data = array_merge($data, array("status" => "enabled")); } - elseif (isset($_GET['disable'], $_GET['token']) && $auth) { - check_csrf($_GET['token']); + elseif (isset($_GET['disable']) && $auth) { + if(isset($_GET["auth"])) + { + if($_GET["auth"] !== $pwhash) + die("Not autorized!"); + } + else + { + // Skip token validation if explicit auth string is given + check_csrf($_GET['token']); + } $disable = intval($_GET['disable']); // intval returns the integer value on success, or 0 on failure if($disable > 0) @@ -87,9 +103,7 @@ { exec('sudo pihole disable'); } - $data = array_merge($data, Array( - "status" => "disabled" - )); + $data = array_merge($data, array("status" => "disabled")); } if (isset($_GET['getGravityDomains'])) { From 8d59283d091e994f16b41e8cb45a373d4f97386b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 23 Feb 2017 14:27:37 +0100 Subject: [PATCH 11/19] Small typo --- api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api.php b/api.php index 8568e6b0..3a7b1e37 100644 --- a/api.php +++ b/api.php @@ -72,7 +72,7 @@ if(isset($_GET["auth"])) { if($_GET["auth"] !== $pwhash) - die("Not autorized!"); + die("Not authorized!"); } else { @@ -86,7 +86,7 @@ if(isset($_GET["auth"])) { if($_GET["auth"] !== $pwhash) - die("Not autorized!"); + die("Not authorized!"); } else { From c4cdcd9e943dfa0938a15aeddb3620cede37c19d Mon Sep 17 00:00:00 2001 From: Jacob Salmela Date: Thu, 23 Feb 2017 11:35:58 -0600 Subject: [PATCH 12/19] change verbiage Main Page to Dashboard --- scripts/pi-hole/php/header.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pi-hole/php/header.php b/scripts/pi-hole/php/header.php index cc0abe49..9fcb975c 100644 --- a/scripts/pi-hole/php/header.php +++ b/scripts/pi-hole/php/header.php @@ -354,7 +354,7 @@ class="active"> - Main Page + Dashboard From 5569ce69b63fac6d4a3f5770b76aa5bfb5905254 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 23 Feb 2017 18:41:57 +0100 Subject: [PATCH 13/19] Also rename on Help page --- help.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/help.php b/help.php index e4960973..4b682b5a 100644 --- a/help.php +++ b/help.php @@ -43,8 +43,8 @@
    -

    Main page

    -

    On the main page, you can see various Pi-hole statistics:

    +

    Dashboard

    +

    On the dashboard, you can see various Pi-hole statistics:

    • Summary: A summary of statistics showing how many total DNS queries have been blocked today, what percentage of DNS queries have been blocked, and how many domains are in the compiled ad list. This summary is updated every 10 seconds.
    • Queries over time: Graph showing DNS queries (total and blocked) over 10 minute time intervals. More information can be acquired by hovering over the lines. This graph is updated every 10 minutes.
    • From 191472c4c37809008962611b7c5bcbd619180497 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 23 Feb 2017 18:43:52 +0100 Subject: [PATCH 14/19] Two further changes on the Help page --- help.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/help.php b/help.php index 4b682b5a..66818b10 100644 --- a/help.php +++ b/help.php @@ -63,7 +63,7 @@
    • Top Clients: Ranking of how many DNS requests each client has made on the local network.
    -

    Note that the login session does not expire on the main page, as the summary is updated every 10 seconds which refreshes the session.

    +

    Note that the login session does not expire on the dashboard, as the summary is updated every 10 seconds which refreshes the session.

    @@ -129,7 +129,7 @@

    Authentication system (currently enableddisabled)

    -

    Using the command

    sudo pihole -a -p pa22w0rd
    where pa22w0rd is the password to be set in this example, one can enable the authentication system of this web interface. Thereafter, a login is required for most pages (the main page will show a limited amount of statistics). Note that the authentication system may be disabled again, by setting an empty password using the command shown above. The Help center will show more details concerning the authentication system only if it is enabled

    +

    Using the command

    sudo pihole -a -p pa22w0rd
    where pa22w0rd is the password to be set in this example, one can enable the authentication system of this web interface. Thereafter, a login is required for most pages (the dashboard will show a limited amount of statistics). Note that the authentication system may be disabled again, by setting an empty password using the command shown above. The Help center will show more details concerning the authentication system only if it is enabled

    From 5a1939497703112d93a2d484b66681b39604bb20 Mon Sep 17 00:00:00 2001 From: Dan Schaper Date: Mon, 27 Feb 2017 11:12:18 -0800 Subject: [PATCH 15/19] Add undocumented -w flag to alter the countdown behavior. Signed-off-by: Dan Schaper --- scripts/pi-hole/php/debug.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/pi-hole/php/debug.php b/scripts/pi-hole/php/debug.php index 996966a7..93ae3166 100644 --- a/scripts/pi-hole/php/debug.php +++ b/scripts/pi-hole/php/debug.php @@ -14,11 +14,11 @@ function echoEvent($datatext) { if(isset($_GET["upload"])) { - $proc = popen("sudo pihole -d -a", "r"); + $proc = popen("sudo pihole -d -a -w", "r"); } else { - $proc = popen("sudo pihole -d", "r"); + $proc = popen("sudo pihole -d -w", "r"); } while (!feof($proc)) { echoEvent(fread($proc, 4096)); From f328595d6df3746a4d096f9c201351a4c4d71865 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 27 Feb 2017 22:17:46 +0100 Subject: [PATCH 16/19] Remove [ ] from SERVER_NAME variable (#405) --- scripts/pi-hole/php/auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pi-hole/php/auth.php b/scripts/pi-hole/php/auth.php index 77871e4d..a8a64e33 100644 --- a/scripts/pi-hole/php/auth.php +++ b/scripts/pi-hole/php/auth.php @@ -30,7 +30,7 @@ function check_cors() { $AUTHORIZED_HOSTNAMES = array( $ipv4, $ipv6, - $_SERVER["SERVER_NAME"], + str_replace(array("[","]"), array("",""), $_SERVER["SERVER_NAME"]), "pi.hole", "localhost" ); From 276f2c1628ffef72c3d3ae489fd5b71ebb800227 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 27 Feb 2017 22:32:03 +0100 Subject: [PATCH 17/19] Allow usage of Teleporter and QueryAds backend only if a valid session is detected (#415) --- scripts/pi-hole/php/queryads.php | 3 +++ scripts/pi-hole/php/teleporter.php | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/pi-hole/php/queryads.php b/scripts/pi-hole/php/queryads.php index 457e235c..55e8f8c2 100644 --- a/scripts/pi-hole/php/queryads.php +++ b/scripts/pi-hole/php/queryads.php @@ -6,6 +6,9 @@ * This file is copyright under the latest version of the EUPL. * Please see LICENSE file for your rights under this license. */ +require "password.php"; +if(!$auth) die("Not authorized"); + ob_end_flush(); ini_set("output_buffering", "0"); ob_implicit_flush(true); diff --git a/scripts/pi-hole/php/teleporter.php b/scripts/pi-hole/php/teleporter.php index e5d9f828..02eacbfc 100644 --- a/scripts/pi-hole/php/teleporter.php +++ b/scripts/pi-hole/php/teleporter.php @@ -4,9 +4,11 @@ * Network-wide ad blocking via your own hardware. * * This file is copyright under the latest version of the EUPL. -* Please see LICENSE file for your rights under this license. */ ?> +* Please see LICENSE file for your rights under this license. */ + +require "password.php"; +if(!$auth) die("Not authorized"); - Date: Mon, 27 Feb 2017 22:33:35 +0100 Subject: [PATCH 18/19] API QR token generator (#410) * Added API QR token generator * Pass only token * Corrected link --- scripts/pi-hole/js/settings.js | 17 + scripts/pi-hole/php/api_token.php | 26 + scripts/vendor/qrcode.php | 1543 +++++++++++++++++++++++++++++ settings.php | 1 + 4 files changed, 1587 insertions(+) create mode 100644 scripts/pi-hole/php/api_token.php create mode 100644 scripts/vendor/qrcode.php diff --git a/scripts/pi-hole/js/settings.js b/scripts/pi-hole/js/settings.js index 84bf41aa..bce784da 100644 --- a/scripts/pi-hole/js/settings.js +++ b/scripts/pi-hole/js/settings.js @@ -68,6 +68,23 @@ $(".confirm-flushlogs").confirm({ dialogClass: "modal-dialog modal-mg" }); +$(".api-token").confirm({ + text: "Make sure that nobody else can scan this code around you. They will have full access to the API without having to know the password. Note that the generation of the QR code will take some time.", + title: "Confirmation required", + confirm(button) { + window.open("scripts/pi-hole/php/api_token.php"); + }, + cancel(button) { + // nothing to do + }, + confirmButton: "Yes, show API token", + cancelButton: "No, go back", + post: true, + confirmButtonClass: "btn-danger", + cancelButtonClass: "btn-success", + dialogClass: "modal-dialog modal-mg" +}); + $("#DHCPchk").click(function() { $("input.DHCPgroup").prop("disabled", !this.checked); $("#dhcpnotice").prop("hidden", !this.checked).addClass("lookatme"); diff --git a/scripts/pi-hole/php/api_token.php b/scripts/pi-hole/php/api_token.php new file mode 100644 index 00000000..be83895f --- /dev/null +++ b/scripts/pi-hole/php/api_token.php @@ -0,0 +1,26 @@ + + 0) + { + require_once("../../vendor/qrcode.php"); + $qr = QRCode::getMinimumQRCode($pwhash, QR_ERROR_CORRECT_LEVEL_Q); + $qr->printHTML("10px"); + } + else + { + ?>

    No password set

    Not authorized!

    + + diff --git a/scripts/vendor/qrcode.php b/scripts/vendor/qrcode.php new file mode 100644 index 00000000..4afb6eac --- /dev/null +++ b/scripts/vendor/qrcode.php @@ -0,0 +1,1543 @@ +typeNumber = 1; + $this->errorCorrectLevel = QR_ERROR_CORRECT_LEVEL_H; + $this->qrDataList = array(); + } + + function getTypeNumber() { + return $this->typeNumber; + } + + function setTypeNumber($typeNumber) { + $this->typeNumber = $typeNumber; + } + + function getErrorCorrectLevel() { + return $this->errorCorrectLevel; + } + + function setErrorCorrectLevel($errorCorrectLevel) { + $this->errorCorrectLevel = $errorCorrectLevel; + } + + function addData($data, $mode = 0) { + + if ($mode == 0) { + $mode = QRUtil::getMode($data); + } + + switch($mode) { + + case QR_MODE_NUMBER : + $this->addDataImpl(new QRNumber($data) ); + break; + + case QR_MODE_ALPHA_NUM : + $this->addDataImpl(new QRAlphaNum($data) ); + break; + + case QR_MODE_8BIT_BYTE : + $this->addDataImpl(new QR8BitByte($data) ); + break; + + case QR_MODE_KANJI : + $this->addDataImpl(new QRKanji($data) ); + break; + + default : + trigger_error("mode:$mode", E_USER_ERROR); + } + } + + function clearData() { + $qrDataList = array(); + } + + function addDataImpl(&$qrData) { + $this->qrDataList[] = $qrData; + } + + function getDataCount() { + return count($this->qrDataList); + } + + function getData($index) { + return $this->qrDataList[$index]; + } + + function isDark($row, $col) { + if ($this->modules[$row][$col] !== null) { + return $this->modules[$row][$col]; + } else { + return false; + } + } + + function getModuleCount() { + return $this->moduleCount; + } + + // used for converting fg/bg colors (e.g. #0000ff = 0x0000FF) + // added 2015.07.27 ~ DoktorJ + function hex2rgb($hex = 0x0) { + return array( + 'r' => floor($hex / 65536), + 'g' => floor($hex / 256) % 256, + 'b' => $hex % 256 + ); + } + + function make() { + $this->makeImpl(false, $this->getBestMaskPattern() ); + } + + function getBestMaskPattern() { + + $minLostPoint = 0; + $pattern = 0; + + for ($i = 0; $i < 8; $i++) { + + $this->makeImpl(true, $i); + + $lostPoint = QRUtil::getLostPoint($this); + + if ($i == 0 || $minLostPoint > $lostPoint) { + $minLostPoint = $lostPoint; + $pattern = $i; + } + } + + return $pattern; + } + + function createNullArray($length) { + $nullArray = array(); + for ($i = 0; $i < $length; $i++) { + $nullArray[] = null; + } + return $nullArray; + } + + function makeImpl($test, $maskPattern) { + + $this->moduleCount = $this->typeNumber * 4 + 17; + + $this->modules = array(); + for ($i = 0; $i < $this->moduleCount; $i++) { + $this->modules[] = QRCode::createNullArray($this->moduleCount); + } + + $this->setupPositionProbePattern(0, 0); + $this->setupPositionProbePattern($this->moduleCount - 7, 0); + $this->setupPositionProbePattern(0, $this->moduleCount - 7); + + $this->setupPositionAdjustPattern(); + $this->setupTimingPattern(); + + $this->setupTypeInfo($test, $maskPattern); + + if ($this->typeNumber >= 7) { + $this->setupTypeNumber($test); + } + + $dataArray = $this->qrDataList; + + $data = QRCode::createData($this->typeNumber, $this->errorCorrectLevel, $dataArray); + + $this->mapData($data, $maskPattern); + } + + function mapData(&$data, $maskPattern) { + + $inc = -1; + $row = $this->moduleCount - 1; + $bitIndex = 7; + $byteIndex = 0; + + for ($col = $this->moduleCount - 1; $col > 0; $col -= 2) { + + if ($col == 6) $col--; + + while (true) { + + for ($c = 0; $c < 2; $c++) { + + if ($this->modules[$row][$col - $c] === null) { + + $dark = false; + + if ($byteIndex < count($data) ) { + $dark = ( ( ($data[$byteIndex] >> $bitIndex) & 1) == 1); + } + + $mask = QRUtil::getMask($maskPattern, $row, $col - $c); + + if ($mask) { + $dark = !$dark; + } + + $this->modules[$row][$col - $c] = $dark; + $bitIndex--; + + if ($bitIndex == -1) { + $byteIndex++; + $bitIndex = 7; + } + } + } + + $row += $inc; + + if ($row < 0 || $this->moduleCount <= $row) { + $row -= $inc; + $inc = -$inc; + break; + } + } + } + } + + function setupPositionAdjustPattern() { + + $pos = QRUtil::getPatternPosition($this->typeNumber); + + for ($i = 0; $i < count($pos); $i++) { + + for ($j = 0; $j < count($pos); $j++) { + + $row = $pos[$i]; + $col = $pos[$j]; + + if ($this->modules[$row][$col] !== null) { + continue; + } + + for ($r = -2; $r <= 2; $r++) { + + for ($c = -2; $c <= 2; $c++) { + + if ($r == -2 || $r == 2 || $c == -2 || $c == 2 + || ($r == 0 && $c == 0) ) { + $this->modules[$row + $r][$col + $c] = true; + } else { + $this->modules[$row + $r][$col + $c] = false; + } + } + } + } + } + } + + function setupPositionProbePattern($row, $col) { + + for ($r = -1; $r <= 7; $r++) { + + for ($c = -1; $c <= 7; $c++) { + + if ($row + $r <= -1 || $this->moduleCount <= $row + $r + || $col + $c <= -1 || $this->moduleCount <= $col + $c) { + continue; + } + + if ( (0 <= $r && $r <= 6 && ($c == 0 || $c == 6) ) + || (0 <= $c && $c <= 6 && ($r == 0 || $r == 6) ) + || (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4) ) { + $this->modules[$row + $r][$col + $c] = true; + } else { + $this->modules[$row + $r][$col + $c] = false; + } + } + } + } + + function setupTimingPattern() { + + for ($r = 8; $r < $this->moduleCount - 8; $r++) { + if ($this->modules[$r][6] !== null) { + continue; + } + $this->modules[$r][6] = ($r % 2 == 0); + } + + for ($c = 8; $c < $this->moduleCount - 8; $c++) { + if ($this->modules[6][$c] !== null) { + continue; + } + $this->modules[6][$c] = ($c % 2 == 0); + } + } + + function setupTypeNumber($test) { + + $bits = QRUtil::getBCHTypeNumber($this->typeNumber); + + for ($i = 0; $i < 18; $i++) { + $mod = (!$test && ( ($bits >> $i) & 1) == 1); + $this->modules[floor($i / 3)][$i % 3 + $this->moduleCount - 8 - 3] = $mod; + } + + for ($i = 0; $i < 18; $i++) { + $mod = (!$test && ( ($bits >> $i) & 1) == 1); + $this->modules[$i % 3 + $this->moduleCount - 8 - 3][floor($i / 3)] = $mod; + } + } + + function setupTypeInfo($test, $maskPattern) { + + $data = ($this->errorCorrectLevel << 3) | $maskPattern; + $bits = QRUtil::getBCHTypeInfo($data); + + for ($i = 0; $i < 15; $i++) { + + $mod = (!$test && ( ($bits >> $i) & 1) == 1); + + if ($i < 6) { + $this->modules[$i][8] = $mod; + } else if ($i < 8) { + $this->modules[$i + 1][8] = $mod; + } else { + $this->modules[$this->moduleCount - 15 + $i][8] = $mod; + } + } + + for ($i = 0; $i < 15; $i++) { + + $mod = (!$test && ( ($bits >> $i) & 1) == 1); + + if ($i < 8) { + $this->modules[8][$this->moduleCount - $i - 1] = $mod; + } else if ($i < 9) { + $this->modules[8][15 - $i - 1 + 1] = $mod; + } else { + $this->modules[8][15 - $i - 1] = $mod; + } + } + + $this->modules[$this->moduleCount - 8][8] = !$test; + } + + function createData($typeNumber, $errorCorrectLevel, $dataArray) { + + $rsBlocks = QRRSBlock::getRSBlocks($typeNumber, $errorCorrectLevel); + + $buffer = new QRBitBuffer(); + + for ($i = 0; $i < count($dataArray); $i++) { + $data = $dataArray[$i]; + $buffer->put($data->getMode(), 4); + $buffer->put($data->getLength(), $data->getLengthInBits($typeNumber) ); + $data->write($buffer); + } + + $totalDataCount = 0; + for ($i = 0; $i < count($rsBlocks); $i++) { + $totalDataCount += $rsBlocks[$i]->getDataCount(); + } + + if ($buffer->getLengthInBits() > $totalDataCount * 8) { + trigger_error("code length overflow. (" + . $buffer->getLengthInBits() + . ">" + . $totalDataCount * 8 + . ")", E_USER_ERROR); + } + + // end code. + if ($buffer->getLengthInBits() + 4 <= $totalDataCount * 8) { + $buffer->put(0, 4); + } + + // padding + while ($buffer->getLengthInBits() % 8 != 0) { + $buffer->putBit(false); + } + + // padding + while (true) { + + if ($buffer->getLengthInBits() >= $totalDataCount * 8) { + break; + } + $buffer->put(QR_PAD0, 8); + + if ($buffer->getLengthInBits() >= $totalDataCount * 8) { + break; + } + $buffer->put(QR_PAD1, 8); + } + + return QRCode::createBytes($buffer, $rsBlocks); + } + + function createBytes(&$buffer, &$rsBlocks) { + + $offset = 0; + + $maxDcCount = 0; + $maxEcCount = 0; + + $dcdata = QRCode::createNullArray(count($rsBlocks) ); + $ecdata = QRCode::createNullArray(count($rsBlocks) ); + + for ($r = 0; $r < count($rsBlocks); $r++) { + + $dcCount = $rsBlocks[$r]->getDataCount(); + $ecCount = $rsBlocks[$r]->getTotalCount() - $dcCount; + + $maxDcCount = max($maxDcCount, $dcCount); + $maxEcCount = max($maxEcCount, $ecCount); + + $dcdata[$r] = QRCode::createNullArray($dcCount); + for ($i = 0; $i < count($dcdata[$r]); $i++) { + $bdata = $buffer->getBuffer(); + $dcdata[$r][$i] = 0xff & $bdata[$i + $offset]; + } + $offset += $dcCount; + + $rsPoly = QRUtil::getErrorCorrectPolynomial($ecCount); + $rawPoly = new QRPolynomial($dcdata[$r], $rsPoly->getLength() - 1); + + $modPoly = $rawPoly->mod($rsPoly); + $ecdata[$r] = QRCode::createNullArray($rsPoly->getLength() - 1); + for ($i = 0; $i < count($ecdata[$r]); $i++) { + $modIndex = $i + $modPoly->getLength() - count($ecdata[$r]); + $ecdata[$r][$i] = ($modIndex >= 0)? $modPoly->get($modIndex) : 0; + } + } + + $totalCodeCount = 0; + for ($i = 0; $i < count($rsBlocks); $i++) { + $totalCodeCount += $rsBlocks[$i]->getTotalCount(); + } + + $data = QRCode::createNullArray($totalCodeCount); + + $index = 0; + + for ($i = 0; $i < $maxDcCount; $i++) { + for ($r = 0; $r < count($rsBlocks); $r++) { + if ($i < count($dcdata[$r]) ) { + $data[$index++] = $dcdata[$r][$i]; + } + } + } + + for ($i = 0; $i < $maxEcCount; $i++) { + for ($r = 0; $r < count($rsBlocks); $r++) { + if ($i < count($ecdata[$r]) ) { + $data[$index++] = $ecdata[$r][$i]; + } + } + } + + return $data; + } + + static function getMinimumQRCode($data, $errorCorrectLevel) { + + $mode = QRUtil::getMode($data); + + $qr = new QRCode(); + $qr->setErrorCorrectLevel($errorCorrectLevel); + $qr->addData($data, $mode); + + $qrData = $qr->getData(0); + $length = $qrData->getLength(); + + for ($typeNumber = 1; $typeNumber <= 10; $typeNumber++) { + if ($length <= QRUtil::getMaxLength($typeNumber, $mode, $errorCorrectLevel) ) { + $qr->setTypeNumber($typeNumber); + break; + } + } + + $qr->make(); + + return $qr; + } + + // added $fg (foreground), $bg (background), and $bgtrans (use transparent bg) parameters + // also added some simple error checking on parameters + // updated 2015.07.27 ~ DoktorJ + function createImage($size = 2, $margin = 2, $fg = 0x000000, $bg = 0xFFFFFF, $bgtrans = false) { + + // size/margin EC + if (!is_numeric($size)) $size = 2; + if (!is_numeric($margin)) $margin = 2; + if ($size < 1) $size = 1; + if ($margin < 0) $margin = 0; + + $image_size = $this->getModuleCount() * $size + $margin * 2; + + $image = imagecreatetruecolor($image_size, $image_size); + + // fg/bg EC + if ($fg < 0 || $fg > 0xFFFFFF) $fg = 0x0; + if ($bg < 0 || $bg > 0xFFFFFF) $bg = 0xFFFFFF; + + // convert hexadecimal RGB to arrays for imagecolorallocate + $fgrgb = $this->hex2rgb($fg); + $bgrgb = $this->hex2rgb($bg); + + // replace $black and $white with $fgc and $bgc + $fgc = imagecolorallocate($image, $fgrgb['r'], $fgrgb['g'], $fgrgb['b']); + $bgc = imagecolorallocate($image, $bgrgb['r'], $bgrgb['g'], $bgrgb['b']); + if ($bgtrans) imagecolortransparent($image, $bgc); + + // update $white to $bgc + imagefilledrectangle($image, 0, 0, $image_size, $image_size, $bgc); + + for ($r = 0; $r < $this->getModuleCount(); $r++) { + for ($c = 0; $c < $this->getModuleCount(); $c++) { + if ($this->isDark($r, $c) ) { + + // update $black to $fgc + imagefilledrectangle($image, + $margin + $c * $size, + $margin + $r * $size, + $margin + ($c + 1) * $size - 1, + $margin + ($r + 1) * $size - 1, + $fgc); + } + } + } + + return $image; + } + + function printHTML($size = "2px") { + + $style = "border-style:none;border-collapse:collapse;margin:0px;padding:0px;"; + + print(""); + + for ($r = 0; $r < $this->getModuleCount(); $r++) { + + print(""); + + for ($c = 0; $c < $this->getModuleCount(); $c++) { + $color = $this->isDark($r, $c)? "#000000" : "#ffffff"; + print(""); + } + + print(""); + } + + print("
    "); + } +} + +//--------------------------------------------------------------- +// QRUtil +//--------------------------------------------------------------- + +define("QR_G15", (1 << 10) | (1 << 8) | (1 << 5) + | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0) ); + +define("QR_G18", (1 << 12) | (1 << 11) | (1 << 10) + | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0) ); + +define("QR_G15_MASK", (1 << 14) | (1 << 12) | (1 << 10) + | (1 << 4) | (1 << 1) ); + +class QRUtil { + + static $QR_MAX_LENGTH = array( + array( array(41, 25, 17, 10), array(34, 20, 14, 8), array(27, 16, 11, 7), array(17, 10, 7, 4) ), + array( array(77, 47, 32, 20), array(63, 38, 26, 16), array(48, 29, 20, 12), array(34, 20, 14, 8) ), + array( array(127, 77, 53, 32), array(101, 61, 42, 26), array(77, 47, 32, 20), array(58, 35, 24, 15) ), + array( array(187, 114, 78, 48), array(149, 90, 62, 38), array(111, 67, 46, 28), array(82, 50, 34, 21) ), + array( array(255, 154, 106, 65), array(202, 122, 84, 52), array(144, 87, 60, 37), array(106, 64, 44, 27) ), + array( array(322, 195, 134, 82), array(255, 154, 106, 65), array(178, 108, 74, 45), array(139, 84, 58, 36) ), + array( array(370, 224, 154, 95), array(293, 178, 122, 75), array(207, 125, 86, 53), array(154, 93, 64, 39) ), + array( array(461, 279, 192, 118), array(365, 221, 152, 93), array(259, 157, 108, 66), array(202, 122, 84, 52) ), + array( array(552, 335, 230, 141), array(432, 262, 180, 111), array(312, 189, 130, 80), array(235, 143, 98, 60) ), + array( array(652, 395, 271, 167), array(513, 311, 213, 131), array(364, 221, 151, 93), array(288, 174, 119, 74) ) + ); + + static $QR_PATTERN_POSITION_TABLE = array( + array(), + array(6, 18), + array(6, 22), + array(6, 26), + array(6, 30), + array(6, 34), + array(6, 22, 38), + array(6, 24, 42), + array(6, 26, 46), + array(6, 28, 50), + array(6, 30, 54), + array(6, 32, 58), + array(6, 34, 62), + array(6, 26, 46, 66), + array(6, 26, 48, 70), + array(6, 26, 50, 74), + array(6, 30, 54, 78), + array(6, 30, 56, 82), + array(6, 30, 58, 86), + array(6, 34, 62, 90), + array(6, 28, 50, 72, 94), + array(6, 26, 50, 74, 98), + array(6, 30, 54, 78, 102), + array(6, 28, 54, 80, 106), + array(6, 32, 58, 84, 110), + array(6, 30, 58, 86, 114), + array(6, 34, 62, 90, 118), + array(6, 26, 50, 74, 98, 122), + array(6, 30, 54, 78, 102, 126), + array(6, 26, 52, 78, 104, 130), + array(6, 30, 56, 82, 108, 134), + array(6, 34, 60, 86, 112, 138), + array(6, 30, 58, 86, 114, 142), + array(6, 34, 62, 90, 118, 146), + array(6, 30, 54, 78, 102, 126, 150), + array(6, 24, 50, 76, 102, 128, 154), + array(6, 28, 54, 80, 106, 132, 158), + array(6, 32, 58, 84, 110, 136, 162), + array(6, 26, 54, 82, 110, 138, 166), + array(6, 30, 58, 86, 114, 142, 170) + ); + + static function getPatternPosition($typeNumber) { + return self::$QR_PATTERN_POSITION_TABLE[$typeNumber - 1]; + } + + static function getMaxLength($typeNumber, $mode, $errorCorrectLevel) { + + $t = $typeNumber - 1; + $e = 0; + $m = 0; + + switch($errorCorrectLevel) { + case QR_ERROR_CORRECT_LEVEL_L : $e = 0; break; + case QR_ERROR_CORRECT_LEVEL_M : $e = 1; break; + case QR_ERROR_CORRECT_LEVEL_Q : $e = 2; break; + case QR_ERROR_CORRECT_LEVEL_H : $e = 3; break; + default : + trigger_error("e:$errorCorrectLevel", E_USER_ERROR); + } + + switch($mode) { + case QR_MODE_NUMBER : $m = 0; break; + case QR_MODE_ALPHA_NUM : $m = 1; break; + case QR_MODE_8BIT_BYTE : $m = 2; break; + case QR_MODE_KANJI : $m = 3; break; + default : + trigger_error("m:$mode", E_USER_ERROR); + } + + return self::$QR_MAX_LENGTH[$t][$e][$m]; + } + + static function getErrorCorrectPolynomial($errorCorrectLength) { + + $a = new QRPolynomial(array(1) ); + + for ($i = 0; $i < $errorCorrectLength; $i++) { + $a = $a->multiply(new QRPolynomial(array(1, QRMath::gexp($i) ) ) ); + } + + return $a; + } + + static function getMask($maskPattern, $i, $j) { + + switch ($maskPattern) { + + case QR_MASK_PATTERN000 : return ($i + $j) % 2 == 0; + case QR_MASK_PATTERN001 : return $i % 2 == 0; + case QR_MASK_PATTERN010 : return $j % 3 == 0; + case QR_MASK_PATTERN011 : return ($i + $j) % 3 == 0; + case QR_MASK_PATTERN100 : return (floor($i / 2) + floor($j / 3) ) % 2 == 0; + case QR_MASK_PATTERN101 : return ($i * $j) % 2 + ($i * $j) % 3 == 0; + case QR_MASK_PATTERN110 : return ( ($i * $j) % 2 + ($i * $j) % 3) % 2 == 0; + case QR_MASK_PATTERN111 : return ( ($i * $j) % 3 + ($i + $j) % 2) % 2 == 0; + + default : + trigger_error("mask:$maskPattern", E_USER_ERROR); + } + } + + static function getLostPoint($qrCode) { + + $moduleCount = $qrCode->getModuleCount(); + + $lostPoint = 0; + + + // LEVEL1 + + for ($row = 0; $row < $moduleCount; $row++) { + + for ($col = 0; $col < $moduleCount; $col++) { + + $sameCount = 0; + $dark = $qrCode->isDark($row, $col); + + for ($r = -1; $r <= 1; $r++) { + + if ($row + $r < 0 || $moduleCount <= $row + $r) { + continue; + } + + for ($c = -1; $c <= 1; $c++) { + + if ($col + $c < 0 || $moduleCount <= $col + $c) { + continue; + } + + if ($r == 0 && $c == 0) { + continue; + } + + if ($dark == $qrCode->isDark($row + $r, $col + $c) ) { + $sameCount++; + } + } + } + + if ($sameCount > 5) { + $lostPoint += (3 + $sameCount - 5); + } + } + } + + // LEVEL2 + + for ($row = 0; $row < $moduleCount - 1; $row++) { + for ($col = 0; $col < $moduleCount - 1; $col++) { + $count = 0; + if ($qrCode->isDark($row, $col ) ) $count++; + if ($qrCode->isDark($row + 1, $col ) ) $count++; + if ($qrCode->isDark($row, $col + 1) ) $count++; + if ($qrCode->isDark($row + 1, $col + 1) ) $count++; + if ($count == 0 || $count == 4) { + $lostPoint += 3; + } + } + } + + // LEVEL3 + + for ($row = 0; $row < $moduleCount; $row++) { + for ($col = 0; $col < $moduleCount - 6; $col++) { + if ($qrCode->isDark($row, $col) + && !$qrCode->isDark($row, $col + 1) + && $qrCode->isDark($row, $col + 2) + && $qrCode->isDark($row, $col + 3) + && $qrCode->isDark($row, $col + 4) + && !$qrCode->isDark($row, $col + 5) + && $qrCode->isDark($row, $col + 6) ) { + $lostPoint += 40; + } + } + } + + for ($col = 0; $col < $moduleCount; $col++) { + for ($row = 0; $row < $moduleCount - 6; $row++) { + if ($qrCode->isDark($row, $col) + && !$qrCode->isDark($row + 1, $col) + && $qrCode->isDark($row + 2, $col) + && $qrCode->isDark($row + 3, $col) + && $qrCode->isDark($row + 4, $col) + && !$qrCode->isDark($row + 5, $col) + && $qrCode->isDark($row + 6, $col) ) { + $lostPoint += 40; + } + } + } + + // LEVEL4 + + $darkCount = 0; + + for ($col = 0; $col < $moduleCount; $col++) { + for ($row = 0; $row < $moduleCount; $row++) { + if ($qrCode->isDark($row, $col) ) { + $darkCount++; + } + } + } + + $ratio = abs(100 * $darkCount / $moduleCount / $moduleCount - 50) / 5; + $lostPoint += $ratio * 10; + + return $lostPoint; + } + + static function getMode($s) { + if (QRUtil::isAlphaNum($s) ) { + if (QRUtil::isNumber($s) ) { + return QR_MODE_NUMBER; + } + return QR_MODE_ALPHA_NUM; + } else if (QRUtil::isKanji($s) ) { + return QR_MODE_KANJI; + } else { + return QR_MODE_8BIT_BYTE; + } + } + + static function isNumber($s) { + for ($i = 0; $i < strlen($s); $i++) { + $c = ord($s[$i]); + if (!(QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9') ) ) { + return false; + } + } + return true; + } + + static function isAlphaNum($s) { + for ($i = 0; $i < strlen($s); $i++) { + $c = ord($s[$i]); + if (!(QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9') ) + && !(QRUtil::toCharCode('A') <= $c && $c <= QRUtil::toCharCode('Z') ) + && strpos(" $%*+-./:", $s[$i]) === false) { + return false; + } + } + return true; + } + + static function isKanji($s) { + + $data = $s; + + $i = 0; + + while ($i + 1 < strlen($data) ) { + + $c = ( (0xff & ord($data[$i]) ) << 8) | (0xff & ord($data[$i + 1]) ); + + if (!(0x8140 <= $c && $c <= 0x9FFC) && !(0xE040 <= $c && $c <= 0xEBBF) ) { + return false; + } + + $i += 2; + } + + if ($i < strlen($data) ) { + return false; + } + + return true; + } + + static function toCharCode($s) { + return ord($s[0]); + } + + static function getBCHTypeInfo($data) { + $d = $data << 10; + while (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G15) >= 0) { + $d ^= (QR_G15 << (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G15) ) ); + } + return ( ($data << 10) | $d) ^ QR_G15_MASK; + } + + static function getBCHTypeNumber($data) { + $d = $data << 12; + while (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G18) >= 0) { + $d ^= (QR_G18 << (QRUtil::getBCHDigit($d) - QRUtil::getBCHDigit(QR_G18) ) ); + } + return ($data << 12) | $d; + } + + static function getBCHDigit($data) { + + $digit = 0; + + while ($data != 0) { + $digit++; + $data >>= 1; + } + + return $digit; + } +} + +//--------------------------------------------------------------- +// QRRSBlock +//--------------------------------------------------------------- + +class QRRSBlock { + + var $totalCount; + var $dataCount; + + static $QR_RS_BLOCK_TABLE = array( + + // L + // M + // Q + // H + + // 1 + array(1, 26, 19), + array(1, 26, 16), + array(1, 26, 13), + array(1, 26, 9), + + // 2 + array(1, 44, 34), + array(1, 44, 28), + array(1, 44, 22), + array(1, 44, 16), + + // 3 + array(1, 70, 55), + array(1, 70, 44), + array(2, 35, 17), + array(2, 35, 13), + + // 4 + array(1, 100, 80), + array(2, 50, 32), + array(2, 50, 24), + array(4, 25, 9), + + // 5 + array(1, 134, 108), + array(2, 67, 43), + array(2, 33, 15, 2, 34, 16), + array(2, 33, 11, 2, 34, 12), + + // 6 + array(2, 86, 68), + array(4, 43, 27), + array(4, 43, 19), + array(4, 43, 15), + + // 7 + array(2, 98, 78), + array(4, 49, 31), + array(2, 32, 14, 4, 33, 15), + array(4, 39, 13, 1, 40, 14), + + // 8 + array(2, 121, 97), + array(2, 60, 38, 2, 61, 39), + array(4, 40, 18, 2, 41, 19), + array(4, 40, 14, 2, 41, 15), + + // 9 + array(2, 146, 116), + array(3, 58, 36, 2, 59, 37), + array(4, 36, 16, 4, 37, 17), + array(4, 36, 12, 4, 37, 13), + + // 10 + array(2, 86, 68, 2, 87, 69), + array(4, 69, 43, 1, 70, 44), + array(6, 43, 19, 2, 44, 20), + array(6, 43, 15, 2, 44, 16) + + ); + + function QRRSBlock($totalCount, $dataCount) { + $this->totalCount = $totalCount; + $this->dataCount = $dataCount; + } + + function getDataCount() { + return $this->dataCount; + } + + function getTotalCount() { + return $this->totalCount; + } + + static function getRSBlocks($typeNumber, $errorCorrectLevel) { + + $rsBlock = QRRSBlock::getRsBlockTable($typeNumber, $errorCorrectLevel); + $length = count($rsBlock) / 3; + + $list = array(); + + for ($i = 0; $i < $length; $i++) { + + $count = $rsBlock[$i * 3 + 0]; + $totalCount = $rsBlock[$i * 3 + 1]; + $dataCount = $rsBlock[$i * 3 + 2]; + + for ($j = 0; $j < $count; $j++) { + $list[] = new QRRSBlock($totalCount, $dataCount); + } + } + + return $list; + } + + static function getRsBlockTable($typeNumber, $errorCorrectLevel) { + + switch($errorCorrectLevel) { + case QR_ERROR_CORRECT_LEVEL_L : + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 0]; + case QR_ERROR_CORRECT_LEVEL_M : + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 1]; + case QR_ERROR_CORRECT_LEVEL_Q : + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 2]; + case QR_ERROR_CORRECT_LEVEL_H : + return self::$QR_RS_BLOCK_TABLE[($typeNumber - 1) * 4 + 3]; + default : + trigger_error("tn:$typeNumber/ecl:$errorCorrectLevel", E_USER_ERROR); + } + } +} + +//--------------------------------------------------------------- +// QRNumber +//--------------------------------------------------------------- + +class QRNumber extends QRData { + + function QRNumber($data) { + QRData::QRData(QR_MODE_NUMBER, $data); + } + + function write(&$buffer) { + + $data = $this->getData(); + + $i = 0; + + while ($i + 2 < strlen($data) ) { + $num = QRNumber::parseInt(substr($data, $i, 3) ); + $buffer->put($num, 10); + $i += 3; + } + + if ($i < strlen($data) ) { + + if (strlen($data) - $i == 1) { + $num = QRNumber::parseInt(substr($data, $i, $i + 1) ); + $buffer->put($num, 4); + } else if (strlen($data) - $i == 2) { + $num = QRNumber::parseInt(substr($data, $i, $i + 2) ); + $buffer->put($num, 7); + } + } + } + + function getLength() { + return strlen($this->getData() ); + } + + static function parseInt($s) { + + $num = 0; + for ($i = 0; $i < strlen($s); $i++) { + $num = $num * 10 + QRNumber::parseIntAt(ord($s[$i]) ); + } + return $num; + } + + static function parseIntAt($c) { + + if (QRUtil::toCharCode('0') <= $c && $c <= QRUtil::toCharCode('9') ) { + return $c - QRUtil::toCharCode('0'); + } + + trigger_error("illegal char : $c", E_USER_ERROR); + } +} + +//--------------------------------------------------------------- +// QRKanji +//--------------------------------------------------------------- + +class QRKanji extends QRData { + + function QRKanji($data) { + QRData::QRData(QR_MODE_KANJI, $data); + } + + function write(&$buffer) { + + $data = $this->getData(); + + $i = 0; + + while ($i + 1 < strlen($data) ) { + + $c = ( (0xff & ord($data[$i]) ) << 8) | (0xff & ord($data[$i + 1]) ); + + if (0x8140 <= $c && $c <= 0x9FFC) { + $c -= 0x8140; + } else if (0xE040 <= $c && $c <= 0xEBBF) { + $c -= 0xC140; + } else { + trigger_error("illegal char at " . ($i + 1) . "/$c", E_USER_ERROR); + } + + $c = ( ($c >> 8) & 0xff) * 0xC0 + ($c & 0xff); + + $buffer->put($c, 13); + + $i += 2; + } + + if ($i < strlen($data) ) { + trigger_error("illegal char at " . ($i + 1), E_USER_ERROR); + } + } + + function getLength() { + return floor(strlen($this->getData() ) / 2); + } +} + +//--------------------------------------------------------------- +// QRAlphaNum +//--------------------------------------------------------------- + +class QRAlphaNum extends QRData { + + function QRAlphaNum($data) { + QRData::QRData(QR_MODE_ALPHA_NUM, $data); + } + + function write(&$buffer) { + + $i = 0; + $c = $this->getData(); + + while ($i + 1 < strlen($c) ) { + $buffer->put(QRAlphaNum::getCode(ord($c[$i]) ) * 45 + + QRAlphaNum::getCode(ord($c[$i + 1]) ), 11); + $i += 2; + } + + if ($i < strlen($c) ) { + $buffer->put(QRAlphaNum::getCode(ord($c[$i])), 6); + } + } + + function getLength() { + return strlen($this->getData() ); + } + + static function getCode($c) { + + if (QRUtil::toCharCode('0') <= $c + && $c <= QRUtil::toCharCode('9') ) { + return $c - QRUtil::toCharCode('0'); + } else if (QRUtil::toCharCode('A') <= $c + && $c <= QRUtil::toCharCode('Z') ) { + return $c - QRUtil::toCharCode('A') + 10; + } else { + switch ($c) { + case QRUtil::toCharCode(' ') : return 36; + case QRUtil::toCharCode('$') : return 37; + case QRUtil::toCharCode('%') : return 38; + case QRUtil::toCharCode('*') : return 39; + case QRUtil::toCharCode('+') : return 40; + case QRUtil::toCharCode('-') : return 41; + case QRUtil::toCharCode('.') : return 42; + case QRUtil::toCharCode('/') : return 43; + case QRUtil::toCharCode(':') : return 44; + default : + trigger_error("illegal char : $c", E_USER_ERROR); + } + } + + } +} + +//--------------------------------------------------------------- +// QR8BitByte +//--------------------------------------------------------------- + +class QR8BitByte extends QRData { + + function QR8BitByte($data) { + QRData::QRData(QR_MODE_8BIT_BYTE, $data); + } + + function write(&$buffer) { + + $data = $this->getData(); + for ($i = 0; $i < strlen($data); $i++) { + $buffer->put(ord($data[$i]), 8); + } + } + + function getLength() { + return strlen($this->getData() ); + } +} + +//--------------------------------------------------------------- +// QRData +//--------------------------------------------------------------- + +class QRData { + + var $mode; + + var $data; + + function QRData($mode, $data) { + $this->mode = $mode; + $this->data = $data; + } + + function getMode() { + return $this->mode; + } + + function getData() { + return $this->data; + } + + function getLength() { + trigger_error("not implemented.", E_USER_ERROR); + } + + function write(&$buffer) { + trigger_error("not implemented.", E_USER_ERROR); + } + + function getLengthInBits($type) { + + if (1 <= $type && $type < 10) { + + // 1 - 9 + + switch($this->mode) { + case QR_MODE_NUMBER : return 10; + case QR_MODE_ALPHA_NUM : return 9; + case QR_MODE_8BIT_BYTE : return 8; + case QR_MODE_KANJI : return 8; + default : + trigger_error("mode:$this->mode", E_USER_ERROR); + } + + } else if ($type < 27) { + + // 10 - 26 + + switch($this->mode) { + case QR_MODE_NUMBER : return 12; + case QR_MODE_ALPHA_NUM : return 11; + case QR_MODE_8BIT_BYTE : return 16; + case QR_MODE_KANJI : return 10; + default : + trigger_error("mode:$this->mode", E_USER_ERROR); + } + + } else if ($type < 41) { + + // 27 - 40 + + switch($this->mode) { + case QR_MODE_NUMBER : return 14; + case QR_MODE_ALPHA_NUM : return 13; + case QR_MODE_8BIT_BYTE : return 16; + case QR_MODE_KANJI : return 12; + default : + trigger_error("mode:$this->mode", E_USER_ERROR); + } + + } else { + trigger_error("mode:$this->mode", E_USER_ERROR); + } + } + +} + +//--------------------------------------------------------------- +// QRMath +//--------------------------------------------------------------- + +class QRMath { + + static $QR_MATH_EXP_TABLE = null; + static $QR_MATH_LOG_TABLE = null; + + static function init() { + + self::$QR_MATH_EXP_TABLE = QRMath::createNumArray(256); + + for ($i = 0; $i < 8; $i++) { + self::$QR_MATH_EXP_TABLE[$i] = 1 << $i; + } + + for ($i = 8; $i < 256; $i++) { + self::$QR_MATH_EXP_TABLE[$i] = self::$QR_MATH_EXP_TABLE[$i - 4] + ^ self::$QR_MATH_EXP_TABLE[$i - 5] + ^ self::$QR_MATH_EXP_TABLE[$i - 6] + ^ self::$QR_MATH_EXP_TABLE[$i - 8]; + } + + self::$QR_MATH_LOG_TABLE = QRMath::createNumArray(256); + + for ($i = 0; $i < 255; $i++) { + self::$QR_MATH_LOG_TABLE[self::$QR_MATH_EXP_TABLE[$i] ] = $i; + } + } + + static function createNumArray($length) { + $num_array = array(); + for ($i = 0; $i < $length; $i++) { + $num_array[] = 0; + } + return $num_array; + } + + static function glog($n) { + + if ($n < 1) { + trigger_error("log($n)", E_USER_ERROR); + } + + return self::$QR_MATH_LOG_TABLE[$n]; + } + + static function gexp($n) { + + while ($n < 0) { + $n += 255; + } + + while ($n >= 256) { + $n -= 255; + } + + return self::$QR_MATH_EXP_TABLE[$n]; + } +} + +// init static table +QRMath::init(); + +//--------------------------------------------------------------- +// QRPolynomial +//--------------------------------------------------------------- + +class QRPolynomial { + + var $num; + + function QRPolynomial($num, $shift = 0) { + + $offset = 0; + + while ($offset < count($num) && $num[$offset] == 0) { + $offset++; + } + + $this->num = QRMath::createNumArray(count($num) - $offset + $shift); + for ($i = 0; $i < count($num) - $offset; $i++) { + $this->num[$i] = $num[$i + $offset]; + } + } + + function get($index) { + return $this->num[$index]; + } + + function getLength() { + return count($this->num); + } + + // PHP5 + function __toString() { + return $this->toString(); + } + + function toString() { + + $buffer = ""; + + for ($i = 0; $i < $this->getLength(); $i++) { + if ($i > 0) { + $buffer .= ","; + } + $buffer .= $this->get($i); + } + + return $buffer; + } + + function toLogString() { + + $buffer = ""; + + for ($i = 0; $i < $this->getLength(); $i++) { + if ($i > 0) { + $buffer .= ","; + } + $buffer .= QRMath::glog($this->get(i) ); + } + + return $buffer; + } + + function multiply($e) { + + $num = QRMath::createNumArray($this->getLength() + $e->getLength() - 1); + + for ($i = 0; $i < $this->getLength(); $i++) { + for ($j = 0; $j < $e->getLength(); $j++) { + $num[$i + $j] ^= QRMath::gexp(QRMath::glog($this->get($i) ) + QRMath::glog($e->get($j) ) ); + } + } + + return new QRPolynomial($num); + } + + function mod($e) { + + if ($this->getLength() - $e->getLength() < 0) { + return $this; + } + + $ratio = QRMath::glog($this->get(0) ) - QRMath::glog($e->get(0) ); + + $num = QRMath::createNumArray($this->getLength() ); + for ($i = 0; $i < $this->getLength(); $i++) { + $num[$i] = $this->get($i); + } + + for ($i = 0; $i < $e->getLength(); $i++) { + $num[$i] ^= QRMath::gexp(QRMath::glog($e->get($i) ) + $ratio); + } + + $newPolynomial = new QRPolynomial($num); + return $newPolynomial->mod($e); + } +} + +//--------------------------------------------------------------- +// Mode +//--------------------------------------------------------------- + +define("QR_MODE_NUMBER", 1 << 0); +define("QR_MODE_ALPHA_NUM", 1 << 1); +define("QR_MODE_8BIT_BYTE", 1 << 2); +define("QR_MODE_KANJI", 1 << 3); + +//--------------------------------------------------------------- +// MaskPattern +//--------------------------------------------------------------- + +define("QR_MASK_PATTERN000", 0); +define("QR_MASK_PATTERN001", 1); +define("QR_MASK_PATTERN010", 2); +define("QR_MASK_PATTERN011", 3); +define("QR_MASK_PATTERN100", 4); +define("QR_MASK_PATTERN101", 5); +define("QR_MASK_PATTERN110", 6); +define("QR_MASK_PATTERN111", 7); + +//--------------------------------------------------------------- +// ErrorCorrectLevel + +// 7%. +define("QR_ERROR_CORRECT_LEVEL_L", 1); +// 15%. +define("QR_ERROR_CORRECT_LEVEL_M", 0); +// 25%. +define("QR_ERROR_CORRECT_LEVEL_Q", 3); +// 30%. +define("QR_ERROR_CORRECT_LEVEL_H", 2); + + +//--------------------------------------------------------------- +// QRBitBuffer +//--------------------------------------------------------------- + +class QRBitBuffer { + + var $buffer; + var $length; + + function QRBitBuffer() { + $this->buffer = array(); + $this->length = 0; + } + + function getBuffer() { + return $this->buffer; + } + + function getLengthInBits() { + return $this->length; + } + + function __toString() { + $buffer = ""; + for ($i = 0; $i < $this->getLengthInBits(); $i++) { + $buffer .= $this->get($i)? '1' : '0'; + } + return $buffer; + } + + function get($index) { + $bufIndex = floor($index / 8); + return ( ($this->buffer[$bufIndex] >> (7 - $index % 8) ) & 1) == 1; + } + + function put($num, $length) { + + for ($i = 0; $i < $length; $i++) { + $this->putBit( ( ($num >> ($length - $i - 1) ) & 1) == 1); + } + } + + function putBit($bit) { + + $bufIndex = floor($this->length / 8); + if (count($this->buffer) <= $bufIndex) { + $this->buffer[] = 0; + } + + if ($bit) { + $this->buffer[$bufIndex] |= (0x80 >> ($this->length % 8) ); + } + + $this->length++; + } +} + +?> diff --git a/settings.php b/settings.php index 01172d50..cf53aa60 100644 --- a/settings.php +++ b/settings.php @@ -696,6 +696,7 @@ From e6d0dd48392f74b48f57bb479c61e7f6f2c78a78 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 27 Feb 2017 23:12:39 +0100 Subject: [PATCH 19/19] Add version/type parameters to API (will be used in the future to decide what backend is powering the frontend) (#414) --- api.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/api.php b/api.php index 5ee3f290..8f748967 100644 --- a/api.php +++ b/api.php @@ -19,6 +19,14 @@ // Non-Auth + if (isset($_GET['type'])) { + $data["type"] = "PHP"; + } + + if (isset($_GET['version'])) { + $data["version"] = 2; + } + if (isset($_GET['summaryRaw'])) { $data = array_merge($data, getSummaryData()); }