]> git.plutz.net Git - rawnet/commitdiff
Squashed 'cgilite/' changes from af27357..6c1784b
authorPaul Hänsch <paul@plutz.net>
Thu, 7 Oct 2021 14:22:56 +0000 (16:22 +0200)
committerPaul Hänsch <paul@plutz.net>
Thu, 7 Oct 2021 14:22:56 +0000 (16:22 +0200)
6c1784b user invite function, handle invite/registration expire, always allow registration of first user

git-subtree-dir: cgilite
git-subtree-split: 6c1784b157a0990a9ad04ebce2176989e0fabcd0

users.sh

index 4c730ee3753367567f6e08e527df6bd9da4f85a0..c13703b418fc057adcdc936d26b515c55a3a74f7 100755 (executable)
--- a/users.sh
+++ b/users.sh
@@ -13,24 +13,70 @@ HTTP_HOST="$(HEADER Host)"
 MAILFROM="${MAILDOMAIN:-noreply@${HTTP_HOST%:*}}"
 
 user_db="${_DATA}/users.db"
-unset USER_ID USER_NAME USER_EMAIL
+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
 
-user_init(){
-   local user_id="$(SESSION_VAR user_id)"
-   local UID   UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
-   [ "$user_id" ] \
-   && read -r UID      UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE <<-EOF
+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")
        EOF
-   [ "$STATUS" -a "$EXPIRE" ] \
-   && if [ "$STATUS" = active -a "$EXPIRE" -gt "$_DATE" ]; then
-     USER_ID="$UID"
-     USER_NAME="$(UNSTRING "$UNAME")"
-     USER_EMAIL="$(UNSTRING "$EMAIL")"
-   fi
+  if [ "$USER_ID" -a "$USER_STATUS" = active -a "$USER_EXPIRE" -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
+  fi
+fi
+unset user_id
+
+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
+  local arg
+
+  for arg in "$@"; do case $arg in
+    uname=*) uname="${arg#*=}";;
+    status=*) status="${arg#*=}";;
+    email=*) email="${arg#*=}";;
+    password=*) pwsalt="$(randomid)"; pwhash="$(user_pwhash "$pwsalt" "${arg#*=}")";;
+    devices=*) devices="${arg#*=}";;
+  esac; done
+
+  if LOCK "$user_db"; then
+    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' \
+             "$uid" "$(STRING "${uname-$(UNSTRING "$UNAME")}")" \
+             "${status:-${status-${STATUS}}${status+\\}}" \
+             "${email:-${email-${EMAIL}}${email+\\}}" \
+             "${pwsalt:-${PWSALT}}" "${pwhash:-${PWHASH}}" \
+             "$((_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' \
+             "$UID" "$UNAME" "$STATUS" "$EMAIL" "$PWSALT" "$PWHASH" \
+             "$EXPIRE" "$DEVICES" "$FUTUREUSE"
+    fi
+    done <"$user_db" >"${user_db}.$$"
+    mv -- "${user_db}.$$" "$user_db"
+    RELEASE "$user_db"
+  else
+    return 1
+  fi
 }
 
 user_checkname(){
@@ -89,7 +135,7 @@ user_register(){
   local pwsalt="$(randomid)"
   local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
 
-  if [ "$USER_REGISTRATION" != true ]; then
+  if [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_REGISTRATION_DISABLED"
   fi
 
@@ -103,6 +149,9 @@ user_register(){
              "$uid" "$(STRING "$email")" "$(( $_DATE + 86400 ))" \
              >>"$user_db"
       RELEASE "$user_db"
+
+      debug "Sending Activation Link:" \
+            "https://${HTTP_HOST%:*}/${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
       sendmail -t -f "$MAILFROM" <<-EOF
        From: ${MAILFROM}
        To: ${email}
@@ -156,6 +205,51 @@ user_register(){
   fi
 }
 
+user_invite(){
+  local uid="$(timeid)"
+  local email="$(POST email |user_checkemail)"
+  local message="$(POST message)"
+
+  if [ ! "email" ]; then
+    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"
+    debug "Sending Invitation Link:" \
+          "https://${HTTP_HOST%:*}/${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
+    sendmail -t -f "$MAILFROM" <<-EOF
+       From: ${MAILFROM}
+       To: ${email}
+       Subject: You have been invited to ${HTTP_HOST%:*}
+
+       ${USER_NAME:-Someone} has offered an invitation to this email address.
+
+       ${message}
+
+       You can create your account using this link:
+
+           https://${HTTP_HOST%:*}/${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")
+
+       This registration link will expire after 24 hours.
+
+       If you do not know what this is about, then someone else probably
+       entered your email address by accident. In this case you shoud
+       simply ignore this message and we will remove your email address from
+       our database within the next day.
+
+       This is an automatic email. Any direct reply will not be received.
+       Your Account Registration Robot.
+       EOF
+    REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
+  else
+    REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
+  fi
+}
+
 user_confirm(){
   # enable account
   local UID    UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
@@ -165,6 +259,10 @@ user_confirm(){
   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
+
   if [ "$signature" != "$(session_mac "$uid")" ]; then
     REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
   elif [ ! "$uname" ]; then
@@ -175,28 +273,12 @@ 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 LOCK "$user_db"; then
-    read -r UID        UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE <<-EOF
-       $(grep "^${uid} " "$user_db")
-       EOF
-
-    if [ "$STATUS" != pending -o "$EXPIRE" -le "$_DATE" ]; then
-      RELEASE "$user_db"
-      REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
-    else
-      printf '%s       %s      active  %s      %s      %s      %i      %s      %s\n' \
-             "$UID" "$(STRING "$uname")" "$EMAIL" \
-             "$pwsalt" "$(user_pwhash "$pwsalt" "$pw")" \
-             "$(( $_DATE + 86400 * 730 ))" "$DEVICES" "$FUTUREUSE" \
-             >"${user_db}.$$"
-      grep -v "^${uid} " "$user_db" >>"${user_db}.$$"
-      mv "${user_db}.$$" "${user_db}"
-      RELEASE "$user_db"
-
-      SESSION_COOKIE new
-      SESSION_BIND user_id "$UID"
-      REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
-    fi
+  elif [ "$STATUS" != pending -o \! "$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
+    SESSION_COOKIE new
+    SESSION_BIND user_id "$UID"
+    REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
   else
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
   fi
@@ -243,11 +325,10 @@ user_disable(){
   :
 }
 
-user_init
-
 [ "$REQUEST_METHOD" = POST ] && case "$(POST action)" in
   user_register) user_register ;;
   user_confirm)  user_confirm ;;
+  user_invite)   user_invite ;;
   user_login)    user_login ;;
   user_logout)   user_logout ;;
   user_update)
@@ -261,7 +342,7 @@ esac
 w_user_register(){
   if [ "$(GET user_confirm)" ]; then
     w_user_confirm
-  elif [ "$USER_REGISTRATION" != true ]; then
+  elif [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
     cat <<-EOF
        [div #user_register .disabled
        User Registration is disabled.
@@ -326,6 +407,26 @@ w_user_confirm(){
   fi
 }
 
+w_user_invite(){
+  if [ "$(GET user_confirm)" ]; then
+    w_user_confirm
+  elif [ "$USER_ID" ]; then
+    cat <<-EOF
+       [form #user_invite method=POST
+         [input placeholder="Email Recipient" name=email autocomplete=off]
+         [textarea name="message" placeholder="Message to recipient" . ]
+         [submit "action" "user_invite" Send Invitation]
+       ]
+       EOF
+  else
+    cat <<-EOF
+       [div #user_invite .notallowed
+         Only registered users may send an invitation to another user.
+       ]
+       EOF
+  fi
+}
+
 w_user_login(){
   if [ ! "$USER_ID" ]; then
     cat <<-EOF