]> git.plutz.net Git - cgilite/commitdiff
better data-layer / UI-layer abstraction in user functions
authorPaul Hänsch <paul@plutz.net>
Wed, 27 Oct 2021 20:39:07 +0000 (22:39 +0200)
committerPaul Hänsch <paul@plutz.net>
Wed, 27 Oct 2021 20:39:07 +0000 (22:39 +0200)
users.sh

index 7721def9c5c07927502309a9a11ed8e60af523b9..a389f15c6fb81ef361c13c36b3f9a82e6dd22142 100755 (executable)
--- a/users.sh
+++ b/users.sh
@@ -12,32 +12,53 @@ USER_REQUIREEMAIL="${USER_REQUIREEMAIL:-true}"
 HTTP_HOST="$(HEADER Host)"
 MAILFROM="${MAILDOMAIN:-noreply@${HTTP_HOST%:*}}"
 
+# == FILE FORMAT ==
+# UID  UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
+#              (pending|active|deleted)
+
+# == GLOBALS ==
+UNSET_USER='unset \
+  USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
+  USER_EXPIRE USER_DEVICES USER_FUTUREUSE
+'
+
+LOCAL_USER='local \
+  USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
+  USER_EXPIRE USER_DEVICES USER_FUTUREUSE
+'
+
+eval "$UNSET_USER"
+
 user_db="${_DATA}/users.db"
-unset USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
-      USER_EXPIRE USER_DEVICES USER_FUTUREUSE
 
-# USER DB
-# UID  UNAME   STATUS (pending|active|deleted) EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
+read_user() {
+  local user="$1"
 
-user_id="$(SESSION_VAR user_id)"
-if [ "$user_id" -a -f "$user_db" -a -r "$user_db" ]; then
-   read -r USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
-           USER_EXPIRE USER_DEVICES USER_FUTUREUSE <<-EOF
-       $(grep "^${user_id}     " "$user_db")
+  # Global exports
+  USER_ID='' USER_NAME='' USER_STATUS='' USER_EMAIL='' USER_PWSALT=''
+  USER_PWHASH='' USER_EXPIRE='' USER_DEVICES='' USER_FUTUREUSE=''
+
+  if [ $# -eq 0 ]; then
+    read -r USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
+            USER_EXPIRE USER_DEVICES USER_FUTUREUSE
+  elif [ "$user" -a -f "$user_db" -a -r "$user_db" ]; then
+    read -r USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
+            USER_EXPIRE USER_DEVICES USER_FUTUREUSE <<-EOF
+       $(grep "^${user}        " "${user_db}")
        EOF
-  if [ "$USER_ID" -a "$USER_STATUS" = active -a "$USER_EXPIRE" -gt "$_DATE" ]; then
+  fi
+  if [ "$USER_ID" -a "${USER_EXPIRE:-0}" -gt "$_DATE" ]; then
        USER_NAME="$(UNSTRING "$USER_NAME")"
       USER_EMAIL="$(UNSTRING "$USER_EMAIL")"
     USER_DEVICES="$(UNSTRING "$USER_DEVICES")"
     unset USER_PWSALT USER_PWHASH
   else
-    unset USER_ID USER_NAME USER_STATUS USER_EMAIL USER_PWSALT USER_PWHASH \
-          USER_EXPIRE USER_DEVICES USER_FUTUREUSE
+    eval "$UNSET_USER"
+    return 1
   fi
-fi
-unset user_id
+}
 
-user_update_user() {
+update_user() {
   # internal function for user update
   local uid="$1" uname status email pwsalt pwhash expire devices futureuse
   local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
@@ -48,6 +69,7 @@ user_update_user() {
     status=*) status="${arg#*=}";;
     email=*) email="${arg#*=}";;
     password=*) pwsalt="$(randomid)"; pwhash="$(user_pwhash "$pwsalt" "${arg#*=}")";;
+    expire=*) expire="${arg#*=}";;
     devices=*) devices="${arg#*=}";;
   esac; done
 
