#!/bin/bash

## Copyright (C) 2025 - 2025 ENCRYPTED SUPPORT LLC <adrelanos@whonix.org>
## See the file COPYING for copying conditions.

# shellcheck source=./accountctl.sh
source "${HELPER_SCRIPTS_PATH:-}"/usr/libexec/helper-scripts/accountctl.sh

USER_CREATE_USERNAME=""
USER_CREATE_GROUP_ADD_LIST=()

zsh_yes_or_no() {
   zsh_enable=""
   if [ -f "/etc/nozsh" ]; then
      printf '%s\n' "$0: INFO: No shell change because file /etc/nozsh exists, ok."
      zsh_enable=no
      return 0
   fi
   if [ -f "/usr/local/etc/nozsh" ]; then
      printf '%s\n' "$0: INFO: No shell change because file /usr/local/etc/nozsh exists, ok."
      zsh_enable=no
      return 0
   fi

   if grep --quiet -- 'nozsh' /proc/cmdline; then
      printf '%s\n' "$0: INFO: No shell change because nozsh in kernel command line, ok."
      zsh_enable=no
      return 0
   fi

   if ! test -x /usr/bin/zsh ; then
      printf '%s\n' "$0: INFO: No shell change because /usr/bin/zsh does not exist or is not executable, ok."
      zsh_enable=no
      return 0
   fi

   true "$0: INFO: /usr/bin/zsh is executable."

   zsh_enable=yes
}

add_linux_user_account() {
  if id -- "$USER_CREATE_USERNAME" &>/dev/null ; then
    true "INFO: User '$USER_CREATE_USERNAME' already exists, skip creation."
    return 0
  fi

  ## adduser and addgroup
  ##
  ## Quoted from Debian adduser manpage:
  ##
  ## They are friendlier front ends to the low level tools like useradd, groupadd and usermod programs,
  ## by default choosing Debian policy conformant UID and GID values,  creating a home directory with
  ## skeletal configuration, running a custom script, and other features.
  ##
  ## https://forums.whonix.org/t/port-from-useradd-groupadd-and-usermod-to-adduser-and-addgroup/7977

  ## Use --no-create-home and leave home folder creation to pam mkhomedir
  ## https://phabricator.whonix.org/T913
  ## https://forums.whonix.org/t/bug-not-all-files-form-etc-skel-are-copied-to-home-user/6778/4
  ##
  ## old:
  #useradd --no-create-home --password "$password" --user-group --shell /bin/bash "$user_to_be_created"
  ##
  ## Prefer adduser rather than useradd.
  ##
  ## No need to user --user-group since this is Debian adduser default.
  ##
  ## Quote adduser man page:
  ## --disabled-password
  ## Do not run passwd(1) to set a password. In most situations, logins are still possible though
  ## (for example using SSH keys or through PAM) for reasons that are beyond adduser's scope.
  adduser --no-create-home --disabled-password --comment "" -- "$USER_CREATE_USERNAME"
  true "INFO: User created."
}

password_empty_for_user_account() {
  ## No longer in use.
  ##
  ## setting password to changeme
  ##
  ## How this password was created:
  ## sudo apt-get install whois
  ## mkpasswd
  ## changeme
  ## Resulted in: aTayYxVyw5kDo
  #password="aTayYxVyw5kDo"

  ## No longer in use.
  ## Use --encrypted to be able to use a static, precalculated hash for reproducible builds.
  #printf '%s\n' "${user_to_be_created}:${password}" | chpasswd --encrypted

  ## adduser '--disabled-password' is not the same as 'passwd --delete user'.
  ## /etc/shadow:
  #user:!:19932:0:99999:7:::

  printf '%s\n' "INFO: Set empty password for account '$USER_CREATE_USERNAME'..."
  passwd --delete -- "$USER_CREATE_USERNAME"
  ## /etc/shadow:
  #user::19932:0:99999:7:::
}

add_groups_to_linux_user_account() {
  local group_item
  for group_item in "${USER_CREATE_GROUP_ADD_LIST[@]}"; do
    ## Use '&>/dev/null' to suppress error from 'is_group'.
    #log error "Group does not exist: '${group}'"
    if ! is_group "$group_item" &>/dev/null; then
      addgroup --system -- "$group_item"
    fi

    adduser -- "$USER_CREATE_USERNAME" "$group_item"
  done
}

linux_user_account_shell_to_zsh() {
  zsh_yes_or_no
  true "zsh_enable: $zsh_enable"
  if [ ! "$zsh_enable" = "yes" ]; then
    return 0
  fi

  printf '%s\n' "$0: INFO: For more information, see: https://www.kicksecure.com/shell#default"

  if ! id -- "$USER_CREATE_USERNAME" &>/dev/null ; then
    printf '%s\n' "$0: INFO: account '$USER_CREATE_USERNAME' does not exist. Not setting shell to 'zsh'."
    return 0
  fi

  ## Use getent to retrieve the account's entry from /etc/passwd
  user_passwd_entry=$(getent passwd -- "$USER_CREATE_USERNAME")

  ## Extract the shell field (the last field) from the account's entry
  user_default_shell=$(printf '%s\n' "$user_passwd_entry" | awk -F: '{print $NF}')

  if [ "$user_default_shell" = "/usr/bin/zsh" ]; then
    true "INFO: user_default_shell is already /usr/bin/zsh. Skipping. Ok."
    return 0
  fi

  printf '%s\n' "$0: INFO: Setting shell for account '$USER_CREATE_USERNAME' to 'zsh'..."
  ## chsh validates the requested shell against /etc/shells and prints
  ## a warning if it is not listed (it still updates /etc/passwd when
  ## run as root, so the operation succeeds -- but the warning is
  ## confusing in build logs). Modern debianutils regenerates
  ## /etc/shells from /usr/share/debianutils/shells.d/* via an
  ## 'interest-noawait' trigger, which means a sibling postinst (e.g.
  ## dist-base-files calling this function) can run before the queued
  ## update-shells fires, leaving /etc/shells without /usr/bin/zsh.
  ## Drain the regeneration ourselves first so chsh's validation
  ## passes cleanly. Idempotent + atomic; missing on pre-trixie
  ## debianutils, hence the '|| true'.
  update-shells >/dev/null 2>&1 || true
  ## Use 'timeout' to prevent unexplained bug password prompt caused by 'chsh'.
  if timeout --kill-after 5 5 chsh --shell /usr/bin/zsh -- "$USER_CREATE_USERNAME" ; then
     printf '%s\n' "$0: INFO: Shell for account '$USER_CREATE_USERNAME' has been set to 'zsh', ok."
  else
    if [ "$derivative_maker" = "true" ]; then
      printf '%s\n' "$0: ERROR: Command 'chsh --shell /usr/bin/zsh -- $USER_CREATE_USERNAME' failed during the build process. (return 1 because derivative_maker=true)"
      return 1
    fi
    if [ -f '/var/lib/dist-base-files/live_build' ]; then
      printf '%s\n' "$0: ERROR: Command 'chsh --shell /usr/bin/zsh -- $USER_CREATE_USERNAME' failed during the build process. (return 1 because /var/lib/dist-base-files/live_build exists)"
      return 1
    fi
    printf '%s\n' "$0: ERROR: Command 'chsh --shell /usr/bin/zsh -- $USER_CREATE_USERNAME' failed. This is only a minor issue."
    return 0
  fi
}
