diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index b0ebb90e..5539cec9 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.3.0 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/merge-conflict.yml b/.github/workflows/merge-conflict.yml index 5674fca1..d86e9cd1 100644 --- a/.github/workflows/merge-conflict.yml +++ b/.github/workflows/merge-conflict.yml @@ -18,4 +18,4 @@ jobs: dirtyLabel: "PR: Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request." - commentOnClean: "Conflicts have been resolved. A maintainer will review the pull request shortly." + commentOnClean: "Conflicts have been resolved." diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a17d5a94..58a2e647 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,7 @@ jobs: issues: write steps: - - uses: actions/stale@v6.0.1 + - uses: actions/stale@v7.0.0 with: repo-token: ${{ secrets.GITHUB_TOKEN }} days-before-stale: 30 diff --git a/.github/workflows/sync-back-to-dev.yml b/.github/workflows/sync-back-to-dev.yml index 3a5133f9..89b6323f 100644 --- a/.github/workflows/sync-back-to-dev.yml +++ b/.github/workflows/sync-back-to-dev.yml @@ -11,7 +11,7 @@ jobs: name: Syncing branches steps: - name: Checkout - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.3.0 - name: Opening pull request run: gh pr create -B development -H master --title 'Sync master back into development' --body 'Created by Github action' --label 'internal' env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index daa18c85..cf84a28a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.3.0 - name: Check scripts in repository are executable run: | @@ -57,18 +57,22 @@ jobs: centos_9, fedora_35, fedora_36, + fedora_37, ] env: DISTRO: ${{matrix.distro}} steps: - name: Checkout repository - uses: actions/checkout@v3.1.0 + uses: actions/checkout@v3.3.0 - name: Set up Python 3.10 - uses: actions/setup-python@v4.3.0 + uses: actions/setup-python@v4.5.0 with: python-version: "3.10" + - name: Install wheel + run: pip install wheel + - name: Install dependencies run: pip install -r test/requirements.txt diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 3cd782bf..c0264d1a 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -394,41 +394,53 @@ os_check() { # Extract dig response response="${cmdResult%%$'\n'*}" - IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"') - for distro_and_versions in "${supportedOS[@]}" - do - distro_part="${distro_and_versions%%=*}" - versions_part="${distro_and_versions##*=}" - - if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then - valid_os=true - IFS="," read -r -a supportedVer <<<"${versions_part}" - for version in "${supportedVer[@]}" - do - if [[ "${detected_version}" =~ $version ]]; then - valid_version=true - break - fi - done - break - fi - done - - log_write "${INFO} dig return code: ${digReturnCode}" - log_write "${INFO} dig response: ${response}" - - if [ "$valid_os" = true ]; then - log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}" - - if [ "$valid_version" = true ]; then - log_write "${TICK} Version: ${COL_GREEN}${detected_version}${COL_NC}" - else - log_write "${CROSS} Version: ${COL_RED}${detected_version}${COL_NC}" - log_write "${CROSS} Error: ${COL_RED}${detected_os^} is supported but version ${detected_version} is currently unsupported (${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}" - fi + if [ "${digReturnCode}" -ne 0 ]; then + log_write "${INFO} Distro: ${detected_os^}" + log_write "${INFO} Version: ${detected_version}" + log_write "${CROSS} dig return code: ${COL_RED}${digReturnCode}${COL_NC}" + log_write "${CROSS} dig response: ${response}" + log_write "${CROSS} Error: ${COL_RED}dig command failed - Unable to check OS${COL_NC}" else - log_write "${CROSS} Distro: ${COL_RED}${detected_os^}${COL_NC}" - log_write "${CROSS} Error: ${COL_RED}${detected_os^} is not a supported distro (${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}" + IFS=" " read -r -a supportedOS < <(echo "${response}" | tr -d '"') + for distro_and_versions in "${supportedOS[@]}" + do + distro_part="${distro_and_versions%%=*}" + versions_part="${distro_and_versions##*=}" + + if [[ "${detected_os^^}" =~ ${distro_part^^} ]]; then + valid_os=true + IFS="," read -r -a supportedVer <<<"${versions_part}" + for version in "${supportedVer[@]}" + do + if [[ "${detected_version}" =~ $version ]]; then + valid_version=true + break + fi + done + break + fi + done + + local finalmsg + if [ "$valid_os" = true ]; then + log_write "${TICK} Distro: ${COL_GREEN}${detected_os^}${COL_NC}" + + if [ "$valid_version" = true ]; then + log_write "${TICK} Version: ${COL_GREEN}${detected_version}${COL_NC}" + finalmsg="${TICK} ${COL_GREEN}Distro and version supported${COL_NC}" + else + log_write "${CROSS} Version: ${COL_RED}${detected_version}${COL_NC}" + finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is supported but version ${detected_version} is currently unsupported ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}" + fi + else + log_write "${CROSS} Distro: ${COL_RED}${detected_os^}${COL_NC}" + finalmsg="${CROSS} Error: ${COL_RED}${detected_os^} is not a supported distro ${COL_NC}(${FAQ_HARDWARE_REQUIREMENTS})${COL_NC}" + fi + + # Print dig response and the final check result + log_write "${TICK} dig return code: ${COL_GREEN}${digReturnCode}${COL_NC}" + log_write "${INFO} dig response: ${response}" + log_write "${finalmsg}" fi } diff --git a/advanced/Scripts/query.sh b/advanced/Scripts/query.sh index ae266ec0..d48e9363 100755 --- a/advanced/Scripts/query.sh +++ b/advanced/Scripts/query.sh @@ -77,7 +77,7 @@ fi # Strip valid options, leaving only the domain and invalid options # This allows users to place the options before or after the domain -options=$(sed -E 's/ ?-(adlists?|all|exact) ?//g' <<< "${options}") +options=$(sed -E 's/ ?-(all|exact) ?//g' <<< "${options}") # Handle remaining options # If $options contain non ASCII characters, convert to punycode diff --git a/advanced/Templates/pihole-FTL-poststop.sh b/advanced/Templates/pihole-FTL-poststop.sh new file mode 100755 index 00000000..ac3898d2 --- /dev/null +++ b/advanced/Templates/pihole-FTL-poststop.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env sh + +# Source utils.sh for getFTLPIDFile() +PI_HOLE_SCRIPT_DIR='/opt/pihole' +utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" +# shellcheck disable=SC1090 +. "${utilsfile}" + +# Get file paths +FTL_PID_FILE="$(getFTLPIDFile)" + +# Cleanup +rm -f /run/pihole/FTL.sock /dev/shm/FTL-* "${FTL_PID_FILE}" diff --git a/advanced/Templates/pihole-FTL-prestart.sh b/advanced/Templates/pihole-FTL-prestart.sh new file mode 100755 index 00000000..ff4abf3a --- /dev/null +++ b/advanced/Templates/pihole-FTL-prestart.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env sh + +# Source utils.sh for getFTLPIDFile() +PI_HOLE_SCRIPT_DIR='/opt/pihole' +utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" +# shellcheck disable=SC1090 +. "${utilsfile}" + +# Get file paths +FTL_PID_FILE="$(getFTLPIDFile)" + +# Touch files to ensure they exist (create if non-existing, preserve if existing) +# shellcheck disable=SC2174 +mkdir -pm 0755 /run/pihole /var/log/pihole +[ -f "${FTL_PID_FILE}" ] || install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}" +[ -f /var/log/pihole/FTL.log ] || install -m 644 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log +[ -f /var/log/pihole/pihole.log ] || install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log +[ -f /etc/pihole/dhcp.leases ] || install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases +# Ensure that permissions are set so that pihole-FTL can edit all necessary files +chown pihole:pihole /run/pihole /etc/pihole /var/log/pihole /var/log/pihole/FTL.log /var/log/pihole/pihole.log /etc/pihole/dhcp.leases +# Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist +chmod -f 0644 /etc/pihole/macvendor.db /etc/pihole/dhcp.leases /var/log/pihole/FTL.log +chmod -f 0640 /var/log/pihole/pihole.log +# Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist +chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db +# Chmod database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist +chmod -f 0664 /etc/pihole/pihole-FTL.db + +# Backward compatibility for user-scripts that still expect log files in /var/log instead of /var/log/pihole +# Should be removed with Pi-hole v6.0 +if [ ! -f /var/log/pihole.log ]; then + ln -sf /var/log/pihole/pihole.log /var/log/pihole.log + chown -h pihole:pihole /var/log/pihole.log +fi +if [ ! -f /var/log/pihole-FTL.log ]; then + ln -sf /var/log/pihole/FTL.log /var/log/pihole-FTL.log + chown -h pihole:pihole /var/log/pihole-FTL.log +fi diff --git a/advanced/Templates/pihole-FTL.service b/advanced/Templates/pihole-FTL.service index bc1b1d20..15096972 100644 --- a/advanced/Templates/pihole-FTL.service +++ b/advanced/Templates/pihole-FTL.service @@ -9,9 +9,10 @@ # Description: Enable service provided by pihole-FTL daemon ### END INIT INFO -#source utils.sh for getFTLPIDFile(), getFTLPID () +# Source utils.sh for getFTLPIDFile(), getFTLPID() PI_HOLE_SCRIPT_DIR="/opt/pihole" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" +# shellcheck disable=SC1090 . "${utilsfile}" @@ -28,33 +29,8 @@ start() { if is_running; then echo "pihole-FTL is already running" else - # Touch files to ensure they exist (create if non-existing, preserve if existing) - mkdir -pm 0755 /run/pihole /var/log/pihole - [ ! -f "${FTL_PID_FILE}" ] && install -D -m 644 -o pihole -g pihole /dev/null "${FTL_PID_FILE}" - [ ! -f /var/log/pihole/FTL.log ] && install -m 644 -o pihole -g pihole /dev/null /var/log/pihole/FTL.log - [ ! -f /var/log/pihole/pihole.log ] && install -m 640 -o pihole -g pihole /dev/null /var/log/pihole/pihole.log - [ ! -f /etc/pihole/dhcp.leases ] && install -m 644 -o pihole -g pihole /dev/null /etc/pihole/dhcp.leases - # Ensure that permissions are set so that pihole-FTL can edit all necessary files - chown pihole:pihole /run/pihole /etc/pihole /var/log/pihole /var/log/pihole/FTL.log /var/log/pihole/pihole.log /etc/pihole/dhcp.leases - # Ensure that permissions are set so that pihole-FTL can edit the files. We ignore errors as the file may not (yet) exist - chmod -f 0644 /etc/pihole/macvendor.db /etc/pihole/dhcp.leases /var/log/pihole/FTL.log - chmod -f 0640 /var/log/pihole/pihole.log - # Chown database files to the user FTL runs as. We ignore errors as the files may not (yet) exist - chown -f pihole:pihole /etc/pihole/pihole-FTL.db /etc/pihole/gravity.db /etc/pihole/macvendor.db - # Chown database file permissions so that the pihole group (web interface) can edit the file. We ignore errors as the files may not (yet) exist - chmod -f 0664 /etc/pihole/pihole-FTL.db - - # Backward compatibility for user-scripts that still expect log files in /var/log instead of /var/log/pihole/ - # Should be removed with Pi-hole v6.0 - if [ ! -f /var/log/pihole.log ]; then - ln -s /var/log/pihole/pihole.log /var/log/pihole.log - chown -h pihole:pihole /var/log/pihole.log - - fi - if [ ! -f /var/log/pihole-FTL.log ]; then - ln -s /var/log/pihole/FTL.log /var/log/pihole-FTL.log - chown -h pihole:pihole /var/log/pihole-FTL.log - fi + # Run pre-start script, which pre-creates all expected files with correct permissions + sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-prestart.sh" if setcap CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_NICE,CAP_IPC_LOCK,CAP_CHOWN+eip "/usr/bin/pihole-FTL"; then su -s /bin/sh -c "/usr/bin/pihole-FTL" pihole || exit $? @@ -89,8 +65,8 @@ stop() { else echo "Not running" fi - # Cleanup - rm -f /run/pihole/FTL.sock /dev/shm/FTL-* "${FTL_PID_FILE}" + # Run post-stop script, which does cleanup among runtime files + sh "${PI_HOLE_SCRIPT_DIR}/pihole-FTL-poststop.sh" echo } @@ -108,11 +84,11 @@ status() { ### main logic ### -# Get file paths +# Get FTL's PID file path FTL_PID_FILE="$(getFTLPIDFile)" # Get FTL's current PID -FTL_PID="$(getFTLPID ${FTL_PID_FILE})" +FTL_PID="$(getFTLPID "${FTL_PID_FILE}")" case "$1" in stop) diff --git a/advanced/Templates/pihole-FTL.systemd b/advanced/Templates/pihole-FTL.systemd new file mode 100644 index 00000000..2a114199 --- /dev/null +++ b/advanced/Templates/pihole-FTL.systemd @@ -0,0 +1,41 @@ +[Unit] +Description=Pi-hole FTL +# This unit is supposed to indicate when network functionality is available, but it is only +# very weakly defined what that is supposed to mean, with one exception: at shutdown, a unit +# that is ordered after network-online.target will be stopped before the network +Wants=network-online.target +After=network-online.target +# A target that should be used as synchronization point for all host/network name service lookups. +# All services for which the availability of full host/network name resolution is essential should +# be ordered after this target, but not pull it in. +Wants=nss-lookup.target +Before=nss-lookup.target + +# Limit (re)start loop to 5 within 1 minute +StartLimitBurst=5 +StartLimitIntervalSec=60s + +[Service] +User=pihole +PermissionsStartOnly=true +AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_NET_ADMIN CAP_SYS_NICE CAP_IPC_LOCK CAP_CHOWN + +ExecStartPre=/opt/pihole/pihole-FTL-prestart.sh +ExecStart=/usr/bin/pihole-FTL -f +Restart=on-failure +RestartSec=5s +ExecReload=/bin/kill -HUP $MAINPID +ExecStopPost=/opt/pihole/pihole-FTL-poststop.sh + +# Use graceful shutdown with a reasonable timeout +TimeoutStopSec=10s + +# Make /usr, /boot, /etc and possibly some more folders read-only... +ProtectSystem=full +# ... except /etc/pihole +# This merely retains r/w access rights, it does not add any new. +# Must still be writable on the host! +ReadWriteDirectories=/etc/pihole + +[Install] +WantedBy=multi-user.target diff --git a/advanced/index.php b/advanced/index.php deleted file mode 100644 index f3f2ce1c..00000000 --- a/advanced/index.php +++ /dev/null @@ -1,81 +0,0 @@ - "true") is configured in lighttpd, - // append $serverName to $authorizedHosts - array_push($authorizedHosts, $serverName); -} else if (!empty($_SERVER["VIRTUAL_HOST"])) { - // Append virtual hostname to $authorizedHosts - array_push($authorizedHosts, $_SERVER["VIRTUAL_HOST"]); -} - -// Determine block page type -if ($serverName === "pi.hole" - || (!empty($_SERVER["VIRTUAL_HOST"]) && $serverName === $_SERVER["VIRTUAL_HOST"])) { - // Redirect to Web Interface - header("Location: /admin"); - exit(); -} elseif (filter_var($serverName, FILTER_VALIDATE_IP) || in_array($serverName, $authorizedHosts)) { - // When directly browsing via IP or authorized hostname - // Render splash/landing page based off presence of $landPage file - // Unset variables so as to not be included in $landPage or $splashPage - unset($authorizedHosts); - // If $landPage file is present - if (is_file(getcwd()."/$landPage")) { - unset($serverName, $viewPort); // unset extra variables not to be included in $landpage - include $landPage; - exit(); - } - // If $landPage file was not present, Set Splash Page output - $splashPage = << - - - - - ● $serverName - - - - -
- Pi-hole logo -
-

Pi-hole: Your black hole for Internet advertisements

- Did you mean to go to the admin panel? -
- - -EOT; - exit($splashPage); -} - -header("HTTP/1.1 404 Not Found"); -exit(); -?> diff --git a/advanced/lighttpd.conf.debian b/advanced/lighttpd.conf.debian index 21e48d6c..06c284fe 100644 --- a/advanced/lighttpd.conf.debian +++ b/advanced/lighttpd.conf.debian @@ -26,7 +26,6 @@ server.modules = ( ) server.document-root = "/var/www/html" -server.error-handler-404 = "/pihole/index.php" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) server.errorlog = "/var/log/lighttpd/error-pihole.log" server.pid-file = "/run/lighttpd.pid" @@ -67,48 +66,9 @@ mimetype.assign = ( ".woff2" => "font/woff2" ) -# Add user chosen options held in external file -# This uses include_shell instead of an include wildcard for compatibility -include_shell "cat external.conf 2>/dev/null" +# Add user chosen options held in (optional) external file +include "external*.conf" # default listening port for IPv6 falls back to the IPv4 port include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port - -# Prevent Lighttpd from enabling Let's Encrypt SSL for every blocked domain -#include_shell "/usr/share/lighttpd/include-conf-enabled.pl" -include_shell "find /etc/lighttpd/conf-enabled -name '*.conf' -a ! -name 'letsencrypt.conf' -printf 'include \"%p\"\n' 2>/dev/null" - -# If the URL starts with /admin, it is the Web interface -$HTTP["url"] =~ "^/admin/" { - # X-Pi-hole is a response header for debugging using curl -I - # X-Frame-Options prevents clickjacking attacks and helps ensure your content is not embedded into other sites via < frame >, < iframe > or < object >. - # X-XSS-Protection sets the configuration for the cross-site scripting filters built into most browsers. This is important because it tells the browser to block the response if a malicious script has been inserted from a user input. - # X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. This is important because the browser will only load external resources if their content-type matches what is expected, and not malicious hidden code. - # Content-Security-Policy tells the browser where resources are allowed to be loaded and if it’s allowed to parse/run inline styles or Javascript. This is important because it prevents content injection attacks, such as Cross Site Scripting (XSS). - # X-Permitted-Cross-Domain-Policies is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains. - # Referrer-Policy allows control/restriction of the amount of information present in the referral header for links away from your page—the URL path or even if the header is sent at all. - setenv.add-response-header = ( - "X-Pi-hole" => "The Pi-hole Web interface is working!", - "X-Frame-Options" => "DENY", - "X-XSS-Protection" => "1; mode=block", - "X-Content-Type-Options" => "nosniff", - "Content-Security-Policy" => "default-src 'self' 'unsafe-inline';", - "X-Permitted-Cross-Domain-Policies" => "none", - "Referrer-Policy" => "same-origin" - ) -} - -# Block . files from being served, such as .git, .github, .gitignore -$HTTP["url"] =~ "^/admin/\.(.*)" { - url.access-deny = ("") -} - -# allow teleporter and API qr code iframe on settings page -$HTTP["url"] =~ "/(teleporter|api_token)\.php$" { - $HTTP["referer"] =~ "/admin/settings\.php" { - setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" ) - } -} - -# Default expire header -expire.url = ( "" => "access plus 0 seconds" ) +include "/etc/lighttpd/conf-enabled/*.conf" diff --git a/advanced/lighttpd.conf.fedora b/advanced/lighttpd.conf.fedora index 3da62839..04f3ee01 100644 --- a/advanced/lighttpd.conf.fedora +++ b/advanced/lighttpd.conf.fedora @@ -27,7 +27,6 @@ server.modules = ( ) server.document-root = "/var/www/html" -server.error-handler-404 = "/pihole/index.php" server.upload-dirs = ( "/var/cache/lighttpd/uploads" ) server.errorlog = "/var/log/lighttpd/error-pihole.log" server.pid-file = "/run/lighttpd.pid" @@ -68,9 +67,8 @@ mimetype.assign = ( ".woff2" => "font/woff2" ) -# Add user chosen options held in external file -# This uses include_shell instead of an include wildcard for compatibility -include_shell "cat external.conf 2>/dev/null" +# Add user chosen options held in (optional) external file +include "external*.conf" # default listening port for IPv6 falls back to the IPv4 port #include_shell "/usr/share/lighttpd/use-ipv6.pl " + server.port @@ -86,37 +84,4 @@ fastcgi.server = ( ) ) -# If the URL starts with /admin, it is the Web interface -$HTTP["url"] =~ "^/admin/" { - # X-Pi-hole is a response header for debugging using curl -I - # X-Frame-Options prevents clickjacking attacks and helps ensure your content is not embedded into other sites via < frame >, < iframe > or < object >. - # X-XSS-Protection sets the configuration for the cross-site scripting filters built into most browsers. This is important because it tells the browser to block the response if a malicious script has been inserted from a user input. - # X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. This is important because the browser will only load external resources if their content-type matches what is expected, and not malicious hidden code. - # Content-Security-Policy tells the browser where resources are allowed to be loaded and if it’s allowed to parse/run inline styles or Javascript. This is important because it prevents content injection attacks, such as Cross Site Scripting (XSS). - # X-Permitted-Cross-Domain-Policies is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains. - # Referrer-Policy allows control/restriction of the amount of information present in the referral header for links away from your page—the URL path or even if the header is sent at all. - setenv.add-response-header = ( - "X-Pi-hole" => "The Pi-hole Web interface is working!", - "X-Frame-Options" => "DENY", - "X-XSS-Protection" => "1; mode=block", - "X-Content-Type-Options" => "nosniff", - "Content-Security-Policy" => "default-src 'self' 'unsafe-inline';", - "X-Permitted-Cross-Domain-Policies" => "none", - "Referrer-Policy" => "same-origin" - ) -} - -# Block . files from being served, such as .git, .github, .gitignore -$HTTP["url"] =~ "^/admin/\.(.*)" { - url.access-deny = ("") -} - -# allow teleporter and API qr code iframe on settings page -$HTTP["url"] =~ "/(teleporter|api_token)\.php$" { - $HTTP["referer"] =~ "/admin/settings\.php" { - setenv.add-response-header = ( "X-Frame-Options" => "SAMEORIGIN" ) - } -} - -# Default expire header -expire.url = ( "" => "access plus 0 seconds" ) +include "/etc/lighttpd/conf.d/pihole-admin.conf" diff --git a/advanced/pihole-admin.conf b/advanced/pihole-admin.conf new file mode 100644 index 00000000..2809d339 --- /dev/null +++ b/advanced/pihole-admin.conf @@ -0,0 +1,82 @@ +# Pi-hole: A black hole for Internet advertisements +# (c) 2017 Pi-hole, LLC (https://pi-hole.net) +# Network-wide ad blocking via your own hardware. +# +# Lighttpd config for Pi-hole +# +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. + +############################################################################### +# FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE INSTALL/UPDATE PROCEDURE. # +# ANY CHANGES MADE TO THIS FILE AFTER INSTALL WILL BE LOST ON THE NEXT UPDATE # +############################################################################### + +server.errorlog := "/var/log/lighttpd/error-pihole.log" + +$HTTP["url"] =~ "^/admin/" { + server.document-root = "/var/www/html" + server.stream-response-body = 1 + accesslog.filename = "/var/log/lighttpd/access-pihole.log" + accesslog.format = "%{%s}t|%h|%V|%r|%s|%b" + + fastcgi.server = ( + ".php" => ( + "localhost" => ( + "socket" => "/tmp/pihole-php-fastcgi.socket", + "bin-path" => "/usr/bin/php-cgi", + "min-procs" => 0, + "max-procs" => 1, + "bin-environment" => ( + "PHP_FCGI_CHILDREN" => "4", + "PHP_FCGI_MAX_REQUESTS" => "10000", + ), + "bin-copy-environment" => ( + "PATH", "SHELL", "USER" + ), + "broken-scriptfilename" => "enable", + ) + ) + ) + + # X-Pi-hole is a response header for debugging using curl -I + # X-Frame-Options prevents clickjacking attacks and helps ensure your content is not embedded into other sites via < frame >, < iframe > or < object >. + # X-XSS-Protection sets the configuration for the cross-site scripting filters built into most browsers. This is important because it tells the browser to block the response if a malicious script has been inserted from a user input. (deprecated; disabled) + # X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. This is important because the browser will only load external resources if their content-type matches what is expected, and not malicious hidden code. + # Content-Security-Policy tells the browser where resources are allowed to be loaded and if it’s allowed to parse/run inline styles or Javascript. This is important because it prevents content injection attacks, such as Cross Site Scripting (XSS). + # X-Permitted-Cross-Domain-Policies is an XML document that grants a web client, such as Adobe Flash Player or Adobe Acrobat (though not necessarily limited to these), permission to handle data across domains. + # Referrer-Policy allows control/restriction of the amount of information present in the referral header for links away from your page—the URL path or even if the header is sent at all. + setenv.add-response-header = ( + "X-Pi-hole" => "The Pi-hole Web interface is working!", + "X-Frame-Options" => "DENY", + "X-XSS-Protection" => "0", + "X-Content-Type-Options" => "nosniff", + "Content-Security-Policy" => "default-src 'self' 'unsafe-inline';", + "X-Permitted-Cross-Domain-Policies" => "none", + "Referrer-Policy" => "same-origin" + ) + + # Block . files from being served, such as .git, .github, .gitignore + $HTTP["url"] =~ "^/admin/\." { + url.access-deny = ("") + } + + # allow teleporter and API qr code iframe on settings page + $HTTP["url"] =~ "/(teleporter|api_token)\.php$" { + $HTTP["referer"] =~ "/admin/settings\.php" { + setenv.set-response-header = ( "X-Frame-Options" => "SAMEORIGIN" ) + } + } +} +else $HTTP["url"] == "/admin" { + url.redirect = ("" => "/admin/") +} + +$HTTP["host"] == "pi.hole" { + $HTTP["url"] == "/" { + url.redirect = ("" => "/admin/") + } +} + +# (keep this on one line for basic-install.sh filtering during install) +server.modules += ( "mod_access", "mod_redirect", "mod_fastcgi", "mod_setenv" ) diff --git a/automated install/basic-install.sh b/automated install/basic-install.sh index 841a04f4..cf27e3ac 100755 --- a/automated install/basic-install.sh +++ b/automated install/basic-install.sh @@ -82,7 +82,6 @@ PI_HOLE_FILES=(chronometer list piholeDebug piholeLogFlush setupLCD update versi PI_HOLE_INSTALL_DIR="/opt/pihole" PI_HOLE_CONFIG_DIR="/etc/pihole" PI_HOLE_BIN_DIR="/usr/local/bin" -PI_HOLE_404_DIR="${webroot}/pihole" FTL_CONFIG_FILE="${PI_HOLE_CONFIG_DIR}/pihole-FTL.conf" if [ -z "$useUpdateVars" ]; then useUpdateVars=false @@ -1380,37 +1379,80 @@ installConfigs() { fi fi - # Install pihole-FTL.service - install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.service" "/etc/init.d/pihole-FTL" + # Install pihole-FTL systemd or init.d service, based on whether systemd is the init system or not + # Follow debhelper logic, which checks for /run/systemd/system to derive whether systemd is the init system + if [[ -d '/run/systemd/system' ]]; then + install -T -m 0644 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.systemd" '/etc/systemd/system/pihole-FTL.service' + + # Remove init.d service if present + if [[ -e '/etc/init.d/pihole-FTL' ]]; then + rm '/etc/init.d/pihole-FTL' + update-rc.d pihole-FTL remove + fi + + # Load final service + systemctl daemon-reload + else + install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL.service" '/etc/init.d/pihole-FTL' + fi + install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL-prestart.sh" "${PI_HOLE_INSTALL_DIR}/pihole-FTL-prestart.sh" + install -T -m 0755 "${PI_HOLE_LOCAL_REPO}/advanced/Templates/pihole-FTL-poststop.sh" "${PI_HOLE_INSTALL_DIR}/pihole-FTL-poststop.sh" # If the user chose to install the dashboard, if [[ "${INSTALL_WEB_SERVER}" == true ]]; then - # and if the Web server conf directory does not exist, - if [[ ! -d "/etc/lighttpd" ]]; then - # make it and set the owners - install -d -m 755 -o "${USER}" -g root /etc/lighttpd - # Otherwise, if the config file already exists - elif [[ -f "${lighttpdConfig}" ]]; then - # back up the original - mv "${lighttpdConfig}"{,.orig} + if grep -q -F "FILE AUTOMATICALLY OVERWRITTEN BY PI-HOLE" "${lighttpdConfig}"; then + # Attempt to preserve backwards compatibility with older versions + install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}" + # Make the directories if they do not exist and set the owners + mkdir -p /run/lighttpd + chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /run/lighttpd + mkdir -p /var/cache/lighttpd/compress + chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress + mkdir -p /var/cache/lighttpd/uploads + chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads fi - # and copy in the config file Pi-hole needs - install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/${LIGHTTPD_CFG} "${lighttpdConfig}" - # Make sure the external.conf file exists, as lighttpd v1.4.50 crashes without it - if [ ! -f /etc/lighttpd/external.conf ]; then - install -m 644 /dev/null /etc/lighttpd/external.conf + # Copy the config file to include for pihole admin interface + if [[ -d "/etc/lighttpd/conf.d" ]]; then + install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/pihole-admin.conf /etc/lighttpd/conf.d/pihole-admin.conf + if grep -q -F 'include "/etc/lighttpd/conf.d/pihole-admin.conf"' "${lighttpdConfig}"; then + : + else + echo 'include "/etc/lighttpd/conf.d/pihole-admin.conf"' >> "${lighttpdConfig}" + fi + # Avoid some warnings trace from lighttpd, which might break tests + conf=/etc/lighttpd/conf.d/pihole-admin.conf + if lighttpd -f "${lighttpdConfig}" -tt 2>&1 | grep -q -F "WARNING: unknown config-key: dir-listing\."; then + echo '# Avoid some warnings trace from lighttpd, which might break tests' >> $conf + echo 'server.modules += ( "mod_dirlisting" )' >> $conf + fi + if lighttpd -f "${lighttpdConfig}" -tt 2>&1 | grep -q -F "warning: please use server.use-ipv6"; then + echo '# Avoid some warnings trace from lighttpd, which might break tests' >> $conf + echo 'server.use-ipv6 := "disable"' >> $conf + fi + elif [[ -d "/etc/lighttpd/conf-available" ]]; then + conf=/etc/lighttpd/conf-available/15-pihole-admin.conf + install -D -m 644 -T ${PI_HOLE_LOCAL_REPO}/advanced/pihole-admin.conf $conf + # disable server.modules += ( ... ) in $conf to avoid module dups + # (needed until Debian 10 no longer supported by pi-hole) + # (server.modules duplication is ignored in lighttpd 1.4.56+) + if awk '!/^server\.modules/{print}' $conf > $conf.$$ && mv $conf.$$ $conf; then + : + else + rm $conf.$$ + fi + chmod 644 $conf + if is_command lighty-enable-mod ; then + lighty-enable-mod pihole-admin access redirect fastcgi setenv > /dev/null || true + else + # Otherwise, show info about installing them + printf " %b Warning: 'lighty-enable-mod' utility not found\\n" "${INFO}" + printf " Please ensure fastcgi is enabled if you experience issues\\n" + fi + else + # lighttpd config include dir not found + printf " %b Warning: lighttpd config include dir not found\\n" "${INFO}" + printf " Please manually install pihole-admin.conf\\n" fi - # If there is a custom block page in the html/pihole directory, replace 404 handler in lighttpd config - if [[ -f "${PI_HOLE_404_DIR}/custom.php" ]]; then - sed -i 's/^\(server\.error-handler-404\s*=\s*\).*$/\1"\/pihole\/custom\.php"/' "${lighttpdConfig}" - fi - # Make the directories if they do not exist and set the owners - mkdir -p /run/lighttpd - chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /run/lighttpd - mkdir -p /var/cache/lighttpd/compress - chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/compress - mkdir -p /var/cache/lighttpd/uploads - chown ${LIGHTTPD_USER}:${LIGHTTPD_GROUP} /var/cache/lighttpd/uploads fi } @@ -1661,30 +1703,6 @@ install_dependent_packages() { # Install the Web interface dashboard installPiholeWeb() { - printf "\\n %b Installing 404 page...\\n" "${INFO}" - - local str="Creating directory for 404 page, and copying files" - printf " %b %s..." "${INFO}" "${str}" - # Install the directory - install -d -m 0755 ${PI_HOLE_404_DIR} - # and the 404 handler - install -D -m 644 ${PI_HOLE_LOCAL_REPO}/advanced/index.php ${PI_HOLE_404_DIR}/ - - printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" - - local str="Backing up index.lighttpd.html" - printf " %b %s..." "${INFO}" "${str}" - # If the default index file exists, - if [[ -f "${webroot}/index.lighttpd.html" ]]; then - # back it up - mv ${webroot}/index.lighttpd.html ${webroot}/index.lighttpd.orig - printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" - else - # Otherwise, don't do anything - printf "%b %b %s\\n" "${OVER}" "${INFO}" "${str}" - printf " No default index.lighttpd.html file found... not backing up\\n" - fi - # Install Sudoers file local str="Installing sudoer file" printf "\\n %b %s..." "${INFO}" "${str}" @@ -1760,20 +1778,35 @@ create_pihole_user() { else # If the pihole user doesn't exist, printf "%b %b %s" "${OVER}" "${CROSS}" "${str}" - local str="Creating user 'pihole'" - printf "%b %b %s..." "${OVER}" "${INFO}" "${str}" - # create her with the useradd command, + local str="Checking for group 'pihole'" + printf " %b %s..." "${INFO}" "${str}" if getent group pihole > /dev/null 2>&1; then - # then add her to the pihole group (as it already exists) + # group pihole exists + printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" + # then create and add her to the pihole group + local str="Creating user 'pihole'" + printf "%b %b %s..." "${OVER}" "${INFO}" "${str}" if useradd -r --no-user-group -g pihole -s /usr/sbin/nologin pihole; then printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" else printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" fi else - # add user pihole with default group settings - if useradd -r -s /usr/sbin/nologin pihole; then + # group pihole does not exist + printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" + local str="Creating group 'pihole'" + # if group can be created + if groupadd pihole; then printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" + # create and add pihole user to the pihole group + local str="Creating user 'pihole'" + printf "%b %b %s..." "${OVER}" "${INFO}" "${str}" + if useradd -r --no-user-group -g pihole -s /usr/sbin/nologin pihole; then + printf "%b %b %s\\n" "${OVER}" "${TICK}" "${str}" + else + printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" + fi + else printf "%b %b %s\\n" "${OVER}" "${CROSS}" "${str}" fi @@ -1872,15 +1905,6 @@ installPihole() { # Give lighttpd access to the pihole group so the web interface can # manage the gravity.db database usermod -a -G pihole ${LIGHTTPD_USER} - # If the lighttpd command is executable, - if is_command lighty-enable-mod ; then - # enable fastcgi and fastcgi-php - lighty-enable-mod fastcgi fastcgi-php > /dev/null || true - else - # Otherwise, show info about installing them - printf " %b Warning: 'lighty-enable-mod' utility not found\\n" "${INFO}" - printf " Please ensure fastcgi is enabled if you experience issues\\n" - fi fi fi # Install base files and web interface @@ -2693,12 +2717,12 @@ main() { restart_service pihole-FTL - # Download and compile the aggregated block list - runGravity - # Update local and remote versions via updatechecker /opt/pihole/updatecheck.sh + # Download and compile the aggregated block list + runGravity + if [[ "${useUpdateVars}" == false ]]; then displayFinalMessage "${pw}" fi diff --git a/automated install/uninstall.sh b/automated install/uninstall.sh index 0b516d0f..c36027fc 100755 --- a/automated install/uninstall.sh +++ b/automated install/uninstall.sh @@ -131,6 +131,7 @@ removeNoPurge() { fi if package_check lighttpd > /dev/null; then + # Attempt to preserve backwards compatibility with older versions if [[ -f /etc/lighttpd/lighttpd.conf.orig ]]; then ${SUDO} mv /etc/lighttpd/lighttpd.conf.orig /etc/lighttpd/lighttpd.conf fi @@ -139,6 +140,29 @@ removeNoPurge() { ${SUDO} rm /etc/lighttpd/external.conf fi + # Fedora-based + if [[ -f /etc/lighttpd/conf.d/pihole-admin.conf ]]; then + ${SUDO} rm /etc/lighttpd/conf.d/pihole-admin.conf + conf=/etc/lighttpd/lighttpd.conf + tconf=/tmp/lighttpd.conf.$$ + if awk '!/^include "\/etc\/lighttpd\/conf\.d\/pihole-admin\.conf"$/{print}' \ + $conf > $tconf && mv $tconf $conf; then + : + else + rm $tconf + fi + ${SUDO} chown root:root $conf + ${SUDO} chmod 644 $conf + fi + + # Debian-based + if [[ -f /etc/lighttpd/conf-available/pihole-admin.conf ]]; then + if is_command lighty-disable-mod ; then + ${SUDO} lighty-disable-mod pihole-admin > /dev/null || true + fi + ${SUDO} rm /etc/lighttpd/conf-available/15-pihole-admin.conf + fi + echo -e " ${TICK} Removed lighttpd configs" fi diff --git a/gravity.sh b/gravity.sh index 14732f31..a5c944ce 100755 --- a/gravity.sh +++ b/gravity.sh @@ -524,15 +524,20 @@ num_target_lines=0 num_source_lines=0 num_invalid=0 parseList() { - local adlistID="${1}" src="${2}" target="${3}" incorrect_lines + local adlistID="${1}" src="${2}" target="${3}" incorrect_lines sample_incorrect_lines # This sed does the following things: - # 1. Remove all domains containing invalid characters. Valid are: a-z, A-Z, 0-9, dot (.), minus (-), underscore (_) - # 2. Append ,adlistID to every line - # 3. Remove trailing period (see https://github.com/pi-hole/pi-hole/issues/4701) - # 4. Ensures there is a newline on the last line - sed -e "/[^a-zA-Z0-9.\_-]/d;s/\.$//;s/$/,${adlistID}/;/.$/a\\" "${src}" >> "${target}" - # Find (up to) five domains containing invalid characters (see above) - incorrect_lines="$(sed -e "/[^a-zA-Z0-9.\_-]/!d" "${src}" | head -n 5)" + # 1. Remove all lines containing no domains + # 2. Remove all domains containing invalid characters. Valid are: a-z, A-Z, 0-9, dot (.), minus (-), underscore (_) + # 3. Append ,adlistID to every line + # 4. Remove trailing period (see https://github.com/pi-hole/pi-hole/issues/4701) + # 5. Ensures there is a newline on the last line + sed -r "/([^\.]+\.)+[^\.]{2,}/!d;/[^a-zA-Z0-9.\_-]/d;s/\.$//;s/$/,${adlistID}/;/.$/a\\" "${src}" >> "${target}" + + # Find lines containing no domains or with invalid characters (see above) + # Remove duplicates and limit to 5 domains + mapfile -t incorrect_lines <<< "$(sed -r "/([^\.]+\.)+[^\.]{2,}/d" < "${src}")" + mapfile -t -O "${#incorrect_lines[@]}" incorrect_lines <<< "$(sed -r "/[^a-zA-Z0-9.\_-]/!d" < "${src}")" + IFS=" " read -r -a sample_incorrect_lines <<< "$(tr ' ' '\n' <<< "${incorrect_lines[@]}" | sort -u | head -n 5| tr '\n' ' ')" local num_target_lines_new num_correct_lines # Get number of lines in source file @@ -551,11 +556,12 @@ parseList() { fi # Display sample of invalid lines if we found some - if [[ -n "${incorrect_lines}" ]]; then + if [ ${#sample_incorrect_lines[@]} -ne 0 ]; then echo " Sample of invalid domains:" - while IFS= read -r line; do - echo " - ${line}" - done <<< "${incorrect_lines}" + for each in "${sample_incorrect_lines[@]}" + do + echo " - ${each}" + done fi } compareLists() { @@ -731,13 +737,13 @@ gravity_ParseFileIntoDomains() { # 3) Remove comments (text starting with "#", include possible spaces before the hash sign) # 4) Remove lines containing "/" # 5) Remove leading tabs, spaces, etc. - # 6) Delete lines not matching domain names + # 6) Remove empty lines < "${src}" tr -d '\r' | \ tr '[:upper:]' '[:lower:]' | \ sed 's/\s*#.*//g' | \ sed -r '/(\/).*$/d' | \ sed -r 's/^.*\s+//g' | \ - sed -r '/([^\.]+\.)+[^\.]{2,}/!d' > "${destination}" + sed '/^$/d'> "${destination}" chmod 644 "${destination}" } diff --git a/manpages/pihole.8 b/manpages/pihole.8 index 11c21b28..1cf8ab35 100644 --- a/manpages/pihole.8 +++ b/manpages/pihole.8 @@ -23,7 +23,7 @@ Pi-hole : A black-hole for internet advertisements .br pihole -r .br -pihole -t +\fBpihole\fR \fB-t\fR [arg] .br pihole -g\fR .br @@ -113,11 +113,15 @@ Available commands and options: Reconfigure or Repair Pi-hole subsystems .br -\fB-t, tail\fR +\fB-t, tail\fR [arg] .br View the live output of the Pi-hole log .br + [arg] Optional argument to filter the log for + (regular expressions are supported) +.br + \fB-a, admin\fR [options] .br diff --git a/pihole b/pihole index ca80bff8..a99a37e7 100755 --- a/pihole +++ b/pihole @@ -23,6 +23,9 @@ source "${colfile}" utilsfile="${PI_HOLE_SCRIPT_DIR}/utils.sh" source "${utilsfile}" +versionsfile="/etc/pihole/versions" +source "${versionsfile}" + webpageFunc() { source "${PI_HOLE_SCRIPT_DIR}/webpage.sh" main "$@" @@ -63,14 +66,22 @@ arpFunc() { } updatePiholeFunc() { - shift - "${PI_HOLE_SCRIPT_DIR}"/update.sh "$@" - exit 0 + if [ -n "${DOCKER_VERSION}" ]; then + unsupportedFunc + else + shift + "${PI_HOLE_SCRIPT_DIR}"/update.sh "$@" + exit 0 + fi } reconfigurePiholeFunc() { - /etc/.pihole/automated\ install/basic-install.sh --reconfigure - exit 0; + if [ -n "${DOCKER_VERSION}" ]; then + unsupportedFunc + else + /etc/.pihole/automated\ install/basic-install.sh --reconfigure + exit 0; + fi } updateGravityFunc() { @@ -91,8 +102,12 @@ chronometerFunc() { uninstallFunc() { - "${PI_HOLE_SCRIPT_DIR}"/uninstall.sh - exit 0 + if [ -n "${DOCKER_VERSION}" ]; then + unsupportedFunc + else + "${PI_HOLE_SCRIPT_DIR}"/uninstall.sh + exit 0 + fi } versionFunc() { @@ -429,6 +444,11 @@ updateCheckFunc() { exit 0 } +unsupportedFunc(){ + echo "Function not supported in Docker images" + exit 0 +} + helpFunc() { echo "Usage: pihole [options] Example: 'pihole -w -h' diff --git a/test/_fedora_37.Dockerfile b/test/_fedora_37.Dockerfile new file mode 100644 index 00000000..b4f939ba --- /dev/null +++ b/test/_fedora_37.Dockerfile @@ -0,0 +1,18 @@ +FROM fedora:37 +RUN dnf install -y git initscripts + +ENV GITDIR /etc/.pihole +ENV SCRIPTDIR /opt/pihole + +RUN mkdir -p $GITDIR $SCRIPTDIR /etc/pihole +ADD . $GITDIR +RUN cp $GITDIR/advanced/Scripts/*.sh $GITDIR/gravity.sh $GITDIR/pihole $GITDIR/automated\ install/*.sh $SCRIPTDIR/ +ENV PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$SCRIPTDIR + +RUN true && \ + chmod +x $SCRIPTDIR/* + +ENV SKIP_INSTALL true +ENV OS_CHECK_DOMAIN_NAME dev-supportedos.pi-hole.net + +#sed '/# Start the installer/Q' /opt/pihole/basic-install.sh > /opt/pihole/stub_basic-install.sh && \ diff --git a/test/requirements.txt b/test/requirements.txt index 0eb22a1b..e891242c 100644 --- a/test/requirements.txt +++ b/test/requirements.txt @@ -1,5 +1,6 @@ -docker-compose -pytest -pytest-xdist -pytest-testinfra -tox +docker-compose == 1.29.2 +pytest == 7.2.1 +pytest-xdist == 3.1.0 +pytest-testinfra == 7.0.0 +tox == 4.2.8 + diff --git a/test/test_any_automated_install.py b/test/test_any_automated_install.py index e6673bb5..c1288287 100644 --- a/test/test_any_automated_install.py +++ b/test/test_any_automated_install.py @@ -129,34 +129,16 @@ def test_installPiholeWeb_fresh_install_no_errors(host): installPiholeWeb """ ) - expected_stdout = info_box + " Installing 404 page..." - assert expected_stdout in installWeb.stdout - expected_stdout = tick_box + ( - " Creating directory for 404 page, " "and copying files" - ) - assert expected_stdout in installWeb.stdout - expected_stdout = info_box + " Backing up index.lighttpd.html" - assert expected_stdout in installWeb.stdout - expected_stdout = "No default index.lighttpd.html file found... " "not backing up" - assert expected_stdout in installWeb.stdout expected_stdout = tick_box + " Installing sudoer file" assert expected_stdout in installWeb.stdout - web_directory = host.run("ls -r /var/www/html/pihole").stdout - assert "index.php" in web_directory def get_directories_recursive(host, directory): if directory is None: return directory - ls = host.run("ls -d {}".format(directory + "/*/")) - directories = list(filter(bool, ls.stdout.splitlines())) - dirs = directories - for dirval in directories: - dir_rec = get_directories_recursive(host, dirval) - if isinstance(dir_rec, str): - dirs.extend([dir_rec]) - else: - dirs.extend(dir_rec) + # returns all non-hidden subdirs of 'directory' + dirs_raw = host.run("find {} -type d -not -path '*/.*'".format(directory)) + dirs = list(filter(bool, dirs_raw.stdout.splitlines())) return dirs @@ -211,6 +193,8 @@ def test_installPihole_fresh_install_readableFiles(host): maninstalled = True if (info_box + " man not installed") in install.stdout: maninstalled = False + if (info_box + " man pages not installed") in install.stdout: + maninstalled = False piholeuser = "pihole" exit_status_success = 0 test_cmd = 'su --shell /bin/bash --command "test -{0} {1}" -p {2}' @@ -287,6 +271,24 @@ def test_installPihole_fresh_install_readableFiles(host): check_lighttpd = test_cmd.format("r", "/etc/lighttpd/lighttpd.conf", piholeuser) actual_rc = host.run(check_lighttpd).rc assert exit_status_success == actual_rc + # check readable /etc/lighttpd/conf*/pihole-admin.conf + check_lighttpd = test_cmd.format("r", "/etc/lighttpd/conf.d", piholeuser) + if host.run(check_lighttpd).rc == exit_status_success: + check_lighttpd = test_cmd.format( + "r", "/etc/lighttpd/conf.d/pihole-admin.conf", piholeuser + ) + actual_rc = host.run(check_lighttpd).rc + assert exit_status_success == actual_rc + else: + check_lighttpd = test_cmd.format( + "r", "/etc/lighttpd/conf-available", piholeuser + ) + if host.run(check_lighttpd).rc == exit_status_success: + check_lighttpd = test_cmd.format( + "r", "/etc/lighttpd/conf-available/15-pihole-admin.conf", piholeuser + ) + actual_rc = host.run(check_lighttpd).rc + assert exit_status_success == actual_rc # check readable and executable manpages if maninstalled is True: check_man = test_cmd.format("x", "/usr/local/share/man", piholeuser) @@ -396,7 +398,7 @@ def test_installPihole_fresh_install_readableBlockpage(host, test_webpage): usergroup="${{LIGHTTPD_USER}}:${{LIGHTTPD_GROUP}}", chmodarg="{{}}", config="/etc/lighttpd/lighttpd.conf", - run="/var/run/lighttpd", + run="/run/lighttpd", cache="/var/cache/lighttpd", uploads="/var/cache/lighttpd/uploads", compress="/var/cache/lighttpd/compress", @@ -512,7 +514,7 @@ def test_installPihole_fresh_install_readableBlockpage(host, test_webpage): check_admin = test_cmd.format("x", webroot + "/admin", webuser) actual_rc = host.run(check_admin).rc assert exit_status_success == actual_rc - directories = get_directories_recursive(host, webroot + "/admin/*/") + directories = get_directories_recursive(host, webroot + "/admin/") for directory in directories: check_pihole = test_cmd.format("r", directory, webuser) actual_rc = host.run(check_pihole).rc @@ -536,16 +538,6 @@ def test_installPihole_fresh_install_readableBlockpage(host, test_webpage): return bool(m) if installWebInterface is True: - check_pihole = test_cmd.format("r", webroot + "/pihole", webuser) - actual_rc = host.run(check_pihole).rc - assert exit_status_success == actual_rc - check_pihole = test_cmd.format("x", webroot + "/pihole", webuser) - actual_rc = host.run(check_pihole).rc - assert exit_status_success == actual_rc - # check most important files in $webroot for read permission - check_index = test_cmd.format("r", webroot + "/pihole/index.php", webuser) - actual_rc = host.run(check_index).rc - assert exit_status_success == actual_rc if test_webpage is True: # check webpage for unreadable files noPHPfopen = re.compile( diff --git a/test/tox.centos_8.ini b/test/tox.centos_8.ini index dc160d2a..dac10e97 100644 --- a/test/tox.centos_8.ini +++ b/test/tox.centos_8.ini @@ -1,8 +1,8 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt -commands = docker build -f _centos_8.Dockerfile -t pytest_pihole:test_container ../ - pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py +commands = docker build -f _centos_8.Dockerfile -t pytest_pihole:test_container ../ + pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_centos_common_support.py diff --git a/test/tox.centos_9.ini b/test/tox.centos_9.ini index 633fc5c4..aa7009e1 100644 --- a/test/tox.centos_9.ini +++ b/test/tox.centos_9.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _centos_9.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.debian_10.ini b/test/tox.debian_10.ini index ef9fa7a0..a012bda4 100644 --- a/test/tox.debian_10.ini +++ b/test/tox.debian_10.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _debian_10.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.debian_11.ini b/test/tox.debian_11.ini index 6d25a0c8..48dc9df1 100644 --- a/test/tox.debian_11.ini +++ b/test/tox.debian_11.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _debian_11.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.fedora_35.ini b/test/tox.fedora_35.ini index 5e90426d..c571a564 100644 --- a/test/tox.fedora_35.ini +++ b/test/tox.fedora_35.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _fedora_35.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.fedora_36.ini b/test/tox.fedora_36.ini index 1d250f82..0cc6f29c 100644 --- a/test/tox.fedora_36.ini +++ b/test/tox.fedora_36.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _fedora_36.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.fedora_37.ini b/test/tox.fedora_37.ini new file mode 100644 index 00000000..d6f44533 --- /dev/null +++ b/test/tox.fedora_37.ini @@ -0,0 +1,8 @@ +[tox] +envlist = py3 + +[testenv] +allowlist_externals = docker +deps = -rrequirements.txt +commands = docker build -f _fedora_37.Dockerfile -t pytest_pihole:test_container ../ + pytest {posargs:-vv -n auto} ./test_any_automated_install.py ./test_any_utils.py ./test_centos_fedora_common_support.py ./test_fedora_support.py diff --git a/test/tox.ubuntu_20.ini b/test/tox.ubuntu_20.ini index 4ae79a0c..88ee0b54 100644 --- a/test/tox.ubuntu_20.ini +++ b/test/tox.ubuntu_20.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _ubuntu_20.Dockerfile -t pytest_pihole:test_container ../ diff --git a/test/tox.ubuntu_22.ini b/test/tox.ubuntu_22.ini index 3ddf7eca..cb5527ab 100644 --- a/test/tox.ubuntu_22.ini +++ b/test/tox.ubuntu_22.ini @@ -1,7 +1,7 @@ [tox] envlist = py3 -[testenv] +[testenv:py3] allowlist_externals = docker deps = -rrequirements.txt commands = docker build -f _ubuntu_22.Dockerfile -t pytest_pihole:test_container ../