]> git.plutz.net Git - cgilite/blobdiff - cgilite.sh
user invite function, handle invite/registration expire, always allow registration...
[cgilite] / cgilite.sh
index 9fa56eef0633f22e7fa5d8f901ddf776143a6a55..a2aa32924bdc7ed30cc35fb053b416859a05f93c 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-# Copyright 2017 - 2020 Paul Hänsch
+# Copyright 2017 - 2021 Paul Hänsch
 #
 # This is CGIlite.
 # A collection of posix shell functions for writing CGI scripts.
 # set -o posix # ksh, not portable
 setopt -o OCTAL_ZEROES 2>&-
 
+# Integrated webserver request timeout
+cgilite_timeout=2
+
+# General environment variables
+# $_EXEC - directory containing application itself
+# $_DATA - direcotry where application data may be stored
+# $_BASE - optional prefix for http path, e.g. "/myapp"
+#
+# Programmers should take care to use those variables throughout the
+# application.
+# Variables may be set via CLI argument, in environment, or left as default.
+
+for cgilite_arg in "$@"; do case $cgilite_arg in
+  --exec=*) _EXEC="${cgilite_arg#*=}";;
+  --data=*) _DATA="${cgilite_arg#*=}";;
+  --base=*) _BASE="${cgilite_arg#*=}";;
+esac; done
+unset cgilite_arg
+
+_EXEC="${_EXEC:-${0%/*}}"
+_DATA="${_DATA:-.}"
+_EXEC="${_EXEC%/}" _DATA="${_DATA%/}" _BASE="${_BASE%/}"
+
+# Carriare Return and Line Break characters for convenience
 CR="\r"
 BR='
 '
-cgilite_timeout=2
 
 PATH(){ 
   local str seg out
+  # normalize path
+  # read from stdin if no arguments are provided
+
   [ $# -eq 0 ] && str="$(cat)" || str="$*"
   while [ "$str" ]; do
     seg=${str%%/*}; str="${str#*/}"
@@ -45,18 +71,58 @@ PATH(){
   [ "${str}" -a "${out}" ] && printf %s "$out" || printf %s/ "${out%/}"
 }
 
-HEX_DECODE='
-  s;\\;\\\\;g; :HEXDECODE_X; s;%([^0-9A-F]);\\045\1;g; tHEXDECODE_X;
-  # Hexadecimal { %00 - %FF } will be transformed to octal { \000 - \377 } for posix printf
-  s;%[0123].;&\\0;g; s;%[4567].;&\\1;g; s;%[89AB].;&\\2;g; s;%[CDEF].;&\\3;g;
-  s;%[048C][0-7]\\.;&0;g; s;%[048C][89A-F]\\.;&1;g; s;%[159D][0-7]\\.;&2;g; s;%[159D][89A-F]\\.;&3;g;
-  s;%[26AE][0-7]\\.;&4;g; s;%[26AE][89A-F]\\.;&5;g; s;%[37BF][0-7]\\.;&6;g; s;%[37BF][89A-F]\\.;&7;g;
-  s;%.[08](\\..);\10;g; s;%.[19](\\..);\11;g; s;%.[2A](\\..);\12;g; s;%.[3B](\\..);\13;g;
-  s;%.[4C](\\..);\14;g; s;%.[5D](\\..);\15;g; s;%.[6E](\\..);\16;g; s;%.[7F](\\..);\17;g;
-'
-
 HEX_DECODE(){
-  printf -- "$(printf %s "$1" |sed -E "$HEX_DECODE")"
+  local pfx="$1" in="$2" out
+  # Print out Data encoded as Hex
+  #
+  # Arguments:
+  # pfx - required, prefix for a hex tupel, e.g. "\x", "%" "\", may be empty
+  # in - required, string to be decoded
+  #
+  # anything that does not constitute a tupel of valid Hex numerals
+  # will be copied to the output literally
+
+  while [ "$in" ]; do
+    case $in in
+      "$pfx"[0-9a-fA-F][0-9a-fA-F]*) in="${in#${pfx}}";;
+      \\*) in="${in#?}"; out="${out}\\\\"; continue;;
+       %*) in="${in#?}"; out="${out}%%";  continue;;
+        *) out="${out}${in%"${in#?}"}"; in="${in#?}"; continue;;
+    esac;
+
+    # Hex escaes for printf (e.g. \x41) are not portable 
+    # The portable way for Hex output is transforming Hex to Octal
+    # (e.g. \x41 = \101)
+    case $in in
+        [0123]?*) out="${out}\\0";;
+        [4567]?*) out="${out}\\1";;
+      [89aAbB]?*) out="${out}\\2";;
+      [c-fC-F]?*) out="${out}\\3";;
+    esac
+    case $in in
+            [048cC][0-7]*) out="${out}0";;
+       [048cC][89a-fA-F]*) out="${out}1";;
+            [159dD][0-7]*) out="${out}2";;
+       [159dD][89a-fA-F]*) out="${out}3";;
+           [26aAeE][0-7]*) out="${out}4";;
+      [26aAeE][89a-fA-F]*) out="${out}5";;
+           [37bBfF][0-7]*) out="${out}6";;
+      [37bBfF][89a-fA-F]*) out="${out}7";;
+    esac
+    case $in in
+       ?[08]*) out="${out}0";;
+       ?[19]*) out="${out}1";;
+      ?[2aA]*) out="${out}2";;
+      ?[3bB]*) out="${out}3";;
+      ?[4cC]*) out="${out}4";;
+      ?[5dD]*) out="${out}5";;
+      ?[6eE]*) out="${out}6";;
+      ?[7fF]*) out="${out}7";;
+    esac
+    in="${in#?}"
+    in="${in#?}"
+  done
+  printf -- "$out"
 }
 
 if [ -z "$REQUEST_METHOD" ]; then
