#!/bin/bash
# Copyright Atomicorp, Inc.
# 2024
# License: Commercial

#########
# Globals
#########
VERSION="5.5.0"
BETA_FLAG=0
CHANNEL=channels/awp-hub-repo/channels/awp-hub-repo
source /etc/asl/awp-mirror.conf

# Check if DISABLED is set to "yes"
if [ "$DISABLED" = "yes" ]; then
  echo "Script is disabled. Exiting."
  exit 0
fi

# Check if BETA=1 is set in /etc/asl/awp-mirror.conf
if [ "$BETA" = "1" ]; then
  BETA_FLAG=1
fi

# Check if OEM_FEED is set
if [ "$OEM_FEED" != "" ] && [ "$OEM_FEED" != "no" ]; then
  CHANNEL=channels/oem/$OEM_FEED/awp-hub-repo
fi

###########
# Functions
###########
function rawurlencode() {
  local string="${1}"
  local strlen=${#string}
  local encoded=""

  for (( pos=0 ; pos<strlen ; pos++ )); do
     c=${string:$pos:1}
     case "$c" in
        [-_.~a-zA-Z0-9] ) o="${c}" ;;
        * )               printf -v o '%%%02x' "'$c"
     esac
     encoded+="${o}"
  done
  echo "${encoded}"
  REPLY="${encoded}"
}

