]> git.plutz.net Git - httpchat/commitdiff
introduce nickname registration
authorPaul Hänsch <paul@plutz.net>
Sat, 23 Nov 2019 06:39:48 +0000 (07:39 +0100)
committerPaul Hänsch <paul@plutz.net>
Sat, 23 Nov 2019 06:39:48 +0000 (07:39 +0100)
channel.sh
index.cgi
usernick.sh [new file with mode: 0755]
webchat.css

index eab42fc6d9b07f012735c384ef050b7037cbbe6a..1f86e5214c061525e5e6486c9db93f03f6367c00 100755 (executable)
@@ -1,11 +1,5 @@
 #!/bin/sh
 
-if [ "$(COOKIE nick)" ]; then
-  nickname="?$(COOKIE nick)"
-else
-  nickname='?Guest'
-fi
-  
 if [ -f "$chatfile" ]; then
   read -r channelkey x <"$chatfile"
   channelkey="$( printf '%s-%s' "$channelkey" "$SESSION_ID" |sha256sum)"
@@ -24,47 +18,38 @@ case $(POST action) in
     fi
     REDIRECT "$(URL "/$LOCATION")"
     ;;
-  nick)
-    SET_COOKIE +1209600 "nick=$(POST nickname |URL)"
-    REDIRECT "$(URL "/$LOCATION")"
-    ;;
-  *) if [ ! -f "$chatfile" ]; then
-      yield_page create <<-EOF
-       [form #nonexist method=POST action="$(URL "/$LOCATION")"
-           There is no channel named $(HTML "$LOCATION")
-           [submit "action" "create" Create]
-        ]
+esac
+
+if [ ! -f "$chatfile" ]; then
+  yield_page create <<-EOF
+       [form #nonexist method="POST"
+          There is no channel named $(HTML "$LOCATION")
+          [submit "action" "create" Create]
+       ]
        EOF
-    else
-      { printf '
-        [form #channel method=POST action="%s"
-          [submit "action" "submit" style="display: none;"]
-          [input type=hidden name=channelkey value="%s"]
-          %s [input name="message" autofocus=true][submit "action" "submit" Send!]
-        ]
-      ' "$(URL "/$LOCATION")" "$channelkey" "$(settings_menu)"
-      SHESCAPE='s;[]&<>#."[];\\&;g;'
+else
+  printf '%s: %s\r\n' Refresh 1
+  { printf '
+    [form #channel method="POST"
+      [submit "action" "submit" style="display: none;"]
+      [input type=hidden name=channelkey value="%s"]
+      [a .settings href="?settings#nick" Settings][input autocomplete="off" name="message" autofocus=true][submit "action" "submit" Send!]
+    ]
+  ' "$channelkey"
+  SHESCAPE='s;[]&<>#."[];\\&;g;'
 
-      printf '[div #chat'
-      # tail -n30 -f "$chatfile" | {
-      #   read x
-      #   while read -r date nick message; do
-      #     printf '[p .message [span .date %s] [span .nick [span .indicator %s]%s:] [span .message %s]]\n' \
-      #            "${date#*_}" "${nick%${nick#?}}" "$(UNSTRING "${nick#?}" |HTML)" "$(UNSTRING "$message" |HTML)"
-      #     done
-      #   }
-      tail -n50 -f "$chatfile" \
-      | sed -nuE '
-        /^[^ ]+ [^ ]+ [^ ]+$/{
-        h; s;^([^ ]+) ([^ ]+) ([^ ]+)$;\1;; s;.*_;;;         s;.+;[p .message [span .date &];p;
-        g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;a\2;; bESC; :A s;.;;; s;(.)(.+);[span .nick [span .indicator \1]\2];p;
-        g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;b\3;; bESC; :B s;.;;; s;.+;[span .message &]];p;
-        }
-        b; :ESC
-        '"$UNSTRING"' '"$SHESCAPE"'
-        /^a/bA; /^b/bB;
-        '
-      } |yield_page channel
-    fi 
-    ;;
-esac
+  while sleep 10; do printf '\n'; done &
+  printf '[div #chat'
+  tail --pid $$ -n50 -f "$chatfile" \
+  | sed -nuE '
+    /^[^ ]+ [^ ]+ [^ ]+$/{
+    h; s;^([^ ]+) ([^ ]+) ([^ ]+)$;\1;; s;.*_;;;         s;.+;[p .message [span .date &];p;
+    g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;a\2;; bESC; :A s;.;;; s;(.)(.+);[span .nick [span .indicator \1]\2];p;
+    g; s;^([^ ]+) ([^ ]+) ([^ ]+)$;b\3;; bESC; :B s;.;;; s;.+;[span .message &]];p;
+    }
+    b; :ESC
+    '"$UNSTRING"' '"$SHESCAPE"'
+    /^a/bA; /^b/bB;
+    '
+  } |yield_page channel
+fi 
index 2daabd824e750495e42b0bf42f318fbd5b576476..16bd9044053803c2ca16b840b5514ab3fde9d106 100755 (executable)
--- a/index.cgi
+++ b/index.cgi
@@ -21,6 +21,7 @@ yield_page(){
       [title Webchat]
     ] [body class="%s"
   ' "$page"
+  [ "$QUERY_STRING" = settings ] && settings_menu
   cat
   printf '] ]'
   } |"$_EXEC/cgilite/html-sh.sed" -u
