]> git.plutz.net Git - cgilite/blobdiff - users.sh
new function RXLITERAL() for escaping regex characters
[cgilite] / users.sh
index 6a6833e96c592043669006bbeec91b628a70667e..32299ff1e3f97f26f7cb2c7d3860d56c1a3e83d2 100755 (executable)
--- a/users.sh
+++ b/users.sh
@@ -1,10 +1,24 @@
 #!/bin/sh
 
 #!/bin/sh
 
+# Copyright 2021 - 2024 Paul Hänsch
+# 
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+# 
+# THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+# SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
+# IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
 [ -n "$include_users" ] && return 0
 include_users="$0"
 
 [ -n "$include_users" ] && return 0
 include_users="$0"
 
-. "${_EXEC}/cgilite/session.sh"
-. "${_EXEC}/cgilite/storage.sh"
+. "${_EXEC:-.}/cgilite/session.sh"
+. "${_EXEC:-.}/cgilite/storage.sh"
 
 SENDMAIL=${SENDMAIL-sendmail}
 
 
 SENDMAIL=${SENDMAIL-sendmail}
 
@@ -15,9 +29,8 @@ USER_ACCOUNTPAGE="${USER_ACCOUNTPAGE}"
 USER_ACCOUNTEXPIRE="${USER_ACCOUNTEXPIRE:-$((86400 * 730))}"
 USER_CONFIRMEXPIRE="${USER_CONFIRMEXPIRE:-86400}"
 
 USER_ACCOUNTEXPIRE="${USER_ACCOUNTEXPIRE:-$((86400 * 730))}"
 USER_CONFIRMEXPIRE="${USER_CONFIRMEXPIRE:-86400}"
 
-MAILFROM="${MAILDOMAIN-noreply@${HTTP_HOST%:*}}"
-
 HTTP_HOST="$(HEADER Host)"
 HTTP_HOST="$(HEADER Host)"
+MAILFROM="noreply@${HTTP_HOST%:*}"
 
 [ "$HTTPS" ] && SCHEMA=https || SCHEMA=http
 
 
 [ "$HTTPS" ] && SCHEMA=https || SCHEMA=http
 
@@ -36,6 +49,10 @@ LOCAL_USER='local \
   USER_EXPIRE USER_DEVICES USER_FUTUREUSE
 '
 
   USER_EXPIRE USER_DEVICES USER_FUTUREUSE
 '
 
+# == TRANSLATIONS ==
+# override all functions marked with "TRANSLATION"
+# sed -n '/TRANSLATION$/,/^}/p;' <cgilite/users.sh
+
 unset USER_IDMAP
 eval "$UNSET_USER"
 
 unset USER_IDMAP
 eval "$UNSET_USER"
 
@@ -218,28 +235,8 @@ user_pwhash(){
   printf '%s\n' "${hash%% *}"
 }
 
   printf '%s\n' "${hash%% *}"
 }
 