function download() {
    if [ $# -lt 2 ]; then
        echo "Usage: download [-k|--insecure] <URL> <destination_path>"
        return 1
    fi

    local insecure=false
    if [ "$1" = "-k" ] || [ "$1" = "--insecure" ]; then
        insecure=true
        shift
    fi

    url=$1
    destination=$2

    if command -v curl >/dev/null; then
        if [ "$insecure" = true ]; then
            curl -o "$destination" -k "$url" || {
                echo "Error downloading file from $url"
                if [[ "$http_proxy" != "" ]]; then
                    echo "This may be a proxy connectivity issue. Check your proxy configuration."
                fi
                return 1;
            }
        else
            curl -o "$destination" "$url" || {
                echo "Error downloading file from $url"
                if [[ "$http_proxy" != "" ]]; then
                    echo "This may be a proxy connectivity issue. Check your proxy configuration."
                fi
                return 1;
            }
        fi
    elif command -v wget >/dev/null; then
        wget -O "$destination" "$url" || {
            echo "Error downloading file from $url"
            if [[ "$http_proxy" != "" ]]; then
                echo "This may be a proxy connectivity issue. Check your proxy configuration."
            fi
            return 1;
        }
    else
        echo "Error: Neither curl nor wget found. Please install either curl or wget."
        return 1
    fi
}

function mirror_repo() {
  MSG=$1
  URL=$2
  local result=0
  local cut_dirs=4
  local dest_dir="/var/www/html/channels/awp-hub-repo"
  local base_url="https://updates.atomicorp.com"

  # Adjust URL and cut-dirs for OEM feeds
  if [[ "$OEM_FEED" != "" && "$OEM_FEED" != "no" ]]; then
    # For OEM feeds, use the correct path structure
    URL="channels/oem/$OEM_FEED/awp-hub-repo/$(echo $URL | sed 's|.*/||')"
    cut_dirs=4
  fi

  # Encode password for server authentication (consistent with check_credentials)
  ENCPASSWORD=$(rawurlencode $PASSWORD)

  if [[ $DEBUG -eq 1 ]]; then
    echo "#############################"
    echo "Mirroring $MSG"
    echo "#############################"

    wget -t 6 --user=${USERNAME} --password=${ENCPASSWORD} -r --trust-server-names -N -np -nH --cut-dirs=${cut_dirs} -P ${dest_dir} ${base_url}/$URL/
    result=$?
    echo
    echo "$MSG COMPLETE"
    echo
  else
    wget -q -t 6 --user=${USERNAME} --password=${ENCPASSWORD} -r --trust-server-names -N -np -nH --cut-dirs=${cut_dirs} -P ${dest_dir} ${base_url}/$URL/
    result=$?
  fi

  # Check for authentication error (exit code 6 is for authentication failure)
  if [ $result -eq 6 ]; then
      if [[ $DEBUG -eq 1 ]]; then
        echo "#############################"
        echo "Mirroring $MSG"
        echo "#############################"

        wget -t 6 --user=${USERNAME} --password=${PASSWORD} -r --trust-server-names -N -np -nH --cut-dirs=${cut_dirs} -P ${dest_dir} ${base_url}/$URL/
        result=$?
        echo
        echo "$MSG COMPLETE"
        echo
      else
        wget -q -t 6 --user=${USERNAME} --password=${PASSWORD} -r --trust-server-names -N -np -nH --cut-dirs=${cut_dirs} -P ${dest_dir} ${base_url}/$URL/
        result=$?
      fi

      if [ $result -eq 6 ]; then
        echo "ERROR: Authentication failed. Please check your username and password."
        exit 1
      fi
  elif [ $result -ne 0 ]; then
    echo "ERROR: Failed to mirror $MSG (error code: $result)"
    return $result
  fi
}

function mirror_repo_ret() {
    local result=0

}


# Create a show_help function
function show_help() {
  echo
  echo "Atomicorp Mirror Update Utility - Version ${VERSION}"
  echo
  echo "Usage: awp-mirror-update [-h|--help] [-d|--debug] [--beta]"
  echo "  -h|--help           Display this help message"
  echo "  -d|--debug          Enable debug mode"
  echo "  --beta              Use beta channel"
  echo
}

# Check credentials before proceeding with mirrors
function check_credentials() {
  if [ -z "$USERNAME" ] || [ -z "$PASSWORD" ]; then
    echo "ERROR: Username or password not set in /etc/asl/config"
    exit 1
  fi

  # Perform a simple authentication test
  if [[ $DEBUG -eq 1 ]]; then
    echo "Testing authentication credentials..."
  fi

  ENCPASSWORD=$(rawurlencode $PASSWORD)

  # Use wget with --spider option to just test authentication without downloading
  wget -q -t 1 --spider --user=${USERNAME} --password=${ENCPASSWORD} https://updates.atomicorp.com/channels/awp-hub-repo/atomicorp/manifest
  if [ $? -eq 6 ]; then
    # retry with unencoded pass
    wget -q -t 1 --spider --user=${USERNAME} --password=${PASSWORD} https://updates.atomicorp.com/channels/awp-hub-repo/atomicorp/manifest
    if [ $? -eq 6 ]; then
      echo "ERROR: Authentication failed. Please check your username and password in /etc/asl/config"
      exit 1
    elif [ $? -ne 0 ]; then
      echo "WARNING: Could not connect to updates.atomicorp.com (error code: $?)"
    fi
  elif [ $? -ne 0 ]; then
    echo "WARNING: Could not connect to updates.atomicorp.com (error code: $?)"
    # Not exiting here as it might be a temporary network issue
  fi
}

######
# Main
######

# Check for command line arguments, -h or --help will display help, -d or --debug will enable debug mode
while [[ $# -gt 0 ]]; do
  key="$1"
  case $key in
    -h|--help)
      show_help
      exit 0
      ;;
    -d|--debug)
      DEBUG=1
      shift
      ;;
    --beta)
      BETA_FLAG=1
      shift
      ;;
    *m)
      show_help
      exit 1
      ;;
  esac
done

# Set CHANNEL based on the --beta flag
if [ "$BETA_FLAG" -eq 1 ]; then
  CHANNEL=channels/awp-hub-repo-testing/channels/awp-hub-repo
fi

# Check credentials early

