#!/bin/bash
# NextcloudPi diagnostics report
#
# Copyleft 2017 by Ignacio Nunez Hernanz <nacho _a_t_ ownyourbits _d_o_t_ com>
# GPL licensed (see end of file) * Use at your own risk!
#
# Usage:
#   sudo ncp-diag
#
# More at https://ownyourbits.com
#
# shellcheck disable=SC1091
source /usr/local/etc/library.sh

# Distro, NCP version and tag
echo "NextcloudPi version|$( cat /usr/local/etc/ncp-version )"
[[ -f /usr/local/etc/ncp-baseimage ]] && echo "NextcloudPi image|$( cat /usr/local/etc/ncp-baseimage )"
echo "OS|$(sed 's| \\n \\l||' /etc/issue). $(uname -r) ($(uname -m))"

# Data
DATADIR="$( grep datadirectory /var/www/nextcloud/config/config.php |
              awk '{ print $3 }' | grep -oP "[^']*[^']" | head -1 )"
test -d "$DATADIR" || DIRINFO=" (doesn't exist)"
USBDEVS="$( lsblk -S -o  NAME,TRAN | awk '{ if ( $2 == "usb" ) print $1; }' | tr '\n' ' ' )"
[[ "$USBDEVS" == "" ]] && USBDEVS="none"

am_cfg="/usr/local/etc/ncp-config.d/nc-automount.cfg"
[[ -f "$am_cfg" ]] && [[ "$(jq -r ".params[0].value" "$am_cfg")" == "yes" ]] && echo "automount|yes" || echo "automount|no"
echo "USB devices|$USBDEVS"
echo "datadir|$DATADIR$DIRINFO"
[[ "$DIRINFO" == "" ]] && {
  echo "data in SD|$( [[ $( stat -fc%d / ) == $( stat -fc%d "$DATADIR" ) ]] && echo yes || echo no )"
  echo "data filesystem|$( stat -fc%T "$DATADIR" )"
  echo "data disk usage|$( df -h "$DATADIR" | tail -1 | awk '{ print $3"/"$2 }')"
}
echo "rootfs usage|$( df -h / | tail -1 | awk '{ print $3"/"$2 }')"
SWP="$( swapon | tail -1 | awk '{ print $1 }' )"
[[ "$SWP" == "" ]] && SWP="none"
echo "swapfile|$SWP"

# Database
DBDIR=$( grep datadir /etc/mysql/mariadb.conf.d/90-ncp.cnf | awk -F "= " '{ print $2 }' )
test -d "$DBDIR" || DBDIRINFO=" (doesn't exist)"
echo "dbdir|$DBDIR$DBDIRINFO"

# Nextcloud
VERSION="$( ncc status | grep "version:" | awk '{ print $3 }' )"
if [[ "$VERSION" != "" ]]; then
  echo "Nextcloud check|ok"
  echo "Nextcloud version|$VERSION"
  else
  echo "Nextcloud check|error"
fi

# Services
echo "HTTPD service|$( pgrep -c apache2 &>/dev/null && echo up || echo down )"
echo "PHP service|$( pgrep -c php-fpm &>/dev/null && echo up || echo down )"
echo "MariaDB service|$( (pgrep -c mysqld || pgrep -c mariadb) &>/dev/null && echo up || echo down )"
echo "Redis service|$( pgrep -c redis-server &>/dev/null && echo up || echo down )"
echo "HPB service|$( ncc notify_push:self-test &>/dev/null && echo up || echo down )"
echo "Postfix service|$( pgrep -fc postfix &>/dev/null && echo up || echo down )"

# WAN
echo "Internet check|$( ping -W 2 -w 1 -q github.com &>/dev/null && echo ok || echo no )"

