. "$_EXEC/cgilite/file.sh"
-REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}"
+# REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}"
attachment_convert(){
local attpath="$1"
;;
*/\[attachment\])
# show attachment page
- # receive uploads
- tsid="$(POST session_key)"; tsid="${tsid%% *}"
- action="$(POST action)"
- attachment_delete="$(POST delete)"
page="${PATH_INFO%\[attachment\]}"
if [ ! -d "$_DATA/pages${page}" -a ! -d "$_DATA/pages${page}" ]; then
# base page does not exist
return 1
- elif [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ] && acl_write "${page}"; then
- . "$_EXEC/multipart.sh"
- multipart_cache
-
- # Use positional parameters for filename collection
- # The positional array is the only array available
- # in plain posix shells, see the documentation for
- # your shells "set" builtin for a hint to this
- # obscure use mode
- set --
-
- # Validate session id from form to prevent CSRF
- # Only validate if username is present, because no username means
- # anonymous uploads are allowed via acl and cgilite/session.sh does not
- # validate anonymous sessions from a multipart/formdata
- if [ "$USER_NAME" -a "$(multipart session_id)" != "$SESSION_ID" ]; then
- rm -- "$multipart_cachefile"
- printf 'Refresh: %i\r\n' 4
- theme_error 403
- return 0
- fi
-
- mkdir -p "$_DATA/pages${page}#attachments/"
- n=1; while filename=$(multipart_filename "file" "$n"); do
- filename="$(printf %s "$filename" |tr /\\0 __)"
- set -- "$@" "pages${page}#attachments/$filename"
- multipart "file" "$n" >"$_DATA/pages${page}#attachments/$filename"
- n=$((n + 1))
- done
- rm -- "$multipart_cachefile"
- if [ "$REV_ATTACHMENTS" = true ]; then
- git -C "$_DATA" add -- "$@"
- git -C "$_DATA" commit -qm "Attachments to # $page # uploaded by @ $USER_NAME @" -- "$@"
- fi
- REDIRECT "${_BASE}${PATH_INFO}"
elif [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ]; then
- printf 'Refresh: %i\r\n' 4
- theme_error 403
- head -c $((CONTENT_LENGTH)) >/dev/null
- return 0
- elif [ "$action" = delete -a "$SESSION_ID" = "$tsid" ] && acl_write "${page}"; then
- set --
- n="$(POST_COUNT select)"; while [ $n -gt 0 ]; do
- delete="$(POST select $n |PATH)"
- set -- "$@" "pages${page}#attachments/${delete##*/}"
- n=$((n - 1))
- done
- if [ "$REV_ATTACHMENTS" = true ]; then
- git -C "$_DATA" rm -- "$@"
- git -C "$_DATA" commit -qm \
- "Attachment to # $page # deleted by @ $USER_NAME @" -- "$@"
- else
- rm -- "$@"
- fi
- REDIRECT "${_BASE}${PATH_INFO}"
- elif [ "$action" = delete ]; then
- printf 'Refresh: %i\r\n' 4
- theme_error 403
- return 0
- # elif [ "$attachment_delete" -a "$SESSION_ID" = "$tsid" ]; then
- # if [ "$REV_ATTACHMENTS" = true ]; then
- # git -C "$_DATA" rm -- \
- # "$_DATA/pages${page}#attachments/$attachment_delete"
- # git -C "$_DATA" commit -qm \
- # "Attachment to # $page # deleted by @ $USER_NAME @" -- \
- # "$_DATA/pages${page}#attachments/$attachment_delete"
- # else
- # rm -- "$_DATA/pages${page}#attachments/$attachment_delete"
- # fi
- # REDIRECT "${_BASE}${PATH_INFO}"
- # elif [ "$attachment_delete" ]; then
- # printf 'Refresh: %i\r\n' 4
- # theme_error 403
- # return 0
+ # pass uploads to next handler
+ return 1
+ elif [ "$(POST action)" ]; then
+ # pass edits to next handler
+ return 1
elif ! acl_read "${page}"; then
theme_error 403
return 0
--- /dev/null
+#!/bin/sh
+
+REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}"
+
+if [ "${PATH_INFO##*/\[attachment\]}" ]; then
+ # Skip any action not happening on attachment page
+ return 1
+fi
+
+page="${PATH_INFO%\[attachment\]}"
+action="$(POST action)"
+
+tsid="$(POST session_key)"; tsid="${tsid%% *}"
+
+
+if ! acl_write "${PATH_INFO%\[attachment\]}"; then
+ # Deny access to write protected pages
+ printf 'Refresh: %i\r\n' 4
+ theme_error 403
+ [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ] \
+ && head -c $((CONTENT_LENGTH)) >/dev/null
+ return 0
+
+elif [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ]; then
+ . "$_EXEC/multipart.sh"
+ multipart_cache
+
+ # Use positional parameters for filename collection
+ # The positional array is the only array available
+ # in plain posix shells, see the documentation for
+ # your shells "set" builtin for a hint to this
+ # obscure use mode
+ set --
+
+ # Validate session id from form to prevent CSRF
+ # Only validate if username is present, because no username means
+ # anonymous uploads are allowed via acl and cgilite/session.sh does not
+ # validate anonymous sessions from a multipart/formdata
+ if [ "$USER_NAME" -a "$(multipart session_id)" != "$SESSION_ID" ]; then
+ rm -- "$multipart_cachefile"
+ printf 'Refresh: %i\r\n' 4
+ theme_error 403
+ return 0
+ fi
+
+ mkdir -p "$_DATA/pages${page}#attachments/"
+ n=1; while filename=$(multipart_filename "file" "$n"); do
+ filename="$(printf %s "$filename" |tr /\\0 __)"
+ set -- "$@" "pages${page}#attachments/$filename"
+ multipart "file" "$n" >"$_DATA/pages${page}#attachments/$filename"
+ n=$((n + 1))
+ done
+ rm -- "$multipart_cachefile"
+ if [ "$REV_ATTACHMENTS" = true ]; then
+ git -C "$_DATA" add -- "$@"
+ git -C "$_DATA" commit -qm "Attachments to # $page # uploaded by @ $USER_NAME @" -- "$@"
+ fi
+ REDIRECT "${_BASE}${PATH_INFO}"
+
+elif [ "$SESSION_ID" != "$tsid" ]; then
+ # Match session key from POST-Data to prevent CSRF:
+ # For authenticated users the POST session_key must match
+ # the session key used for authentication (usually from a
+ # cookie). This should ensure that POST requests were not
+ # triggered by malicious 3rd party sites freeriding on an
+ # existing user authentication.
+ # For pages that are writable by anonymous users, this is
+ # not reliable.
+
+ printf 'Refresh: %i\r\n' 4
+ theme_error 403
+ return 0
+fi
+
+if [ "$action" = delete -o "$action" = move ]; then
+ set --
+ n="$(POST_COUNT select)"; while [ $n -gt 0 ]; do
+ select="$(POST select $n |PATH)"
+ set -- "$@" "pages${page}#attachments/${select##*/}"
+ n=$((n - 1))
+ done
+fi
+
+if [ "$action" = delete ]; then
+ if [ "$REV_ATTACHMENTS" = true ]; then
+ git -C "$_DATA" rm -- "$@"
+ git -C "$_DATA" commit -qm \
+ "Attachment to # $page # deleted by @ $USER_NAME @" -- "$@"
+ else
+ ( cd "$_DATA" && rm -- "$@"; )
+ fi
+ REDIRECT "${_BASE}${PATH_INFO}"
+
+elif [ "$action" = move ]; then
+ moveto="$(POST moveto |PATH)"
+
+ if ! acl_write "$moveto"; then
+ printf 'Refresh: %i\r\n' 4
+ theme_error 403
+ return 0
+
+ elif [ ! -d "${_DATA}/pages${moveto}" ]; then
+ printf 'Refresh: %i\r\n' 4
+ theme_error 404
+ return 0
+
+ elif [ "$REV_ATTACHMENTS" = true ]; then
+ mkdir -p -- "${_DATA}/pages${moveto}/#attachments"
+ git -C "$_DATA" mv -f -- "$@" "pages${moveto}/#attachments/"
+
+ cnt=$#; while [ $cnt -gt 0 ]; do
+ set -- "$@" "$1" "pages/${moveto}/#attachments/${1##*/}"
+ cnt=$((cnt - 1)); shift 1
+ done
+
+ git -C "$_DATA" commit -qm \
+ "Attachment moved from # $page # to # $moveto # by @ $USER_NAME @" -- "$@"
+ else
+ mkdir -p -- "${_DATA}/pages${moveto}/#attachments"
+ ( cd "$_DATA" && mv -- "$@" "pages${moveto}/#attachments/"; )
+ fi
+ REDIRECT "${_BASE}${PATH_INFO}"
+
+fi
+
+return 1