-user_register(){
-  # reserve account, send registration mail
-  # preliminary uid, expiration, signature
-  local uid="$(timeid)"
-  local uname="$(POST uname |user_checkname)"
-  local email="$(POST email |user_checkemail)"
-  local pwsalt="$(randomid)"
-  local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
-
-  if [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
-    REDIRECT "${_BASE}${PATH_INFO}#ERROR_REGISTRATION_DISABLED"
-  fi
-
-  if   [ "$USER_REQUIREEMAIL" = true ]; then
-    if [ ! "email" ]; then
-      REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_INVALID"
-    elif user_emailexist "$email"; then
-      REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_EXISTS"
-    elif new_user "$uid" status=pending email="$email" expire="$((_DATE + USER_CONFIRMEXPIRE))"; then
-      debug "Sending Activation Link:" \
-            "${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
-      "$SENDMAIL" -t -f "$MAILFROM" <<-EOF
+user_register_email() {  # TRANSLATION
+  "$SENDMAIL" -t -f "$MAILFROM" <<-EOF
        From: ${MAILFROM}
        To: ${email}
        Subject: Your account registration at ${HTTP_HOST%:*}
        From: ${MAILFROM}
        To: ${email}
        Subject: Your account registration at ${HTTP_HOST%:*}
@@ -260,6 +257,30 @@ user_register(){
        This is an automatic email. Any direct reply will not be received.
        Your Account Registration Robot.
        EOF
        This is an automatic email. Any direct reply will not be received.
        Your Account Registration Robot.
        EOF
+}
+
+user_register(){
+  # reserve account, send registration mail
+  # preliminary uid, expiration, signature
+  local uid="$(timeid)"
+  local uname="$(POST uname |user_checkname)"
+  local email="$(POST email |user_checkemail)"
+  local pwsalt="$(randomid)"
+  local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
+
+  if [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
+    REDIRECT "${_BASE}${PATH_INFO}#ERROR_REGISTRATION_DISABLED"
+  fi
+
+  if   [ "$USER_REQUIREEMAIL" = true ]; then
+    if [ ! "$email" ]; then
+      REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_INVALID"
+    elif user_emailexist "$email"; then
+      REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_EXISTS"
+    elif new_user "$uid" status=pending email="$email" expire="$((_DATE + USER_CONFIRMEXPIRE))"; then
+      debug "Sending Activation Link:" \
+            "${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
+      user_register_email
       REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
     else
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
       REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
     else
       REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
@@ -289,19 +310,8 @@ user_register(){
   fi
 }
 
   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 new_user "$uid" status=pending email="$email" expire="$((_DATE + USER_CONFIRMEXPIRE))"; then
-    debug "Sending Invitation Link:" \
-          "${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
-    "$SENDMAIL" -t -f "$MAILFROM" <<-EOF
+user_invite_email(){  # TRANSLATION
+  "$SENDMAIL" -t -f "$MAILFROM" <<-EOF
        From: ${MAILFROM}
        To: ${email}
        Subject: You have been invited to ${HTTP_HOST%:*}
        From: ${MAILFROM}
        To: ${email}
        Subject: You have been invited to ${HTTP_HOST%:*}
@@ -324,6 +334,21 @@ user_invite(){
        This is an automatic email. Any direct reply will not be received.
        Your Account Registration Robot.
        EOF
        This is an automatic email. Any direct reply will not be received.
        Your Account Registration Robot.
        EOF
+}
+
+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 new_user "$uid" status=pending email="$email" expire="$((_DATE + USER_CONFIRMEXPIRE))"; then
+    debug "Sending Invitation Link:" \
+          "${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
+    user_invite_email
     REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
   else
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
     REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
   else
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
@@ -403,7 +428,7 @@ user_update(){
 
         uid="$(POST uid)"
       oldpw="$(POST oldpw)"
 
         uid="$(POST uid)"
       oldpw="$(POST oldpw)"
-         pw="$(POST pw |grep -xE '.{6}')"
+         pw="$(POST pw |grep -m1 -xE '.{6,}')"
   pwconfirm="$(POST pwconfirm)"
 
 
   pwconfirm="$(POST pwconfirm)"
 
 
@@ -416,7 +441,7 @@ user_update(){
       update_user "${uid}" password="$pw"
       REDIRECT "${_BASE}${PATH_INFO}#UPDATE_SUCCESS"
     else
       update_user "${uid}" password="$pw"
       REDIRECT "${_BASE}${PATH_INFO}#UPDATE_SUCCESS"
     else
-      REDIRECT "${_BASE}${PATH_INFO}#ERROR_PWMISMATCH"
+      REDIRECT "${_BASE}${PATH_INFO}#ERROR_PW_MISMATCH"
     fi
   elif [ "$UID_" = "$USER_ID" ]; then
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_INVALID_AUTH_PASSWORD"
     fi
   elif [ "$UID_" = "$USER_ID" ]; then
     REDIRECT "${_BASE}${PATH_INFO}#ERROR_INVALID_AUTH_PASSWORD"
@@ -474,17 +499,15 @@ w_user_update(){
   fi
 }
 
   fi
 }
 
-w_user_register(){
-  if [ "$(GET user_confirm)" ]; then
-    w_user_confirm
-  elif [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
-    cat <<-EOF
+w_user_register_disabled(){  # TRANSLATION
+  cat <<-EOF
        [div #user_register .disabled
        User Registration is disabled.
        ]
        EOF
        [div #user_register .disabled
        User Registration is disabled.
        ]
        EOF
-  elif [ "$USER_REQUIREEMAIL" = true ]; then
-    cat <<-EOF
+}
+w_user_register_sendmail(){  # TRANSLATION
+  cat <<-EOF
        [form #user_register .registeremail method=POST
          [p We will send an activation mail to your email address.
            You can continue the signup process when you click on the
        [form #user_register .registeremail method=POST
          [p We will send an activation mail to your email address.
            You can continue the signup process when you click on the
@@ -493,8 +516,9 @@ w_user_register(){
          [submit "action" "user_register" Sign Up]
        ]
        EOF
          [submit "action" "user_register" Sign Up]
        ]
        EOF
-  elif [ "$USER_REQUIREEMAIL" != true ]; then
-    cat <<-EOF
+}
+w_user_register_direct(){  # TRANSLATION
+  cat <<-EOF
        [form #user_register .registername method=POST
           [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
          [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
        [form #user_register .registername method=POST
           [input name=uname placeholder="Choose Username" tooltip="Your username may contain any character but the @ sign. It must be at least 3 characters long, and it must start with a letter." pattern="^\[\\\\p{L}\]\[\\\\p{L}0-9 -~\]{2,127}$" autocomplete=off]
          [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
@@ -502,20 +526,22 @@ w_user_register(){
          [submit "action" "user_register" Sign Up]
        ]
        EOF
          [submit "action" "user_register" Sign Up]
        ]
        EOF
-  fi
 }
 
 }
 
-w_user_confirm(){
-  local UID_   UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
-  local user_confirm="$(GET user_confirm)"
-  local uid="${user_confirm% *}" signature="${user_confirm#* }"
+w_user_register(){
+  if [ "$(GET user_confirm)" ]; then
+    w_user_confirm
+  elif [ "$USER_REGISTRATION" != true -a -s "$user_db" ]; then
+    w_user_register_disabled
+  elif [ "$USER_REQUIREEMAIL" = true ]; then
+    w_user_register_sendmail
+  elif [ "$USER_REQUIREEMAIL" != true ]; then
+    w_user_register_direct
+  fi
+}
 
 
-  if [ "$signature" = "$(session_mac "$uid")" ]; then
-    read -r UID_       UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE <<-EOF
-       $(grep "^${uid} " "$user_db")
-       EOF
-    if [ "$STATUS" = pending -a "$EXPIRE" -gt "$_DATE" ]; then
-      cat <<-EOF
+w_user_confirm_proceed(){  # TRANSLATION
+  cat <<-EOF
        [form #user_confirm method=POST
          [input type=hidden name=uid value="${uid}"]
          [input type=hidden name=signature value="${signature}"]
        [form #user_confirm method=POST
          [input type=hidden name=uid value="${uid}"]
          [input type=hidden name=signature value="${signature}"]
@@ -528,41 +554,52 @@ w_user_confirm(){
          [submit "action" "user_confirm" Finish Registration]
        ]
        EOF
          [submit "action" "user_confirm" Finish Registration]
        ]
        EOF
-    else
-      cat <<-EOF
+}
+w_user_confirm_expired(){  # TRANSLATION
+  cat <<-EOF
        [div #user_confirm .expired
          [p This activation link is not valid anymore.]
        ]
        EOF
        [div #user_confirm .expired
          [p This activation link is not valid anymore.]
        ]
        EOF
-    fi
-  else
-    cat <<-EOF
+}
+w_user_confirm_invalid(){  # TRANSLATION
+  cat <<-EOF
        [div #user_confirm .invalid
          [p This activation link is invalid. Make sure you copied the whole activation link from your email and be careful not to include any line breaks.]
        ]
        EOF
        [div #user_confirm .invalid
          [p This activation link is invalid. Make sure you copied the whole activation link from your email and be careful not to include any line breaks.]
        ]
        EOF
-  fi
 }
 
 }
 
-w_user_invite(){
-  local uid invlink
+w_user_confirm(){
+  local UID_   UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE
+  local user_confirm="$(GET user_confirm)"
+  local uid="${user_confirm% *}" signature="${user_confirm#* }"
 
 
-  if [ "$(GET user_confirm)" ]; then
-    w_user_confirm
-  elif [ "$USER_ID" -a "$SENDMAIL" ]; then
-    cat <<-EOF
+  if [ "$signature" = "$(session_mac "$uid")" ]; then
+    read -r UID_       UNAME   STATUS  EMAIL   PWSALT  PWHASH  EXPIRE  DEVICES FUTUREUSE <<-EOF
+       $(grep "^${uid} " "$user_db")
+       EOF
+    if [ "$STATUS" = pending -a "$EXPIRE" -gt "$_DATE" ]; then
+      w_user_confirm_proceed
+    else
+      w_user_confirm_expired
+    fi
+  else
+    w_user_confirm_invalid
+  fi
+}
+
+w_user_invite_email(){  # TRANSLATION
+  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
        [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
-  elif [ "$USER_ID" ]; then
-    uid="$(timeid)"
-    new_user "$uid" status=pending expire="$((_DATE + USER_CONFIRMEXPIRE))"
-    invlink="${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
-    debug "New Invitation Link: $invlink"
-    cat <<-EOF
+}
+w_user_invite_link(){  # TRANSLATION
+  cat <<-EOF
        [div #user_invite .link
           [p An anonymous user account has been set up. Send the following link to the intended user, so they may claim their account. The link will remain valid for $((USER_CONFIRMEXPIRE / 3600)) hours.]
           [a href="$(HTML "$invlink")" . $(HTML "$invlink")]
        [div #user_invite .link
           [p An anonymous user account has been set up. Send the following link to the intended user, so they may claim their account. The link will remain valid for $((USER_CONFIRMEXPIRE / 3600)) hours.]
           [a href="$(HTML "$invlink")" . $(HTML "$invlink")]
@@ -570,30 +607,55 @@ w_user_invite(){
           [p [a href="#" . Set up another account]]
        ]
        EOF
           [p [a href="#" . Set up another account]]
        ]
        EOF
-  else
-    cat <<-EOF
+}
+w_user_invite_deny(){  # TRANSLATION
+  cat <<-EOF
        [div #user_invite .notallowed
          Only registered users may send an invitation to another user.
        ]
        EOF
        [div #user_invite .notallowed
          Only registered users may send an invitation to another user.
        ]
        EOF
+}
+
+w_user_invite(){
+  local uid invlink
+
+  if [ "$(GET user_confirm)" ]; then
+    w_user_confirm
+  elif [ "$USER_ID" -a "$USER_REQUIREEMAIL" = true ]; then
+    w_user_invite_email
+  elif [ "$USER_ID" ]; then
+    uid="$(timeid)"
+    new_user "$uid" status=pending expire="$((_DATE + USER_CONFIRMEXPIRE))"
+    invlink="${SCHEMA}://${HTTP_HOST}${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")"
+    debug "New Invitation Link: $invlink"
+    w_user_invite_link
+  else
+    w_user_invite_deny
   fi
 }
 
   fi
 }
 
-w_user_login(){
-  if [ ! "$USER_ID" ]; then
-    cat <<-EOF
+w_user_login_logon(){  # TRANSLATION
+  cat <<-EOF
        [form #user_login .login method=POST
        [form #user_login .login method=POST
-         [input name=uname placeholder="Username or Email" autocomplete=off]
+         [input name=uname placeholder="Username or Email"]
          [input type=password name=pw placeholder="Passphrase"]
          [submit "action" "user_login" Login]
        ]
        EOF
          [input type=password name=pw placeholder="Passphrase"]
          [submit "action" "user_login" Login]
        ]
        EOF
-  elif [ "$USER_ID" ]; then
-    cat <<-EOF
+}
+w_user_login_logoff(){  # TRANSLATION
+  cat <<-EOF
        [form #user_login .logout method=POST
          [p Logged in as [span . $(HTML ${USER_NAME})]]
          [submit "action" "user_logout" Logout]
        ]
        EOF
        [form #user_login .logout method=POST
          [p Logged in as [span . $(HTML ${USER_NAME})]]
          [submit "action" "user_logout" Logout]
        ]
        EOF
+}
+
+w_user_login(){
+  if [ ! "$USER_ID" ]; then
+    w_user_login_logon
+  elif [ "$USER_ID" ]; then
+    w_user_login_logoff
   fi
 }
   fi
 }