if [ -f /var/awp/etc/config ]; then
  source /var/awp/etc/config

  # Proxy configuration and validation
  if [[ "$HTTP_PROXY" != "" ]]; then
    PORT=""
    AUTH=""

    # Validate proxy hostname
    if [[ ! "$HTTP_PROXY" =~ ^[a-zA-Z0-9.-]+$ ]]; then
      echo "ERROR: Invalid HTTP_PROXY hostname '$HTTP_PROXY'."
      echo "Hostname must contain only letters, numbers, dots, and hyphens."
      exit 1
    fi

    # Validate port if provided
    if [[ "$HTTP_PROXY_PORT" != "" ]]; then
      if [[ ! "$HTTP_PROXY_PORT" =~ ^[0-9]+$ ]] || [[ "$HTTP_PROXY_PORT" -lt 1 ]] || [[ "$HTTP_PROXY_PORT" -gt 65535 ]]; then
        echo "ERROR: Invalid HTTP_PROXY_PORT '$HTTP_PROXY_PORT'. Must be a number between 1-65535."
        exit 1
      fi
      PORT=":$HTTP_PROXY_PORT"
    fi

    # Handle proxy authentication
    if [[ "$HTTP_PROXY_USERNAME" != "" ]]; then
      if [[ "$HTTP_PROXY_PASSWORD" != "" ]]; then
        # URL encode the password to handle special characters
        ENCPASSWORD=$(rawurlencode $HTTP_PROXY_PASSWORD)
        AUTH="$HTTP_PROXY_USERNAME:$ENCPASSWORD@"
      else
        echo "ERROR: HTTP_PROXY_USERNAME is set but HTTP_PROXY_PASSWORD is empty."
        echo "Both username and password must be provided for proxy authentication."
        exit 1
      fi
    elif [[ "$HTTP_PROXY_PASSWORD" != "" ]]; then
      echo "ERROR: HTTP_PROXY_PASSWORD is set but HTTP_PROXY_USERNAME is empty."
      echo "Both username and password must be provided for proxy authentication."
      exit 1
    fi

    # Set proxy environment variables
    export http_proxy="http://${AUTH}${HTTP_PROXY}${PORT}"
    export https_proxy="http://${AUTH}${HTTP_PROXY}${PORT}"

    # Test proxy connectivity if DEBUG is enabled
    if [[ $DEBUG -eq 1 ]]; then
      echo "Testing proxy connectivity..."
      if command -v curl >/dev/null; then
        if curl -s --connect-timeout 10 --max-time 30 --proxy "$http_proxy" https://updates.atomicorp.com >/dev/null 2>&1; then
          echo "Proxy connectivity test successful."
        else
          echo "WARNING: Proxy connectivity test failed. This may indicate:"
          echo "  - Proxy server is unreachable"
          echo "  - Proxy authentication failed"
          echo "  - Proxy server is blocking the connection"
          echo "Continuing anyway, but operations may fail..."
        fi
      elif command -v wget >/dev/null; then
        if wget -q --timeout=10 --tries=1 --spider --proxy=on --proxy-user="${HTTP_PROXY_USERNAME}" --proxy-password="${HTTP_PROXY_PASSWORD}" https://updates.atomicorp.com >/dev/null 2>&1; then
          echo "Proxy connectivity test successful."
        else
          echo "WARNING: Proxy connectivity test failed. This may indicate:"
          echo "  - Proxy server is unreachable"
          echo "  - Proxy authentication failed"
          echo "  - Proxy server is blocking the connection"
          echo "Continuing anyway, but operations may fail..."
        fi
      fi
    fi
  fi
else
  echo "ERROR: Configuration file /var/awp/etc/config not found."
  exit 1
fi

check_credentials

# Exit if this is a control panel environment. Not Supported
if [ -f /usr/local/psa ] || [ -f /usr/local/cpanel ]; then
  exit 0
fi

# Detect utilities
if [ -f /usr/bin/shuf ]; then
  SHUF=/usr/bin/shuf
elif [ -f /bin/shuf ]; then
  SHUF=/bin/shuf
else
  exit 0
fi

if [ -f /usr/bin/ln ]; then
  LN=/usr/bin/ln
elif [ -f /bin/ln ]; then
  LN=/bin/ln
else
  exit 0
fi

