3 [ -n "$include_users" ] && return 0
6 . "${_EXEC}/cgilite/session.sh"
7 . "${_EXEC}/cgilite/storage.sh"
9 USER_REGISTRATION="${USER_REGISTRATION:-true}"
10 USER_REQUIREEMAIL="${USER_REQUIREEMAIL:-true}"
12 HTTP_HOST="$(HEADER Host)"
13 MAILFROM="${MAILDOMAIN:-noreply@${HTTP_HOST%:*}}"
15 user_db="${_DATA}/users.db"
16 unset USER_ID USER_NAME USER_EMAIL
19 # UID UNAME STATUS (pending|active|deleted) EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
22 local user_id="$(SESSION_VAR user_id)"
23 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
25 && read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE <<-EOF
26 $(grep "^${user_id} " "$user_db")
28 [ "$STATUS" -a "$EXPIRE" ] \
29 && if [ "$STATUS" = active -a "$EXPIRE" -gt "$_DATE" ]; then
31 USER_NAME="$(UNSTRING "$UNAME")"
32 USER_EMAIL="$(UNSTRING "$EMAIL")"
37 { [ $# -gt 0 ] && printf %s "$*" || cat; } \
43 /^[a-zA-Z][a-zA-Z0-9 -~]{2,127}$/!d;
49 { [ $# -gt 0 ] && printf %s "$*" || cat; } \
51 # W3C recommended email regex
52 # https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email)
53 /^[a-zA-Z0-9.!#$%&'\''*+\/=?^_`{|}~-]+@[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/p;
58 local uname="$(STRING "$1")"
59 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
60 [ -f "$user_db" -a -r "$user_db" ] \
61 && while read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE; do
62 [ "$EXPIRE" -gt "$_DATE" -a "$UNAME" = "$uname" ] && return 0
68 local email="$(STRING "$1")"
69 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
70 [ -f "$user_db" -a -r "$user_db" ] \
71 && while read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE; do
72 [ "$EXPIRE" -gt "$_DATE" -a "$EMAIL" = "$email" ] && return 0
78 local salt="$1" secret="$2" hash
79 hash="$(printf '%s\n%s\n' "$secret" "$salt" |sha256sum)"
80 printf '%s\n' "${hash%% *}"
84 # reserve account, send registration mail
85 # preliminary uid, expiration, signature
87 local uname="$(POST uname |user_checkname)"
88 local email="$(POST email |user_checkemail)"
89 local pwsalt="$(randomid)"
90 local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
92 if [ "$USER_REGISTRATION" != true ]; then
93 REDIRECT "${_BASE}${PATH_INFO}#ERROR_REGISTRATION_DISABLED"
96 if [ "$USER_REQUIREEMAIL" = true ]; then
97 if [ ! "email" ]; then
98 REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_INVALID"
99 elif user_emailexist "$email"; then
100 REDIRECT "${_BASE}${PATH_INFO}#ERROR_EMAIL_EXISTS"
101 elif LOCK "$user_db"; then
102 printf '%s \\ pending %s \\ \\ %i \\ \\\n' \
103 "$uid" "$(STRING "$email")" "$(( $_DATE + 86400 ))" \
106 sendmail -t -f "$MAILFROM" <<-EOF
109 Subject: Your account registration at ${HTTP_HOST%:*}
111 Someone tried to sign up for a user account using this email address.
113 You can activate your account using this link:
115 https://${HTTP_HOST%:*}/${_BASE}${PATH_INFO}?user_confirm=${uid}+$(session_mac "$uid")
117 This registration link will expire after 24 hours.
119 If you did not request an account at ${HTTP_HOST%:*}, then someone else
120 probably entered your email address by accident. In this case you shoud
121 simply ignore this message and we will remove your email address from
122 our database within the next day.
124 This is an automatic email. Any direct reply will not be received.
125 Your Account Registration Robot.
127 REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
129 REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
132 elif [ "$USER_REQUIREEMAIL" != true ]; then
133 if [ ! "$uname" ]; then
134 REDIRECT "${_BASE}${PATH_INFO}#ERROR_UNAME_INVALID"
135 elif user_nameexist "$uname"; then
136 REDIRECT "${_BASE}${PATH_INFO}#ERROR_UNAME_EXISTS"
137 elif [ ! "$pw" ]; then
138 REDIRECT "${_BASE}${PATH_INFO}#ERROR_PW_EMPTYTOOSHORT"
139 elif [ "$pw" != "$pwconfirm" ]; then
140 REDIRECT "${_BASE}${PATH_INFO}#ERROR_PW_MISMATCH"
141 elif LOCK "$user_db"; then
142 printf '%s %s active %s %s %s %i \\ \\\n' \
143 "$uid" "$(STRING "$uname")" "$(STRING "$email")" \
144 "$pwsalt" "$(user_pwhash "$pwsalt" "$pw")" \
145 "$(( $_DATE + 86400 * 730 ))" \
150 SESSION_BIND user_id "$uid"
152 REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
154 REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
161 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
162 local uid="$(POST uid |checkid)"
163 local signature="$(POST signature)"
164 local uname="$(POST uname |user_checkname)"
165 local pwsalt="$(randomid)"
166 local pw="$(POST pw |grep -m1 -xE '.{6,}' )" pwconfirm="$(POST pwconfirm)"
168 if [ "$signature" != "$(session_mac "$uid")" ]; then
169 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
170 elif [ ! "$uname" ]; then
171 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_UNAME_INVALID"
172 elif user_nameexist "$uname"; then
173 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_UNAME_EXISTS"
174 elif [ ! "$pw" ]; then
175 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_PW_EMPTYTOOSHORT"
176 elif [ "$pw" != "$pwconfirm" ]; then
177 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_PW_MISMATCH"
178 elif LOCK "$user_db"; then
179 read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE <<-EOF
180 $(grep "^${uid} " "$user_db")
183 if [ "$STATUS" != pending -o "$EXPIRE" -le "$_DATE" ]; then
185 REDIRECT "${_BASE}${PATH_INFO}?${QUERY_STRING}#ERROR_LINK_INVALID"
187 printf '%s %s active %s %s %s %i %s %s\n' \
188 "$UID" "$(STRING "$uname")" "$EMAIL" \
189 "$pwsalt" "$(user_pwhash "$pwsalt" "$pw")" \
190 "$(( $_DATE + 86400 * 730 ))" "$DEVICES" "$FUTUREUSE" \
192 grep -v "^${uid} " "$user_db" >>"${user_db}.$$"
193 mv "${user_db}.$$" "${user_db}"
197 SESSION_BIND user_id "$UID"
198 REDIRECT "${_BASE}${PATH_INFO}#USER_REGISTER_CONFIRM"
201 REDIRECT "${_BASE}${PATH_INFO}#ERROR_USER_NOLOCK"
207 # keep logged in - device cookie?
208 # initialize new session!
209 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
210 local uname="$(POST uname |STRING)" pw="$(POST pw)"
212 [ -f "$user_db" -a -r "$user_db" ] \
213 && while read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE; do
214 if [ "$UNAME" = "$uname" -o "$EMAIL" = "$uname" ]; then
215 if [ "$STATUS" = active -a "$EXPIRE" -gt "$_DATE" -a "$PWHASH" = "$(user_pwhash "$PWSALT" "$pw")" ]; then
217 SESSION_BIND user_id "$UID"
218 REDIRECT "${_BASE}${PATH_INFO}#USER_LOGGED_IN"
222 REDIRECT "${_BASE}${PATH_INFO}#ERROR_INVALID_LOGIN"
226 # destroy cookie, destroy session
230 SET_COOKIE 0 user_id="" Path="/${_BASE#/}" SameSite=Strict HttpOnly
231 REDIRECT "${_BASE}${PATH_INFO}#USER_LOGGED_OUT"
248 [ "$REQUEST_METHOD" = POST ] && case "$(POST action)" in
249 user_register) user_register ;;
250 user_confirm) user_confirm ;;
251 user_login) user_login ;;
252 user_logout) user_logout ;;
262 if [ "$(GET user_confirm)" ]; then
264 elif [ "$USER_REGISTRATION" != true ]; then
266 [div #user_register .disabled
267 User Registration is disabled.
270 elif [ "$USER_REQUIREEMAIL" = true ]; then
272 [form #user_register .registeremail method=POST
273 [p We will send an activation mail to your email address.
274 You can continue the signup process when you click on the
275 activation link in this email.]
276 [input type=email name=email placeholder="Email"]
277 [submit "action" "user_register" Sign Up]
280 elif [ "$USER_REQUIREEMAIL" != true ]; then
282 [form #user_register .registername method=POST
283 [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="^\[a-zA-Z\]\[a-zA-Z0-9 -~\]{2,127}$" autocomplete=off]
284 [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
285 [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
286 [submit "action" "user_register" Sign Up]
293 local UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE
294 local user_confirm="$(GET user_confirm)"
295 local uid="${user_confirm% *}" signature="${user_confirm#* }"
297 if [ "$signature" = "$(session_mac "$uid")" ]; then
298 read -r UID UNAME STATUS EMAIL PWSALT PWHASH EXPIRE DEVICES FUTUREUSE <<-EOF
299 $(grep "^${uid} " "$user_db")
301 if [ "$STATUS" = pending -a "$EXPIRE" -gt "$_DATE" ]; then
303 [form #user_confirm method=POST
304 [input type=hidden name=uid value="${uid}"]
305 [input type=hidden name=signature value="${signature}"]
306 [input disabled=disabled value="$(HTML "$EMAIL")"]
307 [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="^\[a-zA-Z\]\[a-zA-Z0-9 -~\]{2,127}$" autocomplete=off]
308 [input type=password name=pw placeholder="Choose Passphrase" pattern=".{6,}"]
309 [input type=password name=pwconfirm placeholder="Confirm Passphrase" pattern=".{6,}"]
310 [submit "action" "user_confirm" Finish Registration]
315 [div #user_confirm .expired
316 [p This activation link is not valid anymore.]
322 [div #user_confirm .invalid
323 [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.]
330 if [ ! "$USER_ID" ]; then
332 [form #user_login .login method=POST
333 [input name=uname placeholder="Username or Email" autocomplete=off]
334 [input type=password name=pw placeholder="Passphrase"]
335 [submit "action" "user_login" Login]
338 elif [ "$USER_ID" ]; then
340 [form #user_login .logout method=POST
341 [p Logged in as [span . $(HTML ${USER_NAME})]]
342 [submit "action" "user_logout" Logout]