@@ -28,48 +29,55 @@ yield_page(){
 
 settings_menu(){
   printf '
-    [input #check_settings type="checkbox"][label for=check_settings Settings]
-    [div #settings
-      [h1 Settings][label for=check_settings Close]
-      [input #set_nick type=radio name="setting" value="nick" selected][label for=set_nick Nickname]
-      [div [input name="nickname" value="%s"][submit "action" "nick" Set Cookie]]
-    ]
+    [form #settings method="POST" action="?"
+      [h1 Settings][a .settings href="?" Close]'
+  printf '
+      [a .section href="#nick" Nickname]
+      [div #nick [input name="nickname" value="%s"][submit "action" "nick" Set Cookie]]
   ' "$(HTML "${nickname#\?}")"
+  printf '
+      [a .section href="#register" Register Nickname]
+      [div #register
+        [p Registration will set a permanent Cookie in your Browser.
+           Registration requires neither a password, nor an email address.]
+        [input name="regnick" value="%s"][submit "action" "register" Register]
+      ]' "$(HTML "${nickname#\?}")"
+  printf ']'
 }
 
+. "$_EXEC/usernick.sh"
+
 case ${LOCATION} in
-  \&?*) chatfile="$_DATA/${LOCATION}"
-       . $_EXEC/channel.sh
-       exit 0
-   ;;
-  @?*) if [ -d "$_DATA/${LOCATION}" ]; then
-        chatfile="$_DATA/${LOCATION}/?${SESSION_ID}"
-       . $_EXEC/channel.sh
-      else
-        REDIRECT /
-      fi
-       exit 0
-   ;;
-  ~?*) if [ -d "$_DATA/@${LOCATION#~}" ]; then
-        pubinfo="$_DATA/@${LOCATION#~}/pubinfo"
-        page=pubinfo
-      else 
-        REDIRECT /
-      fi
-   ;;
   webchat.css)
-    . "$_EXEC/file.sh"
+    . "$_EXEC/cgilite/file.sh"
     FILE "$_EXEC/webchat.css"
     exit 0
     ;;
-  '') page=front;;
-  *) REDIRECT /;;
-esac
-
-case "$page $(POST action)" in
-  pubinfo\ *);;
-  front\ *) yield_page front <<-EOF
+  \&?*)
+    chatfile="$_DATA/${LOCATION}"
+    . "$_EXEC/channel.sh"
+    exit 0
+    ;;
+  @?*)
+    if [ -d "$_DATA/${LOCATION}" ]; then
+      chatfile="$_DATA/${LOCATION}/?${SESSION_ID}"
+      . "$_EXEC/channel.sh"
+    else
+      REDIRECT /
+    fi
+    exit 0
+    ;;
+  ~?*)
+    if [ -d "$_DATA/@${LOCATION#~}" ]; then
+      pubinfo="$_DATA/@${LOCATION#~}/pubinfo"
+    else 
+      REDIRECT /
+    fi
+    ;;
+  '') yield_page front <<-EOF
        Front
        EOF
     ;;