# Malware signatures
SERVER="https://rule-updates.atomicorp.com/channels/rules/anti-malware"
TEMP_DIR="/var/www/html/channels/rules/anti-malware"

if  [ ! -d /var/www/html/channels/rules/anti-malware ] ; then
	mkdir -p /var/www/html/channels/rules/anti-malware
fi

EXTENSIONS="fp hdb hdu hsb hsu idb ign2 ldb ldu ndb ndu sfp"
for ext in $EXTENSIONS; do
    download -k ${SERVER}/Atomicorp-Linux.${ext}  $TEMP_DIR/Atomicorp-Linux.${ext}
    download -k ${SERVER}/VERSION  $TEMP_DIR/VERSION
done

find /var/ossec/etc/shared/ -type d -exec cp -v "$TEMP_DIR/VERSION" {} \;



# Agent packages
FILES="*.rpm, *.gz, *bz2, *.xml, *asc, *key, *.deb, *exe, *msi, distributions, options, *db, *version, *InRelease, *Release, *Release.gpg, *Packages, *Packages.gz, repodata, *.pkg, *.wpk, VERSION, versions *.html"
if  [ -d /var/www/html ]; then
  	if [ ! -d /var/www/html/channels/ ]; then
    		mkdir -p /var/www/html/channels/
   	fi

  	pushd /var/www/html/ >/dev/null
		if [ -f channels/awp-hub-repo/atomicorp/manifest ]; then
			rm -f channels/awp-hub-repo/atomicorp/manifest
		fi
		mirror_repo "Atomicorp Manifest" ${CHANNEL}/atomicorp/
		if [ -d ${CHANNEL}/rocky ]; then
			rm -rf ${CHANNEL}/rocky
		fi
		if [[ $AIX -eq 1 ]]; then
			mirror_repo "Atomicorp AIX" ${CHANNEL}/aix/7
		fi
		if [[ $AMZN -eq 1 ]]; then
			mirror_repo "Atomicorp Amazon" ${CHANNEL}/amazon/2
			mirror_repo "Atomicorp Amazon 2023" ${CHANNEL}/amazon/2023
		fi
		if [[ $EL5 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Centos EL5" ${CHANNEL}/centos/5
		fi
		if [[ $EL6 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Centos EL6" ${CHANNEL}/centos/6
		fi
		if [[ $EL7 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Centos EL7" ${CHANNEL}/centos/7
		fi
		if [[ $EL8 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Rocky EL8" ${CHANNEL}/rocky/8
		fi
		if [[ $EL9 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Rocky EL9" ${CHANNEL}/rocky/9
		fi
		if [[ $EL10 -eq 1 ]]; then
			mirror_repo "Atomicorp Redhat/Rocky EL10" ${CHANNEL}/rocky/10
		fi
		if [[ $DEBIAN -eq 1 ]]; then
			mirror_repo "Atomicorp Debian" ${CHANNEL}/debian
		fi
		if [[ $SUSE -eq 1 ]]; then
			mirror_repo "Atomicorp OpenSuSE" ${CHANNEL}/opensuse
		fi
		if [[ $OSX -eq 1 ]]; then
			mirror_repo "Atomicorp OSX" ${CHANNEL}/osx
		fi
		if [[ $SOLARIS -eq 1 ]]; then
			mirror_repo "Atomicorp Solaris" ${CHANNEL}/solaris
		fi
		if [[ $UBUNTU -eq 1 ]]; then
			mirror_repo "Atomicorp Ubuntu" ${CHANNEL}/ubuntu
		fi
		if [[ $WINDOWS -eq 1 ]]; then
			mirror_repo "Atomicorp Windows" ${CHANNEL}/windows
		fi


		# Cleanup
		if [ -d /var/www/html/channels/awp-hub-repo ]; then
			cd /var/www/html/channels/awp-hub-repo

			# First remove files not in manifest
			if [ -f atomicorp/manifest ]; then
				# Create a temporary file with normalized manifest paths
				grep -v '^\.$' atomicorp/manifest | sed 's|^\./||' > /tmp/manifest.tmp

				# Find and remove files not in manifest
				find . -type f | while read file; do
					# Skip the manifest file itself
					if [ "$file" = "./atomicorp/manifest" ]; then
						continue
					fi

					# Get relative path without leading ./
					rel_path=$(echo "$file" | sed 's|^\./||')

					# Check if file is in manifest
					if ! grep -q "^$rel_path$" /tmp/manifest.tmp; then
						if [[ $DEBUG -eq 1 ]]; then
							echo "Removing $file (not in manifest)"
						fi
						rm -f "$file"
					fi
				done

				# Clean up temp file
				rm -f /tmp/manifest.tmp
			fi

			# Then remove disabled directories
			if [[ $AIX -eq 0 ]]; then
				rm -rf aix
			fi
            if [[ $AMZN -eq 0 ]]; then
                rm -rf amazon
            fi
			if [[ $EL5 -eq 0 && $EL6 -eq 0 && $EL7 -eq 0 && $EL8 -eq 0 && $EL9 -eq 0 ]]; then
				rm -rf centos
				rm -f redhat rocky
			fi
			if [[ $DEBIAN -eq 0 ]]; then
				rm -rf debian
			fi
			if [[ $SUSE -eq 0 ]]; then
				rm -rf opensuse
			fi
			if [[ $OSX -eq 0 ]]; then
				rm -rf osx
			fi
			if [[ $SOLARIS -eq 0 ]]; then
				rm -rf solaris
			fi
			if [[ $UBUNTU -eq 0 ]]; then
				rm -rf ubuntu
			fi
			if [[ $WINDOWS -eq 0 ]]; then
				rm -rf windows
			fi

			# Clean up any empty directories
			find . -type d -empty -delete

			# Clean up index.html files with query parameters
			find . -type f -name "index.html\?*" -delete

			# Set permissions
			find . -type d -exec chmod 755 {} \;
			find . -type f -exec chmod 644 {} \;
		fi

    # Aliases
    pushd /var/www/html/channels/awp-hub-repo/ > /dev/null
      if [ -d centos ]; then
        if  [ ! -L rocky ]; then
    	  $LN -sf centos rocky
        fi
        if [ ! -L redhat ]; then
    	  $LN -sf centos redhat
        fi
      fi
    popd >/dev/null

    if [ -d /var/www/html/channels/awp-hub-repo/centos ]; then
      pushd /var/www/html/channels/awp-hub-repo/centos >/dev/null
        if [ -d 6 ]; then
          if [ ! -L 6Server ]; then
     	    $LN -sf 6 6Server
          fi
        fi
        if [ -d 7 ]; then
          if [ ! -L 7Server ]; then
     	    $LN -sf 7 7Server
          fi
        fi
        if [ -d 8 ]; then
          if [ ! -L 8Server ]; then
     	    $LN -sf 8 8Server
          fi
        fi
      popd >/dev/null
    fi

    # Remove any Server symlinks from the root directory
    pushd /var/www/html/channels/awp-hub-repo/ >/dev/null
      rm -f 6Server 7Server 8Server
    popd >/dev/null

    # Solaris
    if [ -d /var/www/html/channels/awp-hub-repo/solaris/opencsw/i386/5.10 ]; then
      pushd /var/www/html/channels/awp-hub-repo/solaris/opencsw/i386/ >/dev/null
        if [ ! -L 5.11 ]; then
          ln -sf 5.10 5.11
        fi
      popd >/dev/null
    fi

    if [ -d /var/www/html/channels/awp-hub-repo/solaris/opencsw/sparc/5.10 ]; then
      pushd /var/www/html/channels/awp-hub-repo/solaris/opencsw/sparc/ >/dev/null
        if [ ! -L 5.11 ]; then
          ln -sf 5.10 5.11
        fi
      popd >/dev/null
    fi


	popd >/dev/null
else
  	echo "Error: /var/www/html not found"
  	exit 1
fi
