From 4176213eafe0118f19fc492b3bfa5f23efa4acb0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Paul=20H=C3=A4nsch?= Date: Tue, 2 Aug 2022 11:58:06 +0200 Subject: [PATCH] Separate file for attachment edit functions. Functions to move attached files. --- handlers/20_attachment.sh | 84 ++-------------------- handlers/20_edit_attachment.sh | 126 +++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+), 78 deletions(-) create mode 100755 handlers/20_edit_attachment.sh diff --git a/handlers/20_attachment.sh b/handlers/20_attachment.sh index a116897..1e07190 100755 --- a/handlers/20_attachment.sh +++ b/handlers/20_attachment.sh @@ -2,7 +2,7 @@ . "$_EXEC/cgilite/file.sh" -REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}" +# REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}" attachment_convert(){ local attpath="$1" @@ -78,89 +78,17 @@ case ${PATH_INFO} in ;; */\[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 diff --git a/handlers/20_edit_attachment.sh b/handlers/20_edit_attachment.sh new file mode 100755 index 0000000..f400523 --- /dev/null +++ b/handlers/20_edit_attachment.sh @@ -0,0 +1,126 @@ +#!/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 -- 2.39.2