#!/bin/bash
LOG=/tmp/sdk.log

APP_NAME=$(basename $(dirname $(dirname $0)))
AUTH_XML="/home/$APP_NAME/sfiles/auth.xml"
AUTH_XML_OLD="/home/$APP_NAME/sfiles/auth.xml.old"
AUTH_XML_TEMP="/home/$APP_NAME/sfiles/auth.xml.temp"
HTTP_STATUS=200
ERROR_MESSAGE="Unknown error"

decode() {
  echo -e "$(sed 's/+/ /g;s/%/\\x/g;')"
}

get_users() {
  eval $QUERY_STRING # GET "username" sent from request
  if [ -z "$(echo $QUERY_STRING | grep "username=")" ]; then # username was not passed ( get all users )
    USERS=$(xmlstarlet sel -t -m "users/user" -v "@username" -o ";" -v "@password" -o ";" -v "@roles" -n "$AUTH_XML")
  else # get user with provided "$username"
    username=$(echo $username | decode)
    USERS=$(xmlstarlet sel -t -m "users/user[@username='$username']" -v "@username" -o ";" -v "@password" -o ";" -v "@roles" -n "$AUTH_XML")
    if [ -z "$USERS" ]; then # no users with provided username
      {
        HTTP_STATUS=500
        ERROR_MESSAGE="User with username '$username' not found."
        return 51
      }
    fi
  fi

  if [ -z "$USERS" ]; then # no users
    {
      HTTP_STATUS=500
      ERROR_MESSAGE="No users found."
      return 52
    }
  fi

  if [ -z "$username" ]; then # if get all create array
    USERS_JSON="["
  fi

  # for all users
  for USER in $(echo "$USERS"); do
    USER_NAME="$(printf "%s" "$USER" | cut -d ';' -f 1)"
    USER_PASS="$(printf "%s" "$USER" | cut -d ';' -f 2)"
    USER_ROLES="$(printf "%s" "$USER" | cut -d ';' -f 3)"
    USERS_JSON="$USERS_JSON {\"username\": \"$USER_NAME\", "
    USERS_JSON="$USERS_JSON \"password\": \"$USER_PASS\", "
    if [ -z $USER_ROLES ]; then # empty roles
      USERS_JSON="$USERS_JSON \"roles\":[]"
    else # add all roles to JSON string
      ROLE_COUNT=0
      USERS_JSON="$USERS_JSON \"roles\":["
      for role in $(echo "$USER_ROLES" | tr ',' '\n'); do
        if [ "$ROLE_COUNT" -eq "0" ]; then
          USERS_JSON="$USERS_JSON \"$role\""
        else
          USERS_JSON="$USERS_JSON , \"$role\""
        fi
        ROLE_COUNT=$(expr $ROLE_COUNT + 1)
      done
      USERS_JSON="$USERS_JSON ]" # close roles array
    fi
    USERS_JSON="$USERS_JSON }," # close user object
  done

  if [ -z "$username" ]; then # if get all close array
    USERS_JSON="${USERS_JSON%?} ]" # remove last comma and close array
  else
    USERS_JSON="${USERS_JSON%?}" # remove last comma
  fi
  return 0

}