+  *) REDIRECT /
+    ;;
 esac
diff --git a/usernick.sh b/usernick.sh
new file mode 100755 (executable)
index 0000000..8d62390
--- /dev/null
@@ -0,0 +1,69 @@
+#!/bin/sh
+
+UNAME_VALID='
+  # Remove trailing CR, which may have been added by browser
+  s;\r$;;;
+  # Collapse white spaces
+  s;[\r\t\n ]+; ;;
+  # Remove starting and trailing white spaces
+  s;^ ;;; s; $;;;
+  # Usernames starting with & # ? @ + will be invalid
+  /^[&#?@+]/d;
+  # Usernames containing a / will be invalid
+  /\//d;
+  # Usernames must be between 3 and 24 characters
+  /...+/!d; /.{25}/d;
+  # Usernames may not span multiple lines
+  q;'
+username(){
+  { [ $# -eq 0 ] && cat || printf %s "$*"; } \
+  | sed -E ':X; $!{N;bX;}'"$UNAME_VALID"
+}
+
+nickname="$(COOKIE nick |username)"
+if [ ! "$nickname" ]; then
+  nickname='?Guest'
+elif [ ! -d "$_DATA/@$nickname" ]; then
+  nickname="?$nickname"
+else
+  userclient="$(COOKIE user_client)"
+  secuid="$(cat "$_DATA/@$nickname/secuid")"
+  clientid="${userclient%%-*}"
+  clientid="${clientid}-$(printf '%s%s' "${clientid}" "${secuid}" |sha256sum)"
+  clientid="${clientid%% *}"
+  if [ "$clientid" = "$userclient" ]; then
+    nickname=" $nickname"
+    SET_COOKIE +"$((86400 * 365))" "user_client=${clientid}" HttpOnly
+    SET_COOKIE +"$((86400 * 365))" "nick=$(URL "${nickname}")"
+  else
+    nickname='?Guest'
+  fi
+fi
+
+case $(POST action) in
+  nick)
+    nick="$(POST nickname |username)"
+    if [ ! -d "$_DATA/@$nick" ]; then
+      SET_COOKIE +1209600 "nick=$(POST nickname |URL)"
+      REDIRECT "$(URL "/$LOCATION")"
+    else
+      # ToDo: Return Error Message
+      REDIRECT "$(URL "/$LOCATION")?settings#nick"
+    fi
+    ;;
+  register)
+    regnick="$(POST regnick |username)"
+    userdir="$_DATA/@${regnick}"
+    if [ "$regnick" ] && mkdir "$userdir"; then
+      secuid="$(randomid)"; clientid="$(randomid)"
+      printf %s\\n "$secuid" >"${userdir}/secuid"
+      clientid="${clientid}-$(printf '%s%s' "${clientid}" "${secuid}" |sha256sum |cut -d\  -f1)"
+      SET_COOKIE +"$((86400 * 365))" "user_client=${clientid}" HttpOnly
+      SET_COOKIE +"$((86400 * 365))" "nick=$(URL "${regnick}")"
+      REDIRECT "$(URL "/$LOCATION")"
+    else
+      # ToDo: Return Error Message
+      REDIRECT "$(URL "/$LOCATION")?settings#register"
+    fi
+    ;;
+esac
index 4f36157b778eaaa463f233526c9e366c31708a92..ff70761ded124d6d67b36679022e8fda019ba947 100644 (file)
@@ -1,41 +1,32 @@
 * {
   box-sizing: border-box;
-  background-color: #FFF;
-  color: #000;
   font: normal normal normal medium/1.25 Sans-Serif;
   font: normal normal normal normal medium/1.25 Sans-Serif;
   text-decoration: none;
   margin: 0; padding: 0;
   border: none;
+  color: inherit;
 }
 
-#chat {
-  position: fixed;
-  bottom: 2.5em;
-  left: 0; right: 0;
-  border: 1px solid #08b;
-  padding: 1ex;
-  margin: .5ex;
-  z-index: -1;
-}
-form#channel {
-  position: fixed;
-  bottom: 0;
-  left: 0; right: 0;
+body {
+  background-color: #FFF;
+  color: #000;
 }
 
