From 4cf7a827137be494678913afc78f6932fabe3c56 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Tue, 31 Jan 2023 20:10:53 +0100 Subject: [PATCH 001/583] First steps into the v6.0 world. Login and logout is now possible and all pages load without PHP errors (even when they are mostly empty until we added all the new API methods) Signed-off-by: DL6ER --- README.md | 6 - api.php | 197 -- api_FTL.php | 437 ----- api_db.php | 423 ---- auditlog.php | 86 - login.php | 17 +- logout.php | 15 - scripts/pi-hole/js/auditlog.js | 153 -- scripts/pi-hole/js/utils.js | 10 + scripts/pi-hole/php/FTL.php | 105 - scripts/pi-hole/php/api_token.php | 50 - scripts/pi-hole/php/auth.php | 9 +- scripts/pi-hole/php/customcname.php | 28 - scripts/pi-hole/php/customdns.php | 28 - scripts/pi-hole/php/database.php | 286 --- scripts/pi-hole/php/debug.php | 71 - scripts/pi-hole/php/footer.php | 5 - scripts/pi-hole/php/func.php | 96 +- scripts/pi-hole/php/gravity.php | 3 + scripts/pi-hole/php/gravity.sh.php | 40 - scripts/pi-hole/php/groups.php | 1169 ----------- scripts/pi-hole/php/header_authenticated.php | 126 +- scripts/pi-hole/php/message.php | 58 - scripts/pi-hole/php/network.php | 65 - scripts/pi-hole/php/password.php | 108 - scripts/pi-hole/php/persistentlogin_token.php | 88 - scripts/pi-hole/php/queryads.php | 67 - scripts/pi-hole/php/savesettings.php | 605 ------ scripts/pi-hole/php/sidebar.php | 16 +- scripts/pi-hole/php/tailLog.php | 68 - scripts/pi-hole/php/teleporter.php | 620 ------ scripts/pi-hole/php/update_checker.php | 136 -- scripts/vendor/qrcode.php | 1737 ----------------- settings.php | 26 +- 34 files changed, 66 insertions(+), 6888 deletions(-) delete mode 100644 api.php delete mode 100644 api_FTL.php delete mode 100644 api_db.php delete mode 100644 auditlog.php delete mode 100644 logout.php delete mode 100644 scripts/pi-hole/js/auditlog.js delete mode 100644 scripts/pi-hole/php/FTL.php delete mode 100644 scripts/pi-hole/php/api_token.php delete mode 100644 scripts/pi-hole/php/customcname.php delete mode 100644 scripts/pi-hole/php/customdns.php delete mode 100644 scripts/pi-hole/php/database.php delete mode 100644 scripts/pi-hole/php/debug.php delete mode 100644 scripts/pi-hole/php/gravity.sh.php delete mode 100644 scripts/pi-hole/php/groups.php delete mode 100644 scripts/pi-hole/php/message.php delete mode 100644 scripts/pi-hole/php/network.php delete mode 100644 scripts/pi-hole/php/password.php delete mode 100644 scripts/pi-hole/php/persistentlogin_token.php delete mode 100644 scripts/pi-hole/php/queryads.php delete mode 100644 scripts/pi-hole/php/savesettings.php delete mode 100644 scripts/pi-hole/php/tailLog.php delete mode 100644 scripts/pi-hole/php/teleporter.php delete mode 100644 scripts/pi-hole/php/update_checker.php delete mode 100644 scripts/vendor/qrcode.php diff --git a/README.md b/README.md index ad323bab6..bcadadbae 100644 --- a/README.md +++ b/README.md @@ -133,12 +133,6 @@ While we are primarily reachable on our

-## An audit log - -

- Pi-hole Web interface -

- ## Long-term statistics to view data over user defined time ranges