function is_port_open()
{
  # The URL leads to an application I've deployed for NCP on https://fly.io using a Docker container I made.
  # The image for the container is available on Docker Hub (zendai/checkport:sanic) if you wish to deploy one yourself.
  # The code for the Sanic server and Docker image is available at: https://github.com/ZendaiOwl/Build/tree/master/Docker/Python/Sanic/checkport
  # I only have a free tier with limited outbound data per month, 100GB p/month.
  # If we go over 100GB outbound data in a month, I will start being charged for the data going over that limit.
  # I used a low level Python socket library & fortunately each request only consumes aprox. ~ 60-74 bytes p/second.
  # Meaning 100GB should be plenty, it should be enough to handle a little less
  # than 450 request p/second a month, unless my calculations are wrong.
  # Thank you :pray: from Victor-ray, S. https://github.com/ZendaiOwl
  local -r PORTURL="https://checkport.zendai.net.eu.org/check"
  local TYPE="${1?}" IPType
  # Checks both port 80 & 443 for IPv4/IPv6 and returns the result or [N/A] [N/A]
  if ! [[ "$TYPE" =~ ^(0|4|6)$ ]]
  then
    # As this echo is redirected to STDERR it will not be
    # asssigned in the arrays of the if-statement below this function
    echo "Invalid type: $TYPE" 1>&2
    return 1
  elif [[ "$TYPE" == 0 ]]
  then
    # Public IPv4/6 is not available
    echo -e "[N/A]\n[N/A]"
  else
    IPType="--ipv6"
    [[ "$TYPE" -eq 6 ]] || IPType="--ipv4"
    curl --silent --max-time 4 "$IPType" "$PORTURL" | jq -r '."80",."443"'
  fi
}
publicIPv4=$(curl --silent --max-time 4 --ipv4 "https://ipv4.icanhazip.com" 2>/dev/null) || unset publicIPv4
echo "Public IPv4|${publicIPv4:-"not found"}"
publicIPv6=$(curl --silent --max-time 4 --ipv6 "https://ipv6.icanhazip.com" 2>/dev/null) || unset publicIPv6
echo "Public IPv6|${publicIPv6:-"not found"}"

# Declares the array variables for mapfile to work
declare -a IPv4PORTS
declare -a IPv6PORTS

# Mapfile reads lines from standard input into an indexed array variable
if [[ -n "$publicIPv4" ]]
then
  mapfile -t IPv4PORTS < <(is_port_open 4)
else
  mapfile -t IPv4PORTS < <(is_port_open 0)
fi

if [[ -n "$publicIPv6" ]]
then
  mapfile -t IPv6PORTS < <(is_port_open 6)
else
  mapfile -t IPv6PORTS < <(is_port_open 0)
fi

# Checks if Port 80 is open on IPv4 or IPv6
if [[ "${IPv4PORTS[0]}" == "open" ]] || [[ "${IPv6PORTS[0]}" == "open" ]]
then
  PORT80="open"
elif [[ "${IPv4PORTS[0]}" == "[N/A]" ]] && [[ "${IPv6PORTS[0]}" == "[N/A]" ]]
then
  PORT80="[N/A]"
else
  PORT80="closed"
fi
# Checks if Port 443 is open on IPv4 or IPv6
if [[ "${IPv4PORTS[1]}" == "open" ]] || [[ "${IPv6PORTS[1]}" == "open" ]]
then
  PORT443="open"
elif [[ "${IPv4PORTS[1]}" == "[N/A]" ]] && [[ "${IPv6PORTS[1]}" == "[N/A]" ]]
then
  PORT443="[N/A]"
else
  PORT443="closed"
fi

echo "Port 80|$PORT80"
echo "Port 443|$PORT443"

# LAN
IFACE=$( ip r | grep "default via" | awk '{ print $5 }' | head -1 )
GW=$(    ip r | grep "default via" | awk '{ print $3 }' | head -1 )
IP="$(get_ip)"

echo "IP|$IP"
echo "Gateway|$GW"
echo "Interface|$IFACE"

# Certificates
CERTS="$( grep "SSLCertificateFile */etc/letsencrypt/live/" /etc/apache2/sites-available/001-nextcloud.conf \
        | sed 's|.*SSLCertificateFile */etc/letsencrypt/live/||;s|/fullchain.pem||' )"
[[ "$CERTS" == "" ]] && CERTS=none
echo "Certificates|$CERTS"

RESOLV="$( ping -c1 -w1 "$CERTS" 2>/dev/null | head -1 | grep -oP '\d{1,3}(.\d{1,3}){3}' )"
echo "NAT loopback|$( [[ "$RESOLV" == "$IP" ]] && echo yes || echo no )"

# Other
echo "Uptime|$( uptime | cut -f1 -d',' | awk '{ $1=""; $2=""; print }' | tr -d "  " )"
# Get kernel version

# License
#
# This script is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this script; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
# Boston, MA  02111-1307  USA