@@ -79,7 +145,7 @@ if [ -z "$REQUEST_METHOD" ]; then
     kill $cgilite_watchdog
 
     SERVER_PROTOCOL="${SERVER_PROTOCOL%${CR}}"
-    PATH_INFO="$(HEX_DECODE "${REQUEST_URI%\?*}" |PATH)"
+    PATH_INFO="$(HEX_DECODE "${REQUEST_URI%\?*}" |PATH)"
     [ "${REQUEST_URI}" = "${REQUEST_URI#*\?}" ] \
     && QUERY_STRING='' \
     || QUERY_STRING="${REQUEST_URI#*\?}"
@@ -132,6 +198,8 @@ fi
 debug(){ [ $# -gt 0 ] && printf '%s\n' "$@" >&2 || tee -a /dev/stderr; }
 [ "${DEBUG+x}" ] && env >&2
 
+# general helper functions, see GET, POST, and REF below
+
 cgilite_count(){
   printf %s "&$1" \
   | grep -oE '&'"$2"'=[^&]*' \
@@ -145,7 +213,7 @@ cgilite_value(){
     str="${str#*&${name}=}"
     cnt=$((cnt - 1))
   done
-  printf -- "$(printf %s "${str%%&*}" |sed -E 's;\+; ;g;'"$HEX_DECODE")"
+  HEX_DECODE % "$(printf %s "${str%%&*}" |tr + \  )"
 }
 
 cgilite_keys(){
@@ -157,6 +225,17 @@ cgilite_keys(){
   | sort -u
 }
 
+# Read arguments from GET, POST, or the query string of the referrer (REF).
+# Example:
+# GET varname n
+#
+# where n is number for the Nth occurence of a variable and defaults to 1
+#
+# *_COUNT varname
+# -> returns number of ocurences
+# *_KEYS
+# -> returns list of available varnames
+
 GET(){ cgilite_value "${QUERY_STRING}" "$@"; }
 GET_COUNT(){ cgilite_count "${QUERY_STRING}" $1; }
 GET_KEYS(){ cgilite_keys "${QUERY_STRING}"; }
@@ -185,7 +264,8 @@ HEADER(){
 }
 
 COOKIE(){
-  HEX_DECODE "$(
+  # Read value of cookie
+  HEX_DECODE % "$(
     HEADER Cookie \
     | grep -oE '(^|; ?)'"$1"'=[^;]*' \
     | sed -En "${2:-1}"'{s;^[^=]+=;;; s;\+; ;g; p;}'
@@ -259,6 +339,7 @@ SET_COOKIE(){
 }
 
 REDIRECT(){
+  # Trigger redirct and terminate script
   printf '%s: %s\r\n' \
     Status "303 See Other" \
     Content-Length 0 \