diff --git a/.pullapprove.yml b/.pullapprove.yml index f9d10062..ff970b29 100644 --- a/.pullapprove.yml +++ b/.pullapprove.yml @@ -33,6 +33,6 @@ groups: conditions: branches: - master - required: -1 + required: 4 teams: - admin diff --git a/advanced/Scripts/list.sh b/advanced/Scripts/list.sh index 90d1b7f0..537ebac3 100755 --- a/advanced/Scripts/list.sh +++ b/advanced/Scripts/list.sh @@ -84,6 +84,9 @@ PoplistFile() { if ${addmode}; then AddDomain "${dom}" "${listMain}" RemoveDomain "${dom}" "${listAlt}" + if [[ "${listMain}" == "${whitelist}" || "${listMain}" == "${blacklist}" ]]; then + RemoveDomain "${dom}" "${wildcardlist}" + fi else RemoveDomain "${dom}" "${listMain}" fi diff --git a/advanced/Scripts/piholeCheckout.sh b/advanced/Scripts/piholeCheckout.sh new file mode 100644 index 00000000..3b7abbef --- /dev/null +++ b/advanced/Scripts/piholeCheckout.sh @@ -0,0 +1,202 @@ +#!/usr/bin/env bash +# 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. +# +# Checkout other branches than master +# +# This file is copyright under the latest version of the EUPL. +# Please see LICENSE file for your rights under this license. + +readonly PI_HOLE_FILES_DIR="/etc/.pihole" +PH_TEST="true" source "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" + +# webInterfaceGitUrl set in basic-install.sh +# webInterfaceDir set in basic-install.sh +# piholeGitURL set in basic-install.sh +# is_repo() sourced from basic-install.sh +# setupVars set in basic-install.sh + +source "${setupVars}" + +update="false" + +fully_fetch_repo() { + # Add upstream branches to shallow clone + local directory="${1}" + + cd "${directory}" || return 1 + if is_repo "${directory}"; then + git remote set-branches origin '*' || return 1 + git fetch --quiet || return 1 + else + return 1 + fi + return 0 +} + +get_available_branches(){ + # Return available branches + local directory="${1}" + + cd "${directory}" || return 1 + # Get reachable remote branches + git remote show origin | grep 'tracked' | sed 's/tracked//;s/ //g' + return +} + + +fetch_checkout_pull_branch() { + # Check out specified branch + local directory="${1}" + local branch="${2}" + + # Set the reference for the requested branch, fetch, check it put and pull it + cd "${directory}" + git remote set-branches origin "${branch}" || return 1 + git fetch --quiet || return 1 + checkout_pull_branch "${directory}" "${branch}" || return 1 +} + +checkout_pull_branch() { + # Check out specified branch + local directory="${1}" + local branch="${2}" + local oldbranch + + cd "${directory}" || return 1 + + oldbranch="$(git symbolic-ref HEAD)" + + git checkout "${branch}" || return 1 + + if [ "$(git diff "${oldbranch}" | grep -c "^")" -gt "0" ]; then + update="true" + fi + + git pull || return 1 + return 0 +} + +warning1() { + echo "::: Note that changing the branch is a severe change of your Pi-hole system." + echo "::: This is not supported unless one of the developers explicitly asks you to do this!" + read -r -p "::: Have you read and understood this? [y/N] " response + case ${response} in + [yY][eE][sS]|[yY]) + echo "::: Continuing." + return 0 + ;; + *) + echo "::: Aborting." + return 1 + ;; + esac +} + +checkout() +{ + local corebranches + local webbranches + + # Avoid globbing + set -f + + #This is unlikely + if ! is_repo "${PI_HOLE_FILES_DIR}" ; then + echo "::: Critical Error: Core Pi-Hole repo is missing from system!" + echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + exit 1; + fi + if [[ ${INSTALL_WEB} == "true" ]]; then + if ! is_repo "${webInterfaceDir}" ; then + echo "::: Critical Error: Web Admin repo is missing from system!" + echo "::: Please re-run install script from https://github.com/pi-hole/pi-hole" + exit 1; + fi + fi + + if [[ -z "${1}" ]]; then + echo "::: No option detected. Please use 'pihole checkout '." + echo "::: Or enter the repository and branch you would like to check out:" + echo "::: 'pihole checkout '" + exit 1 + fi + + if ! warning1 ; then + exit 1 + fi + + if [[ "${1}" == "dev" ]] ; then + # Shortcut to check out development branches + echo "::: Shortcut \"dev\" detected - checking out development / devel branches ..." + echo "::: Pi-hole core" + fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "development" || { echo "Unable to pull Core developement branch"; exit 1; } + if [[ ${INSTALL_WEB} == "true" ]]; then + echo "::: Web interface" + fetch_checkout_pull_branch "${webInterfaceDir}" "devel" || { echo "Unable to pull Web development branch"; exit 1; } + fi + echo "::: done!" + elif [[ "${1}" == "master" ]] ; then + # Shortcut to check out master branches + echo "::: Shortcut \"master\" detected - checking out master branches ..." + echo "::: Pi-hole core" + fetch_checkout_pull_branch "${PI_HOLE_FILES_DIR}" "master" || { echo "Unable to pull Core master branch"; exit 1; } + if [[ ${INSTALL_WEB} == "true" ]]; then + echo "::: Web interface" + fetch_checkout_pull_branch "${webInterfaceDir}" "master" || { echo "Unable to pull web master branch"; exit 1; } + fi + echo "::: done!" + elif [[ "${1}" == "core" ]] ; then + echo -n "::: Fetching remote branches for Pi-hole core from ${piholeGitUrl} ... " + if ! fully_fetch_repo "${PI_HOLE_FILES_DIR}" ; then + echo "::: Fetching all branches for Pi-hole core repo failed!" + exit 1 + fi + corebranches=($(get_available_branches "${PI_HOLE_FILES_DIR}")) + echo " done!" + echo "::: ${#corebranches[@]} branches available" + echo ":::" + # Have to user chosing the branch he wants + if ! (for e in "${corebranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then + echo "::: Requested branch \"${2}\" is not available!" + echo "::: Available branches for core are:" + for e in "${corebranches[@]}"; do echo "::: $e"; done + exit 1 + fi + checkout_pull_branch "${PI_HOLE_FILES_DIR}" "${2}" + elif [[ "${1}" == "web" && "${INSTALL_WEB}" == "true" ]] ; then + echo -n "::: Fetching remote branches for the web interface from ${webInterfaceGitUrl} ... " + if ! fully_fetch_repo "${webInterfaceDir}" ; then + echo "::: Fetching all branches for Pi-hole web interface repo failed!" + exit 1 + fi + webbranches=($(get_available_branches "${webInterfaceDir}")) + echo " done!" + echo "::: ${#webbranches[@]} branches available" + echo ":::" + # Have to user chosing the branch he wants + if ! (for e in "${webbranches[@]}"; do [[ "$e" == "${2}" ]] && exit 0; done); then + echo "::: Requested branch \"${2}\" is not available!" + echo "::: Available branches for web are:" + for e in "${webbranches[@]}"; do echo "::: $e"; done + exit 1 + fi + checkout_pull_branch "${webInterfaceDir}" "${2}" + else + echo "::: Requested option \"${1}\" is not available!" + exit 1 + fi + + # Force updating everything + if [[ ! "${1}" == "web" && "${update}" == "true" ]]; then + echo "::: Running installer to upgrade your installation" + if "${PI_HOLE_FILES_DIR}/automated install/basic-install.sh" --unattended; then + exit 0 + else + echo "Unable to complete update, contact Pi-hole" + exit 1 + fi + fi +} + diff --git a/advanced/Scripts/piholeDebug.sh b/advanced/Scripts/piholeDebug.sh index 70d73379..0b8a2571 100755 --- a/advanced/Scripts/piholeDebug.sh +++ b/advanced/Scripts/piholeDebug.sh @@ -24,6 +24,8 @@ WHITELISTFILE="/etc/pihole/whitelist.txt" BLACKLISTFILE="/etc/pihole/blacklist.txt" ADLISTFILE="/etc/pihole/adlists.list" PIHOLELOG="/var/log/pihole.log" +PIHOLEGITDIR="/etc/.pihole/" +ADMINGITDIR="/var/www/html/admin/" WHITELISTMATCHES="/tmp/whitelistmatches.list" TIMEOUT=60 @@ -111,22 +113,61 @@ version_check() { header_write "Detecting Installed Package Versions:" local error_found + local pi_hole_ver + local pi_hole_branch + local pi_hole_commit + local admin_ver + local admin_branch + local admin_commit + local light_ver + local php_ver + local status error_found=0 - local pi_hole_ver="$(cd /etc/.pihole/ && git describe --tags --abbrev=0)" \ - && log_echo -r "Pi-hole: $pi_hole_ver" || (log_echo "Pi-hole git repository not detected." && error_found=1) - local admin_ver="$(cd /var/www/html/admin && git describe --tags --abbrev=0)" \ - && log_echo -r "WebUI: $admin_ver" || (log_echo "Pi-hole Admin Pages git repository not detected." && error_found=1) - local light_ver="$(lighttpd -v |& head -n1 | cut -d " " -f1)" \ - && log_echo -r "${light_ver}" || (log_echo "lighttpd not installed." && error_found=1) - local php_ver="$(php -v |& head -n1)" \ - && log_echo -r "${php_ver}" || (log_echo "PHP not installed." && error_found=1) + cd "${PIHOLEGITDIR}" &> /dev/null || \ + { status="Pi-hole git directory not found."; error_found=1; } + if git status &> /dev/null; then + pi_hole_ver=$(git describe --tags --abbrev=0) + pi_hole_branch=$(git rev-parse --abbrev-ref HEAD) + pi_hole_commit=$(git describe --long --dirty --tags --always) + log_echo -r "Pi-hole: ${pi_hole_ver:-Untagged} (${pi_hole_branch:-Detached}:${pi_hole_commit})" + else + status=${status:-"Pi-hole repository damaged."} + error_found=1 + fi + if [[ "${status}" ]]; then + log_echo "${status}" + unset status + fi - (local pi_hole_branch="$(cd /etc/.pihole/ && git rev-parse --abbrev-ref HEAD)" && log_echo -r "Pi-hole branch: ${pi_hole_branch}") || log_echo "Unable to obtain Pi-hole branch" - (local pi_hole_rev="$(cd /etc/.pihole/ && git describe --long --dirty --tags)" && log_echo -r "Pi-hole rev: ${pi_hole_rev}") || log_echo "Unable to obtain Pi-hole revision" + cd "${ADMINGITDIR}" || \ + { status="Pi-hole Dashboard git directory not found."; error_found=1; } + if git status &> /dev/null; then + admin_ver=$(git describe --tags --abbrev=0) + admin_branch=$(git rev-parse --abbrev-ref HEAD) + admin_commit=$(git describe --long --dirty --tags --always) + log_echo -r "Pi-hole Dashboard: ${admin_ver:-Untagged} (${admin_branch:-Detached}:${admin_commit})" + else + status=${status:-"Pi-hole Dashboard repository damaged."} + error_found=1 + fi + if [[ "${status}" ]]; then + log_echo "${status}" + unset status + fi - (local admin_branch="$(cd /var/www/html/admin && git rev-parse --abbrev-ref HEAD)" && log_echo -r "AdminLTE branch: ${admin_branch}") || log_echo "Unable to obtain AdminLTE branch" - (local admin_rev="$(cd /var/www/html/admin && git describe --long --dirty --tags)" && log_echo -r "AdminLTE rev: ${admin_rev}") || log_echo "Unable to obtain AdminLTE revision" + if light_ver=$(lighttpd -v |& head -n1 | cut -d " " -f1); then + log_echo -r "${light_ver}" + else + log_echo "lighttpd not installed." + error_found=1 + fi + if php_ver=$(php -v |& head -n1); then + log_echo -r "${php_ver}" + else + log_echo "PHP not installed." + error_found=1 + fi return "${error_found}" } diff --git a/advanced/Scripts/version.sh b/advanced/Scripts/version.sh index 11a7af00..7f96e29a 100755 --- a/advanced/Scripts/version.sh +++ b/advanced/Scripts/version.sh @@ -8,67 +8,104 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. - - -# Flags: -latest=false -current=false - +# Variables DEFAULT="-1" +PHGITDIR="/etc/.pihole/" +WEBGITDIR="/var/www/html/admin/" + +getLocalVersion() { + # Get the tagged version of the local repository + local directory="${1}" + local version + + cd "${directory}" || { echo "${DEFAULT}"; return 1; } + version=$(git describe --tags --always || \ + echo "${DEFAULT}") + if [[ "${version}" =~ ^v ]]; then + echo "${version}" + elif [[ "${version}" == "${DEFAULT}" ]]; then + echo "ERROR" + return 1 + else + echo "Untagged" + fi + return 0 +} + +getLocalHash() { + # Get the short hash of the local repository + local directory="${1}" + local hash + + cd "${directory}" || { echo "${DEFAULT}"; return 1; } + hash=$(git rev-parse --short HEAD || \ + echo "${DEFAULT}") + if [[ "${hash}" == "${DEFAULT}" ]]; then + echo "ERROR" + return 1 + else + echo "${hash}" + fi + return 0 +} + +getRemoteVersion(){ + # Get the version from the remote origin + local daemon="${1}" + local version + + version=$(curl --silent --fail https://api.github.com/repos/pi-hole/${daemon}/releases/latest | \ + awk -F: '$1 ~/tag_name/ { print $2 }' | \ + tr -cd '[[:alnum:]]._-') + if [[ "${version}" =~ ^v ]]; then + echo "${version}" + else + echo "ERROR" + return 1 + fi + return 0 +} + +#PHHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/commits/master | \ +# grep sha | \ +# head -n1 | \ +# awk -F ' ' '{ print $2 }' | \ +# tr -cd '[[:alnum:]]._-') + +#WEBHASHLATEST=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/commits/master | \ +# grep sha | \ +# head -n1 | \ +# awk -F ' ' '{ print $2 }' | \ +# tr -cd '[[:alnum:]]._-') + normalOutput() { - piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0) - webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0) - - piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - - echo "::: Pi-hole version is ${piholeVersion} (Latest version is ${piholeVersionLatest:-${DEFAULT}})" - echo "::: Web-Admin version is ${webVersion} (Latest version is ${webVersionLatest:-${DEFAULT}})" + echo "::: Pi-hole version is $(getLocalVersion "${PHGITDIR}") (Latest version is $(getRemoteVersion pi-hole))" + if [ -d "${WEBGITDIR}" ]; then + echo "::: Web-Admin version is $(getLocalVersion "${WEBGITDIR}") (Latest version is $(getRemoteVersion AdminLTE))" + fi } webOutput() { - for var in "$@"; do - case "${var}" in - "-l" | "--latest" ) latest=true;; - "-c" | "--current" ) current=true;; - * ) echo "::: Invalid Option!"; exit 1; - esac - done - - if [[ "${latest}" == true && "${current}" == false ]]; then - webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - echo "${webVersionLatest:--1}" - elif [[ "${latest}" == false && "${current}" == true ]]; then - webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0) - echo "${webVersion}" - else - webVersion=$(cd /var/www/html/admin/ && git describe --tags --abbrev=0) - webVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/AdminLTE/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - echo "::: Web-Admin version is ${webVersion} (Latest version is ${webVersionLatest:-${DEFAULT}})" - fi + if [ -d "${WEBGITDIR}" ]; then + case "${1}" in + "-l" | "--latest" ) echo $(getRemoteVersion AdminLTE);; + "-c" | "--current" ) echo $(getLocalVersion "${WEBGITDIR}");; + "-h" | "--hash" ) echo $(getLocalHash "${WEBGITDIR}");; + * ) echo "::: Invalid Option!"; exit 1; + esac + else + echo "::: Web interface not installed!"; exit 1; + fi } coreOutput() { - for var in "$@"; do - case "${var}" in - "-l" | "--latest" ) latest=true;; - "-c" | "--current" ) current=true;; - * ) echo "::: Invalid Option!"; exit 1; - esac - done - - if [[ "${latest}" == true && "${current}" == false ]]; then - piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - echo "${piholeVersionLatest:--1}" - elif [[ "${latest}" == false && "${current}" == true ]]; then - piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0) - echo "${piholeVersion}" - else - piholeVersion=$(cd /etc/.pihole/ && git describe --tags --abbrev=0) - piholeVersionLatest=$(curl -s https://api.github.com/repos/pi-hole/pi-hole/releases/latest | grep -Po '"tag_name":.*?[^\\]",' | perl -pe 's/"tag_name": "//; s/^"//; s/",$//') - echo "::: Pi-hole version is ${piholeVersion} (Latest version is ${piholeVersionLatest:-${DEFAULT}})" - fi + case "${1}" in + "-l" | "--latest" ) echo $(getRemoteVersion pi-hole);; + "-c" | "--current" ) echo $(getLocalVersion "${PHGITDIR}");; + "-h" | "--hash" ) echo $(getLocalHash "${PHGITDIR}");; + * ) echo "::: Invalid Option!"; exit 1; + esac } helpFunc() { @@ -93,10 +130,8 @@ if [[ $# = 0 ]]; then normalOutput fi -for var in "$@"; do - case "${var}" in - "-a" | "--admin" ) shift; webOutput "$@";; - "-p" | "--pihole" ) shift; coreOutput "$@" ;; - "-h" | "--help" ) helpFunc;; - esac -done +case "${1}" in + "-a" | "--admin" ) shift; webOutput "$@";; + "-p" | "--pihole" ) shift; coreOutput "$@" ;; + "-h" | "--help" ) helpFunc;; +esac diff --git a/advanced/Scripts/webpage.sh b/advanced/Scripts/webpage.sh index a21300ad..5f032ed1 100755 --- a/advanced/Scripts/webpage.sh +++ b/advanced/Scripts/webpage.sh @@ -134,7 +134,7 @@ trust-anchor=.,19036,8,2,49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE3 delete_dnsmasq_setting "host-record" - if [ ! -z "${HOSTRECORD+x}" ]; then + if [ ! -z "${HOSTRECORD}" ]; then add_dnsmasq_setting "host-record" "${HOSTRECORD}" fi diff --git a/advanced/bash-completion/pihole b/advanced/bash-completion/pihole index 05baa820..fc8f2162 100644 --- a/advanced/bash-completion/pihole +++ b/advanced/bash-completion/pihole @@ -3,7 +3,7 @@ _pihole() { COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="admin blacklist chronometer debug disable enable flush help logging query reconfigure restartdns setupLCD status tail uninstall updateGravity updatePihole version whitelist" + opts="admin blacklist chronometer debug disable enable flush help logging query reconfigure restartdns setupLCD status tail uninstall updateGravity updatePihole version whitelist checkout" COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) ) return 0 diff --git a/pihole b/pihole index 41946f35..dda6d750 100755 --- a/pihole +++ b/pihole @@ -8,9 +8,8 @@ # This file is copyright under the latest version of the EUPL. # Please see LICENSE file for your rights under this license. +readonly PI_HOLE_SCRIPT_DIR="/opt/pihole" - -PI_HOLE_SCRIPT_DIR="/opt/pihole" readonly wildcardlist="/etc/dnsmasq.d/03-pihole-wildcard.conf" # Must be root to use this tool if [[ ! $EUID -eq 0 ]];then @@ -128,17 +127,19 @@ queryFunc() { done # Scan for possible wildcard matches - local wildcards=($(processWildcards "${domain}")) - for domain in ${wildcards[@]}; do - result=$(scanList "\/${domain}\/" ${wildcardlist}) - # Remove empty lines before couting number of results - count=$(sed '/^\s*$/d' <<< "$result" | wc -l) - if [[ ${count} > 0 ]]; then - echo "::: Wildcard blocking ${domain} (${count} results)" - echo "${result}" - echo "" - fi - done + if [ -e "${wildcardlist}" ]; then + local wildcards=($(processWildcards "${domain}")) + for domain in ${wildcards[@]}; do + result=$(scanList "\/${domain}\/" ${wildcardlist}) + # Remove empty lines before couting number of results + count=$(sed '/^\s*$/d' <<< "$result" | wc -l) + if [[ ${count} > 0 ]]; then + echo "::: Wildcard blocking ${domain} (${count} results)" + echo "${result}" + echo "" + fi + done + fi exit 0 } @@ -278,6 +279,12 @@ tailFunc() { exit 0 } +piholeCheckoutFunc() { + source "${PI_HOLE_SCRIPT_DIR}"/piholeCheckout.sh + shift + checkout "$@" +} + helpFunc() { cat << EOM ::: Control all PiHole specific functions! @@ -311,6 +318,7 @@ helpFunc() { ::: Blocking can also be disabled only temporarily, e.g., ::: 'pihole disable 5m' - will disable blocking for 5 minutes ::: restartdns Restart dnsmasq +::: checkout Check out different branches EOM exit 0 } @@ -341,5 +349,6 @@ case "${1}" in "restartdns" ) restartDNS;; "-a" | "admin" ) webpageFunc "$@";; "-t" | "tail" ) tailFunc;; + "checkout" ) piholeCheckoutFunc "$@";; * ) helpFunc;; esac