]> git.plutz.net Git - shellwiki/commitdiff
basic ACLs
authorPaul Hänsch <paul@plutz.net>
Tue, 10 May 2022 17:22:18 +0000 (19:22 +0200)
committerPaul Hänsch <paul@plutz.net>
Tue, 10 May 2022 17:22:18 +0000 (19:22 +0200)
acl.sh [new file with mode: 0755]
index.cgi
pages/[wiki]/403/#page.md [new file with mode: 0644]
themes/default.sh

diff --git a/acl.sh b/acl.sh
new file mode 100755 (executable)
index 0000000..9ec2597
--- /dev/null
+++ b/acl.sh
@@ -0,0 +1,114 @@
+#!/bin/sh
+
+# ACL_OVERRIDE="${ACL_OVERRIDE:-Admin:read,write}"
+ACL_DEFAULT="${ACL_DEFAULT:-All:read${BR}Known:read,write}"
+
+acl_cachepath=''
+acl_collection=''
+
+acl_collect(){
+  local path="${1:-${PATH_INFO}}"
+  # Get directory part of PATH_INFO
+  local path="${path%/*}/./"
+  local pagefile head acl
+
+  if [ "$acl_cachepath" = "$path" ]; then
+    printf '%s\n' "$ACL_OVERRIDE" "$acl_collection" "$ACL_DEFAULT"
+    return 0
+  else
+    acl_cachepath="$path"
+    acl_collection=''
+  fi
+
+  printf '%s\n' "$ACL_OVERRIDE"
+
+  while :; do
+    [ "$path" = / ] && break
+    path="${path%/*/}/"
+
+    if   [ -f "$_DATA/pages/$path/#page.md" ]; then
+      pagefile="$_DATA/pages/$path/#page.md"
+    elif [ -f "$_EXEC/pages/$path/#page.md" ]; then
+      pagefile="$_EXEC/pages/$path/#page.md"
+    else
+      continue
+    fi
+
+    n=20; while read -r head acl; do
+      if [ "$head" = "%acl" ]; then
+        acl_collection="${acl%${CR}}${BR}"
+        printf "%s\n" "${acl%${CR}}"
+        n=$((n+1))
+      fi
+
+      n="$((n - 1))"
+      [ "$n" -eq 0 ] && break
+    done <"$pagefile"
+  done
+
+  printf '%s\n' "$ACL_DEFAULT"
+}
+
+acl_read(){
+  local page="${1:-${PATH_INFO}}"
+  local acl
+
+  while read -r acl; do
+    case ${acl##*:} in
+      read|*,read,*|read,*|*,read)
+         acl="${acl%%:*}:read";;
+      *) acl="${acl%%:*}:";;
+    esac
+    [ "$USER_NAME" ] && case $acl in
+       "Known:read") return 0;;
+       "Known:")     return 1;;
+      "+Known:read") return 0;;
+      "-Known:read") return 1;;
+       "${USER_NAME}:read") return 0;;
+       "${USER_NAME}:")      return 1;;
+      "+{$USER_NAME}:read") return 0;;
+      "-{$USER_NAME}:read") return 1;;
+    esac
+    case $acl in
+       "All:read") return 0;;
+       "All:")     return 1;;
+      "+All:read") return 0;;
+      "-All:read") return 1;;
+    esac
+  done <<-EOF
+       $(acl_collect "$page")
+       EOF
+  return 1
+}
+
+acl_write(){
+  local page="${1:-${PATH_INFO}}"
+  local acl
+
+  while read -r acl; do
+    case ${acl##*:} in
+      write|*,write,*|write,*|*,write)
+         acl="${acl%%:*}:write";;
+      *) acl="${acl%%:*}:";;
+    esac
+    [ "$USER_NAME" ] && case ${acl} in
+       "Known:write") return 0;;
+       "Known:")      return 1;;
+      "+Known:write") return 0;;
+      "-Known:write") return 1;;
+       "${USER_NAME}:write") return 0;;
+       "${USER_NAME}:")      return 1;;
+      "+{$USER_NAME}:write") return 0;;
+      "-{$USER_NAME}:write") return 1;;
+    esac
+    case $acl in
+       "All:write") return 0;;
+       "All:")      return 1;;
+      "+All:write") return 0;;
+      "-All:write") return 1;;
+    esac
+  done <<-EOF
+       $(acl_collect "$page")
+       EOF
+  return 1
+}
index 9b38362b665dffae0b6a0f59286e0aff5d8da30e..b1b2c2dd2ab11cc4a0c7b8e7cc332503579ad41b 100755 (executable)
--- a/index.cgi
+++ b/index.cgi
@@ -4,6 +4,7 @@
 . "${_EXEC}/cgilite/session.sh"
 . "${_EXEC}/cgilite/file.sh"
 . "${_EXEC}/cgilite/users.sh"
