From aaf78b73ef86bfa892e60a2d9608b6c68bc4b2c4 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Mon, 15 Nov 2021 17:12:16 +0100 Subject: [PATCH] Squashed 'cgilite/' changes from 5a44f82..b191eb8 b191eb8 export application globals dba2d39 idmap functions f477dc5 better data-layer / UI-layer abstraction in user functions git-subtree-dir: cgilite git-subtree-split: b191eb8df453e7e1877443d75214f8b89ee96eaf --- cgilite.sh | 2 + users.sh | 164 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 118 insertions(+), 48 deletions(-) diff --git a/cgilite.sh b/cgilite.sh index 310dd64..a0a96d1 100755 --- a/cgilite.sh +++ b/cgilite.sh @@ -48,6 +48,8 @@ _EXEC="${_EXEC:-${0%/*}}" _DATA="${_DATA:-.}" _EXEC="${_EXEC%/}" _DATA="${_DATA%/}" _BASE="${_BASE%/}" +export _EXEC _DATA _BASE + # Carriage Return and Line Break characters for convenience CR=" " BR=' diff --git a/users.sh b/users.sh index 7721def..873edf0 100755 --- a/users.sh +++ b/users.sh @@ -12,32 +12,54 @@ USER_REQUIREEMAIL="${USER_REQUIREEMAIL:-true}" HTTP_HOST="$(HEADER Host)" MAILFROM="${MAILDOMAIN:-noreply@${HTTP_HOST%:*}}" -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 - -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") +# == 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 +' + +unset USER_IDMAP +eval "$UNSET_USER" + +user_db="${user_db:-${_DATA}/users.db}" + +read_user() { + local user="$1" + + # 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 +70,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 +78,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 +102,66 @@ 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_idmap(){ + local uid="$1" ret + eval "$LOCAL_USER" + + if [ ! "$USER_IDMAP" ]; then + while read_user; do + USER_IDMAP="${USER_IDMAP}${USER_ID} ${USER_NAME}${BR}" + done <"$user_db" + fi + if [ "$uid" -a "$USER_IDMAP" != "${USER_IDMAP##*${uid} }" ]; then + ret="${USER_IDMAP##*${uid} }"; ret="${ret%%${BR}*}"; + printf '%s\n' "$ret" + return 0 + elif [ "$uid" ]; then + return 1 + else + printf '%s' "$USER_IDMAP" + return 0 + fi +} + +user_idof(){ + local name="$(STRING "$1")" ret + [ "$USER_IDMAP" ] || user_idmap >/dev/null + + if [ "${name%\\}" -a "$USER_IDMAP" != "${USER_IDMAP% ${name}${BR}*}" ]; then + ret="${USER_IDMAP% ${name}${BR}*}"; ret="${ret##*${BR}}" + printf '%s\n' "$ret" + return 0 + else + return 1 + fi +} + user_checkname(){ { [ $# -gt 0 ] && printf %s "$*" || cat; } \ | sed -nE ' @@ -144,12 +227,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 +265,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 +285,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 +319,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 +338,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 +390,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 ;; -- 2.39.2