#!/bin/bash
# adds/removes/reconfigures web users

SPATH="$(dirname "$(readlink -f ${BASH_SOURCE[0]})")"    # dir of the script
SNAME="$(basename ${BASH_SOURCE[0]})"                    # name of the script

ASCEDSCONF='local site certbot'
ASCEDSLIBS='utils'

if [ ! -r "${SPATH}/asceds-head" ] ; then
   echo "No header ${SPATH}/asceds-head. Exiting"
   exit 9
fi

. ${SPATH}/asceds-head

asceds-web-user-usage()
{
  cat << ENDUSAGE

Usage: asceds-web-user [-h] [-l] 
                       [-p] [-a <username>] [-d <username>] 
                       [-e] [-c] [-x] [-m <username>]

Adds/removes/reconfigures web users

-h --> display usage and exit
-l --> list current users and their domains, then exit
-p --> use simple auth password file ${ASCEDSWEBDIR}/html/cert/.htpasswd
-a <username> --> adds username to the website;
-d <username> --> deletes user from the website;
-m <username> --> modifies (if -e, -c, or -x present) or deletes/re-adds user;
-e --> modifies email address (works with -m);
-c --> modifies authorized domains (works with -m);
-x --> modifies simple auth password (works with -m if .htpasswd exists);

Options -a/-d/-m are mutually exclusive.
Wildcard ALL gives user authority over all available domains.
Sets/removes list of authorized domains in ${ASCEDSWEBDIR}/etc/users.php
Sets/removes user password for simple auth in ${ASCEDSWEBDIR}/html/cert/.htpasswd
   (if it exists or -p)
If file ${ASCEDSWEBDIR}/html/cert/.htpasswd exists, -p is forced.
<Username> must be valid email address used for sending notifications,
   or a mail alias is set.
User deletion is allowed only if no unmanaged clients are recorded to the user.

ENDUSAGE
exit 0
}

# initialize user to be added
ADDUSER=""

# initialize user to be deleted
DELUSER=""

# initialize user to be modified
MODUSER=""

# simple auth flag (Shibboleth by default; overriden by autodetect)
SIMPLEAUTH=''

# modifies simple auth password (works with -m if .htpasswd exists)
MODPASSWD=''

# modifies email address (works with -m)
MODEMAIL=''

# modifies authorized domains (works with -m)
MODAUTHDOM=''

# list current users and their domains
LISTUSERS=''