-#check_settings { display: none; }
-#check_settings + label {
-  display: inline-block;
+b, strong { font-weight: bold; }
+i, em { font-style: italic; }
+
+input[type=text], input:not([type]) {
+  border: 1px solid #08b;
+  padding: .125ex .5ex;
 }
-#check_settings + label:before {
-  content: '\2699';
-  padding: .5ex;
-  margin-left: .5ex;
-  margin-right: 2em;
+button {
+  border: outset #DDD;
+  padding: .125ex 1ex;
+  background-color: #EEE;
 }
-#check_settings + label + #settings { display: none; }
-#check_settings:checked + label + #settings {
+
+#settings {
   display: block;
   position: fixed;
   min-width: 20%; max-width: 90%;
@@ -55,7 +46,7 @@ form#channel {
   border-bottom: 1px solid;
   border-radius: 1ex 1ex 0 0;
 }
-#settings label[for=check_settings] {
+#settings a.settings {
   position: absolute;
   top: 0; right: 1px;
   background-color: #F88;
@@ -64,39 +55,71 @@ form#channel {
   width: 3ex;
   overflow: hidden;
 }
-#settings label[for=check_settings]:before {
+#settings a.settings:before {
   content: "x";
   padding: 0 1ex;
 }
-#settings input[type=radio] { display: none; }
-#settings input[type=radio] + label + * { display: none; }
-#settings input[type=radio]:checked + label + * { display: block; }
-#settings input[type=radio] + label {
+#settings a.section {
   display: block;
   font-weight: bold;
   text-decoration: underline;
-  margin: -1px 1px; padding: 0 1ex;
+  margin: -1px 1px 0 0; padding: .5ex 1ex;
   border-top: 1px solid;
   background-color: #EEE;
 }
-#settings input[type=radio] + label + * {
+#settings a.section + * {
+  display: block;
+  padding: .5ex 1ex 0 1ex;
+  max-height: .5ex;
+  overflow: hidden;
+  transition: max-height .5s;
+}
+#settings a.section + *:target {
+  max-height: 20ex;
   padding: 1ex 1ex .5ex 1ex;
 }
+#settings input {margin-right: 1ex;}
 
+form#channel {
+  position: fixed;
+  bottom: 1ex;
+  left: .5ex; right: .5ex;
+}
+form#channel a.settings {
+  display: inline-block;
+}
+form#channel a.settings:before {
+  content: '\2699';
+  padding: 0 .75ex;
+  margin-left: .5ex;
+  margin-right: 2em;
+}
 form#channel input[name=message] {
   display: inline-block;
   position: absolute;
-  left: 4.5ex;
-  width: calc(100% - 5ex - 1px);
+  right: 0;
+  width: calc(100% - 4.5ex);
 }
 form#channel button[value=submit] { display: none; }
 #chat .message .date {
   color: #888;
   font-size: .75em;
 }
+
+#chat {
+  position: fixed;
+  bottom: 2em;
+  left: 0; right: 0;
+  border: 1px solid #08b;
+  padding: 1ex;
+  margin: .5ex;
+  z-index: -1;
+}
+
 #chat .message .nick {
   font-weight: bold;
 }
+
 #chat .message .nick .indicator {
   color: #888;
 }