@@ -55,19 +77,19 @@ user_update_user() {
     while read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES \
                   FUTUREUSE; do
     if [ "$UID" = "$uid" ]; then
-      printf '%s       %s      %s      %s      %s      %s      %s      %s      %s\n' \
+      printf '%s       %s      %s      %s      %s      %s      %i      %s      %s\n' \
              "$uid" "$(STRING "${uname-$(UNSTRING "$UNAME")}")" \
              "${status:-${status-${STATUS}}${status+\\}}" \
              "${email:-${email-${EMAIL}}${email+\\}}" \
              "${pwsalt:-${PWSALT}}" "${pwhash:-${PWHASH}}" \
-             "$((_DATE + 86400 * 730))" \
+             "${expire:-$((_DATE + 86400 * 730))}" \
              "$(STRING "${devices-$(UNSTRING "$DEVICES")}")" \
              "${FUTUREUSE:-\\}"
     elif [ "$STATUS" = pending -a ! "$EXPIRE" -ge "$_DATE" ]; then
       # omit expired invitations from output
       :
     else
-      printf '%s       %s      %s      %s      %s      %s      %s      %s      %s\n' \
+      printf '%s       %s      %s      %s      %s      %s      %i      %s      %s\n' \
              "$UID" "$UNAME" "$STATUS" "$EMAIL" "$PWSALT" "$PWHASH" \
              "$EXPIRE" "$DEVICES" "$FUTUREUSE"
     fi
@@ -79,6 +101,32 @@ user_update_user() {
   fi
 }
 
+new_user(){
+  local user="${1:-$(timeid)}"
+  shift 1
+
+  if LOCK "$user_db"; then
+    if grep -q "^${user}       " "$user_db"; then
+      RELEASE "$user_db"
+      return 1
+    fi
+    printf '%s \\      %s      \\      \\      \\      %i      \\      \\\n' \
+           "$user" "pending" "$(( $_DATE + 86400 ))" >>"$user_db"
+  else
+    return 1
+  fi
+
+  if [ $# -eq 0 ]; then
+    RELEASE "$user_db"
+    return 0
+  elif update_user "$user" "$@"; then
+    return 0
+  else
+    RELEASE "$user_db"
+    return 1
+  fi
+}
+
 user_checkname(){
   { [ $# -gt 0 ] && printf %s "$*" || cat; } \
   | sed -nE '
@@ -144,12 +192,7 @@ user_register(){
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_INVALID"
     elif user_emailexist "$email"; then
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_EXISTS"
-    elif LOCK "$user_db"; then
-      printf '%s       \\      pending %s      \\      \\      %i      \\      \\\n' \
-             "$uid" "$(STRING "$email")" "$(( $_DATE + 86400 ))" \
-             >>"$user_db"
-      RELEASE "$user_db"
-
+    elif new_user "$uid" status=pending email="$email" expire="$((_DATE + 86400))"; then
       debug "Sending Activation Link:" \
             "https://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
       sendmail -t -f "$MAILFROM" <<-EOF
@@ -187,14 +230,7 @@ user_register(){
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_PW_EMPTYTOOSHORT"
     elif [ "$pw" != "$pwconfirm" ]; then
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_PW_MISMATCH"
-    elif LOCK "$user_db"; then
-      printf '%s       %s      active  %s      %s      %s      %i      \\      \\\n' \
-             "$uid" "$(STRING "$uname")" "$(STRING "$email")" \
-             "$pwsalt" "$(user_pwhash "$pwsalt" "$pw")" \
-             "$(( $_DATE + 86400 * 730 ))" \
-             >>"$user_db"
-      RELEASE "$user_db"
-
+    elif new_user "$uid" uname="$uname" status=active email="$email" password="$pw" expire="$((_DATE + 86400 * 730))"; then
       SESSION_COOKIE new
       SESSION_BIND user_id "$uid"
 
@@ -214,11 +250,7 @@ user_invite(){
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_INVALID"
   elif user_emailexist "$email"; then
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_EXISTS"
-  elif LOCK "$user_db"; then
-    printf '%s \\      pending %s      \\      \\      %i      \\      \\\n' \
-           "$uid" "$(STRING "$email")" "$(( $_DATE + 86400 ))" \
-           >>"$user_db"
-    RELEASE "$user_db"
+  elif new_user "$uid" status=pending email="$email" expire="$((_DATE + 86400))"; then
     debug "Sending Invitation Link:" \
           "https://${HTTP_HOST}${BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
     sendmail -t -f "$MAILFROM" <<-EOF
@@ -252,16 +284,14 @@ user_invite(){
 
 user_confirm(){
   # enable account
-  local UID    UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
-  local uid="$(POST uid |checkid)"
+  eval "$LOCAL_USER"
+  local uid="$(POST uid |checkid || printf invalid)"
   local signature="$(POST signature)"
   local uname="$(POST uname |user_checkname)"
   local pwsalt="$(randomid)"
   local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
 
-  read -r UID  UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE <<-EOF
-       $(grep "^${uid:-invalid}        " "$user_db")
-       EOF
+  read_user "${uid}"
 
   if [ "$signature" != "$(session_mac "$uid")" ]; then
     REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
@@ -273,11 +303,11 @@ user_confirm(){
     REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_PW_EMPTYTOOSHORT"
   elif [ "$pw" != "$pwconfirm" ]; then
     REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_PW_MISMATCH"
-  elif [ "$STATUS" != pending -o \! "$EXPIRE" -gt "$_DATE" ]; then
+  elif [ "$USER_STATUS" != pending -o \! "$USER_EXPIRE" -gt "$_DATE" ]; then
     REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
-  elif user_update_user "$UID" uname="$uname" status=active password="$pw"; then
+  elif update_user "$USER_ID" uname="$uname" status=active password="$pw"; then
     SESSION_COOKIE new
-    SESSION_BIND user_id "$UID"
+    SESSION_BIND user_id "$USER_ID"
     REDIRECT "${_BASE}${PATH_INFO}?user_register=confirm#USER_REGISTER_CONFIRM"
   else
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
@@ -325,6 +355,9 @@ user_disable(){
   :
 }
 
+read_user "$(SESSION_VAR user_id)"
+[ "$USER_STATUS" -a "$USER_STATUS" != active ] && eval $UNSET_USER
+
 [ "$REQUEST_METHOD" = POST ] && case "$(POST action)" in
   user_register) user_register ;;
   user_confirm)  user_confirm ;;