+. "${_EXEC}/acl.sh"
 
 . "${_EXEC}/themes/default.sh"
 
@@ -19,35 +20,39 @@ else
   md() { cat; }
 fi
 
-wiki_text() {
-  # Print source text of a wiki page
-  # Get page from data or underlay dir
+mdfile(){
   local page="$(PATH "$1")"
 
-  if [ -f "$_DATA/pages/$page/#page.md" ]; then
-    cat -- "$_DATA/pages/$page/#page.md"
+  if   [ -f "$_DATA/pages/$page/#page.md" ]; then
+    printf %s\\n "$_DATA/pages/$page/#page.md"
   elif [ -f "$_EXEC/pages/$page/#page.md" ]; then
-    cat -- "$_EXEC/pages/$page/#page.md"
+    printf %s\\n "$_EXEC/pages/$page/#page.md"
   else
     return 1
   fi
 }
 
+wiki_text() {
+  # Print source text of a wiki page
+  # Get page from data or underlay dir
+  local page="$(PATH "$1")" mdfile
+
+  mdfile="$(mdfile "$page")" || return 4
+  acl_read "$page" || return 3
+  cat -- "$mdfile"
+}
+
 wiki() {
   # Print content of a wiki page
   # Get page from data or underlay dir, handle caching
-  local page="$(PATH "$1")" md cache cachetime
+  local page="$(PATH "$1")" mdfile cache cachetime
 
-  cache="$_DATA/pages/$page/#page.cache"
-  if [ -f "$_DATA/pages/$page/#page.md" ]; then
-    md="$_DATA/pages/$page/#page.md"
-  elif [ -f "$_EXEC/pages/$page/#page.md" ]; then
-    md="$_EXEC/pages/$page/#page.md"
-  else
-    return 1
-  fi
+  cache="$_DATA/pages/$page/#page.${USER_ID}.cache"
 
-  cachetime="$(stat -c %Y -- "$md" "$cache" 2>/dev/null)"
+  mdfile="$(mdfile "$page")" || return 4
+  acl_read "$page" || return 3
+
+  cachetime="$(stat -c %Y -- "$mdfile" "$cache" 2>/dev/null)"
 
   if [ "${cachetime#*${BR}}" -gt "${cachetime%${BR}*}" \
     -a "${cachetime#*${BR}}" -gt "$((_DATE - CACHE_AGE))" ]; then
@@ -56,37 +61,18 @@ wiki() {
     mkdir -p -- "$_DATA/pages/$page/"
     # Macros expect to find page directory as working dir
     ( cd -- "$_DATA/pages/$page/";
-      md <"$md" |tee -- "${cache}.$$"
+      md <"$mdfile" |tee -- "${cache}.$$"
     )
     mv -- "${cache}.$$" "${cache}"
   fi
 }
 
-attachment() {
-  local file="$(PATH "$1")"
-
-  # TODO: deliver downscaled images, etc.
-  if [ -f "$_DATA/pages/${file%/*}/#attachments/${file#*/}" ]; then
-    FILE "$_DATA/pages/${file%/*}/#attachments/${file#*/}"
-  elif [ -f "$_EXEC/pages/${file%/*}/#attachments/${file#*/}" ]; then
-    FILE "$_EXEC/pages/${file%/*}/#attachments/${file#*/}"
-  elif [ -d "$_DATA/pages/${file}/" -o -d "$_EXEC/pages/${file}" ]; then
-    # path looks like a rogue page name (without trailing slash), so redirect
-    REDIRECT "$_BASE/${file}/"
-  else
-    return 1
-  fi
-}
-
 case "${PATH_INFO}" in
   /"[.]"/*)
     FILE "${_EXEC}/${PATH_INFO#/\[.\]}"
     ;;
   */)
-    if [ -f "$_DATA/pages/$PATH_INFO/#page.md" \
-      -o -f "$_EXEC/pages/$PATH_INFO/#page.md" ]; then
-      theme_page "${PATH_INFO}"
-    fi
+    theme_page "${PATH_INFO}"
     ;;
   */"[login]")
     [ "$USER_NAME" ] \