# general validation and parse of the command line
for ARG in ${ARGS} ; do
   #echo "ARG=${ARG}"
   if [ "${ARG}" != "${ARG//[^-_a-zA-Z0-9.@]/}" ] ; then
      asceds-error "Malformed argument ${ARG}"
   elif [ "${ARG}" == "-h" ] ; then
      asceds-web-user-usage
   elif [ "${ARG}" == "-l" ] ; then
      shift
      LISTUSERS='yes'
   elif [ "${ARG}" == "-p" ] ; then
      shift
      SIMPLEAUTH='yes'
   elif [ "${ARG}" == "-e" ] ; then
      shift
      MODEMAIL='yes'
   elif [ "${ARG}" == "-c" ] ; then
      shift
      MODAUTHDOM='yes'
   elif [ "${ARG}" == "-x" ] ; then
      shift
      MODPASSWD='yes'
   elif [ "${ARG}" == "-d" ] ; then
      shift
      if [[ "$1" != -* ]] && [ -n "$1" ] ; then
         # usernames should be lower case 
         DELUSER=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
         TESTUSER=$( ${GREP} "\['${DELUSER}'\]" ${ASCEDSWEBDIR}/etc/users.php )
         if [ -z "${TESTUSER}" ] ; then
            asceds-error "Web user ${DELUSER} does not exist. Nothing to delete."
         fi
      fi
   elif [ "${ARG}" == "-a" ] ; then
      shift
      if [[ "$1" != -* ]] && [ -n "$1" ] ; then
         if  [[ "$1" == "@"* ]] || [[ "$1" == *"@" ]] ; then
            asceds-error "Web user ${ADDUSER} has the wrong format. Use a real email address or a-z0-9 characters"
         fi
         # usernames should be lower case
         ADDUSER=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
         TESTUSER=$( ${GREP} "\['${ADDUSER}'\]" ${ASCEDSWEBDIR}/etc/users.php )
         if [ -n "${TESTUSER}" ] ; then
            asceds-error "Web user ${ADDUSER} exists already. Use -m to modify it."
         fi

         if [ "${ADDUSER}" == "${ADDUSER//@/}" ] ; then 
            # if not an email address
            # test if users doesn't already exist on the server
            TESTUSER=$( ${GREP} "^${ADDUSER}:" /etc/passwd )
            if [ -n "${TESTUSER}" ] ; then
               asceds-error "Web user ${ADDUSER} exists as regular user. Pick another name or use an email address."
            fi
            if [ "${ADDUSER}" != "${ADDUSER//./}" ] ; then
               asceds-error "Web user name ${ADDUSER} must not contain . in it."
            fi
         else
            # if it should be an email address, validate the format
            if [[ ! "${ADDUSER}" =~ ^[a-z][-_a-z0-9]{0,31}@[a-z0-9][-a-z0-9]{0,31}(\.[a-z0-9][-a-z0-9]{0,31})*$ ]] ; then
               asceds-error "Web user ${ADDUSER} looks like an improperly formatted email address. Please try again."
            fi
         fi
      fi
   elif [ "${ARG}" == "-m" ] ; then
      shift
      if [[ "$1" != -* ]] && [ -n "$1" ] ; then
         # usernames should be lower case
         MODUSER=$( cat <<< $1 | tr '[:upper:]' '[:lower:]' )
         TESTUSER=$( ${GREP} "\['${MODUSER}'\]" ${ASCEDSWEBDIR}/etc/users.php )
         if [ -z "${TESTUSER}" ] ; then
            asceds-error "Web user ${MODUSER} does not exist. Nothing to modify."
         fi
      fi
   else
      shift
   fi
done

if [ -n "${LISTUSERS}" ] ; then
   if [ -r "${ASCEDSWEBDIR}/etc/users.php" ] ; then
      cat ${ASCEDSWEBDIR}/etc/users.php | \
         sed -e '/>/d ; /</d ; s/array//g ; s/\;\s*$//' | tr -d '$'
      exit 0
   else
      asceds-error "Users config file ${ASCEDSWEBDIR}/etc/users.php not accessible"
   fi
fi

# options -d/-a/-m should be mutually exclusive
if [ -n "${DELUSER}" ] && [ -n "${ADDUSER}" ] ; then
   asceds-error "Options -a/-d are mutually exclusive"
elif [ -n "${MODUSER}" ] && [ -n "${DELUSER}" ] ; then
   asceds-error "Options -m/-d are mutually exclusive"
elif [ -n "${ADDUSER}" ] && [ -n "${MODUSER}" ] ; then
   asceds-error "Options -a/-m are mutually exclusive"
fi

# options -e/-c/-x should work only with -c
if [ -z "${MODUSER}" ] ; then
   if [ -n "${MODAUTHDOM}" ] ; then
      MODAUTHDOM=''
      asceds-warning "Option -c works only with -m"
   fi
   if [ -n "${MODEMAIL}" ] ; then
      MODEMAIL=''
      asceds-warning "Option -e works only with -m"
   fi
   if [ -n "${MODPASSWD}" ] ; then
      MODPASSWD=''
      asceds-warning "Option -x works only with -m"
   fi
fi
if [ ! -r "${ASCEDSWEBDIR}/html/cert/.htpasswd" ] ; then
   asceds-warning "Option -x works only if ${ASCEDSWEBDIR}/html/cert/.htpasswd exists."
   MODPASSWD=''