update_users() {
  cp $AUTH_XML $AUTH_XML_OLD
  cp $AUTH_XML_OLD $AUTH_XML_TEMP

  if [ "$CONTENT_LENGTH" -gt 0 ]; then
    POST_DATA=$(cat -)
  fi
  USERNAME=$(echo $POST_DATA | jq -r '.username')
  PASSWORD=$(echo $POST_DATA | jq -r '.password // ""')
  JSON_ROLES=$(echo $POST_DATA | jq -r '.roles')
  [[ $(echo $POST_DATA | jq -e 'has("username")') == "false" ]] && {
    HTTP_STATUS=400
    ERROR_MESSAGE="Parameter 'username' is required."
    return 2
  }

  USERS=$(xmlstarlet sel -t -m "users/user[@username='$USERNAME']" -v "@username" -o ";" -n "$AUTH_XML_TEMP")
  for role in $(echo "${JSON_ROLES}" | jq -r '.[]'); do
    ROLES="$ROLES$role,"
  done

  ROLES="${ROLES%?}" # remove last comma from roles string
  if [ -z "$USERS" ]; then # user does not exist ( create new )
    [[ $(echo $POST_DATA | jq -e 'has("password")') == "false" || $(echo $POST_DATA | jq -e 'has("roles")') == "false" ]] && {
      HTTP_STATUS=400
      ERROR_MESSAGE="Parameters 'password' and 'roles' are required."
      return 3
    }

    if [ -z "$ROLES" ]; then
      ROLES=""
    fi

    # busybox shell test cmd does not work reliably, checking for ability to open file as more reliable option
    # if [ -w $AUTH_XML_TEMP ]; then
    if >>"$AUTH_XML_TEMP"; then
      PWD_HASH=$(printf "%s" "$PASSWORD" | sha256sum | awk -F' ' '{print $1}')
      $(xmlstarlet ed -L -s 'users' \
        -t 'elem' -n 'user' -v '' \
        -i 'users/user[not(@username)]' \
        -t 'attr' -n 'username' -v "$USERNAME" \
        -i 'users/user[not(@password)]' \
        -t 'attr' -n 'password' -v "$PWD_HASH" \
        -i 'users/user[not(@roles)]' \
        -t 'attr' -n 'roles' -v "$ROLES" "$AUTH_XML_TEMP")
    else
      {
        HTTP_STATUS=500
        ERROR_MESSAGE="Error adding new user. Check '$AUTH_XML_TEMP' file permissions."
        return 53
      }
    fi

  else # user exits ( update )
    [[ $(echo $POST_DATA | jq -e 'has("password")') == "false" && $(echo $POST_DATA | jq -e 'has("roles")') == "false" ]] && {
      HTTP_STATUS=400
      ERROR_MESSAGE="Parameters 'password' or 'roles' is required when updating user."
      return 4
    }
    if [ $(echo $POST_DATA | jq -e 'has("password")') == "true" ]; then
      # busybox shell test cmd does not work reliably, checking for ability to open file as more reliable option
      # if [ -w $AUTH_XML_TEMP ]; then
      if >>"$AUTH_XML_TEMP"; then
        PWD_HASH=$(printf "%s" "$PASSWORD" | sha256sum | awk -F' ' '{print $1}')
        $(xmlstarlet ed --inplace -u "users/user[@username='$USERNAME']/@password" -v "$PWD_HASH" "$AUTH_XML_TEMP")
      else
        {
          HTTP_STATUS=500
          ERROR_MESSAGE="Error updating user password. Check '$AUTH_XML_TEMP' file permissions."
          return 54
        }
      fi
    fi

    if [ $(echo $POST_DATA | jq -e 'has("roles")') == "true" ]; then
      if [ -z "$ROLES" ]; then
        ROLES=""
      fi
      # busybox shell test cmd does not work reliably, checking for ability to open file as more reliable option
      # if [ -w $AUTH_XML_TEMP ]; then
      if >>"$AUTH_XML_TEMP"; then
        $(xmlstarlet ed --inplace -u "users/user[@username='$USERNAME']/@roles" -v "$ROLES" "$AUTH_XML_TEMP")
      else
        {
          HTTP_STATUS=500
          ERROR_MESSAGE="Error updating user roles. Check '$AUTH_XML_TEMP' file permissions."
          return 55
        }
      fi
    fi

  fi

  mv $AUTH_XML_TEMP $AUTH_XML
  sync
  return 0
}

delete_user() {
  cp $AUTH_XML $AUTH_XML_OLD
  cp $AUTH_XML_OLD $AUTH_XML_TEMP

  if [ "$CONTENT_LENGTH" -gt 0 ]; then
    POST_DATA=$(cat -)
  fi
  USERNAME=$(echo $POST_DATA | jq -r '.username')
  USERS=$(xmlstarlet sel -t -m "users/user[@username='$USERNAME']" -v "@username" -o ";" -n "$AUTH_XML_TEMP")
  if [ -z "$USERS" ]; then # user does not exist can't delete
    {
      HTTP_STATUS=500
      ERROR_MESSAGE="User with username '$USERNAME' not found."
      return 56
    }
  else # delete user
    # busybox shell test cmd does not work reliably, checking for ability to open file as more reliable option
    # if [ -w $AUTH_XML_TEMP ]; then
    if >>"$AUTH_XML_TEMP"; then
      $(xmlstarlet ed -L -d "users/user[@username='$USERNAME']" "$AUTH_XML_TEMP")
    else
      {
        HTTP_STATUS=500
        ERROR_MESSAGE="Error deleting user. Check '$AUTH_XML_TEMP' file permissions."
        return 57
      }
    fi
  fi
  
  mv $AUTH_XML_TEMP $AUTH_XML
  sync
  return 0
}

main() {
  if [ -f $AUTH_XML ]; then
    if [ "$REQUEST_METHOD" = "GET" ]; then
      get_users
    elif [ "$REQUEST_METHOD" = "POST" ]; then
      update_users
    elif [ "$REQUEST_METHOD" = "DELETE" ]; then
      delete_user
    fi
    STATUS_CODE=$?
  else
    {
      HTTP_STATUS=500
      ERROR_MESSAGE="'$AUTH_XML' file does not exists."
      STATUS_CODE=50
    }
  fi
  echo "Status: $HTTP_STATUS"
  echo "Content-type: application/json"
  echo ""
  if [ "$STATUS_CODE" -ne 0 ]; then
    echo "{\"errorCode\": \"$STATUS_CODE\", \"errorMessage\": \"$ERROR_MESSAGE\"}"
  else
    if [ "$REQUEST_METHOD" = "GET" ]; then
      echo "$USERS_JSON"
    else
      echo "{}"
    fi
  fi
}

main
