]> git.plutz.net Git - shellwiki/blob - handlers/40_edit_attachment.sh
Merge commit '6bc502434737d7f08379e79b94fc6fda424ef779'
[shellwiki] / handlers / 40_edit_attachment.sh
1 #!/bin/sh
2
3 # Copyright 2022 - 2023 Paul Hänsch
4
5 # Permission to use, copy, modify, and/or distribute this software for any
6 # purpose with or without fee is hereby granted, provided that the above
7 # copyright notice and this permission notice appear in all copies.
8
9 # THE SOFTWARE IS PROVIDED “AS IS” AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
12 # SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
15 # IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16
17 REV_ATTACHMENTS="${REV_ATTACHMENTS:-false}"
18
19 if [ "${PATH_INFO##*/\[attachment\]}" ]; then
20   # Skip any action not happening on attachment page
21   return 1
22 fi
23
24 page="${PATH_INFO%\[attachment\]}"
25 action="$(POST action)"
26
27 tsid="$(POST session_key)"; tsid="${tsid%% *}"
28
29
30 if ! acl_write "${PATH_INFO%\[attachment\]}"; then
31   # Deny access to write protected pages
32   printf 'Refresh: %i\r\n' 4
33   theme_error 403
34   [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ] \
35   && head -c $((CONTENT_LENGTH)) >/dev/null
36   return 0
37
38 elif [ "${CONTENT_TYPE%%;*}" = "multipart/form-data" ]; then
39   . "$_EXEC/multipart.sh"
40   multipart_cache
41
42   # Use positional parameters for filename collection
43   # The positional array is the only array available
44   # in plain posix shells, see the documentation for
45   # your shells "set" builtin for a hint to this
46   # obscure use mode
47   set --
48
49   # Validate session id from form to prevent CSRF
50   # Only validate if username is present, because no username means
51   # anonymous uploads are allowed via acl and cgilite/session.sh does not
52   # validate anonymous sessions from a multipart/formdata
53   if [ "$USER_NAME" -a "$(multipart session_id)" != "$SESSION_ID" ]; then
54     rm -- "$multipart_cachefile"
55     printf 'Refresh: %i\r\n' 4
56     theme_error 403
57     return 0
58   fi
59
60   mkdir -p "$_DATA/pages${page}#attachments/"
61   n=1; while filename=$(multipart_filename "file" "$n"); do
62     filename="$(printf %s "$filename" |tr /\\0 __)"
63     set -- "$@" "pages${page}#attachments/$filename"
64     multipart "file" "$n" >"$_DATA/pages${page}#attachments/$filename"
65     n=$((n + 1))
66   done
67   rm -- "$multipart_cachefile"
68   if [ "$REV_ATTACHMENTS" = true ]; then
69     git -C "$_DATA" add -- "$@"
70     git -C "$_DATA" commit -qm "Attachments to # $page # uploaded by @ $USER_NAME @" -- "$@"
71   fi
72   REDIRECT "${_BASE}${PATH_INFO}"
73
74 elif [ "$SESSION_ID" != "$tsid" ]; then
75   # Match session key from POST-Data to prevent CSRF:
76   # For authenticated users the POST session_key must match
77   # the session key used for authentication (usually from a
78   # cookie). This should ensure that POST requests were not
79   # triggered by malicious 3rd party sites freeriding on an
80   # existing user authentication.
81   # For pages that are writable by anonymous users, this is
82   # not reliable.
83
84   printf 'Refresh: %i\r\n' 4
85   theme_error 403
86   return 0
87 fi
88
89 if [ "$action" = delete -o "$action" = move ]; then
90   set --
91   n="$(POST_COUNT select)"; while [ $n -gt 0 ]; do
92     select="$(POST select $n |PATH)"
93     set -- "$@" "pages${page}#attachments/${select##*/}"
94     n=$((n - 1))
95   done
96 fi
97
98 if [ "$action" = delete ]; then
99   if [ "$REV_ATTACHMENTS" = true ]; then
100     git -C "$_DATA" rm -- "$@"
101     git -C "$_DATA" commit -qm \
102         "Attachment to # $page # deleted by @ $USER_NAME @" -- "$@"
103   else
104     ( cd "$_DATA" && rm -- "$@"; )
105   fi
106   REDIRECT "${_BASE}${PATH_INFO}"
107
108 elif [ "$action" = move ]; then
109   moveto="$(POST moveto |PATH)"
110
111   if ! acl_write "$moveto"; then
112     printf 'Refresh: %i\r\n' 4
113     theme_error 403
114     return 0
115
116   elif [ ! -d "${_DATA}/pages${moveto}" ]; then
117     printf 'Refresh: %i\r\n' 4
118     theme_error 404
119     return 0
120
121   elif [ "$REV_ATTACHMENTS" = true ]; then
122     mkdir -p -- "${_DATA}/pages${moveto}/#attachments"
123     git -C "$_DATA" mv -f -- "$@" "pages${moveto}/#attachments/"
124
125     cnt=$#; while [ $cnt -gt 0 ]; do
126       set -- "$@" "$1" "pages/${moveto}/#attachments/${1##*/}"
127       cnt=$((cnt - 1)); shift 1
128     done
129
130     git -C "$_DATA" commit -qm \
131         "Attachment moved from # $page # to # $moveto # by @ $USER_NAME @" -- "$@"
132   else
133     mkdir -p -- "${_DATA}/pages${moveto}/#attachments"
134     ( cd "$_DATA" && mv -- "$@" "pages${moveto}/#attachments/"; )
135   fi
136   REDIRECT "${_BASE}${PATH_INFO}"
137
138 elif [ "$action" = rename ]; then
139   fail='' success=''
140   set --
141
142   for file in "${_DATA}/pages${page}#attachments"/*; do
143     rename="$(POST rename_"$(slopecode "${file##*/}" |sed 's;=;%3D;g')")"
144
145     if [ "$REV_ATTACHMENTS" = true -a \
146          -f "${file}" -a \
147          "$rename" -a \
148          "${rename%/*}" = "${rename}" -a \
149          ! -e "${_DATA}/pages${page}#attachments/${rename}" ] \
150        && git -C "$_DATA" mv -- "pages${page}#attachments/${file##*/}" "pages${page}#attachments/${rename}"; then
151       success="${success}$(HTML "${file##*/}/${rename}")${BR}"
152       set -- "$@" "pages${page}#attachments/${file##*/}" "pages${page}#attachments/${rename}"
153
154     elif [ "$REV_ATTACHMENTS" = true -a "${rename}" ]; then
155       fail="${fail}$(HTML "${file##*/}/${rename}")${BR}"
156
157     elif [ -f "${file}" -a \
158            "$rename" -a \
159            "${rename%/*}" = "${rename}" -a \
160            ! -e "${_DATA}/pages${page}#attachments/${rename}" ] \
161          && mv -- "${file}" "${_DATA}/pages${page}#attachments/${rename}"; then
162       success="${success}$(HTML "${file##*/}/${rename}")${BR}"
163
164     elif [ "${rename}" ]; then
165       fail="${fail}$(HTML "${file##*/}/${rename}")${BR}"
166
167     fi
168   done
169
170   if [ "$REV_ATTACHMENTS" = true -a $# -gt 2 ]; then
171     git -C "$_DATA" commit -qm \
172         "Attachment files renamed by @ $USER_NAME @" -- "$@"
173   elif [ "$REV_ATTACHMENTS" = true -a $# -eq 2 ]; then
174     git -C "$_DATA" commit -qm \
175         "Attachment file renamed by @ $USER_NAME @" -- "$@"
176   fi
177
178   if [ "$success" -a "$fail" ]; then
179     printf "%s\r\n" "Status: 500 Internal Server Error"
180     theme_page - "$(_ "Attachment rename")" <<-EOF
181         <h1 class="rename partial">$(_ Some files could not be renamed)</h1>
182         <h2 class="rename success">$(_ Successfully renamed:)</h2>
183         <ul class="rename success">
184         $(printf %s "$success" |while read html; do
185           printf '<li><span class=from>%s</span> -&gt; <span class=to>%s</span></li>' \
186                  "${html%%/*}" "${html##*/}"
187         done)
188         </ul>
189         <h2 class="rename fail">$(_ Errors:)</h2>
190         <ul class="rename fail">
191         $(printf %s "$fail" |while read html; do
192           printf '<li><span class=from>%s</span> -&gt; <span class=to>%s</span></li>' \
193                  "${html%%/*}" "${html##*/}"
194         done)
195         </ul>
196         <a class="button rename fail" href="[attachment]">$(_ OK)</a>
197         EOF
198     exit 0
199
200   elif [ "$fail" ]; then
201     printf "%s\r\n" "Status: 500 Internal Server Error"
202     theme_page - "$(_ "Attachment rename")" <<-EOF
203         <h1 class="rename fail">$(_ "Files could not be renamed")</h1>
204         <ul class="rename fail">
205         $(printf %s "$fail" |while read html; do
206           printf '<li><span class=from>%s</span> -&gt; <span class=to>%s</span></li>' \
207                  "${html%%/*}" "${html##*/}"
208         done)
209         </ul>
210         <a class="button rename fail" href="[attachment]">$(_ OK)</a>
211         EOF
212     exit 0
213
214   elif [ "$success" ]; then
215     printf 'Refresh: %i\r\n' 4
216     theme_page - "Attachment rename" <<-EOF
217         <h1 class="rename success">$(_ Files were renamed)</h1>
218         <ul class="rename success">
219         $(printf %s "$success" |while read html; do
220           printf '<li><span class=from>%s</span> -&gt; <span class=to>%s</span></li>' \
221                  "${html%%/*}" "${html##*/}"
222         done)
223         </ul>
224         <a class="button rename success" href="[attachment]">$(_ OK)</a>
225         EOF
226     exit 0
227
228   else
229     REDIRECT "${_BASE}${PATH_INFO}"
230
231   fi
232 fi
233
234 return 1