diff --git a/api.php b/api.php deleted file mode 100644 index 4caecfecd..000000000 --- a/api.php +++ /dev/null @@ -1,197 +0,0 @@ - 'enabled')); - if (file_exists('../custom_disable_timer')) { - unlink('../custom_disable_timer'); - } -} elseif (isset($_GET['disable']) && $auth) { - if (isset($_GET['auth'])) { - if ($_GET['auth'] !== $pwhash) { - exit('Not authorized!'); - } - } 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) { - $timestamp = time(); - pihole_execute('disable '.$disable.'s'); - file_put_contents('../custom_disable_timer', ($timestamp + $disable) * 1000); - } else { - pihole_execute('disable'); - if (file_exists('../custom_disable_timer')) { - unlink('../custom_disable_timer'); - } - } - $data = array_merge($data, array('status' => 'disabled')); -} elseif (isset($_GET['versions'])) { - // Determine if updates are available for Pi-hole - // using the same script that we use for the footer - // on the dashboard (update notifications are - // suppressed if on development branches) - require 'scripts/pi-hole/php/update_checker.php'; - $updates = array('core_update' => $core_update, - 'web_update' => $web_update, - 'FTL_update' => $FTL_update, ); - $current = array('core_current' => $core_current, - 'web_current' => $web_current, - 'FTL_current' => $FTL_current, ); - $latest = array('core_latest' => $core_latest, - 'web_latest' => $web_latest, - 'FTL_latest' => $FTL_latest, ); - $branches = array('core_branch' => $core_branch, - 'web_branch' => $web_branch, - 'FTL_branch' => $FTL_branch, ); - $data = array_merge($data, $updates); - $data = array_merge($data, $current); - $data = array_merge($data, $latest); - $data = array_merge($data, $branches); -} elseif (isset($_GET['list'])) { - if (!$auth) { - exit('Not authorized!'); - } - - if (!isset($_GET['list'])) { - exit('List has not been specified.'); - } - - switch ($_GET['list']) { - case 'black': - $_POST['type'] = LISTTYPE_BLACKLIST; - - break; - - case 'regex_black': - $_POST['type'] = LISTTYPE_REGEX_BLACKLIST; - - break; - - case 'white': - $_POST['type'] = LISTTYPE_WHITELIST; - - break; - - case 'regex_white': - $_POST['type'] = LISTTYPE_REGEX_WHITELIST; - - break; - - default: - exit('Invalid list [supported: black, regex_black, white, regex_white]'); - } - - if (isset($_GET['add'])) { - // Set POST parameters and invoke script to add domain to list - $_POST['domain'] = $_GET['add']; - $_POST['action'] = 'add_domain'; - require 'scripts/pi-hole/php/groups.php'; - } elseif (isset($_GET['sub'])) { - // Set POST parameters and invoke script to remove domain from list - $_POST['domain'] = $_GET['sub']; - $_POST['action'] = 'delete_domain_string'; - require 'scripts/pi-hole/php/groups.php'; - } else { - // Set POST parameters and invoke script to get all domains - $_POST['action'] = 'get_domains'; - require 'scripts/pi-hole/php/groups.php'; - } - - return; -} elseif (isset($_GET['customdns']) && $auth) { - if (isset($_GET['auth'])) { - if ($_GET['auth'] !== $pwhash) { - exit('Not authorized!'); - } - } else { - // Skip token validation if explicit auth string is given - check_csrf($_GET['token']); - } - - switch ($_GET['action']) { - case 'get': - $data = echoCustomDNSEntries(); - - break; - - case 'add': - $data = addCustomDNSEntry(); - - break; - - case 'delete': - $data = deleteCustomDNSEntry(); - - break; - - default: - exit('Wrong action'); - } -} elseif (isset($_GET['customcname']) && $auth) { - if (isset($_GET['auth'])) { - if ($_GET['auth'] !== $pwhash) { - exit('Not authorized!'); - } - } else { - // Skip token validation if explicit auth string is given - check_csrf($_GET['token']); - } - - switch ($_GET['action']) { - case 'get': - $data = echoCustomCNAMEEntries(); - - break; - - case 'add': - $data = addCustomCNAMEEntry(); - - break; - - case 'delete': - $data = deleteCustomCNAMEEntry(); - - break; - - default: - exit('Wrong action'); - } -} - -// Other API functions -require 'api_FTL.php'; - -header('Content-type: application/json'); -if (isset($_GET['jsonForceObject'])) { - echo json_encode($data, JSON_FORCE_OBJECT); -} else { - echo json_encode($data); -} diff --git a/api_FTL.php b/api_FTL.php deleted file mode 100644 index 7e7fb1fa2..000000000 --- a/api_FTL.php +++ /dev/null @@ -1,437 +0,0 @@ - true); - } else { - if (in_array('status enabled', $return)) { - $data = array_merge($data, array('status' => 'enabled')); - } else { - $data = array_merge($data, array('status' => 'disabled')); - } - } -} - -if ((isset($_GET['summary']) || isset($_GET['summaryRaw']) || !count($_GET)) && $auth) { - require_once 'scripts/pi-hole/php/gravity.php'; - - $return = callFTLAPI('stats'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $stats = array(); - foreach ($return as $line) { - $tmp = explode(' ', $line); - - 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]); - } - } - $stats['gravity_last_updated'] = gravity_last_update(true); - $data = array_merge($data, $stats); - } -} - -if (isset($_GET['getMaxlogage']) && $auth) { - $return = callFTLAPI('maxlogage'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - // 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; - - $data = array_merge($data, array('maxlogage' => $ret)); - } -} - -if (isset($_GET['overTimeData10mins']) && $auth) { - $return = callFTLAPI('overTime'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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['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 (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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 ($_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'); - } - - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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_queries' => $top_queries, - 'top_ads' => $top_ads, - ); - - $data = array_merge($data, $result); - } -} - -if ((isset($_GET['topClients']) || isset($_GET['getQuerySources'])) && $auth) { - if (isset($_GET['topClients'])) { - $number = $_GET['topClients']; - } elseif (isset($_GET['getQuerySources'])) { - $number = $_GET['getQuerySources']; - } - - if (is_numeric($number)) { - $return = callFTLAPI('top-clients ('.$number.')'); - } else { - $return = callFTLAPI('top-clients'); - } - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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('top_sources' => $top_clients); - $data = array_merge($data, $result); - } -} - -if (isset($_GET['topClientsBlocked']) && $auth) { - if (isset($_GET['topClientsBlocked'])) { - $number = $_GET['topClientsBlocked']; - } - - if (is_numeric($number)) { - $return = callFTLAPI('top-clients blocked ('.$number.')'); - } else { - $return = callFTLAPI('top-clients blocked'); - } - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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('top_sources_blocked' => $top_clients); - $data = array_merge($data, $result); - } -} - -if (isset($_GET['getForwardDestinations']) && $auth) { - if ($_GET['getForwardDestinations'] === 'unsorted') { - $return = callFTLAPI('forward-dest unsorted'); - } else { - $return = callFTLAPI('forward-dest'); - } - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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('forward_destinations' => $forward_dest); - $data = array_merge($data, $result); - } -} - -if (isset($_GET['getQueryTypes']) && $auth) { - $return = callFTLAPI('querytypes'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $querytypes = array(); - foreach ($return as $ret) { - $tmp = explode(': ', $ret); - // Reply cannot contain non-ASCII characters - $querytypes[$tmp[0]] = floatval($tmp[1]); - } - - $result = array('querytypes' => $querytypes); - $data = array_merge($data, $result); - } -} - -if (isset($_GET['getCacheInfo']) && $auth) { - $return = callFTLAPI('cacheinfo'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $cacheinfo = array(); - foreach ($return as $ret) { - $tmp = explode(': ', $ret); - // Reply cannot contain non-ASCII characters - $cacheinfo[$tmp[0]] = floatval($tmp[1]); - } - - $result = array('cacheinfo' => $cacheinfo); - $data = array_merge($data, $result); - } -} - -if (isset($_GET['getAllQueries']) && $auth) { - if (isset($_GET['from'], $_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 (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - // Set the header - header('Content-type: application/json'); - - // Start the JSON string - echo '{"data":['; - $first = true; - - foreach ($return as $line) { - // Insert a comma before the next record (except on the first one) - if (!$first) { - echo ','; - } else { - $first = false; - } - - $row = str_getcsv($line, ' '); - // UTF-8 encode domain - $domain = utf8_encode(str_replace('~', ' ', $row[2])); - // UTF-8 encode client host name - $client = utf8_encode($row[3]); - - // Insert into array and output it in JSON format - // array: time type domain client status dnssecStatus reply response_time CNAMEDomain regexID upstream destination EDE - echo json_encode(array($row[0], $row[1], $domain, $client, $row[4], $row[5], $row[6], $row[7], $row[8], $row[9], $row[10], $row[11])); - } - // Finish the JSON string - echo ']}'; - // exit at the end - exit; - } -} - -if (isset($_GET['recentBlocked']) && $auth) { - exit(utf8_encode(callFTLAPI('recentBlocked')[0])); - unset($data); -} - -if (isset($_GET['getForwardDestinationNames']) && $auth) { - $return = callFTLAPI('forward-names'); - - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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'); - - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $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']); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $data['delete_lease'] = $return[0]; - } -} - -if (isset($_GET['dns-port']) && $auth) { - $return = callFTLAPI('dns-port'); - if (array_key_exists('FTLnotrunning', $return)) { - $data = array('FTLnotrunning' => true); - } else { - $data['dns-port'] = $return[0]; - } -} diff --git a/api_db.php b/api_db.php deleted file mode 100644 index f060d47bb..000000000 --- a/api_db.php +++ /dev/null @@ -1,423 +0,0 @@ -query('SELECT * FROM network'); - - while ($results !== false && $res = $results->fetchArray(SQLITE3_ASSOC)) { - $id = intval($res['id']); - - // Get IP addresses and host names for this device - $res['ip'] = array(); - $res['name'] = array(); - $network_addresses = $db->query("SELECT ip,name FROM network_addresses WHERE network_id = {$id} ORDER BY lastSeen DESC"); - while ($network_addresses !== false && $network_address = $network_addresses->fetchArray(SQLITE3_ASSOC)) { - array_push($res['ip'], $network_address['ip']); - if ($network_address['name'] !== null) { - array_push($res['name'], utf8_encode($network_address['name'])); - } else { - array_push($res['name'], ''); - } - } - $network_addresses->finalize(); - - // UTF-8 encode vendor - $res['macVendor'] = utf8_encode($res['macVendor']); - array_push($network, $res); - } - $results->finalize(); - - $data = array_merge($data, array('network' => $network)); -} - -if (isset($_GET['getAllQueries']) && $auth) { - $allQueries = array(); - if ($_GET['getAllQueries'] !== 'empty') { - $from = intval($_GET['from']); - $until = intval($_GET['until']); - - // Use table "query_storage" - // - replace domain ID with domain - // - replace client ID with client name - // - replace forward ID with forward destination - $dbquery = 'SELECT timestamp, type,'; - $dbquery .= " CASE typeof(domain) WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain,"; - $dbquery .= " CASE typeof(client) WHEN 'integer' THEN ("; - $dbquery .= " SELECT CASE TRIM(name) WHEN '' THEN c.ip ELSE c.name END name FROM client_by_id c WHERE c.id = q.client"; - $dbquery .= ' ) ELSE client END client,'; - $dbquery .= " CASE typeof(forward) WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward,"; - $dbquery .= ' status, reply_type, reply_time, dnssec'; - $dbquery .= ' FROM query_storage q'; - $dbquery .= ' WHERE timestamp >= :from AND timestamp <= :until '; - if (isset($_GET['status'])) { - // if some query status should be excluded - $excludedStatus = $_GET['status']; - if (preg_match('/^[0-9]+(?:,[0-9]+)*$/', $excludedStatus) === 1) { - // Append selector to DB query. The used regex ensures - // that only numbers, separated by commas are accepted - // to avoid code injection and other malicious things - // We accept only valid lists like "1,2,3" - // We reject ",2,3", "1,2," and similar arguments - $dbquery .= 'AND status NOT IN ('.$excludedStatus.') '; - } else { - exit('Error. Selector status specified using an invalid format.'); - } - } - $dbquery .= 'ORDER BY timestamp ASC'; - $stmt = $db->prepare($dbquery); - $stmt->bindValue(':from', intval($from), SQLITE3_INTEGER); - $stmt->bindValue(':until', intval($until), SQLITE3_INTEGER); - $results = $stmt->execute(); - - // Start the JSON string - echo '{"data":['; - - if (!is_bool($results)) { - $first = true; - while ($row = $results->fetchArray(SQLITE3_ASSOC)) { - // Insert a comma before the next record (except on the first one) - if (!$first) { - echo ','; - } else { - $first = false; - } - - // Format, encode, transform each field (if necessary). - $time = $row['timestamp']; - $query_type = getQueryTypeStr($row['type']); // Convert query type ID to name - $domain = utf8_encode(str_replace('~', ' ', $row['domain'])); - $client = $row['client']; - $status = $row['status']; - $destination = utf8_encode($row['forward']); - $reply_type = $row['reply_type']; - $reply_time = $row['reply_time']; - $dnssec = $row['dnssec']; - - // Insert into array and output it in JSON format - echo json_encode(array($time, $query_type, $domain, $client, $status, $destination, $reply_type, $reply_time, $dnssec)); - } - } - - // Finish the JSON string - echo ']}'; - - // exit at the end - exit; - } - // only used if getAllQueries==empty - $result = array('data' => $allQueries); - $data = array_merge($data, $result); -} - -if (isset($_GET['topClients']) && $auth) { - // $from = intval($_GET["from"]); - $limit = ''; - if (isset($_GET['from'], $_GET['until'])) { - $limit = 'WHERE timestamp >= :from AND timestamp <= :until'; - } elseif (isset($_GET['from']) && !isset($_GET['until'])) { - $limit = 'WHERE timestamp >= :from'; - } elseif (!isset($_GET['from']) && isset($_GET['until'])) { - $limit = 'WHERE timestamp <= :until'; - } - $dbquery = "SELECT CASE typeof(client) WHEN 'integer' THEN ("; - $dbquery .= " SELECT CASE TRIM(name) WHEN '' THEN c.ip ELSE c.name END name FROM client_by_id c WHERE c.id = q.client)"; - $dbquery .= ' ELSE client END client, count(client) FROM query_storage q '.$limit.' GROUP BY client ORDER BY count(client) DESC LIMIT 20'; - - $stmt = $db->prepare($dbquery); - $stmt->bindValue(':from', intval($_GET['from']), SQLITE3_INTEGER); - $stmt->bindValue(':until', intval($_GET['until']), SQLITE3_INTEGER); - $results = $stmt->execute(); - - $clientnums = array(); - - if (!is_bool($results)) { - while ($row = $results->fetchArray()) { - // $row[0] is the client IP - - if (array_key_exists($row[0], $clientnums)) { - // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database) - $clientnums[$row[0]] += intval($row[1]); - } else { - // Entry does not yet exist - $clientnums[$row[0]] = intval($row[1]); - } - } - } - - // Sort by number of hits - arsort($clientnums); - - // Extract only the first ten entries - $clientnums = array_slice($clientnums, 0, 10); - - $result = array('top_sources' => $clientnums); - $data = array_merge($data, $result); -} - -if (isset($_GET['topDomains']) && $auth) { - $limit = ''; - - if (isset($_GET['from'], $_GET['until'])) { - $limit = ' AND timestamp >= :from AND timestamp <= :until'; - } elseif (isset($_GET['from']) && !isset($_GET['until'])) { - $limit = ' AND timestamp >= :from'; - } elseif (!isset($_GET['from']) && isset($_GET['until'])) { - $limit = ' AND timestamp <= :until'; - } - // Select top permitted domains only - $stmt = $db->prepare('SELECT domain,count(domain) FROM queries WHERE status IN (2,3,12,13,14,17)'.$limit.' GROUP by domain order by count(domain) desc limit 20'); - $stmt->bindValue(':from', intval($_GET['from']), SQLITE3_INTEGER); - $stmt->bindValue(':until', intval($_GET['until']), SQLITE3_INTEGER); - $results = $stmt->execute(); - - $domains = array(); - - if (!is_bool($results)) { - while ($row = $results->fetchArray()) { - // Convert domain to lower case UTF-8 - $c = utf8_encode(strtolower($row[0])); - if (array_key_exists($c, $domains)) { - // Entry already exists, add to it (might appear multiple times due to mixed capitalization in the database) - $domains[$c] += intval($row[1]); - } else { - // Entry does not yet exist - $domains[$c] = intval($row[1]); - } - } - } - - // Sort by number of hits - arsort($domains); - - // Extract only the first ten entries - $domains = array_slice($domains, 0, 10); - - $result = array('top_domains' => $domains); - $data = array_merge($data, $result); -} - -if (isset($_GET['topAds']) && $auth) { - $limit = ''; - - if (isset($_GET['from'], $_GET['until'])) { - $limit = ' AND timestamp >= :from AND timestamp <= :until'; - } elseif (isset($_GET['from']) && !isset($_GET['until'])) { - $limit = ' AND timestamp >= :from'; - } elseif (!isset($_GET['from']) && isset($_GET['until'])) { - $limit = ' AND timestamp <= :until'; - } - $stmt = $db->prepare('SELECT domain,count(domain) FROM queries WHERE status IN (1,4,5,6,7,8,9,10,11)'.$limit.' GROUP by domain order by count(domain) desc limit 10'); - $stmt->bindValue(':from', intval($_GET['from']), SQLITE3_INTEGER); - $stmt->bindValue(':until', intval($_GET['until']), SQLITE3_INTEGER); - $results = $stmt->execute(); - - $addomains = array(); - - if (!is_bool($results)) { - while ($row = $results->fetchArray()) { - $addomains[utf8_encode($row[0])] = intval($row[1]); - } - } - $result = array('top_ads' => $addomains); - $data = array_merge($data, $result); -} - -if (isset($_GET['getMinTimestamp']) && $auth) { - $results = $db->query('SELECT MIN(timestamp) FROM queries'); - - if (!is_bool($results)) { - $result = array('mintimestamp' => $results->fetchArray()[0]); - } else { - $result = array(); - } - - $data = array_merge($data, $result); -} - -if (isset($_GET['getMaxTimestamp']) && $auth) { - $results = $db->query('SELECT MAX(timestamp) FROM queries'); - - if (!is_bool($results)) { - $result = array('maxtimestamp' => $results->fetchArray()[0]); - } else { - $result = array(); - } - - $data = array_merge($data, $result); -} - -if (isset($_GET['getQueriesCount']) && $auth) { - $results = $db->query('SELECT COUNT(timestamp) FROM queries'); - - if (!is_bool($results)) { - $result = array('count' => $results->fetchArray()[0]); - } else { - $result = array(); - } - - $data = array_merge($data, $result); -} - -if (isset($_GET['getDBfilesize']) && $auth) { - $filesize = filesize('/etc/pihole/pihole-FTL.db'); - $result = array('filesize' => $filesize); - $data = array_merge($data, $result); -} - -if (isset($_GET['getGraphData']) && $auth) { - $limit = ''; - - if (isset($_GET['from'], $_GET['until'])) { - $limit = 'timestamp >= :from AND timestamp <= :until'; - } elseif (isset($_GET['from']) && !isset($_GET['until'])) { - $limit = 'timestamp >= :from'; - } elseif (!isset($_GET['from']) && isset($_GET['until'])) { - $limit = 'timestamp <= :until'; - } - - $interval = 600; - - if (isset($_GET['interval'])) { - $q = intval($_GET['interval']); - if ($q >= 10) { - $interval = $q; - } - } - - // Round $from and $until to match the requested $interval - $from = intval((intval($_GET['from']) / $interval) * $interval); - $until = intval((intval($_GET['until']) / $interval) * $interval); - - // Count domains and blocked queries using the same intervals - $sqlcommand = " - SELECT - (timestamp / :interval) * :interval AS interval, - SUM(CASE - WHEN status !=0 THEN 1 - ELSE 0 - END) AS domains, - SUM(CASE - WHEN status IN (1,4,5,6,7,8,9,10,11,15,16) THEN 1 - ELSE 0 - END) AS blocked - FROM queries - WHERE $limit - GROUP BY interval - ORDER BY interval"; - - $stmt = $db->prepare($sqlcommand); - $stmt->bindValue(':from', $from, SQLITE3_INTEGER); - $stmt->bindValue(':until', $until, SQLITE3_INTEGER); - $stmt->bindValue(':interval', $interval, SQLITE3_INTEGER); - $results = $stmt->execute(); - - // Parse the DB result into graph data, filling in missing interval sections with zero - function parseDBData($results, $interval, $from, $until) - { - $domains = array(); - $blocked = array(); - $first_db_timestamp = -1; - - if (!is_bool($results)) { - // Read in the data - while ($row = $results->fetchArray()) { - $domains[$row['interval']] = intval($row['domains']); - $blocked[$row['interval']] = intval($row['blocked']); - if ($first_db_timestamp === -1) { - $first_db_timestamp = intval($row[0]); - } - } - } - - // It is unpredictable what the first timestamp returned by the database will be. - // This depends on live data. The bar graph can handle "gaps", but the Area graph can't. - // Hence, we filling the "missing" timeslots with 0 to avoid wrong graphic render. - // (https://github.com/pi-hole/AdminLTE/pull/2374#issuecomment-1261865428) - $aligned_from = $from + (($first_db_timestamp - $from) % $interval); - - // Fill gaps in returned data - for ($i = $aligned_from; $i < $until; $i += $interval) { - if (!array_key_exists($i, $domains)) { - $domains[$i] = 0; - $blocked[$i] = 0; - } - } - - return array('domains_over_time' => $domains, 'ads_over_time' => $blocked); - } - - $over_time = parseDBData($results, $interval, $from, $until); - $data = array_merge($data, $over_time); -} - -if (isset($_GET['status']) && $auth) { - $extra = ';'; - if (isset($_GET['ignore']) && $_GET['ignore'] === 'DNSMASQ_WARN') { - $extra = "WHERE type != 'DNSMASQ_WARN';"; - } - $results = $db->query('SELECT COUNT(*) FROM message '.$extra); - - if (!is_bool($results)) { - $result = array('message_count' => $results->fetchArray()[0]); - } else { - $result = array(); - } - - $data = array_merge($data, $result); -} - -if (isset($_GET['messages']) && $auth) { - $extra = ';'; - if (isset($_GET['ignore']) && $_GET['ignore'] === 'DNSMASQ_WARN') { - $extra = "WHERE type != 'DNSMASQ_WARN';"; - } - - $messages = array(); - $results = $db->query('SELECT * FROM message '.$extra); - - while ($results !== false && $res = $results->fetchArray(SQLITE3_ASSOC)) { - // Convert string to to UTF-8 encoding to ensure php-json can handle it. - // Furthermore, convert special characters to HTML entities to prevent XSS attacks. - foreach ($res as $key => $value) { - if (is_string($value)) { - $res[$key] = htmlspecialchars(utf8_encode($value)); - } - } - array_push($messages, $res); - } - - $data = array_merge($data, array('messages' => $messages)); -} - -if (isset($_GET['jsonForceObject'])) { - echo json_encode($data, JSON_FORCE_OBJECT); -} else { - echo json_encode($data); -} diff --git a/auditlog.php b/auditlog.php deleted file mode 100644 index 3c311ac60..000000000 --- a/auditlog.php +++ /dev/null @@ -1,86 +0,0 @@ - - - -

- -
-
-
-
-

Allowed queries

-
- -
-
- - - - - - - - - - -
DomainHitsActions
-
-
-
- -
- -
- -
- - -
-
-
-

Blocked queries

-
- -
-
- - - - - - - - - - -
DomainHitsActions
-
-
-
- -
- -
- -
- -
- - - - - diff --git a/login.php b/login.php index 34b11da37..126dd779f 100644 --- a/login.php +++ b/login.php @@ -8,16 +8,11 @@ * Please see LICENSE file for your rights under this license. */ -require 'scripts/pi-hole/php/password.php'; - -// Go directly to index, if authenticated. -if ($_SESSION['auth']) { - header('Location: index.php'); - exit; -} - +$wrongpassword = false; +require_once 'func.php'; require 'scripts/pi-hole/php/theme.php'; require 'scripts/pi-hole/php/header.php'; + ?> -
+ @@ -95,6 +90,8 @@ Donate if you found this useful. + + diff --git a/logout.php b/logout.php deleted file mode 100644 index cfeaf168d..000000000 --- a/logout.php +++ /dev/null @@ -1,15 +0,0 @@ -' + domain + ""; - domaintable.append( - "" + - url + - " " + - data.top_queries[domain] + - " " + - '' + - '' + - " " - ); - } - } - - for (domain in data.top_ads) { - if (Object.prototype.hasOwnProperty.call(data.top_ads, domain)) { - var input = domain.split(" "); - // Sanitize domain - var printdomain = utils.escapeHtml(input[0]); - if (input.length > 1) { - url = - '' + - printdomain + - " (wildcard blocked)"; - adtable.append( - "" + - url + - " " + - data.top_ads[domain] + - " " + - '' + - " " - ); - } else { - url = '' + printdomain + ""; - adtable.append( - "" + - url + - " " + - data.top_ads[domain] + - " " + - '' + - '' + - " " - ); - } - } - } - - $("#domain-frequency .overlay").hide(); - $("#ad-frequency .overlay").hide(); - // Update top lists data every ten seconds - // Updates are also triggered by button actions - // and reset the running timer - if (auditTimeout !== null) { - window.clearTimeout(auditTimeout); - } - - auditTimeout = setTimeout(updateTopLists, 10000); - }); -} - -function add(domain, list) { - var token = $("#token").text(); - $.ajax({ - url: "scripts/pi-hole/php/groups.php", - method: "post", - data: { - domain: domain, - list: list, - token: token, - action: list === "audit" ? "add_audit" : "add_domain", - comment: "Added from Audit Log", - }, - success: function () { - updateTopLists(); - }, - error: function (jqXHR, exception) { - console.log(exception); // eslint-disable-line no-console - }, - }); -} - -function blacklistUrl(url) { - // We add to audit last as it will reload the table on success - add(url, "black"); - add(url, "audit"); -} - -function whitelistUrl(url) { - // We add to audit last as it will reload the table on success - add(url, "white"); - add(url, "audit"); -} - -function auditUrl(url) { - add(url, "audit"); -} - -$(function () { - // Pull in data via AJAX - updateTopLists(); - - $("#domain-frequency tbody").on("click", "button", function (event) { - var url = $(this).parents("tr")[0].textContent.split(" ")[0]; - - if (event.target.textContent.trim() === "Blacklist") { - blacklistUrl(url); - } else { - auditUrl(url); - } - }); - - $("#ad-frequency tbody").on("click", "button", function (event) { - var url = $(this).parents("tr")[0].textContent.split(" ")[0]; - - if (event.target.textContent.trim() === "Whitelist") { - whitelistUrl(url); - } else { - auditUrl(url); - } - }); -}); diff --git a/scripts/pi-hole/js/utils.js b/scripts/pi-hole/js/utils.js index f81bb5a4b..0be6ad024 100644 --- a/scripts/pi-hole/js/utils.js +++ b/scripts/pi-hole/js/utils.js @@ -408,6 +408,15 @@ function changeBulkDeleteStates(table) { } } +function doLogout() { + $.ajax({ + url: "/api/auth", + method: "DELETE" + }).always(function (data) { + if (data.status === 410) location.reload(); + }); +} + window.utils = (function () { return { escapeHtml: escapeHtml, @@ -432,5 +441,6 @@ window.utils = (function () { colorBar: colorBar, checkMessages: checkMessages, changeBulkDeleteStates: changeBulkDeleteStates, + doLogout: doLogout, }; })(); diff --git a/scripts/pi-hole/php/FTL.php b/scripts/pi-hole/php/FTL.php deleted file mode 100644 index 5a60d76de..000000000 --- a/scripts/pi-hole/php/FTL.php +++ /dev/null @@ -1,105 +0,0 @@ -'.$requestin; - fwrite($socket, $request) or exit('{"error":"Could not send data to server"}'); -} - -function getResponseFTL($socket) -{ - $response = array(); - - $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 - exit('{"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; - } - - $out = rtrim($out); - if (strlen($out) > 0) { - $response[] = $out; - } - } - - return $response; -} - -function disconnectFTL($socket) -{ - if (is_resource($socket)) { - fclose($socket); - } -} - -function callFTLAPI($request) -{ - $socket = connectFTL(); - - if (!is_resource($socket)) { - $data = array('FTLnotrunning' => true); - } else { - sendRequestFTL($request, $socket); - $data = getResponseFTL($socket); - } - disconnectFTL($socket); - - return $data; -} diff --git a/scripts/pi-hole/php/api_token.php b/scripts/pi-hole/php/api_token.php deleted file mode 100644 index 39c43214b..000000000 --- a/scripts/pi-hole/php/api_token.php +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - - - 0) { - echo '
'; - require_once '../../vendor/qrcode.php'; - $qr = QRCode::getMinimumQRCode($pwhash, QR_ERROR_CORRECT_LEVEL_Q); - // The size of each block (in pixels) should be an integer - $qr->printSVG(10); - echo '
'; - echo 'Raw API Token: '.$pwhash.''; - } else { - echo '

No password set

'; - } -} else { - echo '

Not authorized!

'; -} -?> - - diff --git a/scripts/pi-hole/php/auth.php b/scripts/pi-hole/php/auth.php index 0db345003..113fe0722 100644 --- a/scripts/pi-hole/php/auth.php +++ b/scripts/pi-hole/php/auth.php @@ -55,7 +55,12 @@ function check_cors() // Allow user set CORS $cors_hosts = getenv('CORS_HOSTS'); if (!empty($cors_hosts)) { - array_push($AUTHORIZED_HOSTNAMES, ...explode(',', $cors_hosts)); + // Push all hosts from comma separated list + $cors_hosts_array = explode(',', $cors_hosts); + // Add all hosts to the list of authorized hosts + foreach ($cors_hosts_array as $host) { + array_push($AUTHORIZED_HOSTNAMES, $host); + } } // Since the Host header is easily manipulated, we can only check if it's wrong and can't use it @@ -93,7 +98,7 @@ function check_cors() if (!in_array($server_origin, $AUTHORIZED_HOSTNAMES)) { log_and_die('Failed CORS: '.htmlspecialchars($server_origin).' vs '.htmlspecialchars(join(', ', $AUTHORIZED_HOSTNAMES))); } - header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}"); + /* header("Access-Control-Allow-Origin: ${_SERVER['HTTP_ORIGIN']}"); */ } // If there's no HTTP_ORIGIN, CORS should not be used } diff --git a/scripts/pi-hole/php/customcname.php b/scripts/pi-hole/php/customcname.php deleted file mode 100644 index 7b89dfe77..000000000 --- a/scripts/pi-hole/php/customcname.php +++ /dev/null @@ -1,28 +0,0 @@ -getMessage(); - } -} - -function SQLite3_connect($filename, $mode = SQLITE3_OPEN_READONLY) -{ - if (strlen($filename) > 0) { - $db = SQLite3_connect_try($filename, $mode, true); - } else { - exit('No database available'); - } - if (is_string($db)) { - exit("Error connecting to database\n".$db); - } - - // Add busy timeout so methods don't fail immediately when, e.g., FTL is currently reading from the DB - $db->busyTimeout(5000); - - return $db; -} - -/** - * Add domains to a given table. - * - * @param $db object The SQLite3 database connection object - * @param $table string The target table - * @param $domains array Array of domains (strings) to be added to the table - * @param $wildcardstyle boolean Whether to format the input domains in legacy wildcard notation - * @param $returnnum boolean Whether to return an integer or a string - * @param $type integer The target type (0 = exact whitelist, 1 = exact blacklist, 2 = regex whitelist, 3 = regex blacklist) - * @param mixed|null $comment - * - * @return string Success/error and number of processed domains - */ -function add_to_table($db, $table, $domains, $comment = null, $wildcardstyle = false, $returnnum = false, $type = -1) -{ - if (!is_int($type)) { - return 'Error: Argument type has to be of type integer (is '.gettype($type).')'; - } - - // Begin transaction - if (!$db->exec('BEGIN TRANSACTION;')) { - if ($returnnum) { - return 0; - } - - return "Error: Unable to begin transaction for {$table} table."; - } - - // To which column should the record be added to? - if ($table === 'adlist') { - $field = 'address'; - } else { - $field = 'domain'; - } - - // Get initial count of domains in this table - if ($type === -1) { - $countquery = "SELECT COUNT(*) FROM {$table};"; - } else { - $countquery = "SELECT COUNT(*) FROM {$table} WHERE type = {$type};"; - } - $initialcount = intval($db->querySingle($countquery)); - - // Prepare INSERT SQLite statement - $bindcomment = false; - if ($table === 'domain_audit') { - $querystr = "INSERT OR IGNORE INTO {$table} ({$field}) VALUES (:{$field});"; - } elseif ($type === -1) { - $querystr = "INSERT OR IGNORE INTO {$table} ({$field},comment) VALUES (:{$field}, :comment);"; - $bindcomment = true; - } else { - $querystr = "REPLACE INTO {$table} ({$field},comment,type) VALUES (:{$field}, :comment, {$type});"; - $bindcomment = true; - } - $stmt = $db->prepare($querystr); - - // Return early if we failed to prepare the SQLite statement - if (!$stmt) { - if ($returnnum) { - return 0; - } - - return "Error: Failed to prepare statement for {$table} table (type = {$type}, field = {$field})."; - } - - // Loop over domains and inject the lines into the database - $num = 0; - foreach ($domains as $domain) { - // Limit max length for a domain entry to 253 chars - if (strlen($domain) > 253) { - continue; - } - - if ($wildcardstyle) { - $domain = '(\\.|^)'.str_replace('.', '\\.', $domain).'$'; - } - - $stmt->bindValue(":{$field}", htmlentities($domain), SQLITE3_TEXT); - if ($bindcomment) { - $stmt->bindValue(':comment', htmlentities($comment), SQLITE3_TEXT); - } - - if ($stmt->execute() && $stmt->reset()) { - ++$num; - } else { - $stmt->close(); - if ($returnnum) { - return $num; - } - if ($num === 1) { - $plural = ''; - } else { - $plural = 's'; - } - - return 'Error: '.$db->lastErrorMsg().', added '.$num.' domain'.$plural; - } - } - - // Close prepared statement and return number of processed rows - $stmt->close(); - $db->exec('COMMIT;'); - - if ($returnnum) { - return $num; - } - $finalcount = intval($db->querySingle($countquery)); - $modified = $finalcount - $initialcount; - - // If we add less domains than the user specified, then they wanted to add duplicates - if ($modified !== $num) { - $delta = $num - $modified; - $extra = ' (skipped '.$delta.' duplicates)'; - } else { - $extra = ''; - } - - if ($num === 1) { - $plural = ''; - } else { - $plural = 's'; - } - - return 'Success, added '.$modified.' of '.$num.' domain'.$plural.$extra; -} - -/** - * Remove domains from a given table. - * - * @param $db object The SQLite3 database connection object - * @param $table string The target table - * @param $domains array Array of domains (strings) to be removed from the table - * @param $returnnum boolean Whether to return an integer or a string - * @param $type integer The target type (0 = exact whitelist, 1 = exact blacklist, 2 = regex whitelist, 3 = regex blacklist) - * - * @return string Success/error and number of processed domains - */ -function remove_from_table($db, $table, $domains, $returnnum = false, $type = -1) -{ - if (!is_int($type)) { - return 'Error: Argument type has to be of type integer (is '.gettype($type).')'; - } - - // Begin transaction - if (!$db->exec('BEGIN TRANSACTION;')) { - if ($returnnum) { - return 0; - } - - return 'Error: Unable to begin transaction for domainlist table.'; - } - - // Get initial count of domains in this table - if ($type === -1) { - $countquery = "SELECT COUNT(*) FROM {$table};"; - } else { - $countquery = "SELECT COUNT(*) FROM {$table} WHERE type = {$type};"; - } - $initialcount = intval($db->querySingle($countquery)); - - // Prepare SQLite statement - if ($type === -1) { - $querystr = "DELETE FROM {$table} WHERE domain = :domain AND type = {$type};"; - } else { - $querystr = "DELETE FROM {$table} WHERE domain = :domain;"; - } - $stmt = $db->prepare($querystr); - - // Return early if we failed to prepare the SQLite statement - if (!$stmt) { - if ($returnnum) { - return 0; - } - - return 'Error: Failed to prepare statement for '.$table.' table (type = '.$type.').'; - } - - // Loop over domains and remove the lines from the database - $num = 0; - foreach ($domains as $domain) { - $stmt->bindValue(':domain', $domain, SQLITE3_TEXT); - - if ($stmt->execute() && $stmt->reset()) { - ++$num; - } else { - $stmt->close(); - if ($returnnum) { - return $num; - } - if ($num === 1) { - $plural = ''; - } else { - $plural = 's'; - } - - return 'Error: '.$db->lastErrorMsg().', removed '.$num.' domain'.$plural; - } - } - - // Close prepared statement and return number or processed rows - $stmt->close(); - $db->exec('COMMIT;'); - - if ($returnnum) { - return $num; - } - if ($num === 1) { - $plural = ''; - } else { - $plural = 's'; - } - - return 'Success, removed '.$num.' domain'.$plural; -} diff --git a/scripts/pi-hole/php/debug.php b/scripts/pi-hole/php/debug.php deleted file mode 100644 index a994feee1..000000000 --- a/scripts/pi-hole/php/debug.php +++ /dev/null @@ -1,71 +0,0 @@ - '', - chr(27).'[1;32m' => '', - chr(27).'[1;33m' => '', - chr(27).'[1;34m' => '', - chr(27).'[1;35m' => '', - chr(27).'[1;36m' => '', - - chr(27).'[90m' => '', - chr(27).'[91m' => '', - chr(27).'[32m' => '', - chr(27).'[33m' => '', - chr(27).'[94m' => '', - chr(27).'[95m' => '', - chr(27).'[96m' => '', - - chr(27).'[1m' => '', - chr(27).'[4m' => '', - - chr(27).'[0m' => '', - ); - - $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; - } -} - -// Execute "pihole" using Web option -$command = 'export TERM=dumb && sudo pihole -d -w'; - -// Add auto-upload option -if (isset($_GET['upload'])) { - $command .= ' -a'; -} - -// Execute database integrity_check -if (isset($_GET['dbcheck'])) { - $command .= ' -c'; -} - -$proc = popen($command, 'r'); - -while (!feof($proc)) { - echoEvent(fread($proc, 4096)); -} diff --git a/scripts/pi-hole/php/footer.php b/scripts/pi-hole/php/footer.php index e96cf20ae..c88a98357 100644 --- a/scripts/pi-hole/php/footer.php +++ b/scripts/pi-hole/php/footer.php @@ -44,11 +44,6 @@ // Flushes the system write buffers of PHP. This attempts to push everything we have so far all the way to the client's browser. flush(); -// Run update checker -// - determines local branch each time, -// - determines local and remote version every 30 minutes -require 'scripts/pi-hole/php/update_checker.php'; - if (isset($core_commit) || isset($web_commit) || isset($FTL_commit)) { $list_class = 'list-unstyled'; } else { diff --git a/scripts/pi-hole/php/func.php b/scripts/pi-hole/php/func.php index 6a7ed0f5a..3b7744e89 100644 --- a/scripts/pi-hole/php/func.php +++ b/scripts/pi-hole/php/func.php @@ -9,7 +9,8 @@ // Credit: http://stackoverflow.com/a/4694816/2087442 // Modified because of https://github.com/pi-hole/AdminLTE/pull/533 -ini_set('pcre.recursion_limit', 1500); +/* ini_set('pcre.recursion_limit', 1500); */ +/* function validDomain($domain_name, &$message = null) { // special handling of the root zone `.` @@ -101,7 +102,7 @@ function get_ip_type($ip) (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ? 6 : 0); } - +*/ function checkfile($filename) { if (is_readable($filename)) { @@ -207,10 +208,10 @@ function getCustomDNSEntries() continue; } - $data = new \stdClass(); - $data->ip = $explodedLine[0]; - $data->domain = $explodedLine[1]; - $data->domains = array_slice($explodedLine, 0, -1); + $data = array(); + $data["ip"] = $explodedLine[0]; + $data["domain"] = $explodedLine[1]; + $data["domains"] = array_slice($explodedLine, 0, -1); $entries[] = $data; } @@ -284,7 +285,7 @@ function addCustomDNSEntry($ip = '', $domain = '', $reload = '', $json = true) } return returnSuccess('', $json); - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage(), $json); } } @@ -323,7 +324,7 @@ function deleteCustomDNSEntry() pihole_execute('-a removecustomdns '.$ip.' '.$domain); return returnSuccess(); - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage()); } } @@ -340,7 +341,7 @@ function deleteAllCustomDNSEntries($reload = '') foreach ($existingEntries as $entry) { pihole_execute('-a removecustomdns '.$entry->ip.' '.$entry->domain.' '.$reload); } - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage()); } @@ -384,10 +385,10 @@ function getCustomCNAMEEntries() continue; } - $data = new \stdClass(); - $data->domains = array_slice($explodedLine, 0, -1); - $data->domain = implode(',', $data->domains); - $data->target = $explodedLine[count($explodedLine) - 1]; + $data = array(); + $data["domains"] = array_slice($explodedLine, 0, -1); + $data["domain"] = implode(',', $data["domains"]); + $data["target"] = $explodedLine[count($explodedLine) - 1]; $entries[] = $data; } @@ -465,7 +466,7 @@ function addCustomCNAMEEntry($domain = '', $target = '', $reload = '', $json = t } return returnSuccess('', $json); - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage(), $json); } } @@ -504,7 +505,7 @@ function deleteCustomCNAMEEntry() pihole_execute('-a removecustomcname '.$domain.' '.$target); return returnSuccess(); - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage()); } } @@ -521,7 +522,7 @@ function deleteAllCustomCNAMEEntries($reload = '') foreach ($existingEntries as $entry) { pihole_execute('-a removecustomcname '.$entry->domain.' '.$entry->target.' '.$reload); } - } catch (\Exception $ex) { + } catch (Exception $ex) { return returnError($ex->getMessage()); } @@ -566,14 +567,14 @@ function getQueryTypeStr($querytype) // Return Success message in JSON format function JSON_success($message = null) { - header('Content-type: application/json'); + /* header('Content-type: application/json'); */ echo json_encode(array('success' => true, 'message' => $message)); } // Return Error message in JSON format function JSON_error($message = null) { - header('Content-type: application/json'); + /* header('Content-type: application/json'); */ $response = array('success' => false, 'message' => $message); if (isset($_POST['action'])) { array_push($response, array('action' => $_POST['action'])); @@ -586,7 +587,7 @@ function JSON_error($message = null) // - sends "warning" to use the correct alert type. function JSON_warning($message = null) { - header('Content-type: application/json'); + /* header('Content-type: application/json'); */ echo json_encode(array( 'success' => true, 'warning' => true, @@ -594,51 +595,6 @@ function JSON_warning($message = null) )); } -// Returns an integer representing pihole blocking status -function piholeStatus() -{ - // Retrieve DNS Port calling FTL API directly - $port = callFTLAPI('dns-port'); - - // Retrieve FTL status - $FTLstats = callFTLAPI('stats'); - - 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 $ret; -} - -// Returns the default gateway address and interface -function getGateway() -{ - $gateway = callFTLAPI('gateway'); - if (array_key_exists('FTLnotrunning', $gateway)) { - $ret = array('ip' => -1); - } else { - $ret = array_combine(array('ip', 'iface'), explode(' ', $gateway[0])); - } - - return $ret; -} - // Try to convert possible IDNA domain to Unicode function convertIDNAToUnicode($IDNA) { @@ -690,12 +646,6 @@ function convertUnicodeToIDNA($unicode) } } -// Return PID of FTL (used in settings.php) -function pidofFTL() -{ - return shell_exec('pidof pihole-FTL'); -} - // Get FTL process information (used in settings.php) function get_FTL_data($FTLpid, $arg) { @@ -722,8 +672,8 @@ function convertseconds($argument) function start_php_session() { // Prevent Session ID from being passed through URLs - ini_set('session.use_only_cookies', 1); - session_start(); + /* ini_set('session.use_only_cookies', 1); */ + /* session_start(); */ // HttpOnly: Prevents javascript XSS attacks aimed to steal the session ID // // SameSite=Strict: Allows servers to assert that a cookie ought not to be @@ -732,5 +682,5 @@ function start_php_session() // protection against cross-site request forgery attacks. // Direct support of Samesite has been added to PHP only in version 7.3 // We manually set the cookie option ourselves to ensure backwards compatibility - header('Set-Cookie: PHPSESSID='.session_id().'; path=/; HttpOnly; SameSite=Strict'); + /* header('Set-Cookie: PHPSESSID='.session_id().'; path=/; HttpOnly; SameSite=Strict'); */ } diff --git a/scripts/pi-hole/php/gravity.php b/scripts/pi-hole/php/gravity.php index dc926394a..930e7ffd2 100644 --- a/scripts/pi-hole/php/gravity.php +++ b/scripts/pi-hole/php/gravity.php @@ -11,6 +11,8 @@ function gravity_last_update($raw = false) { + return 'Adlists updated ??.?? ago'; + /* $db = SQLite3_connect(getGravityDBFilename()); $date_file_created_unix = $db->querySingle("SELECT value FROM info WHERE property = 'updated';"); if ($date_file_created_unix === false) { @@ -50,4 +52,5 @@ function gravity_last_update($raw = false) // String output (less than one day ago) return $gravitydiff->format('Adlists updated %H:%I (hh:mm) ago'); + */ } diff --git a/scripts/pi-hole/php/gravity.sh.php b/scripts/pi-hole/php/gravity.sh.php deleted file mode 100644 index e7c3323d3..000000000 --- a/scripts/pi-hole/php/gravity.sh.php +++ /dev/null @@ -1,40 +0,0 @@ -query('SELECT * FROM "group";'); - $data = array(); - while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { - array_push($data, $res); - } - - header('Content-type: application/json'); - echo json_encode(array('data' => $data)); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'add_group') { - // Add new group - try { - $input = html_entity_decode(trim($_POST['name'])); - $names = str_getcsv($input, ' '); - $total = count($names); - $added = 0; - $stmt = $db->prepare('INSERT INTO "group" (name,description) VALUES (:name,:desc)'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $desc = $_POST['desc']; - if (strlen($desc) === 0) { - // Store NULL in database for empty descriptions - $desc = null; - } - if (!$stmt->bindValue(':desc', $desc, SQLITE3_TEXT)) { - throw new Exception('While binding desc: '.$db->lastErrorMsg()); - } - - foreach ($names as $name) { - // Silently skip this entry when it is empty or not a string (e.g. NULL) - if (!is_string($name) || strlen($name) == 0) { - continue; - } - - if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) { - throw new Exception('While binding name: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' groups'); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' groups'); - } - ++$added; - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'edit_group') { - // Edit group identified by ID - try { - $name = html_entity_decode($_POST['name']); - $desc = html_entity_decode($_POST['desc']); - - $stmt = $db->prepare('UPDATE "group" SET enabled=:enabled, name=:name, description=:desc WHERE id = :id'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $status = ((int) $_POST['status']) !== 0 ? 1 : 0; - if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { - throw new Exception('While binding enabled: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) { - throw new Exception('While binding name: '.$db->lastErrorMsg()); - } - - if (strlen($desc) === 0) { - // Store NULL in database for empty descriptions - $desc = null; - } - if (!$stmt->bindValue(':desc', $desc, SQLITE3_TEXT)) { - throw new Exception('While binding desc: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'delete_group') { - // Delete group identified by ID - try { - $ids = json_decode($_POST['id']); - - // Exploit prevention: Ensure all entries in the ID array are integers - verify_ID_array($ids); - - $table_name = array('domainlist_by_group', 'client_by_group', 'adlist_by_group', '"group"'); // quote reserved word - $table_keys = array('group_id', 'group_id', 'group_id', 'id'); - - for ($i = 0; $i < count($table_name); ++$i) { - $table = $table_name[$i]; - $key = $table_keys[$i]; - - $stmt = $db->prepare('DELETE FROM '.$table.' WHERE '.$key.' IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception("While preparing DELETE FROM {$table} statement: ".$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception("While executing DELETE FROM {$table} statement: ".$db->lastErrorMsg()); - } - - if (!$stmt->reset()) { - throw new Exception("While resetting DELETE FROM {$table} statement: ".$db->lastErrorMsg()); - } - } - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'get_clients') { - // List all available groups - try { - $QUERYDB = getQueriesDBFilename(); - $FTLdb = SQLite3_connect($QUERYDB); - - $query = $db->query('SELECT * FROM client;'); - if (!$query) { - throw new Exception('Error while querying gravity\'s client table: '.$db->lastErrorMsg()); - } - - $data = array(); - while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { - $group_query = $db->query('SELECT group_id FROM client_by_group WHERE client_id = '.$res['id'].';'); - if (!$group_query) { - throw new Exception('Error while querying gravity\'s client_by_group table: '.$db->lastErrorMsg()); - } - - $stmt = $FTLdb->prepare('SELECT name FROM network_addresses WHERE ip = :ip;'); - if (!$stmt) { - throw new Exception('Error while preparing network table statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':ip', $res['ip'], SQLITE3_TEXT)) { - throw new Exception('While binding to network table statement: '.$db->lastErrorMsg()); - } - - $result = $stmt->execute(); - if (!$result) { - throw new Exception('While executing network table statement: '.$db->lastErrorMsg()); - } - - // Check if got a hostname from the database. This may not be the case if the client is - // specified by MAC address, a hostname or via a more general selector like an interface. - $name_result = $result->fetchArray(SQLITE3_ASSOC); - if (!is_bool($name_result)) { - $res['name'] = $name_result['name']; - error_log('IP: '.$name_result['name']); - } else { - // Check if we can get a host name from the database when looking up the MAC - // address of this client instead. - $stmt = $FTLdb->prepare('SELECT name FROM network n JOIN network_addresses na ON na.network_id = n.id WHERE hwaddr=:hwaddr COLLATE NOCASE AND name IS NOT NULL;'); - if (!$stmt) { - throw new Exception('Error while preparing network table statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':hwaddr', $res['ip'], SQLITE3_TEXT)) { - throw new Exception('While binding to network table statement: '.$db->lastErrorMsg()); - } - - $result = $stmt->execute(); - if (!$result) { - throw new Exception('While executing network table statement: '.$db->lastErrorMsg()); - } - - // Check if we found a result. There may be multiple entries for - // this client in the network_addresses table. We use the first - // hostname we find for the sake of simplicity. - $name_result = $result->fetchArray(SQLITE3_ASSOC); - if (!is_bool($name_result)) { - $res['name'] = $name_result['name']; - } else { - $res['name'] = null; - } - } - - $groups = array(); - while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { - array_push($groups, $gres['group_id']); - } - $group_query->finalize(); - $res['groups'] = $groups; - array_push($data, $res); - } - - header('Content-type: application/json'); - echo json_encode(array('data' => $data)); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'get_unconfigured_clients') { - // List all available clients WITHOUT already configured clients - try { - $QUERYDB = getQueriesDBFilename(); - $FTLdb = SQLite3_connect($QUERYDB); - - $query = $FTLdb->query('SELECT DISTINCT id,hwaddr,macVendor FROM network ORDER BY firstSeen DESC;'); - if (!$query) { - throw new Exception('Error while querying FTL\'s database: '.$db->lastErrorMsg()); - } - - // Loop over results - $ips = array(); - while ($res = $query->fetchArray(SQLITE3_ASSOC)) { - $id = intval($res['id']); - - // Get possibly associated IP addresses and hostnames for this client - $query_ips = $FTLdb->query("SELECT ip,name FROM network_addresses WHERE network_id = {$id} ORDER BY lastSeen DESC;"); - $addresses = array(); - $names = array(); - while ($res_ips = $query_ips->fetchArray(SQLITE3_ASSOC)) { - array_push($addresses, utf8_encode($res_ips['ip'])); - if ($res_ips['name'] !== null) { - array_push($names, utf8_encode($res_ips['name'])); - } - } - $query_ips->finalize(); - - // Prepare extra information - $extrainfo = ''; - // Add list of associated host names to info string (if available) - if (count($names) === 1) { - $extrainfo .= 'hostname: '.$names[0]; - } elseif (count($names) > 0) { - $extrainfo .= 'hostnames: '.implode(', ', $names); - } - - // Add device vendor to info string (if available) - if (strlen($res['macVendor']) > 0) { - if (count($names) > 0) { - $extrainfo .= '; '; - } - $extrainfo .= 'vendor: '.htmlspecialchars($res['macVendor']); - } - - // Add list of associated host names to info string (if available and if this is not a mock device) - if (stripos($res['hwaddr'], 'ip-') === false) { - if ((count($names) > 0 || strlen($res['macVendor']) > 0) && count($addresses) > 0) { - $extrainfo .= '; '; - } - - if (count($addresses) === 1) { - $extrainfo .= 'address: '.$addresses[0]; - } elseif (count($addresses) > 0) { - $extrainfo .= 'addresses: '.implode(', ', $addresses); - } - } - - $ips[strtoupper($res['hwaddr'])] = $extrainfo; - } - $FTLdb->close(); - - $query = $db->query('SELECT ip FROM client;'); - if (!$query) { - throw new Exception('Error while querying gravity\'s database: '.$db->lastErrorMsg()); - } - - // Loop over results, remove already configured clients - while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { - if (isset($ips[$res['ip']])) { - unset($ips[$res['ip']]); - } - if (isset($ips['IP-'.$res['ip']])) { - unset($ips['IP-'.$res['ip']]); - } - } - - header('Content-type: application/json'); - echo json_encode($ips); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'add_client') { - // Add new client - try { - $ips = explode(' ', trim($_POST['ip'])); - $total = count($ips); - $added = 0; - $stmt = $db->prepare('INSERT INTO client (ip,comment) VALUES (:ip,:comment)'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - foreach ($ips as $ip) { - // Encode $ip variable to prevent XSS - $ip = htmlspecialchars($ip); - // Silently skip this entry when it is empty or not a string (e.g. NULL) - if (!is_string($ip) || strlen($ip) == 0) { - continue; - } - - if (!$stmt->bindValue(':ip', $ip, SQLITE3_TEXT)) { - throw new Exception('While binding ip: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' clients'); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' clients'); - } - ++$added; - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'edit_client') { - // Edit client identified by ID - try { - $db->query('BEGIN TRANSACTION;'); - - $stmt = $db->prepare('UPDATE client SET comment=:comment WHERE id = :id'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg()); - } - - $stmt = $db->prepare('DELETE FROM client_by_group WHERE client_id = :id'); - if (!$stmt) { - throw new Exception('While preparing DELETE statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing DELETE statement: '.$db->lastErrorMsg()); - } - - $groups = array(); - if (isset($_POST['groups'])) { - $groups = $_POST['groups']; - } - foreach ($groups as $gid) { - $stmt = $db->prepare('INSERT INTO client_by_group (client_id,group_id) VALUES(:id,:gid);'); - if (!$stmt) { - throw new Exception('While preparing INSERT INTO statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { - throw new Exception('While binding gid: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing INSERT INTO statement: '.$db->lastErrorMsg()); - } - } - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'delete_client') { - // Delete client identified by ID - try { - $ids = json_decode($_POST['id']); - - // Exploit prevention: Ensure all entries in the ID array are integers - verify_ID_array($ids); - - $db->query('BEGIN TRANSACTION;'); - - // Delete from: client_by_group - $stmt = $db->prepare('DELETE FROM client_by_group WHERE client_id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing client_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing client_by_group statement: '.$db->lastErrorMsg()); - } - - // Delete from: client - $stmt = $db->prepare('DELETE FROM client WHERE id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing client statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing client statement: '.$db->lastErrorMsg()); - } - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'get_domains') { - // List all available groups - try { - $limit = ''; - if (isset($_POST['type']) && is_numeric($_POST['type'])) { - $limit = ' WHERE type = '.$_POST['type']; - } - $query = $db->query('SELECT * FROM domainlist'.$limit); - if (!$query) { - throw new Exception('Error while querying gravity\'s domainlist table: '.$db->lastErrorMsg()); - } - - $data = array(); - while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { - $group_query = $db->query('SELECT group_id FROM domainlist_by_group WHERE domainlist_id = '.$res['id'].';'); - if (!$group_query) { - throw new Exception('Error while querying gravity\'s domainlist_by_group table: '.$db->lastErrorMsg()); - } - - $groups = array(); - while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { - array_push($groups, $gres['group_id']); - } - $res['groups'] = $groups; - if ($res['type'] === LISTTYPE_WHITELIST || $res['type'] === LISTTYPE_BLACKLIST) { - // Convert domain name to international form - $utf8_domain = convertIDNAToUnicode($res['domain']); - - // if domain and international form are different, show both - if ($res['domain'] !== $utf8_domain) { - $res['domain'] = $utf8_domain.' ('.$res['domain'].')'; - } - } - // Prevent domain and comment fields from returning any arbitrary javascript code which could be executed on the browser. - $res['domain'] = htmlentities($res['domain']); - $res['comment'] = htmlentities($res['comment']); - array_push($data, $res); - } - - header('Content-type: application/json'); - echo json_encode(array('data' => $data)); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'add_domain' || $_POST['action'] == 'replace_domain') { - // Add new domain - try { - $domains = explode(' ', html_entity_decode(trim($_POST['domain']))); - $before = intval($db->querySingle('SELECT COUNT(*) FROM domainlist;')); - $total = count($domains); - $added = 0; - - $db->query('BEGIN TRANSACTION;'); - - // Prepare INSERT INTO statement - $insert_stmt = $db->prepare('INSERT OR IGNORE INTO domainlist (domain,type) VALUES (:domain,:type)'); - if (!$insert_stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - // Prepare UPDATE statement - $update_stmt = $db->prepare('UPDATE domainlist SET comment = :comment WHERE domain = :domain AND type = :type'); - if (!$update_stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $check_stmt = null; - $delete_stmt = null; - if ($_POST['action'] == 'replace_domain') { - // Check statement will reveal any group associations for a given (domain,type) which do NOT belong to the default group - $check_stmt = $db->prepare('SELECT EXISTS(SELECT domain FROM domainlist_by_group dlbg JOIN domainlist dl on dlbg.domainlist_id = dl.id WHERE dl.domain = :domain AND dlbg.group_id != 0)'); - if (!$check_stmt) { - throw new Exception('While preparing check statement: '.$db->lastErrorMsg()); - } - // Delete statement will remove this domain from any type of list - $delete_stmt = $db->prepare('DELETE FROM domainlist WHERE domain = :domain'); - if (!$delete_stmt) { - throw new Exception('While preparing delete statement: '.$db->lastErrorMsg()); - } - } - - if (isset($_POST['type'])) { - $type = intval($_POST['type']); - } elseif (isset($_POST['list']) && $_POST['list'] === 'white') { - $type = LISTTYPE_WHITELIST; - } elseif (isset($_POST['list']) && $_POST['list'] === 'black') { - $type = LISTTYPE_BLACKLIST; - } - - if (!$insert_stmt->bindValue(':type', $type, SQLITE3_TEXT) - || !$update_stmt->bindValue(':type', $type, SQLITE3_TEXT)) { - throw new Exception('While binding type: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$update_stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg()); - } - - foreach ($domains as $domain) { - // Silently skip this entry when it is empty or not a string (e.g. NULL) - if (!is_string($domain) || strlen($domain) == 0) { - continue; - } - - if (isset($_POST['type']) && $_POST['type'] != '2' && $_POST['type'] != '3') { - // If not adding a RegEx.... - $input = $domain; - // Convert domain name to IDNA ASCII form for international domains - $domain = convertUnicodeToIDNA($domain); - // convert the domain lower case and check whether it is valid - $domain = strtolower($domain); - $msg = ''; - if (!validDomain($domain, $msg)) { - // This is the case when convertUnicodeToIDNA() modified the string - if ($input !== $domain && strlen($domain) > 0) { - $errormsg = 'Domain '.htmlentities($input).' (converted to "'.htmlentities(utf8_encode($domain)).'") is not a valid domain because '.$msg.'.'; - } elseif ($input !== $domain) { - $errormsg = 'Domain '.htmlentities($input).' is not a valid domain because '.$msg.'.'; - } else { - $errormsg = 'Domain '.htmlentities(utf8_encode($domain)).' is not a valid domain because '.$msg.'.'; - } - - throw new Exception($errormsg.'
Added '.$added.' out of '.$total.' domains'); - } - } - - if (isset($_POST['type']) && strlen($_POST['type']) === 2 && $_POST['type'][1] === 'W') { - // Apply wildcard-style formatting - $domain = '(\\.|^)'.str_replace('.', '\\.', $domain).'$'; - } - - // First try to delete any occurrences of this domain if we're in - // replace mode. Only do this when the domain to be replaced is in - // the default group! Otherwise, we would shuffle group settings and - // just throw an error at the user to tell them to change this - // domain manually. This ensures user's will really get what they - // want from us. - if ($_POST['action'] == 'replace_domain') { - if (!$check_stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain to check: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - $check_result = $check_stmt->execute(); - if (!$check_result) { - throw new Exception('While executing check: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - // Check return value of CHECK query (0 = only default group, 1 = special group assignments) - $only_default_group = ($check_result->fetchArray(SQLITE3_NUM)[0] == 0) ? true : false; - if (!$only_default_group) { - throw new Exception('Domain '.$domain.' is configured with special group settings.
Please modify the domain on the respective group management pages.'); - } - - if (!$delete_stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - if (!$delete_stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - } - - if (!$insert_stmt->bindValue(':domain', $domain, SQLITE3_TEXT) - || !$update_stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - // First execute INSERT OR IGNORE statement to create a record for - // this domain (ignore if already existing) - if (!$insert_stmt->execute()) { - throw new Exception('While executing INSERT OR IGNORE: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - // Then update the record with a new comment (and modification date - // due to the trigger event) We are not using REPLACE INTO to avoid - // the initial DELETE event (losing group assignments in case an - // entry did already exist). - if (!$update_stmt->execute()) { - throw new Exception('While executing UPDATE: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - ++$added; - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $after = intval($db->querySingle('SELECT COUNT(*) FROM domainlist;')); - $difference = $after - $before; - if ($total === 1) { - if ($difference !== 1) { - $msg = 'Not adding '.htmlentities(utf8_encode($domain)).' as it is already on the list'; - } else { - $msg = 'Added '.htmlentities(utf8_encode($domain)); - } - } else { - if ($difference !== $total) { - $msg = 'Added '.($after - $before).' out of '.$total.' domains (skipped duplicates)'; - } else { - $msg = 'Added '.$total.' domains'; - } - } - $reload = true; - JSON_success($msg); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'edit_domain') { - // Edit domain identified by ID - try { - $db->query('BEGIN TRANSACTION;'); - - $stmt = $db->prepare('UPDATE domainlist SET enabled=:enabled, comment=:comment, type=:type WHERE id = :id'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $status = intval($_POST['status']); - if ($status !== 0) { - $status = 1; - } - - if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { - throw new Exception('While binding enabled: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':type', intval($_POST['type']), SQLITE3_INTEGER)) { - throw new Exception('While binding type: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg()); - } - - $stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id = :id'); - if (!$stmt) { - throw new Exception('While preparing DELETE statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing DELETE statement: '.$db->lastErrorMsg()); - } - - $groups = array(); - if (isset($_POST['groups'])) { - $groups = $_POST['groups']; - } - foreach ($groups as $gid) { - $stmt = $db->prepare('INSERT INTO domainlist_by_group (domainlist_id,group_id) VALUES(:id,:gid);'); - if (!$stmt) { - throw new Exception('While preparing INSERT INTO statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { - throw new Exception('While binding gid: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing INSERT INTO statement: '.$db->lastErrorMsg()); - } - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'delete_domain') { - // Delete domain identified by ID - try { - $ids = json_decode($_POST['id']); - - // Exploit prevention: Ensure all entries in the ID array are integers - verify_ID_array($ids); - - $db->query('BEGIN TRANSACTION;'); - - // Delete from: domainlist_by_group - $stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - // Delete from: domainlist - $stmt = $db->prepare('DELETE FROM domainlist WHERE id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'delete_domain_string') { - // Delete domain identified by the domain string itself - try { - $db->query('BEGIN TRANSACTION;'); - - $domain = html_entity_decode(trim($_POST['domain'])); - // Convert domain name to IDNA ASCII form for international domains - $domain = convertUnicodeToIDNA($domain); - - $stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id=(SELECT id FROM domainlist WHERE domain=:domain AND type=:type);'); - if (!$stmt) { - throw new Exception('While preparing domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain to domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':type', intval($_POST['type']), SQLITE3_INTEGER)) { - throw new Exception('While binding type to domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing domainlist_by_group statement: '.$db->lastErrorMsg()); - } - - $stmt = $db->prepare('DELETE FROM domainlist WHERE domain=:domain AND type=:type'); - if (!$stmt) { - throw new Exception('While preparing domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain to domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':type', intval($_POST['type']), SQLITE3_INTEGER)) { - throw new Exception('While binding type to domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing domainlist statement: '.$db->lastErrorMsg()); - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'get_adlists') { - // List all available groups - try { - $query = $db->query('SELECT * FROM adlist;'); - if (!$query) { - throw new Exception('Error while querying gravity\'s adlist table: '.$db->lastErrorMsg()); - } - - $data = array(); - while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) { - $group_query = $db->query('SELECT group_id FROM adlist_by_group WHERE adlist_id = '.$res['id'].';'); - if (!$group_query) { - throw new Exception('Error while querying gravity\'s adlist_by_group table: '.$db->lastErrorMsg()); - } - - $groups = array(); - while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) { - array_push($groups, $gres['group_id']); - } - $res['groups'] = $groups; - array_push($data, $res); - } - - header('Content-type: application/json'); - echo json_encode(array('data' => $data)); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'add_adlist') { - // Add new adlist - try { - $db->query('BEGIN TRANSACTION;'); - - $addresses = explode(' ', html_entity_decode(trim($_POST['address']))); - $total = count($addresses); - $added = 0; - $ignored = 0; - - $stmt = $db->prepare('INSERT INTO adlist (address,comment) VALUES (:address,:comment)'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg()); - } - - $added_list = ''; - $ignored_list = ''; - foreach ($addresses as $address) { - // Silently skip this entry when it is empty or not a string (e.g. NULL) - if (!is_string($address) || strlen($address) == 0) { - continue; - } - - // this will remove first @ that is after schema and before domain - // $1 is optional schema, $2 is userinfo - $check_address = preg_replace('|([^:/]*://)?([^/]+)@|', '$1$2', $address, 1); - - if (preg_match('/[^a-zA-Z0-9:\\/?&%=~._()-;]/', $check_address) !== 0) { - throw new Exception('Invalid adlist URL '.htmlentities($address).'
Added '.$added.' out of '.$total.' adlists'); - } - - if (!$stmt->bindValue(':address', $address, SQLITE3_TEXT)) { - throw new Exception('While binding address: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' adlists'); - } - - if (!$stmt->execute()) { - if ($db->lastErrorCode() == 19) { - // ErrorCode 19 is "Constraint violation", here the unique constraint of `address` - // is violated (https://www.sqlite.org/rescode.html#constraint). - // If the list is already in database, add to ignored list, but don't throw error - ++$ignored; - $ignored_list .= ''.$address.'
'; - } else { - throw new Exception('While executing: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' adlists'); - } - } else { - ++$added; - $added_list .= ''.$address.'
'; - } - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - if ($ignored_list != '') { - // Send added and ignored lists - $msg = 'Ignored duplicated adlists: '.$ignored.'
'.$ignored_list; - if ($added_list != '') { - $msg .= '
Added adlists: '.$added.'
'.$added_list; - } - $msg .= '
Total: '.$total.' adlist(s) processed.'; - JSON_warning($msg); - } else { - // All adlists added - $msg = $added_list.'
Total: '.$total.' adlist(s) processed.'; - JSON_success($msg); - } - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'edit_adlist') { - // Edit adlist identified by ID - try { - $db->query('BEGIN TRANSACTION;'); - - $stmt = $db->prepare('UPDATE adlist SET enabled=:enabled, comment=:comment WHERE id = :id'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - $status = intval($_POST['status']); - if ($status !== 0) { - $status = 1; - } - - if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) { - throw new Exception('While binding enabled: '.$db->lastErrorMsg()); - } - - $comment = html_entity_decode($_POST['comment']); - if (strlen($comment) === 0) { - // Store NULL in database for empty comments - $comment = null; - } - if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) { - throw new Exception('While binding comment: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg()); - } - - $stmt = $db->prepare('DELETE FROM adlist_by_group WHERE adlist_id = :id'); - if (!$stmt) { - throw new Exception('While preparing DELETE statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing DELETE statement: '.$db->lastErrorMsg()); - } - - $groups = array(); - if (isset($_POST['groups'])) { - $groups = $_POST['groups']; - } - foreach ($groups as $gid) { - $stmt = $db->prepare('INSERT INTO adlist_by_group (adlist_id,group_id) VALUES(:id,:gid);'); - if (!$stmt) { - throw new Exception('While preparing INSERT INTO statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) { - throw new Exception('While binding id: '.$db->lastErrorMsg()); - } - - if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) { - throw new Exception('While binding gid: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing INSERT INTO statement: '.$db->lastErrorMsg()); - } - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'delete_adlist') { - // Delete adlist identified by ID - try { - // Accept only an array - $ids = json_decode($_POST['id']); - - // Exploit prevention: Ensure all entries in the ID array are integers - verify_ID_array($ids); - - $db->query('BEGIN TRANSACTION;'); - - // Delete from: adlists_by_group - $stmt = $db->prepare('DELETE FROM adlist_by_group WHERE adlist_id IN ('.implode(',', $ids).')'); - - if (!$stmt) { - throw new Exception('While preparing adlist_by_group statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing adlist_by_group statement: '.$db->lastErrorMsg()); - } - - // Delete from: adlists - $stmt = $db->prepare('DELETE FROM adlist WHERE id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing adlist statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing adlist statement: '.$db->lastErrorMsg()); - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} elseif ($_POST['action'] == 'add_audit') { - // Add new domain - try { - $domains = explode(' ', html_entity_decode(trim($_POST['domain']))); - $before = intval($db->querySingle('SELECT COUNT(*) FROM domain_audit;')); - $total = count($domains); - $added = 0; - - $db->query('BEGIN TRANSACTION;'); - - $stmt = $db->prepare('REPLACE INTO domain_audit (domain) VALUES (:domain)'); - if (!$stmt) { - throw new Exception('While preparing statement: '.$db->lastErrorMsg()); - } - - foreach ($domains as $domain) { - // Silently skip this entry when it is empty or not a string (e.g. NULL) - if (!is_string($domain) || strlen($domain) == 0) { - continue; - } - - if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) { - throw new Exception('While binding domain: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - - if (!$stmt->execute()) { - throw new Exception('While executing: '.$db->lastErrorMsg().'
Added '.$added.' out of '.$total.' domains'); - } - ++$added; - } - - if (!$db->query('COMMIT;')) { - throw new Exception('While committing changes to the database: '.$db->lastErrorMsg()); - } - - $after = intval($db->querySingle('SELECT COUNT(*) FROM domain_audit;')); - $difference = $after - $before; - if ($total === 1) { - if ($difference !== 1) { - $msg = 'Not adding '.htmlentities(utf8_encode($domain)).' as it is already on the list'; - } else { - $msg = 'Added '.htmlentities(utf8_encode($domain)); - } - } else { - if ($difference !== $total) { - $msg = 'Added '.($after - $before).' out of '.$total.' domains (skipped duplicates)'; - } else { - $msg = 'Added '.$total.' domains'; - } - } - - // Reloading isn't necessary for audit domains (no effect on blocking) - $reload = false; - JSON_success($msg); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} else { - log_and_die('Requested action not supported!'); -} -// Reload lists in pihole-FTL after having added something -if ($reload) { - $output = pihole_execute('restartdns reload-lists'); -} diff --git a/scripts/pi-hole/php/header_authenticated.php b/scripts/pi-hole/php/header_authenticated.php index f84ee5efc..c4ed0129e 100644 --- a/scripts/pi-hole/php/header_authenticated.php +++ b/scripts/pi-hole/php/header_authenticated.php @@ -8,133 +8,12 @@ * Please see LICENSE file for your rights under this license. */ -require 'scripts/pi-hole/php/password.php'; -if (!$auth) { - $_SESSION['prev_url'] = $_SERVER['REQUEST_URI']; - header('Location: login.php'); - exit; -} - require 'scripts/pi-hole/php/auth.php'; -require_once 'scripts/pi-hole/php/FTL.php'; require_once 'scripts/pi-hole/php/func.php'; require 'scripts/pi-hole/php/theme.php'; -// Retrieve layout setting from setupVars -if (isset($setupVars['WEBUIBOXEDLAYOUT']) && !($setupVars['WEBUIBOXEDLAYOUT'] === 'boxed')) { - $boxedlayout = false; -} else { - $boxedlayout = true; -} - -// Override layout setting if layout is changed via Settings page -if (isset($_POST['field'])) { - if ($_POST['field'] === 'webUI' && isset($_POST['boxedlayout'])) { - $boxedlayout = true; - } elseif ($_POST['field'] === 'webUI' && !isset($_POST['boxedlayout'])) { - $boxedlayout = false; - } -} - -// Return memory usage to show on status block -function getMemUsage() -{ - $data = explode("\n", file_get_contents('/proc/meminfo')); - $meminfo = array(); - if (count($data) > 0) { - foreach ($data as $line) { - $expl = explode(':', $line); - if (count($expl) == 2) { - // remove " kB" from the end of the string and make it an integer - $meminfo[$expl[0]] = intval(trim(substr($expl[1], 0, -3))); - } - } - $memused = $meminfo['MemTotal'] - $meminfo['MemFree'] - $meminfo['Buffers'] - $meminfo['Cached']; - $memusage = $memused / $meminfo['MemTotal']; - } else { - $memusage = -1; - } - - return $memusage; -} - -// Try to get temperature value from different places (OS dependent) -// - return an array, containing the temperature and limit. -function getTemperature() -{ - global $setupVars; - - if (file_exists('/sys/class/thermal/thermal_zone0/temp')) { - $output = rtrim(file_get_contents('/sys/class/thermal/thermal_zone0/temp')); - } elseif (file_exists('/sys/class/hwmon/hwmon0/temp1_input')) { - $output = rtrim(file_get_contents('/sys/class/hwmon/hwmon0/temp1_input')); - } else { - $output = ''; - } - - // Test if we succeeded in getting the temperature - if (is_numeric($output)) { - // $output could be either 4-5 digits or 2-3, and we only divide by 1000 if it's 4-5 - // ex. 39007 vs 39 - $celsius = intval($output); - - // If celsius is greater than 1 degree and is in the 4-5 digit format - if ($celsius > 1000) { - // Use multiplication to get around the division-by-zero error - $celsius *= 1e-3; - } - - // Get user-defined temperature limit if set - if (isset($setupVars['TEMPERATURE_LIMIT'])) { - $limit = intval($setupVars['TEMPERATURE_LIMIT']); - } else { - $limit = 60; - } - } else { - // Nothing can be colder than -273.15 degree Celsius (= 0 Kelvin) - // This is the minimum temperature possible (AKA absolute zero) - $celsius = -273.16; - // Set templimit to null if no tempsensor was found - $limit = null; - } - - return array($celsius, $limit); -} - check_cors(); -// Generate CSRF token -if (empty($_SESSION['token'])) { - $_SESSION['token'] = base64_encode(openssl_random_pseudo_bytes(32)); -} -$token = $_SESSION['token']; - -// For session timer -$maxlifetime = ini_get('session.gc_maxlifetime'); - -// Get temperature -list($celsius, $temperaturelimit) = getTemperature(); - -// Get CPU load -$loaddata = sys_getloadavg(); -foreach ($loaddata as $key => $value) { - $loaddata[$key] = round($value, 2); -} - -// Get number of processing units available to PHP -// (may be less than the number of online processors) -$nproc = shell_exec('nproc'); -if (!is_numeric($nproc)) { - $cpuinfo = file_get_contents('/proc/cpuinfo'); - preg_match_all('/^processor/m', $cpuinfo, $matches); - $nproc = count($matches[0]); -} - -// Get memory usage -$memory_usage = getMemUsage(); - -$piholeFTLConf = piholeFTLConfig(); - require 'header.php'; ?> @@ -208,10 +87,7 @@ function getTemperature() Pi-hole Forum GitHub Pi-hole Releases - 0) { // Show "Logout" link only when the user has the password protection enabled.?> -
- Log out - + Log out diff --git a/scripts/pi-hole/php/message.php b/scripts/pi-hole/php/message.php deleted file mode 100644 index 7ecfccea6..000000000 --- a/scripts/pi-hole/php/message.php +++ /dev/null @@ -1,58 +0,0 @@ -prepare('DELETE FROM message WHERE id IN ('.implode(',', $ids).')'); - if (!$stmt) { - throw new Exception('While preparing message statement: '.$db->lastErrorMsg()); - } - - if (!$stmt->execute()) { - throw new Exception('While executing message statement: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} else { - log_and_die('Requested action not supported!'); -} diff --git a/scripts/pi-hole/php/network.php b/scripts/pi-hole/php/network.php deleted file mode 100644 index 4b570cea4..000000000 --- a/scripts/pi-hole/php/network.php +++ /dev/null @@ -1,65 +0,0 @@ -prepare('DELETE FROM network_addresses WHERE network_id=:id'); - 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()) { - throw new Exception('While executing message statement: '.$db->lastErrorMsg()); - } - - $stmt = $db->prepare('DELETE FROM network WHERE id=:id'); - 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()) { - throw new Exception('While executing message statement: '.$db->lastErrorMsg()); - } - - $reload = true; - JSON_success(); - } catch (\Exception $ex) { - JSON_error($ex->getMessage()); - } -} else { - log_and_die('Requested action not supported!'); -} diff --git a/scripts/pi-hole/php/password.php b/scripts/pi-hole/php/password.php deleted file mode 100644 index 028726306..000000000 --- a/scripts/pi-hole/php/password.php +++ /dev/null @@ -1,108 +0,0 @@ - 0) { - // Check for and authorize from persistent cookie - if (isset($_COOKIE['persistentlogin'])) { - if (checkValidityPersistentLoginToken($_COOKIE['persistentlogin'])) { - $_SESSION['auth'] = true; - } else { - // Invalid cookie - $_SESSION['auth'] = false; - setcookie('persistentlogin', '', 1); - } - } elseif (isset($_POST['pw'])) { - // Compare doubly hashes password input with saved hash - $postinput = hash('sha256', hash('sha256', $_POST['pw'])); - - if (hash_equals($pwhash, $postinput)) { - // Save previously accessed page, before clear the session - $redirect_url = 'index.php'; - if (isset($_SESSION['prev_url'])) { - $redirect_url = $_SESSION['prev_url']; - } - - // Regenerate session ID to prevent session fixation - session_regenerate_id(); - - // Clear the old session - $_SESSION = array(); - - // Set hash in new session - $_SESSION['hash'] = $pwhash; - - // Set persistent cookie if selected - if (isset($_POST['persistentlogin'])) { - // Generate cookie with new expiry - $token = genPersistentLoginToken(); - $time = time() + 60 * 60 * 24 * 7; // 7 days - writePersistentLoginToken($token, $time); - // setcookie($name, $value, $expire, $path, $domain, $secure, $httponly) - setcookie('persistentlogin', $token, $time, null, null, null, true); - } - - $_SESSION['auth'] = true; - - // Login successful, redirect the user to the original requested page - if ( - $_SERVER['REQUEST_METHOD'] === 'POST' && - strlen($_SERVER['SCRIPT_NAME']) >= 10 && - substr_compare($_SERVER['SCRIPT_NAME'], '/login.php', -10) === 0 - ) { - header('Location: '.$redirect_url); - exit; - } - } else { - $_SESSION['auth'] = false; - $validpassword = false; - } - } elseif (isset($_SESSION['hash'])) { - // Compare auth hash with saved hash - if (hash_equals($pwhash, $_SESSION['hash'])) { - $_SESSION['auth'] = true; - } - } elseif ($use_api && isset($_GET['auth'])) { - // API can use the hash to get data without logging in via plain-text password - if (hash_equals($pwhash, $_GET['auth'])) { - $_SESSION['auth'] = true; - } - } else { - // Password or hash wrong - $_SESSION['auth'] = false; - } - } else { - // No password set - $_SESSION['auth'] = true; - } - - return $validpassword; -} - -$wrongpassword = !verifyPassword($pwhash, isset($api)); -$auth = $_SESSION['auth']; diff --git a/scripts/pi-hole/php/persistentlogin_token.php b/scripts/pi-hole/php/persistentlogin_token.php deleted file mode 100644 index 7338c6efb..000000000 --- a/scripts/pi-hole/php/persistentlogin_token.php +++ /dev/null @@ -1,88 +0,0 @@ -= time()) { - return true; - } - } - } - - return false; -} - -function writePersistentLoginToken($token, $time) -{ - $token_file = getPathPersistentLoginToken($token); - - if ($token_file and !file_exists($token_file)) { - $t_file = fopen($token_file, 'w'); - if ($t_file) { - // make sure persistent login token file is not readable by other users - chmod($token_file, 0600); - - fwrite($t_file, $time); - fclose($t_file); - - return true; - } - } - - return false; -} - -function logoutPersistentLoginToken($token) -{ - setcookie('persistentlogin', '', 1); - - $token_file = getPathPersistentLoginToken($token); - if ($token_file and file_exists($token_file) and is_writable($token_file)) { - unlink($token_file); - } -} diff --git a/scripts/pi-hole/php/queryads.php b/scripts/pi-hole/php/queryads.php deleted file mode 100644 index b63685203..000000000 --- a/scripts/pi-hole/php/queryads.php +++ /dev/null @@ -1,67 +0,0 @@ - 0) { - ob_end_flush(); -} - -require_once 'func.php'; -ini_set('output_buffering', '0'); -ob_implicit_flush(true); -header('Content-Type: text/event-stream'); -header('Cache-Control: no-cache'); - -function echoEvent($datatext, $url = '') -{ - if (!isset($_GET['IE'])) { - $txt = 'data:'.implode("\ndata:", explode("\n", $datatext))."\n\n"; - } else { - $txt = $datatext; - } - - $txt = str_replace('This can be overridden using the -all option', 'Select the checkbox to remove the limitation', $txt); - $txt = str_replace($url, ''.$url.'', $txt); - - echo $txt; -} - -// Test if domain is set -if (isset($_GET['domain'])) { - // Is this a valid domain? - // Convert domain name to IDNA ASCII form for international domains - $url = convertUnicodeToIDNA($_GET['domain']); - if (!validDomain($url)) { - echoEvent(htmlentities($url).' is an invalid domain!', $url); - - exit; - } -} else { - echoEvent('No domain provided'); - - exit; -} - -$options = ''; -if (isset($_GET['exact'])) { - $options .= ' -exact'; -} - -if (isset($_GET['showall'])) { - $options .= ' -all'; -} - -$proc = popen('sudo pihole -q '.$url.$options, 'r'); -while (!feof($proc)) { - echoEvent(fread($proc, 4096), $url); -} diff --git a/scripts/pi-hole/php/savesettings.php b/scripts/pi-hole/php/savesettings.php deleted file mode 100644 index 41f03a64f..000000000 --- a/scripts/pi-hole/php/savesettings.php +++ /dev/null @@ -1,605 +0,0 @@ - 0) { - return $matches[0]; - } - - return null; -} - -$dhcp_static_leases = array(); -function readStaticLeasesFile($origin_file = '/etc/dnsmasq.d/04-pihole-static-dhcp.conf') -{ - global $dhcp_static_leases; - $dhcp_static_leases = array(); - if (!file_exists($origin_file) || !is_readable($origin_file)) { - return false; - } - - $dhcpstatic = @fopen($origin_file, 'r'); - if (!is_resource($dhcpstatic)) { - return false; - } - - while (!feof($dhcpstatic)) { - // Remove any possibly existing variable with this name - $mac = ''; - $one = ''; - $two = ''; - sscanf(trim(fgets($dhcpstatic)), 'dhcp-host=%[^,],%[^,],%[^,]', $mac, $one, $two); - if (strlen($mac) > 0 && validMAC($mac)) { - if (validIP($one) && strlen($two) == 0) { - // dhcp-host=mac,IP - no HOST - array_push($dhcp_static_leases, array('hwaddr' => $mac, 'IP' => $one, 'host' => '')); - } elseif (strlen($two) == 0) { - // dhcp-host=mac,hostname - no IP - array_push($dhcp_static_leases, array('hwaddr' => $mac, 'IP' => '', 'host' => $one)); - } else { - // dhcp-host=mac,IP,hostname - array_push($dhcp_static_leases, array('hwaddr' => $mac, 'IP' => $one, 'host' => $two)); - } - } elseif (validIP($one) && validDomain($mac)) { - // dhcp-host=hostname,IP - no MAC - array_push($dhcp_static_leases, array('hwaddr' => '', 'IP' => $one, 'host' => $mac)); - } - } - - return true; -} - -function isequal(&$argument, &$compareto) -{ - if (isset($argument)) { - if ($argument === $compareto) { - return true; - } - } - - return false; -} - -function isinserverlist($addr) -{ - global $DNSserverslist; - foreach ($DNSserverslist as $key => $value) { - if (isequal($value['v4_1'], $addr) || isequal($value['v4_2'], $addr)) { - return true; - } - if (isequal($value['v6_1'], $addr) || isequal($value['v6_2'], $addr)) { - return true; - } - } - - return false; -} - -$DNSserverslist = array(); -function readDNSserversList() -{ - // Reset list - $list = array(); - $handle = @fopen('/etc/pihole/dns-servers.conf', 'r'); - if ($handle) { - while (($line = fgets($handle)) !== false) { - $line = rtrim($line); - $line = explode(';', $line); - $name = $line[0]; - $values = array(); - if (!empty($line[1]) && validIP($line[1])) { - $values['v4_1'] = $line[1]; - } - if (!empty($line[2]) && validIP($line[2])) { - $values['v4_2'] = $line[2]; - } - if (!empty($line[3]) && validIP($line[3])) { - $values['v6_1'] = $line[3]; - } - if (!empty($line[4]) && validIP($line[4])) { - $values['v6_2'] = $line[4]; - } - $list[$name] = $values; - } - fclose($handle); - } - - return $list; -} - -require_once 'database.php'; - -function addStaticDHCPLease($mac, $ip, $hostname) -{ - global $error, $success, $dhcp_static_leases; - - try { - if (!validMAC($mac)) { - throw new Exception('MAC address ('.htmlspecialchars($mac).') is invalid!
', 0); - } - $mac = strtoupper($mac); - - if (!validIP($ip) && strlen($ip) > 0) { - throw new Exception('IP address ('.htmlspecialchars($ip).') is invalid!
', 1); - } - - if (!validDomain($hostname) && strlen($hostname) > 0) { - throw new Exception('Host name ('.htmlspecialchars($hostname).') is invalid!
', 2); - } - - if (strlen($hostname) == 0 && strlen($ip) == 0) { - throw new Exception('You can not omit both the IP address and the host name!
', 3); - } - - if (strlen($hostname) == 0) { - $hostname = 'nohost'; - } - - if (strlen($ip) == 0) { - $ip = 'noip'; - } - - // Test if this lease is already included - readStaticLeasesFile(); - - foreach ($dhcp_static_leases as $lease) { - if ($lease['hwaddr'] === $mac) { - throw new Exception('Static lease for MAC address ('.htmlspecialchars($mac).') already defined!
', 4); - } - if ($ip !== 'noip' && $lease['IP'] === $ip) { - throw new Exception('Static lease for IP address ('.htmlspecialchars($ip).') already defined!
', 5); - } - if ($lease['host'] === $hostname) { - throw new Exception('Static lease for hostname ('.htmlspecialchars($hostname).') already defined!
', 6); - } - } - - pihole_execute('-a addstaticdhcp '.$mac.' '.$ip.' '.$hostname); - $success .= 'A new static address has been added'; - - return true; - } catch (Exception $exception) { - $error .= $exception->getMessage(); - - return false; - } -} - -// Read available DNS server list -$DNSserverslist = readDNSserversList(); - -$error = ''; -$success = ''; - -if (isset($_POST['field'])) { - // Handle CSRF - check_csrf(isset($_POST['token']) ? $_POST['token'] : ''); - - // Process request - switch ($_POST['field']) { - // Set DNS server - case 'DNS': - $DNSservers = array(); - // Add selected predefined servers to list - foreach ($DNSserverslist as $key => $value) { - foreach (array('v4_1', 'v4_2', 'v6_1', 'v6_2') as $type) { - // Skip if this IP type does not - // exist (e.g. IPv4-only or only - // one IPv6 address upstream - // server) - if (!array_key_exists($type, $value)) { - continue; - } - - // If server exists and is set - // (POST), we add it to the - // array of DNS servers - $server = str_replace('.', '_', $value[$type]); - if (array_key_exists('DNSserver'.$server, $_POST)) { - array_push($DNSservers, $value[$type]); - } - } - } - - // Test custom server fields - for ($i = 1; $i <= 4; ++$i) { - if (array_key_exists('custom'.$i, $_POST)) { - $exploded = explode('#', $_POST['custom'.$i.'val'], 2); - $IP = trim($exploded[0]); - - if (!validIP($IP)) { - $error .= 'IP ('.htmlspecialchars($IP).') is invalid!
'; - } else { - if (count($exploded) > 1) { - $port = trim($exploded[1]); - if (!is_numeric($port)) { - $error .= 'Port ('.htmlspecialchars($port).') is invalid!
'; - } else { - $IP .= '#'.$port; - } - } - - array_push($DNSservers, $IP); - } - } - } - $DNSservercount = count($DNSservers); - - // Check if at least one DNS server has been added - if ($DNSservercount < 1) { - $error .= 'No DNS server has been selected.
'; - } - - // Check if domain-needed is requested - if (isset($_POST['DNSrequiresFQDN'])) { - $extra = 'domain-needed '; - } else { - $extra = 'domain-not-needed '; - } - - // Check if domain-needed is requested - if (isset($_POST['DNSbogusPriv'])) { - $extra .= 'bogus-priv '; - } else { - $extra .= 'no-bogus-priv '; - } - - // Check if DNSSEC is requested - if (isset($_POST['DNSSEC'])) { - $extra .= 'dnssec'; - } else { - $extra .= 'no-dnssec'; - } - - // Check if rev-server is requested - if (isset($_POST['rev_server'])) { - // Validate CIDR IP - $cidr = trim($_POST['rev_server_cidr']); - if (!validCIDRIP($cidr)) { - $error .= 'Conditional forwarding subnet ("'.htmlspecialchars($cidr).'") is invalid!
'. - 'This field requires CIDR notation for local subnets (e.g., 192.168.0.0/16).
'; - } - - // Validate target IP - $target = trim($_POST['rev_server_target']); - if (!validIP($target)) { - $error .= 'Conditional forwarding target IP ("'.htmlspecialchars($target).'") is invalid!
'; - } - - // Validate conditional forwarding domain name (empty is okay) - $domain = trim($_POST['rev_server_domain']); - if (strlen($domain) > 0 && !validDomain($domain)) { - $error .= 'Conditional forwarding domain name ("'.htmlspecialchars($domain).'") is invalid!
'; - } - - if (!$error) { - $extra .= ' rev-server '.$cidr.' '.$target.' '.$domain; - } - } - - // Check if DNSinterface is set - if (isset($_POST['DNSinterface'])) { - if ($_POST['DNSinterface'] === 'single') { - $DNSinterface = 'single'; - } elseif ($_POST['DNSinterface'] === 'bind') { - $DNSinterface = 'bind'; - } elseif ($_POST['DNSinterface'] === 'all') { - $DNSinterface = 'all'; - } else { - $DNSinterface = 'local'; - } - } else { - // Fallback - $DNSinterface = 'local'; - } - pihole_execute('-a -i '.$DNSinterface.' -web'); - - // Add rate-limiting settings - if (isset($_POST['rate_limit_count'], $_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)) { - $IPs = implode(',', $DNSservers); - $return = pihole_execute('-a setdns "'.$IPs.'" '.$extra); - $success .= htmlspecialchars(end($return)).'
'; - $success .= 'The DNS settings have been updated (using '.$DNSservercount.' DNS servers)'; - } else { - $error .= 'The settings have been reset to their previous values'; - } - - break; - // Set query logging - case 'Logging': - if ($_POST['action'] === 'Disable') { - pihole_execute('-l off'); - $success .= 'Logging has been disabled and logs have been flushed'; - } elseif ($_POST['action'] === 'Disable-noflush') { - pihole_execute('-l off noflush'); - $success .= 'Logging has been disabled, your logs have not been flushed'; - } else { - pihole_execute('-l on'); - $success .= 'Logging has been enabled'; - } - - break; - // Set domains to be excluded from being shown in Top Domains (or Ads) and Top Clients - case 'API': - // Explode the contents of the textareas into PHP arrays - // \n (Unix) and \r\n (Win) will be considered as newline - // array_filter( ... ) will remove any empty lines - $domains = array_filter(preg_split('/\r\n|[\r\n]/', $_POST['domains'])); - $clients = array_filter(preg_split('/\r\n|[\r\n]/', $_POST['clients'])); - - $domainlist = ''; - $first = true; - foreach ($domains as $domain) { - if (!validDomainWildcard($domain) || validIP($domain)) { - $error .= 'Top Domains/Ads entry '.htmlspecialchars($domain).' is invalid (use only domains)!
'; - } - if (!$first) { - $domainlist .= ','; - } else { - $first = false; - } - $domainlist .= $domain; - } - - $clientlist = ''; - $first = true; - foreach ($clients as $client) { - if (!validDomainWildcard($client) && !validIP($client)) { - $error .= 'Top Clients entry '.htmlspecialchars($client).' is invalid (use only host names and IP addresses)!
'; - } - if (!$first) { - $clientlist .= ','; - } else { - $first = false; - } - $clientlist .= $client; - } - - // Set Top Lists options - if (!strlen($error)) { - // All entries are okay - pihole_execute('-a setexcludedomains '.$domainlist); - pihole_execute('-a setexcludeclients '.$clientlist); - $success .= 'The API settings have been updated
'; - } else { - $error .= 'The settings have been reset to their previous values'; - } - - // Set query log options - if (isset($_POST['querylog-permitted'], $_POST['querylog-blocked'])) { - pihole_execute('-a setquerylog all'); - $success .= 'All entries will be shown in Query Log'; - } elseif (isset($_POST['querylog-permitted'])) { - pihole_execute('-a setquerylog permittedonly'); - $success .= 'Only permitted will be shown in Query Log'; - } elseif (isset($_POST['querylog-blocked'])) { - pihole_execute('-a setquerylog blockedonly'); - $success .= 'Only blocked entries will be shown in Query Log'; - } else { - pihole_execute('-a setquerylog nothing'); - $success .= 'No entries will be shown in Query Log'; - } - - break; - - case 'webUI': - if (isset($_POST['boxedlayout'])) { - pihole_execute('-a layout boxed'); - } else { - pihole_execute('-a layout traditional'); - } - if (isset($_POST['webtheme'])) { - global $available_themes; - if (array_key_exists($_POST['webtheme'], $available_themes)) { - exec('sudo pihole -a theme '.$_POST['webtheme']); - } - } - $success .= 'The webUI settings have been updated'; - - break; - - case 'poweroff': - pihole_execute('-a poweroff'); - $success = 'The system will poweroff in 5 seconds...'; - - break; - - case 'reboot': - pihole_execute('-a reboot'); - $success = 'The system will reboot in 5 seconds...'; - - break; - - case 'restartdns': - pihole_execute('-a restartdns'); - $success = 'The DNS server has been restarted'; - - break; - - case 'flushlogs': - pihole_execute('-f'); - $success = 'The Pi-hole log file has been flushed'; - - break; - - case 'DHCP': - if (isset($_POST['addstatic'])) { - $mac = trim($_POST['AddMAC']); - $ip = trim($_POST['AddIP']); - $hostname = trim($_POST['AddHostname']); - - addStaticDHCPLease($mac, $ip, $hostname); - - break; - } - - if (isset($_POST['removestatic'])) { - $mac = $_POST['removestatic']; - if (!validMAC($mac)) { - $error .= 'MAC address ('.htmlspecialchars($mac).') is invalid!
'; - } - $mac = strtoupper($mac); - - if (!strlen($error)) { - pihole_execute('-a removestaticdhcp '.$mac); - $success .= 'The static address with MAC address '.htmlspecialchars($mac).' has been removed'; - } - - break; - } - - if (isset($_POST['active'])) { - // Validate from IP - $from = $_POST['from']; - if (!validIP($from)) { - $error .= 'From IP ('.htmlspecialchars($from).') is invalid!
'; - } - - // Validate to IP - $to = $_POST['to']; - if (!validIP($to)) { - $error .= 'To IP ('.htmlspecialchars($to).') is invalid!
'; - } - - // Validate router IP - $router = $_POST['router']; - if (!validIP($router)) { - $error .= 'Router IP ('.htmlspecialchars($router).') is invalid!
'; - } - - $domain = $_POST['domain']; - - // Validate Domain name - if (!validDomain($domain)) { - $error .= 'Domain name '.htmlspecialchars($domain).' is invalid!
'; - } - - $leasetime = $_POST['leasetime']; - - // Validate Lease time length - if (!is_numeric($leasetime) || intval($leasetime) < 0) { - $error .= 'Lease time '.htmlspecialchars($leasetime).' is invalid!
'; - } - - if (isset($_POST['useIPv6'])) { - $ipv6 = 'true'; - $type = '(IPv4 + IPv6)'; - } else { - $ipv6 = 'false'; - $type = '(IPv4)'; - } - - if (isset($_POST['DHCP_rapid_commit'])) { - $rapidcommit = 'true'; - } else { - $rapidcommit = 'false'; - } - - if (!strlen($error)) { - pihole_execute('-a enabledhcp '.$from.' '.$to.' '.$router.' '.$leasetime.' '.$domain.' '.$ipv6.' '.$rapidcommit); - $success .= 'The DHCP server has been activated '.htmlspecialchars($type); - } - } else { - pihole_execute('-a disabledhcp'); - $success = 'The DHCP server has been deactivated'; - } - - break; - - case 'privacyLevel': - $level = intval($_POST['privacylevel']); - if ($level >= 0 && $level <= 4) { - // Check if privacylevel is already set - if (isset($piholeFTLConf['PRIVACYLEVEL'])) { - $privacylevel = intval($piholeFTLConf['PRIVACYLEVEL']); - } else { - $privacylevel = 0; - } - - // Store privacy level - pihole_execute('-a privacylevel '.$level); - - if ($privacylevel > $level) { - pihole_execute('-a restartdns'); - $success .= 'The privacy level has been decreased and the DNS resolver has been restarted'; - } elseif ($privacylevel < $level) { - $success .= 'The privacy level has been increased'; - } else { - $success .= 'The privacy level has not been changed'; - } - } else { - $error .= 'Invalid privacy level ('.$level.')!'; - } - - break; - // Flush network table - case 'flusharp': - $output = pihole_execute('arpflush quiet'); - $error = ''; - if (is_array($output)) { - $error = implode('
', $output); - } - if (strlen($error) == 0) { - $success .= 'The network table has been flushed'; - } - - break; - - default: - // Option not found - $error = 'Invalid option'; - } -} - -// Credit: http://stackoverflow.com/a/5501447/2087442 -function formatSizeUnits($bytes) -{ - if ($bytes >= 1073741824) { - $bytes = number_format($bytes / 1073741824, 2).' GB'; - } elseif ($bytes >= 1048576) { - $bytes = number_format($bytes / 1048576, 2).' MB'; - } elseif ($bytes >= 1024) { - $bytes = number_format($bytes / 1024, 2).' kB'; - } elseif ($bytes > 1) { - $bytes = $bytes.' bytes'; - } elseif ($bytes == 1) { - $bytes = $bytes.' byte'; - } else { - $bytes = '0 bytes'; - } - - return $bytes; -} diff --git a/scripts/pi-hole/php/sidebar.php b/scripts/pi-hole/php/sidebar.php index b15a67178..dbc2b3e91 100644 --- a/scripts/pi-hole/php/sidebar.php +++ b/scripts/pi-hole/php/sidebar.php @@ -10,18 +10,18 @@

Status

Active'; } elseif ($pistatus == 0) { echo ' Blocking disabled'; } elseif ($pistatus == -1) { echo ' DNS service not running'; - } elseif ($pistatus == -2) { - echo ' Unknown'; + } elseif ($pistatus == -2) {*/ + echo ' Unknown'; /* } else { echo ' DNS service on port '.$pistatus.''; - } + }*/ ?>
System - - -
  • - - Audit log - -
  • diff --git a/scripts/pi-hole/php/tailLog.php b/scripts/pi-hole/php/tailLog.php deleted file mode 100644 index 2530acbe4..000000000 --- a/scripts/pi-hole/php/tailLog.php +++ /dev/null @@ -1,68 +0,0 @@ -'.$txt.''; - } elseif (strpos($line, 'query[A') || strpos($line, 'query[DHCP')) { - $txt = ''.$txt.''; - } else { - $txt = ''.$txt.''; - } - - return $txt; -} - -// Not using SplFileObject here, since direct -// usage of f-streams will be much faster for -// files as large as the pihole.log -if (isset($_GET['FTL'])) { - $file = fopen('/var/log/pihole/FTL.log', 'r'); -} else { - $file = fopen('/var/log/pihole/pihole.log', 'r'); -} - -if (!$file) { - exit(json_encode(array('offset' => 0, 'lines' => array("Failed to open log file. Check permissions!\n")))); -} - -if (isset($_GET['offset'])) { - $offset = intval($_GET['offset']); - if ($offset > 0) { - // If offset is grater then current file end it means the file was truncated (log rotation) - fseek($file, 0, SEEK_END); - if ($offset > ftell($file)) { - $offset = 0; - } - - // Seeks on the file pointer where we want to continue reading is known - fseek($file, $offset); - - $lines = array(); - while (!feof($file)) { - array_push($lines, formatLine(fgets($file))); - } - - exit(json_encode(array('offset' => ftell($file), 'lines' => $lines))); - } -} - -// Locate the current position of the file read/write pointer -fseek($file, -1, SEEK_END); - -// Add one to skip the very last "\n" in the log file -exit(json_encode(array('offset' => ftell($file) + 1))); diff --git a/scripts/pi-hole/php/teleporter.php b/scripts/pi-hole/php/teleporter.php deleted file mode 100644 index 0161a9ad7..000000000 --- a/scripts/pi-hole/php/teleporter.php +++ /dev/null @@ -1,620 +0,0 @@ - -1) { - $querystr = "SELECT * FROM \"{$table}\" WHERE type = {$type};"; - } else { - $querystr = "SELECT * FROM \"{$table}\";"; - } - $results = $db->query($querystr); - - // Return early without creating a file if the - // requested table cannot be accessed - if (is_null($results)) { - return; - } - - $content = array(); - while ($row = $results->fetchArray(SQLITE3_ASSOC)) { - array_push($content, $row); - } - - $archive[$name] = json_encode($content); -} - -/** - * Restore the contents of a table from an uploaded archive. - * - * @param $file object The file in the archive to restore the table from - * @param $table string The table to import - * @param $flush boolean Whether to flush the table before importing the archived data - * - * @return int Number of restored rows - */ -function archive_restore_table($file, $table, $flush = false) -{ - global $db, $flushed_tables; - - $json_string = file_get_contents($file); - // Return early if we cannot extract the JSON string - if (is_null($json_string)) { - return 0; - } - - $contents = json_decode($json_string, true); - // Return early if we cannot decode the JSON string - if (is_null($contents)) { - return 0; - } - - // Flush table if requested. Only flush each table once, and only if it exists - if ($flush && !in_array($table, $flushed_tables)) { - $tableExists = $db->querySingle("SELECT name FROM sqlite_master WHERE type='table' AND name='".$table."';"); - if ($tableExists) { - $db->exec('DELETE FROM "'.$table.'"'); - array_push($flushed_tables, $table); - } - } - - // Prepare fields depending on the table we restore to - if ($table === 'adlist') { - $sql = 'INSERT OR IGNORE INTO adlist'; - $sql .= ' (id,address,enabled,date_added,comment)'; - $sql .= ' VALUES (:id,:address,:enabled,:date_added,:comment);'; - } elseif ($table === 'domain_audit') { - $sql = 'INSERT OR IGNORE INTO domain_audit'; - $sql .= ' (id,domain,date_added)'; - $sql .= ' VALUES (:id,:domain,:date_added);'; - } elseif ($table === 'domainlist') { - $sql = 'INSERT OR IGNORE INTO domainlist'; - $sql .= ' (id,domain,enabled,date_added,comment,type)'; - $sql .= ' VALUES (:id,:domain,:enabled,:date_added,:comment,:type);'; - } elseif ($table === 'group') { - $sql = 'INSERT OR IGNORE INTO "group"'; - $sql .= ' (id,name,date_added,description)'; - $sql .= ' VALUES (:id,:name,:date_added,:description);'; - } elseif ($table === 'client') { - $sql = 'INSERT OR IGNORE INTO client'; - $sql .= ' (id,ip,date_added,comment)'; - $sql .= ' VALUES (:id,:ip,:date_added,:comment);'; - } elseif ($table === 'domainlist_by_group') { - $sql = 'INSERT OR IGNORE INTO domainlist_by_group'; - $sql .= ' (domainlist_id,group_id)'; - $sql .= ' VALUES (:domainlist_id,:group_id);'; - } elseif ($table === 'client_by_group') { - $sql = 'INSERT OR IGNORE INTO client_by_group'; - $sql .= ' (client_id,group_id)'; - $sql .= ' VALUES (:client_id,:group_id);'; - } elseif ($table === 'adlist_by_group') { - $sql = 'INSERT OR IGNORE INTO adlist_by_group'; - $sql .= ' (adlist_id,group_id)'; - $sql .= ' VALUES (:adlist_id,:group_id);'; - } else { - if ($table === 'whitelist') { - $type = 0; - } elseif ($table === 'blacklist') { - $type = 1; - } elseif ($table === 'regex_whitelist') { - $type = 2; - } elseif ($table === 'regex_blacklist') { - $type = 3; - } - - $sql = 'INSERT OR IGNORE INTO domainlist'; - $sql .= ' (id,domain,enabled,date_added,comment,type)'; - $sql .= " VALUES (:id,:domain,:enabled,:date_added,:comment,{$type});"; - $field = 'domain'; - } - - // Prepare SQLite statement - $stmt = $db->prepare($sql); - - // Return early if we fail to prepare the SQLite statement - if (!$stmt) { - echo 'Failed to prepare statement for '.$table.' table.'; - echo $sql; - - return 0; - } - - // Loop over rows and inject the entries into the database - $num = 0; - foreach ($contents as $row) { - // Limit max length for a domain entry to 253 chars - if (isset($field) && strlen($row[$field]) > 253) { - continue; - } - - // Bind properties from JSON data - // Note that only defined above are actually used - // so even maliciously modified Teleporter files - // cannot be dangerous in any way - foreach ($row as $key => $value) { - $type = gettype($value); - $sqltype = null; - - switch ($type) { - case 'integer': - $sqltype = SQLITE3_INTEGER; - - break; - - case 'string': - $sqltype = SQLITE3_TEXT; - - break; - - case 'NULL': - $sqltype = SQLITE3_NULL; - - break; - - default: - $sqltype = 'UNK'; - } - $stmt->bindValue(':'.$key, htmlentities($value), $sqltype); - } - - if ($stmt->execute() && $stmt->reset() && $stmt->clear()) { - ++$num; - } else { - $stmt->close(); - - return $num; - } - } - - // Close database connection and return number or processed rows - $stmt->close(); - - return $num; -} - -/** - * Create table rows from an uploaded archive file. - * - * @param $file object The file in the archive to import - * @param $table string The target table - * @param $flush boolean Whether to flush the table before importing the archived data - * @param $wildcardstyle boolean Whether to format the input domains in legacy wildcard notation - * - * @return int Number of processed rows from the imported file - */ -function archive_insert_into_table($file, $table, $flush = false, $wildcardstyle = false) -{ - global $db; - - $domains = array_filter(explode("\n", file_get_contents($file))); - // Return early if we cannot extract the lines in the file - if (is_null($domains)) { - return 0; - } - - // Generate comment - $prefix = 'phar:///tmp/'; - if (substr($file, 0, strlen($prefix)) == $prefix) { - $file = substr($file, strlen($prefix)); - } - $comment = 'Imported from '.$file; - - // Determine table and type to import to - $type = null; - if ($table === 'whitelist') { - $table = 'domainlist'; - $type = LISTTYPE_WHITELIST; - } elseif ($table === 'blacklist') { - $table = 'domainlist'; - $type = LISTTYPE_BLACKLIST; - } elseif ($table === 'regex_blacklist') { - $table = 'domainlist'; - $type = LISTTYPE_REGEX_BLACKLIST; - } elseif ($table === 'domain_audit') { - $table = 'domain_audit'; - $type = -1; // -1 -> not used inside add_to_table() - } elseif ($table === 'adlist') { - $table = 'adlist'; - $type = -1; // -1 -> not used inside add_to_table() - } - - // Flush table if requested - if ($flush) { - flush_table($table, $type); - } - - // Add domains to requested table - return add_to_table($db, $table, $domains, $comment, $wildcardstyle, true, $type); -} - -/** - * Flush table if requested. This subroutine flushes each table only once. - * - * @param $table string The target table - * @param $type integer Type of item to flush in table (applies only to domainlist table) - */ -function flush_table($table, $type = null) -{ - global $db, $flushed_tables; - - if (!in_array($table, $flushed_tables)) { - if ($type !== null) { - $sql = 'DELETE FROM "'.$table.'" WHERE type = '.$type; - array_push($flushed_tables, $table.$type); - } else { - $sql = 'DELETE FROM "'.$table.'"'; - array_push($flushed_tables, $table); - } - $db->exec($sql); - } -} - -function archive_add_directory($path, $subdir = '') -{ - if ($dir = opendir($path)) { - while (false !== ($entry = readdir($dir))) { - if ($entry !== '.' && $entry !== '..') { - archive_add_file($path, $entry, $subdir); - } - } - closedir($dir); - } -} - -function limit_length(&$item, $key) -{ - // limit max length for a domain entry to 253 chars - // return only a part of the string if it is longer - $item = substr($item, 0, 253); -} - -function process_file($contents) -{ - $domains = array_filter(explode("\n", $contents)); - // Walk array and apply a max string length - // function to every member of the array of domains - array_walk($domains, 'limit_length'); - - return $domains; -} - -function noun($num) -{ - if ($num === 1) { - return ' entry'; - } - - return ' entries'; -} - -if (isset($_POST['action'])) { - if ($_FILES['zip_file']['name'] && $_POST['action'] == 'in') { - $filename = $_FILES['zip_file']['name']; - $source = $_FILES['zip_file']['tmp_name']; - $type = mime_content_type($source); - - // verify the file mime type - $accepted_types = array('application/gzip', 'application/tar', 'application/x-compressed', 'application/x-gzip'); - $mime_valid = in_array($type, $accepted_types); - - // verify the file extension (Looking for ".tar.gz" at the end of the file name) - $ext = array_slice(explode('.', $filename), -2, 2); - $ext_valid = strtolower($ext[0]) == 'tar' && strtolower($ext[1]) == 'gz' ? true : false; - - if (!$ext_valid || !$mime_valid) { - exit('The file you are trying to upload is not a .tar.gz file (filename: '.htmlentities($filename).', type: '.htmlentities($type).'). Please try again.'); - } - - $fullfilename = sys_get_temp_dir().'/'.$filename; - - if (!move_uploaded_file($source, $fullfilename)) { - exit('Failed moving '.htmlentities($source).' to '.htmlentities($fullfilename)); - } - - $archive = new PharData($fullfilename); - - $importedsomething = false; - $fullpiholerestart = false; - $reloadsettingspage = false; - - $flushtables = isset($_POST['flushtables']); - - foreach (new RecursiveIteratorIterator($archive) as $file) { - if (isset($_POST['blacklist']) && $file->getFilename() === 'blacklist.txt') { - $num = archive_insert_into_table($file, 'blacklist', $flushtables); - echo 'Processed blacklist (exact) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['whitelist']) && $file->getFilename() === 'whitelist.txt') { - $num = archive_insert_into_table($file, 'whitelist', $flushtables); - echo 'Processed whitelist (exact) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['regexlist']) && $file->getFilename() === 'regex.list') { - $num = archive_insert_into_table($file, 'regex_blacklist', $flushtables); - echo 'Processed blacklist (regex) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - // Also try to import legacy wildcard list if found - if (isset($_POST['regexlist']) && $file->getFilename() === 'wildcardblocking.txt') { - $num = archive_insert_into_table($file, 'regex_blacklist', $flushtables, true); - echo 'Processed blacklist (regex, wildcard style) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['auditlog']) && $file->getFilename() === 'auditlog.list') { - $num = archive_insert_into_table($file, 'domain_audit', $flushtables); - echo 'Processed audit log ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['adlist']) && $file->getFilename() === 'adlists.list') { - $num = archive_insert_into_table($file, 'adlist', $flushtables); - echo 'Processed adlists ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['blacklist']) && $file->getFilename() === 'blacklist.exact.json') { - $num = archive_restore_table($file, 'blacklist', $flushtables); - echo 'Processed blacklist (exact) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['regexlist']) && $file->getFilename() === 'blacklist.regex.json') { - $num = archive_restore_table($file, 'regex_blacklist', $flushtables); - echo 'Processed blacklist (regex) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['whitelist']) && $file->getFilename() === 'whitelist.exact.json') { - $num = archive_restore_table($file, 'whitelist', $flushtables); - echo 'Processed whitelist (exact) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['regex_whitelist']) && $file->getFilename() === 'whitelist.regex.json') { - $num = archive_restore_table($file, 'regex_whitelist', $flushtables); - echo 'Processed whitelist (regex) ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['adlist']) && $file->getFilename() === 'adlist.json') { - $num = archive_restore_table($file, 'adlist', $flushtables); - echo 'Processed adlist ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['auditlog']) && $file->getFilename() === 'domain_audit.json') { - $num = archive_restore_table($file, 'domain_audit', $flushtables); - echo 'Processed domain_audit ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['group']) && $file->getFilename() === 'group.json') { - $num = archive_restore_table($file, 'group', $flushtables); - echo 'Processed group ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['client']) && $file->getFilename() === 'client.json') { - $num = archive_restore_table($file, 'client', $flushtables); - echo 'Processed client ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['client']) && $file->getFilename() === 'client_by_group.json') { - $num = archive_restore_table($file, 'client_by_group', $flushtables); - echo 'Processed client group assignments ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if ((isset($_POST['whitelist']) || isset($_POST['regex_whitelist']) - || isset($_POST['blacklist']) || isset($_POST['regex_blacklist'])) - && $file->getFilename() === 'domainlist_by_group.json') { - $num = archive_restore_table($file, 'domainlist_by_group', $flushtables); - echo 'Processed black-/whitelist group assignments ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['adlist']) && $file->getFilename() === 'adlist_by_group.json') { - $num = archive_restore_table($file, 'adlist_by_group', $flushtables); - echo 'Processed adlist group assignments ('.$num.noun($num).")
    \n"; - $importedsomething = true; - } - - if (isset($_POST['staticdhcpleases']) && $file->getFilename() === '04-pihole-static-dhcp.conf') { - if ($flushtables) { - $local_file = @fopen('/etc/dnsmasq.d/04-pihole-static-dhcp.conf', 'r+'); - if ($local_file !== false) { - ftruncate($local_file, 0); - fclose($local_file); - } - } - $num = 0; - $staticdhcpleases = process_file(file_get_contents($file)); - foreach ($staticdhcpleases as $lease) { - list($mac, $ip, $hostname) = explode(',', $lease); - $mac = formatMAC($mac); - if (addStaticDHCPLease($mac, $ip, $hostname)) { - ++$num; - } - } - - readStaticLeasesFile(); - echo 'Processed static DHCP leases ('.$num.noun($num).")
    \n"; - if ($num > 0) { - $importedsomething = true; - $reloadsettingspage = true; - } - } - - if (isset($_POST['localdnsrecords']) && $file->getFilename() === 'custom.list') { - ob_start(); - $reload = 'false'; - if ($flushtables) { - // Defined in func.php included via auth.php - // passing reload="false" will not restart Pi-hole - deleteAllCustomDNSEntries($reload); - } - $num = 0; - $localdnsrecords = process_file(file_get_contents($file)); - foreach ($localdnsrecords as $record) { - list($ip, $domain) = explode(' ', $record); - if (addCustomDNSEntry($ip, $domain, $reload, false)) { - ++$num; - } - } - ob_end_clean(); - echo 'Processed local DNS records ('.$num.noun($num).")
    \n"; - if ($num > 0) { - // we need a full pihole restart - $fullpiholerestart = true; - } - } - - if (isset($_POST['localcnamerecords']) && $file->getFilename() === '05-pihole-custom-cname.conf') { - ob_start(); - $reload = 'false'; - if ($flushtables) { - // Defined in func.php included via auth.php - // passing reload="false" will not restart Pi-hole - deleteAllCustomCNAMEEntries($reload); - } - - $num = 0; - $localcnamerecords = process_file(file_get_contents($file)); - foreach ($localcnamerecords as $record) { - $line = str_replace('cname=', '', $record); - $line = str_replace("\r", '', $line); - $line = str_replace("\n", '', $line); - $explodedLine = explode(',', $line); - - $domain = implode(',', array_slice($explodedLine, 0, -1)); - $target = $explodedLine[count($explodedLine) - 1]; - - if (addCustomCNAMEEntry($domain, $target, $reload, false)) { - ++$num; - } - } - ob_end_clean(); - echo 'Processed local CNAME records ('.$num.noun($num).")
    \n"; - if ($num > 0) { - // we need a full pihole restart - $fullpiholerestart = true; - } - } - } - - // do we need a full restart of Pi-hole or reloading the lists? - if ($fullpiholerestart) { - pihole_execute('restartdns'); - } else { - if ($importedsomething) { - pihole_execute('restartdns reload'); - } - } - - unlink($fullfilename); - echo 'OK'; - if ($reloadsettingspage) { - echo "
    \n"; - } - } else { - exit('No file transmitted or parameter error.'); - } -} else { - $hostname = gethostname() ? str_replace('.', '_', gethostname()).'-' : ''; - $tarname = 'pi-hole-'.$hostname.'teleporter_'.date('Y-m-d_H-i-s').'.tar'; - $filename = $tarname.'.gz'; - $archive_file_name = tempnam(sys_get_temp_dir(), 'pihole_teleporter_'); // create a random file name in the system's tmp dir for the intermediate archive - unlink($archive_file_name); // remove intermediate file created by tempnam() - $archive_file_name .= '.tar'; // Append ".tar" extension - - $archive = new PharData($archive_file_name); - - if ($archive->isWritable() !== true) { - exit('cannot open/create '.htmlentities($archive_file_name)."
    \nPHP user: ".exec('whoami')."\n"); - } - - archive_add_table('whitelist.exact.json', 'domainlist', LISTTYPE_WHITELIST); - archive_add_table('whitelist.regex.json', 'domainlist', LISTTYPE_REGEX_WHITELIST); - archive_add_table('blacklist.exact.json', 'domainlist', LISTTYPE_BLACKLIST); - archive_add_table('blacklist.regex.json', 'domainlist', LISTTYPE_REGEX_BLACKLIST); - archive_add_table('adlist.json', 'adlist'); - archive_add_table('domain_audit.json', 'domain_audit'); - archive_add_table('group.json', 'group'); - archive_add_table('client.json', 'client'); - - // Group linking tables - archive_add_table('domainlist_by_group.json', 'domainlist_by_group'); - archive_add_table('adlist_by_group.json', 'adlist_by_group'); - archive_add_table('client_by_group.json', 'client_by_group'); - - archive_add_file('/etc/pihole/', 'setupVars.conf'); - archive_add_file('/etc/pihole/', 'dhcp.leases'); - archive_add_file('/etc/pihole/', 'custom.list'); - archive_add_file('/etc/pihole/', 'pihole-FTL.conf'); - archive_add_file('/etc/', 'hosts', 'etc/'); - archive_add_directory('/etc/dnsmasq.d/', 'dnsmasq.d/'); - - $archive->compress(Phar::GZ); // Creates a gzipped copy - unlink($archive_file_name); // Unlink original tar file as it is not needed anymore - $archive_file_name .= '.gz'; // Append ".gz" extension to ".tar" - - header('Content-type: application/gzip'); - header('Content-Transfer-Encoding: binary'); - header('Content-Disposition: attachment; filename='.$filename); - header('Content-length: '.filesize($archive_file_name)); - header('Pragma: no-cache'); - header('Expires: 0'); - if (ob_get_length() > 0) { - ob_end_clean(); - } - readfile($archive_file_name); - ignore_user_abort(true); - unlink($archive_file_name); - - exit; -} diff --git a/scripts/pi-hole/php/update_checker.php b/scripts/pi-hole/php/update_checker.php deleted file mode 100644 index 00f7b3499..000000000 --- a/scripts/pi-hole/php/update_checker.php +++ /dev/null @@ -1,136 +0,0 @@ -'.htmlentities($core_current).'
    '; -} - -if (isset($web_commit)) { - $webVersionStr = htmlentities($web_current.' ('.$web_branch.', '.$web_commit.')'); -} else { - $webVersionStr = ''.htmlentities($web_current).''; -} - -if (isset($FTL_commit)) { - $ftlVersionStr = htmlentities($FTL_current.' ('.$FTL_branch.', '.$FTL_commit.')'); -} else { - $ftlVersionStr = ''.htmlentities($FTL_current).''; -} - -if ($docker_current) { - if ($docker_current == 'dev' || $docker_current == 'nightly') { - $dockerVersionStr = htmlentities($docker_current); - } else { - $dockerVersionStr = ''.htmlentities($docker_current).''; - } -} else { - $dockerVersionStr = ''; -} diff --git a/scripts/vendor/qrcode.php b/scripts/vendor/qrcode.php deleted file mode 100644 index 0420533c2..000000000 --- a/scripts/vendor/qrcode.php +++ /dev/null @@ -1,1737 +0,0 @@ -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: - $d = new QRNumber($data); - $this->addDataImpl($d); - break; - - case QR_MODE_ALPHA_NUM: - $d = new QRAlphaNum($data); - $this->addDataImpl($d); - break; - - case QR_MODE_8BIT_BYTE: - $d = new QR8BitByte($data); - $this->addDataImpl($d); - break; - - case QR_MODE_KANJI: - $d = new QRKanji($data); - $this->addDataImpl($d); - break; - - default: - trigger_error("mode:$mode", E_USER_ERROR); - } - } - - function clearData() { - $this->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); - } - - if (QRUtil::getMask($maskPattern, $row, $col - $c)) { - $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++) { - $this->modules[$row + $r][$col + $c] = - $r == -2 || $r == 2 || $c == -2 || $c == 2 || ($r == 0 && $c == 0); - } - } - } - } - } - - 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; - } - - $this->modules[$row + $r][$col + $c] = - (0 <= $r && $r <= 6 && ($c == 0 || $c == 6) ) - || (0 <= $c && $c <= 6 && ($r == 0 || $r == 6) ) - || (2 <= $r && $r <= 4 && 2 <= $c && $c <= 4); - } - } - } - - function setupTimingPattern() { - - for ($i = 8; $i < $this->moduleCount - 8; $i++) { - - if ($this->modules[$i][6] !== null || $this->modules[6][$i] !== null) { - continue; - } - - $this->modules[$i][6] = ($i % 2 == 0); - $this->modules[6][$i] = ($i % 2 == 0); - } - } - - function setupTypeNumber($test) { - - $bits = QRUtil::getBCHTypeNumber($this->typeNumber); - - for ($i = 0; $i < 18; $i++) { - $mod = (!$test && ( ($bits >> $i) & 1) == 1); - $this->modules[(int)floor($i / 3)][$i % 3 + $this->moduleCount - 8 - 3] = $mod; - $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; - } - - 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++) { - /** @var \QRData $data */ - $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); - } - - /** - * @param \QRBitBuffer $buffer - * @param \QRRSBlock[] $rsBlocks - * - * @return array - */ - function createBytes(&$buffer, &$rsBlocks) { - - $offset = 0; - - $maxDcCount = 0; - $maxEcCount = 0; - - $dcdata = QRCode::createNullArray(count($rsBlocks) ); - $ecdata = QRCode::createNullArray(count($rsBlocks) ); - - $rsBlockCount = count($rsBlocks); - for ($r = 0; $r < $rsBlockCount; $r++) { - - $dcCount = $rsBlocks[$r]->getDataCount(); - $ecCount = $rsBlocks[$r]->getTotalCount() - $dcCount; - - $maxDcCount = max($maxDcCount, $dcCount); - $maxEcCount = max($maxEcCount, $ecCount); - - $dcdata[$r] = QRCode::createNullArray($dcCount); - $dcDataCount = count($dcdata[$r]); - for ($i = 0; $i < $dcDataCount; $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); - - $ecDataCount = count($ecdata[$r]); - for ($i = 0; $i < $ecDataCount; $i++) { - $modIndex = $i + $modPoly->getLength() - count($ecdata[$r]); - $ecdata[$r][$i] = ($modIndex >= 0)? $modPoly->get($modIndex) : 0; - } - } - - $totalCodeCount = 0; - for ($i = 0; $i < $rsBlockCount; $i++) { - $totalCodeCount += $rsBlocks[$i]->getTotalCount(); - } - - $data = QRCode::createNullArray($totalCodeCount); - - $index = 0; - - for ($i = 0; $i < $maxDcCount; $i++) { - for ($r = 0; $r < $rsBlockCount; $r++) { - if ($i < count($dcdata[$r]) ) { - $data[$index++] = $dcdata[$r][$i]; - } - } - } - - for ($i = 0; $i < $maxEcCount; $i++) { - for ($r = 0; $r < $rsBlockCount; $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 <= 40; $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("
    "); - } - - public function printSVG($size = 2) - { - $size = (int) $size; - $width = $this->getModuleCount() * $size; - $height = $width; - print(''); - - for ($r = 0; $r < $this->getModuleCount(); $r++) { - for ($c = 0; $c < $this->getModuleCount(); $c++) { - $color = $this->isDark($r, $c) ? "#000000" : "#ffffff"; - 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); - } - } - - /** - * @param \QRCode $qrCode - * - * @return float|int - */ - 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) || ($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), - - // 11 - array(4, 101, 81), - array(1, 80, 50, 4, 81, 51), - array(4, 50, 22, 4, 51, 23), - array(3, 36, 12, 8, 37, 13), - - // 12 - array(2, 116, 92, 2, 117, 93), - array(6, 58, 36, 2, 59, 37), - array(4, 46, 20, 6, 47, 21), - array(7, 42, 14, 4, 43, 15), - - // 13 - array(4, 133, 107), - array(8, 59, 37, 1, 60, 38), - array(8, 44, 20, 4, 45, 21), - array(12, 33, 11, 4, 34, 12), - - // 14 - array(3, 145, 115, 1, 146, 116), - array(4, 64, 40, 5, 65, 41), - array(11, 36, 16, 5, 37, 17), - array(11, 36, 12, 5, 37, 13), - - // 15 - array(5, 109, 87, 1, 110, 88), - array(5, 65, 41, 5, 66, 42), - array(5, 54, 24, 7, 55, 25), - array(11, 36, 12, 7, 37, 13), - - // 16 - array(5, 122, 98, 1, 123, 99), - array(7, 73, 45, 3, 74, 46), - array(15, 43, 19, 2, 44, 20), - array(3, 45, 15, 13, 46, 16), - - // 17 - array(1, 135, 107, 5, 136, 108), - array(10, 74, 46, 1, 75, 47), - array(1, 50, 22, 15, 51, 23), - array(2, 42, 14, 17, 43, 15), - - // 18 - array(5, 150, 120, 1, 151, 121), - array(9, 69, 43, 4, 70, 44), - array(17, 50, 22, 1, 51, 23), - array(2, 42, 14, 19, 43, 15), - - // 19 - array(3, 141, 113, 4, 142, 114), - array(3, 70, 44, 11, 71, 45), - array(17, 47, 21, 4, 48, 22), - array(9, 39, 13, 16, 40, 14), - - // 20 - array(3, 135, 107, 5, 136, 108), - array(3, 67, 41, 13, 68, 42), - array(15, 54, 24, 5, 55, 25), - array(15, 43, 15, 10, 44, 16), - - // 21 - array(4, 144, 116, 4, 145, 117), - array(17, 68, 42), - array(17, 50, 22, 6, 51, 23), - array(19, 46, 16, 6, 47, 17), - - // 22 - array(2, 139, 111, 7, 140, 112), - array(17, 74, 46), - array(7, 54, 24, 16, 55, 25), - array(34, 37, 13), - - // 23 - array(4, 151, 121, 5, 152, 122), - array(4, 75, 47, 14, 76, 48), - array(11, 54, 24, 14, 55, 25), - array(16, 45, 15, 14, 46, 16), - - // 24 - array(6, 147, 117, 4, 148, 118), - array(6, 73, 45, 14, 74, 46), - array(11, 54, 24, 16, 55, 25), - array(30, 46, 16, 2, 47, 17), - - // 25 - array(8, 132, 106, 4, 133, 107), - array(8, 75, 47, 13, 76, 48), - array(7, 54, 24, 22, 55, 25), - array(22, 45, 15, 13, 46, 16), - - // 26 - array(10, 142, 114, 2, 143, 115), - array(19, 74, 46, 4, 75, 47), - array(28, 50, 22, 6, 51, 23), - array(33, 46, 16, 4, 47, 17), - - // 27 - array(8, 152, 122, 4, 153, 123), - array(22, 73, 45, 3, 74, 46), - array(8, 53, 23, 26, 54, 24), - array(12, 45, 15, 28, 46, 16), - - // 28 - array(3, 147, 117, 10, 148, 118), - array(3, 73, 45, 23, 74, 46), - array(4, 54, 24, 31, 55, 25), - array(11, 45, 15, 31, 46, 16), - - // 29 - array(7, 146, 116, 7, 147, 117), - array(21, 73, 45, 7, 74, 46), - array(1, 53, 23, 37, 54, 24), - array(19, 45, 15, 26, 46, 16), - - // 30 - array(5, 145, 115, 10, 146, 116), - array(19, 75, 47, 10, 76, 48), - array(15, 54, 24, 25, 55, 25), - array(23, 45, 15, 25, 46, 16), - - // 31 - array(13, 145, 115, 3, 146, 116), - array(2, 74, 46, 29, 75, 47), - array(42, 54, 24, 1, 55, 25), - array(23, 45, 15, 28, 46, 16), - - // 32 - array(17, 145, 115), - array(10, 74, 46, 23, 75, 47), - array(10, 54, 24, 35, 55, 25), - array(19, 45, 15, 35, 46, 16), - - // 33 - array(17, 145, 115, 1, 146, 116), - array(14, 74, 46, 21, 75, 47), - array(29, 54, 24, 19, 55, 25), - array(11, 45, 15, 46, 46, 16), - - // 34 - array(13, 145, 115, 6, 146, 116), - array(14, 74, 46, 23, 75, 47), - array(44, 54, 24, 7, 55, 25), - array(59, 46, 16, 1, 47, 17), - - // 35 - array(12, 151, 121, 7, 152, 122), - array(12, 75, 47, 26, 76, 48), - array(39, 54, 24, 14, 55, 25), - array(22, 45, 15, 41, 46, 16), - - // 36 - array(6, 151, 121, 14, 152, 122), - array(6, 75, 47, 34, 76, 48), - array(46, 54, 24, 10, 55, 25), - array(2, 45, 15, 64, 46, 16), - - // 37 - array(17, 152, 122, 4, 153, 123), - array(29, 74, 46, 14, 75, 47), - array(49, 54, 24, 10, 55, 25), - array(24, 45, 15, 46, 46, 16), - - // 38 - array(4, 152, 122, 18, 153, 123), - array(13, 74, 46, 32, 75, 47), - array(48, 54, 24, 14, 55, 25), - array(42, 45, 15, 32, 46, 16), - - // 39 - array(20, 147, 117, 4, 148, 118), - array(40, 75, 47, 7, 76, 48), - array(43, 54, 24, 22, 55, 25), - array(10, 45, 15, 67, 46, 16), - - // 40 - array(19, 148, 118, 6, 149, 119), - array(18, 75, 47, 31, 76, 48), - array(34, 54, 24, 34, 55, 25), - array(20, 45, 15, 61, 46, 16) - - ); - - function __construct($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 __construct($data) { - parent::__construct(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); - } - } - } - - 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 __construct($data) { - parent::__construct(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 __construct($data) { - parent::__construct(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); - } - } - - 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 __construct($data) { - parent::__construct(QR_MODE_8BIT_BYTE, $data); - } - - function write(&$buffer) { - - $data = $this->getData(); - for ($i = 0; $i < strlen($data); $i++) { - $buffer->put(ord($data[$i]), 8); - } - } - -} - -//--------------------------------------------------------------- -// QRData -//--------------------------------------------------------------- - -abstract class QRData { - - var $mode; - - var $data; - - function __construct($mode, $data) { - $this->mode = $mode; - $this->data = $data; - } - - function getMode() { - return $this->mode; - } - - function getData() { - return $this->data; - } - - /** - * @return int - */ - function getLength() { - return strlen($this->getData() ); - } - - /** - * @param \QRBitBuffer $buffer - */ - abstract function write(&$buffer); - - 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 __construct($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; - } - - /** - * @param \QRPolynomial $e - * - * @return \QRPolynomial - */ - function multiply($e) { - - $num = QRMath::createNumArray($this->getLength() + $e->getLength() - 1); - - for ($i = 0; $i < $this->getLength(); $i++) { - $vi = QRMath::glog($this->get($i) ); - - for ($j = 0; $j < $e->getLength(); $j++) { - $num[$i + $j] ^= QRMath::gexp($vi + QRMath::glog($e->get($j) ) ); - } - } - - return new QRPolynomial($num); - } - - /** - * @param \QRPolynomial $e - * - * @return $this|\QRPolynomial - */ - 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 __construct() { - $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 = (int)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 = (int)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 f024b894b..bbe483dbe 100644 --- a/settings.php +++ b/settings.php @@ -9,26 +9,24 @@ */ require 'scripts/pi-hole/php/header_authenticated.php'; -require 'scripts/pi-hole/php/savesettings.php'; -require_once 'scripts/pi-hole/php/FTL.php'; // Reread ini file as things might have been changed // DEFAULT_FTLCONFFILE is set in "scripts/pi-hole/php/FTL.php"; $setupVars = parse_ini_file('/etc/pihole/setupVars.conf'); -$piholeFTLConf = piholeFTLConfig(DEFAULT_FTLCONFFILE, true); +$piholeFTLConf = array(); // Handling of PHP internal errors $last_error = error_get_last(); if (isset($last_error) && ($last_error['type'] === E_WARNING || $last_error['type'] === E_ERROR)) { $error .= 'There was a problem applying your settings.
    Debugging information:
    PHP error ('.htmlspecialchars($last_error['type']).'): '.htmlspecialchars($last_error['message']).' in '.htmlspecialchars($last_error['file']).':'.htmlspecialchars($last_error['line']); } - +/* // Timezone is set in docker via ENV otherwise get it from commandline $timezone = htmlspecialchars(getenv('TZ')); if (empty($timezone)) { $timezone = shell_exec("date +'%Z'"); } - +*/ ?> - - refresh to the gravity page and start updating immediately - ?> - - - - 0) { ?> - - - - 0) { ?> - - - - - - - - - -
    -
    +
    -

    FTL Information

    +

    System Information

    - - - + + + + + + - - + + - - + + - - + + - - + + + +
    FTL version:Hostname:
    CPU:
    Process identifier (PID):Used memory:
    Time FTL started:Used swap:
    User / Group: / Kernel:
    Total CPU utilization:%Uptime:
    +
    +
    +
    +
    + +
    +
    +
    +
    +

    FTL Information

    +
    +
    +
    +
    + + - - + + - - + + + +
    Memory utilization:%FTL's PID:
    - Used memory: - Privacy level:
    +
    +
    +
    +
    + +
    +
    +
    +
    +
    +
    +

    DNS Information

    +
    +
    +
    +
    + + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    DNS cache size:   
    DNS cache insertions:   
    DNS cache evictions:   
    + Valid A records in cache: +  
    + Valid AAAA records in cache: +  
    + Valid CNAME records in cache: +  
    + Valid SRV records in cache: +  
    + Valid DS records in cache: +  
    + Valid DNSKEY records in cache: +  
    + Other valid records in cache: +  
    + DNS cache expiries: +  
    + Immortal DNS cache entries: +  
    See also our DNS cache documentation. - -
    The FTL service is offline!
    -
    +
    + +
    @@ -598,7 +505,7 @@ } } -//readStaticLeasesFile(); +// readStaticLeasesFile(); ?>
    @@ -1434,7 +1341,7 @@
    - +
    @@ -1445,7 +1352,6 @@
    -
  • From ccced4c1a8f0401bee228f80741da0511e2f181b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Thu, 2 Feb 2023 20:57:10 +0100 Subject: [PATCH 010/583] Fix "undefined" hit counts on the dashboard Signed-off-by: DL6ER --- scripts/pi-hole/js/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/pi-hole/js/index.js b/scripts/pi-hole/js/index.js index f4e1d4c26..c6642ce39 100644 --- a/scripts/pi-hole/js/index.js +++ b/scripts/pi-hole/js/index.js @@ -543,7 +543,7 @@ function updateTopDomainsTable(blocked) { domaintable.append( " " + utils.addTD(url) + - utils.addTD(domain.count) + + utils.addTD(item.count) + utils.addTD(utils.colorBar(percentage, sum, style)) + " " ); From d7eada81569ff97264c445d70bcdde0ea2c17ffa Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 3 Feb 2023 18:07:11 +0100 Subject: [PATCH 011/583] Remove "Remember me for 7 days" checkbox. Each user gets their own independent session. By default, the session will expire after 5 minutes of no web interface being open (otherwise, it is continuously prolonged because of all the background API activity while refreshing the statistics). This timeout, however, can be set freely in pihole.toml and soon also in the web interface so this checkbox has stoped being useful. Signed-off-by: DL6ER --- login.php | 7 +- scripts/pi-hole/php/auth.php | 134 --------- scripts/pi-hole/php/func.php | 290 ------------------- scripts/pi-hole/php/header_authenticated.php | 5 - scripts/pi-hole/php/sidebar.php | 4 +- style/pi-hole.css | 1 - 6 files changed, 3 insertions(+), 438 deletions(-) delete mode 100644 scripts/pi-hole/php/auth.php delete mode 100644 scripts/pi-hole/php/func.php diff --git a/login.php b/login.php index 126dd779f..e837e3367 100644 --- a/login.php +++ b/login.php @@ -9,7 +9,6 @@ */ $wrongpassword = false; -require_once 'func.php'; require 'scripts/pi-hole/php/theme.php'; require 'scripts/pi-hole/php/header.php'; @@ -27,7 +26,7 @@
    diff --git a/scripts/pi-hole/php/auth.php b/scripts/pi-hole/php/auth.php deleted file mode 100644 index 113fe0722..000000000 --- a/scripts/pi-hole/php/auth.php +++ /dev/null @@ -1,134 +0,0 @@ -= 0; --$i) { - $ret |= ord($res[$i]); - } - - return !$ret; - } -} - -function returnSuccess($message = '', $json = true) -{ - if ($json) { - return array('success' => true, 'message' => $message); - } - echo $message.'
    '; - - return true; -} - -function returnError($message = '', $json = true) -{ - $message = htmlentities($message); - if ($json) { - return array('success' => false, 'message' => $message); - } - echo $message.'
    '; - - return false; -} - -function getQueryTypeStr($querytype) -{ - $qtypes = array('A', 'AAAA', 'ANY', 'SRV', 'SOA', 'PTR', 'TXT', 'NAPTR', 'MX', 'DS', 'RRSIG', 'DNSKEY', 'NS', 'OTHER', 'SVCB', 'HTTPS'); - $qtype = intval($querytype); - if ($qtype > 0 && $qtype <= count($qtypes)) { - return $qtypes[$qtype - 1]; - } - - return 'TYPE'.($qtype - 100); -} - -// Functions to return Alert messages (success, error, warning) in JSON format. -// Used in multiple pages. - -// Return Success message in JSON format -function JSON_success($message = null) -{ - /* header('Content-type: application/json'); */ - echo json_encode(array('success' => true, 'message' => $message)); -} - -// Return Error message in JSON format -function JSON_error($message = null) -{ - /* header('Content-type: application/json'); */ - $response = array('success' => false, 'message' => $message); - if (isset($_POST['action'])) { - array_push($response, array('action' => $_POST['action'])); - } - echo json_encode($response); -} - -// Return Warning message in JSON format. -// - sends "success", because it wasn't a failure. -// - sends "warning" to use the correct alert type. -function JSON_warning($message = null) -{ - /* header('Content-type: application/json'); */ - echo json_encode(array( - 'success' => true, - 'warning' => true, - 'message' => $message, - )); -} - -// Try to convert possible IDNA domain to Unicode -function convertIDNAToUnicode($IDNA) -{ - if (extension_loaded('intl')) { - // 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 - 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 - $unicode = idn_to_utf8($IDNA, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); - } elseif (defined('INTL_IDNA_VARIANT_2003')) { - // If conversion failed, try with the (deprecated!) IDNA 2003 variant - // We have to check for its existence 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 - $unicode = idn_to_utf8($IDNA, IDNA_DEFAULT, INTL_IDNA_VARIANT_2003); - } - } - - // if the conversion failed (e.g. domain to long) return the original domain - if ($unicode == false) { - return $IDNA; - } else { - return $unicode; - } -} - -// Convert a given (unicode) domain to IDNA ASCII -function convertUnicodeToIDNA($unicode) -{ - if (extension_loaded('intl')) { - // Be prepared that this may fail and see our comments about convertIDNAToUnicode() - if (defined('INTL_IDNA_VARIANT_UTS46')) { - $IDNA = idn_to_ascii($unicode, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46); - } elseif (defined('INTL_IDNA_VARIANT_2003')) { - $IDNA = idn_to_ascii($unicode, IDNA_DEFAULT, INTL_IDNA_VARIANT_2003); - } - } - - // if the conversion failed (e.g. domain to long) return the original domain - if ($IDNA == false) { - return $unicode; - } else { - return $IDNA; - } -} - -// Get FTL process information (used in settings.php) -function get_FTL_data($FTLpid, $arg) -{ - return trim(exec('ps -p '.$FTLpid.' -o '.$arg)); -} - -// Convert seconds into readable time (used in settings.php) -function convertseconds($argument) -{ - $seconds = round($argument); - if ($seconds < 60) { - return sprintf('%ds', $seconds); - } - if ($seconds < 3600) { - return sprintf('%dm %ds', $seconds / 60, $seconds % 60); - } - if ($seconds < 86400) { - return sprintf('%dh %dm %ds', $seconds / 3600 % 24, $seconds / 60 % 60, $seconds % 60); - } - - return sprintf('%dd %dh %dm %ds', $seconds / 86400, $seconds / 3600 % 24, $seconds / 60 % 60, $seconds % 60); -} - -function start_php_session() -{ - // Prevent Session ID from being passed through URLs - /* ini_set('session.use_only_cookies', 1); */ - /* session_start(); */ - // HttpOnly: Prevents javascript XSS attacks aimed to steal the session ID - // - // SameSite=Strict: Allows servers to assert that a cookie ought not to be - // sent along with cross-site requests. This assertion allows user agents to - // mitigate the risk of cross-origin information leakage, and provides some - // protection against cross-site request forgery attacks. - // Direct support of Samesite has been added to PHP only in version 7.3 - // We manually set the cookie option ourselves to ensure backwards compatibility - /* header('Set-Cookie: PHPSESSID='.session_id().'; path=/; HttpOnly; SameSite=Strict'); */ -} diff --git a/scripts/pi-hole/php/header_authenticated.php b/scripts/pi-hole/php/header_authenticated.php index c586b1cfe..c7b1cdfc1 100644 --- a/scripts/pi-hole/php/header_authenticated.php +++ b/scripts/pi-hole/php/header_authenticated.php @@ -8,12 +8,7 @@ * Please see LICENSE file for your rights under this license. */ -require 'scripts/pi-hole/php/auth.php'; -require_once 'scripts/pi-hole/php/func.php'; require 'scripts/pi-hole/php/theme.php'; - -check_cors(); - require 'header.php'; ?> diff --git a/scripts/pi-hole/php/sidebar.php b/scripts/pi-hole/php/sidebar.php index 6d43f9b29..96f50faab 100644 --- a/scripts/pi-hole/php/sidebar.php +++ b/scripts/pi-hole/php/sidebar.php @@ -86,8 +86,8 @@ Adists - - + + diff --git a/style/pi-hole.css b/style/pi-hole.css index bbdb06af7..6bb79a3c0 100644 --- a/style/pi-hole.css +++ b/style/pi-hole.css @@ -582,7 +582,6 @@ td.details-control { .login-options div:last-child { margin-right: 2px; margin-bottom: 0 !important; - flex: 0 1 auto; font-size: 95%; } From fff54aef3f6f913b8ff270d1ffc59abbb023852d Mon Sep 17 00:00:00 2001 From: DL6ER Date: Fri, 3 Feb 2023 19:09:52 +0100 Subject: [PATCH 012/583] Remove further obsolete PHP code Signed-off-by: DL6ER --- login.php | 1 - scripts/pi-hole/js/login.js | 86 ++++++++++++++++++++ scripts/pi-hole/php/footer.php | 12 +-- scripts/pi-hole/php/header.php | 3 +- scripts/pi-hole/php/header_authenticated.php | 5 +- scripts/pi-hole/php/theme.php | 55 ------------- settings.php | 2 +- 7 files changed, 91 insertions(+), 73 deletions(-) create mode 100644 scripts/pi-hole/js/login.js delete mode 100644 scripts/pi-hole/php/theme.php diff --git a/login.php b/login.php index e837e3367..8ca6e955b 100644 --- a/login.php +++ b/login.php @@ -9,7 +9,6 @@ */ $wrongpassword = false; -require 'scripts/pi-hole/php/theme.php'; require 'scripts/pi-hole/php/header.php'; ?> diff --git a/scripts/pi-hole/js/login.js b/scripts/pi-hole/js/login.js new file mode 100644 index 000000000..fe9890a55 --- /dev/null +++ b/scripts/pi-hole/js/login.js @@ -0,0 +1,86 @@ +/* Pi-hole: A black hole for Internet advertisements + * (c) 2023 Pi-hole, LLC (https://pi-hole.net) + * Network-wide ad blocking via your own hardware. + * + * This file is copyright under the latest version of the EUPL. + * Please see LICENSE file for your rights under this license. */ + +/* global sha256:false */ + +function getParams() { + var GETDict = {}; + window.location.search + .substr(1) + .split("&") + .forEach(function (item) { + GETDict[item.split("=")[0]] = item.split("=")[1]; + }); + return GETDict; +} + +function computeResponse(password, challenge) { + // Compute password hash twice to mitigate rainbow + // table vulnerability + return sha256(challenge + ":" + sha256(sha256(password))); +} + +function redirect() { + // Login succeeded or not needed (empty password) + // Default: Send back to index.php (dashboard) + var target = "index.php"; + + // If specified: Send to requested page + var GETDict = getParams(); + if ("target" in GETDict) { + target = GETDict.target; + } + + // Redirect to target + window.location.replace(target); +} + +function doLogin(response) { + $.ajax({ + url: "/api/auth", + method: "POST", + data: JSON.stringify({ response: response }), + }) + .done(function () { + redirect(); + }) + .fail(function (data) { + if (data.status === 401) { + // Login failed + $("#pw-field").addClass("has-error"); + $("#error-label").show(); + } + }); +} + +$("#loginform").submit(function (e) { + // Cancel the native submit event (prevent the form from being + // submitted) because we want to do a two-step challenge-response login + e.preventDefault(); + + // Get challenge + $.ajax({ + url: "/api/auth", + method: "GET", + }).done(function (data) { + if ("challenge" in data) { + var response = computeResponse($("#loginpw").val(), data.challenge); + doLogin(response); + } else if (data.session.valid === true) + // Password may have been remove meanwhile + redirect(); + }); +}); + +$(function () { + // Check if we need to login at all + $.ajax({ + url: "/api/auth", + }).done(function (data) { + if (data.session.valid === true) redirect(); + }); +}); diff --git a/scripts/pi-hole/php/footer.php b/scripts/pi-hole/php/footer.php index c4a0bf0f4..8a333efd5 100644 --- a/scripts/pi-hole/php/footer.php +++ b/scripts/pi-hole/php/footer.php @@ -40,16 +40,6 @@
    -