--- /dev/null
+#!/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
+}
. "${_EXEC}/cgilite/session.sh"
. "${_EXEC}/cgilite/file.sh"
. "${_EXEC}/cgilite/users.sh"
+. "${_EXEC}/acl.sh"
. "${_EXEC}/themes/default.sh"
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
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" ] \
--- /dev/null
+403
+===
+
+**Forbidden**
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" ""
</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)
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" ""
}
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
}