else
   SIMPLEAUTH='yes'
fi

# run as root only
asceds-run-asroot

# consistency tests
if [ ! -d "${ASCEDSWEBDIR}/etc" ] ; then
   asceds-error "No dir ${ASCEDSWEBDIR}/etc on this website"
fi
if [ ! -r "${ASCEDSWEBDIR}/etc/users.php" ] ; then
   asceds-error "No users file ${ASCEDSWEBDIR}/etc/users.php
        on this website"
fi
if [ -n "${SIMPLEAUTH}" ] && [ -z "$( which htpasswd 2>/dev/null )" ] ; then
   asceds-error "No htpasswd found on this system, simple auth cannot be set."
fi

TRANSFERUNC='yes'

# modify user
if [ -n "${MODUSER}" ] ; then

   echo
   echo "Modifying user ${MODUSER}"
   echo

   CHANGESOME=''
   if [ -n "${MODAUTHDOM}" ] ; then
      echo "Changing authority domains for user ${MODUSER}"
      asceds-change-userdom "${MODUSER}" '' && CHANGESOME='yes'
   fi
   if [ -n "${MODEMAIL}" ] ; then
      echo "Changing email address for user ${MODUSER}"
      asceds-change-email "${MODUSER}" '' && CHANGESOME='yes'
   fi
   if [ -n "${MODPASSWD}" ] && [ -n "${SIMPLEAUTH}" ] ; then
      echo "Changing simple auth password for user ${MODUSER}"
      asceds-change-passwd "${MODUSER}" '' && CHANGESOME='yes'
   fi
   # if no specific change was requested, delete and create the user fresh
   if [ -z "${CHANGESOME}" ] ; then
      DELUSER="${MODUSER}"
      ADDUSER="${MODUSER}"
      # no unmanaged client transfer should be performed
      TRANSFERUNC=''
   fi
fi

# delete user
if [ -n "${DELUSER}" ] ; then

   echo
   echo "Deleting user ${DELUSER}"
   echo

   if [ -n "${TRANSFERUNC}" ] ; then
      echo "Checking for unamaged clients requested by this user"
      #TBD test if there are no unmanaged clients requested by this user:
      #TBD if any, transfer the clients first
      #TBD (using TBD asceds-transfer-unmanaged)
      #TBD or maybe offer the option to remove them from certbot/asceds
   fi

   asceds-change-userdom "${DELUSER}" 'del' || \
         asceds-error "The user ${DELUSER} could not be removed from users.php."
   if [ -n "${SIMPLEAUTH}" ] ; then
      asceds-change-passwd "${DELUSER}" 'del' || \
         asceds-error "The password for user ${DELUSER} could not be deleted."
   fi
   # delete email address from /etc/aliases
   asceds-change-email "${DELUSER}" 'del' || \
      asceds-error "The email for user ${DELUSER} could not be deleted."
fi

# add user
if [ -n "${ADDUSER}" ] ; then

   echo
   echo "Adding user ${ADDUSER}"
   echo

   if [ "${ADDUSER}" != "${ADDUSER//[^-_@a-z0-9.]/}" ] ; then
      echo 
      echo "User ${ADDUSER} contains undesired characters."
      echo "Please try again, using only -_@a-z0-9 and lower case. "
      exit 2
   fi

   echo
   echo "Adding web user ${ADDUSER}"
   # set email if username doesn't look like an email address
   asceds-change-email "${ADDUSER}" '' || \
      asceds-error "The email for user ${ADDUSER} could not be added."
   
   # add simple auth password
   if [ -n "${SIMPLEAUTH}" ] ; then
      asceds-change-passwd "${ADDUSER}" '' || \
         asceds-error "The password for user ${ADDUSER} could not be set."
   fi
   
   # authorized domains management
   asceds-change-userdom "${ADDUSER}" '' || \
         asceds-error "The domains for user ${ADDUSER} could not be set."
fi