diff --git a/pages/[wiki]/403/#page.md b/pages/[wiki]/403/#page.md
new file mode 100644 (file)
index 0000000..66ea5e2
--- /dev/null
@@ -0,0 +1,4 @@
+403
+===
+
+**Forbidden**
index 1830e26673ccd60c29e95a85f446143cce3dd18c..022a29ab4985bbad8dd05a8624fdbae6dc6084d9 100755 (executable)
@@ -22,6 +22,14 @@ theme_page(){
   local page="$1" title
   title="${page%/}"; title="${title##*/}"
 
+  if [ ! "$(mdfile "$page")" ]; then
+    theme_404
+    return 0
+  elif ! acl_read "$page"; then
+    theme_403
+    return 0
+  fi
+
   # Important! Web Server response including newline
   printf "%s\r\n" "Content-Type: text/html; charset=utf-8" ""
 
@@ -33,12 +41,14 @@ theme_page(){
        </head><body id="$(HTML "$page")">
          $(theme_header)
          <main>
-           <ul class="pagemenu">
-             <li><a href="[edit]">Edit</a></li>
-             <li><a href="[attachment]/">Attachments</a></li>
-           </ul>
+           $(acl_write "$page" && printf %s \
+             '<ul class="pagemenu">
+                <li><a href="[edit]">Edit</a></li>
+                <li><a href="[attachment]/">Attachments</a></li>
+              </ul>'
+           )
            <article>
-             $(wiki "$page" || printf 'Page not found')
+             $(wiki "$page" || printf 'Error while loading page <br> function "wiki" of index.sh returned with an error.')
            </article>
          </main>
          $(theme_footer)
@@ -50,6 +60,14 @@ theme_editor(){
   local page="$1" title
   title="${page%/}"; title="${title##*/}"
 
+  if [ ! "$(mdfile "$page")" ]; then
+    theme_404
+    return 0
+  elif ! acl_write "$page"; then
+    theme_403
+    return 0
+  fi
+
   # Important! Web Server response including newline
   printf "%s\r\n" "Content-Type: text/html; charset=utf-8" ""
 
@@ -110,15 +128,29 @@ theme_attachments(){
 }
 
 theme_login(){
-  theme_page '[wiki]/login/'
+  theme_page '/[wiki]/login/'
 }
 
 theme_register(){
-  theme_page '[wiki]/register/'
+  theme_page '/[wiki]/register/'
+}
+
+theme_403(){
+  printf "%s\r\n" "Status: 403 Forbidden"
+
+  if [ "$(mdfile '/[wiki]/403/')" ]; then
+    theme_page '/[wiki]/403/'
+  else
+    printf "Content-Length: 0\r\n\r\n"
+  fi
 }
 
 theme_404(){
   printf "%s\r\n" "Status: 404 Not Found"
 
-  theme_page '[wiki]/404/'
+  if [ "$(mdfile '/[wiki]/404/')" ]; then
+    theme_page '/[wiki]/404/'
+  else
+    printf "Content-Length: 0\r\n\r\n"
+  fi
 }