diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..98212f28c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,7 @@ +FROM node:21-alpine3.18 +RUN apk add --no-cache \ + git \ + nano\ + openssh + +USER node diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..58e0d8b67 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,23 @@ +{ + "name": "Pi-hole web devcontainer", + "dockerFile": "Dockerfile", + // Use 'postCreateCommand' to run commands after the container is created. + "postCreateCommand": "npm install", + "customizations": { + // Configure properties specific to VS Code. + "vscode": { + "settings": {}, + "extensions": [ + "eamodio.gitlens", + "EditorConfig.EditorConfig", + "github.vscode-github-actions" + ] + } + }, + "containerEnv": { + "GIT_EDITOR": "nano" + }, + "mounts": [ + "type=bind,source=/home/${localEnv:USER}/.ssh,target=/home/node/.ssh,readonly" + ] +} diff --git a/.editorconfig b/.editorconfig index 81d63a06e..e00293208 100644 --- a/.editorconfig +++ b/.editorconfig @@ -17,7 +17,7 @@ indent_size = 2 [*.js] indent_size = 2 -[package.json] +[*.json] indent_size = 2 [.yamllint.conf] diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 829de9da1..0ed8a37a3 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,8 +1,8 @@ **In raising this issue, I confirm the following:** `{please fill the checkboxes, e.g: [X]}` -- [] I have read and understood the [contributors guide](https://github.com/pi-hole/AdminLTE/blob/master/CONTRIBUTING.md). +- [] I have read and understood the [contributors guide](https://github.com/pi-hole/web/blob/master/CONTRIBUTING.md). - [] The issue I am reporting can be _replicated_. -- [] The issue I am reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/AdminLTE/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/AdminLTE/issues)). +- [] The issue I am reporting isn't a duplicate (see [FAQs](https://github.com/pi-hole/pi-hole/wiki/FAQs), [closed issues](https://github.com/pi-hole/web/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aclosed%20), and [open issues](https://github.com/pi-hole/web/issues)). **How familiar are you with the the source code relevant to this issue?:** diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 91eb58745..ce7fd50fd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -28,7 +28,7 @@ updates: day: saturday time: "10:00" open-pull-requests-limit: 10 - target-branch: devel + target-branch: development-v6 reviewers: - "pi-hole/web-maintainers" diff --git a/.github/workflows/codespell.yml b/.github/workflows/codespell.yml index bd022664b..25371084d 100644 --- a/.github/workflows/codespell.yml +++ b/.github/workflows/codespell.yml @@ -1,6 +1,9 @@ name: Codespell on: + push: + branches: + - '**' pull_request: types: [opened, synchronize, reopened, ready_for_review] @@ -17,4 +20,4 @@ jobs: uses: codespell-project/actions-codespell@master with: ignore_words_file: .codespellignore - skip: ./scripts/vendor,./style/vendor,./package.json,./package-lock.json,./composer.json,./composer.lock + skip: ./scripts/vendor,./style/vendor,./package.json,./package-lock.json diff --git a/.github/workflows/php-cs-fixer.yml b/.github/workflows/php-cs-fixer.yml deleted file mode 100644 index a1a255de6..000000000 --- a/.github/workflows/php-cs-fixer.yml +++ /dev/null @@ -1,13 +0,0 @@ -# .github/workflows/php-cs-fixer.yml -on: [push, pull_request] -name: Lint -jobs: - php-cs-fixer: - name: PHP-CS-Fixer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.1.7 - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga - with: - args: --diff --dry-run diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml deleted file mode 100644 index f698cf03e..000000000 --- a/.github/workflows/phpstan.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: PHPStan - -on: - push: - pull_request: - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4.1.7 - - - name: Install composer - uses: php-actions/composer@v6 - - - name: Run PHPStan - uses: php-actions/phpstan@v3 - with: - configuration: phpstan.neon.dist - memory_limit: 256M - diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3d6c62c29..95c1eefc6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -24,7 +24,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v4.0.3 with: - node-version: "16.x" + node-version: "20.x" cache: npm - name: Install npm dependencies diff --git a/.gitignore b/.gitignore index c8bdf0d6d..84260ef59 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,3 @@ test.html # vim *.swp - -# Composer -/vendor/ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php deleted file mode 100644 index dfcb0c3ea..000000000 --- a/.php-cs-fixer.dist.php +++ /dev/null @@ -1,31 +0,0 @@ -ignoreDotFiles(false) - ->ignoreVCSIgnored(true) - ->exclude('scripts/vendor') - ->in(__DIR__) -; - -$config = new PhpCsFixer\Config(); -$config - ->setRules(array( - '@Symfony' => true, - 'array_syntax' => array('syntax' => 'long'), - 'yoda_style' => array('equal' => false, 'identical' => false, 'less_and_greater' => false, 'always_move_variable' => false), - )) - ->setLineEnding(PHP_EOL) - ->setFinder($finder) -; - -return $config; diff --git a/.stickler.yml b/.stickler.yml deleted file mode 100644 index 92beabd94..000000000 --- a/.stickler.yml +++ /dev/null @@ -1,9 +0,0 @@ ---- -linters: - yamllint: - config: ./.yamllint.conf - remarklint: -files: - ignore: - - 'scripts/vendor/*' - - 'style/vendor/*' diff --git a/.yamllint.conf b/.yamllint.conf deleted file mode 100644 index d1b0953bd..000000000 --- a/.yamllint.conf +++ /dev/null @@ -1,3 +0,0 @@ -rules: - line-length: disable - document-start: disable 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 - -- -
- ## Long-term statistics to view data over user defined time rangesdiff --git a/api.php b/api.php deleted file mode 100644 index 02c07669d..000000000 --- a/api.php +++ /dev/null @@ -1,215 +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, ); - if (isset($versions['DOCKER_VERSION'])) { - // Docker info is available only inside containers - $updates['docker_update'] = $docker_update; - $current['docker_current'] = $docker_current; - $latest['docker_latest'] = $docker_latest; - } - - $data = array_merge($data, $updates); - $data = array_merge($data, $current); - $data = array_merge($data, $latest); - $data = array_merge($data, $branches); -} elseif (isset($_GET['setTempUnit']) && $auth) { - $unit = strtolower($_GET['setTempUnit']); - if ($unit == 'c' || $unit == 'f' || $unit == 'k') { - pihole_execute('-a -'.$unit); - $result = 'success'; - } else { - // invalid unit - $result = 'error'; - } - - $data = array_merge($data, array('result' => $result)); -} 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 927bbbba7..000000000 --- a/api_FTL.php +++ /dev/null @@ -1,453 +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) { - $maxlogage = getMaxlogage(); - - if ($maxlogage < 0) { - // FTL is offline - $data = array('FTLnotrunning' => true); - } else { - $data = array_merge($data, array('maxlogage' => $maxlogage)); - } -} - -if (isset($_GET['overTimeData10mins']) && $auth) { - $maxlogage = getMaxlogage(); - - $return = callFTLAPI('overTime'); - if (array_key_exists('FTLnotrunning', $return) || $maxlogage < 0) { - $data = array('FTLnotrunning' => true); - } else { - $domains_over_time = array(); - $ads_over_time = array(); - - // Use current time and maxlogage to limit the time range - $time_end = time(); - $time_start = $time_end - ($maxlogage * 3600); - - foreach ($return as $line) { - $tmp = explode(' ', $line); - $timeslot = intval($tmp[0]); - if ($timeslot >= $time_start && $timeslot <= $time_end) { - $domains_over_time[$timeslot] = intval($tmp[1]); - $ads_over_time[$timeslot] = 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) { - $maxlogage = getMaxlogage(); - - $return = callFTLAPI('ClientsoverTime'); - if (array_key_exists('FTLnotrunning', $return) || $maxlogage < 0) { - $data = array('FTLnotrunning' => true); - } else { - $over_time = array(); - - // Use current time and maxlogage to limit the time range - $time_end = time(); - $time_start = $time_end - ($maxlogage * 3600); - - foreach ($return as $line) { - $tmp = explode(' ', $line); - for ($i = 0; $i < count($tmp) - 1; ++$i) { - $timeslot = intval($tmp[0]); - if ($timeslot >= $time_start && $timeslot <= $time_end) { - $over_time[$timeslot][$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 @@ - - - -
Domain | -Hits | -Actions | -
---|
Domain | -Hits | -Actions | -
---|
Domain | -Target | -Action | -
---|
Domain | -Hits | -Frequency | -
---|
Domain | -Hits | -Frequency | -
---|
Client | -Requests | -Frequency | -
---|
Total Queries
-Queries Blocked
-Queries Blocked (Wildcards)
-Percentage Blocked
-Time | -Type | -Domain | -Client | -Status | -Reply | -Action | -
---|---|---|---|---|---|---|
Time | -Type | -Domain | -Client | -Status | -Reply | -Action | -
Once you click this button a debug log will be generated and can automatically be uploaded if we detect a working internet connection.
- - - - - - diff --git a/dns_records.php b/dns_records.php deleted file mode 100644 index 25870f4e5..000000000 --- a/dns_records.php +++ /dev/null @@ -1,91 +0,0 @@ - - - -Domain | -IP | -Action | -
---|
+ You don't have permission to access =mg.request_info.request_uri?>
on this server.
+ Did you mean to go to your Pi-hole's dashboard instead?
+