]> git.plutz.net Git - shellwiki/commitdiff
Separate file for attachment edit functions. Functions to move attached files.
authorPaul Hänsch <paul@plutz.net>
Tue, 2 Aug 2022 09:58:06 +0000 (11:58 +0200)
committerPaul Hänsch <paul@plutz.net>
Tue, 2 Aug 2022 09:58:06 +0000 (11:58 +0200)
handlers/20_attachment.sh
handlers/20_edit_attachment.sh [new file with mode: 0755]

index a1168978d769f5d57ce90829a5e1abed756c10fc..1e0719037ee0d4642601abb1141ad456dbe64d2b 100755 (executable)
@@ -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 (executable)
index 0000000..f400523
--- /dev/null
@@ -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