simplefiles

A lightweight C CGI web application for managing files.
git clone https://scm.kuandu.systems/git-raw/simplefiles.git
Log | Files | Refs | README | LICENSE

list.sh (7603B)


      1 #!/bin/sh
      2 
      3 set -eu
      4 
      5 . "$(dirname "$0")/testlib.sh"
      6 
      7 CGI=${1:-build/list.cgi}
      8 
      9 list() {
     10   env \
     11     STORAGE_ROOT="$TESTROOT/storage" \
     12     SIMPLEFILES_ROOT=./html \
     13     REMOTE_USER=alice \
     14     REQUEST_METHOD=GET \
     15     "$CGI"
     16 }
     17 
     18 list_repo() {
     19   env \
     20     STORAGE_ROOT="$TESTROOT/storage" \
     21     SIMPLEFILES_ROOT=./html \
     22     SCRIPT_NAME="/$1/list.cgi" \
     23     REMOTE_USER=alice \
     24     REQUEST_METHOD=GET \
     25     "$CGI"
     26 }
     27 
     28 list_user() {
     29     user=$1
     30 
     31     env \
     32         SCRIPT_NAME=/default/list.cgi \
     33         STORAGE_ROOT="$TESTROOT/storage" \
     34 	SIMPLEFILES_ROOT=./html \
     35         REQUEST_METHOD=GET \
     36         REMOTE_USER="$user" \
     37         "$CGI"
     38 }
     39 
     40 list_no_user() {
     41     (
     42         unset REMOTE_USER
     43 
     44         export SCRIPT_NAME=/default/list.cgi
     45 	export SIMPLEFILES_ROOT=./html
     46         export SIMPLEFILES_CONFIG="$TEST_CONFIG"
     47         export STORAGE_ROOT="$TESTROOT/storage"
     48         export REQUEST_METHOD=GET
     49 
     50         "$CGI"
     51     )
     52 }
     53 
     54 list_no_user_root() {
     55     root=$1
     56 
     57     (
     58         unset REMOTE_USER
     59 
     60         export SCRIPT_NAME=/default/list.cgi
     61         export SIMPLEFILES_ROOT="$root"
     62         export SIMPLEFILES_CONFIG="$TEST_CONFIG"
     63         export STORAGE_ROOT="$TESTROOT/storage"
     64         export REQUEST_METHOD=GET
     65 
     66         "$CGI"
     67     )
     68 }
     69 
     70 ##############################################################################
     71 
     72 reset_testroot
     73 
     74 check_body \
     75   "empty page" \
     76   "SimpleFiles" \
     77   list
     78 
     79 check_body \
     80   "table header" \
     81   "<th>Name</th>" \
     82   list
     83 
     84 ##############################################################################
     85 
     86 printf 'dummy\n' > "$TESTROOT/storage/default/file1.txt"
     87 
     88 check_body \
     89   "one filename" \
     90   "file1.txt" \
     91   list
     92 
     93 ##############################################################################
     94 
     95 printf 'dummy\n' > "$TESTROOT/storage/default/file2.txt"
     96 
     97 check_body \
     98   "second filename" \
     99   "file2.txt" \
    100   list
    101 
    102 ##############################################################################
    103 
    104 mkdir "$TESTROOT/storage/default/subdir"
    105 
    106 check_not_body \
    107   "ignore directories" \
    108   "subdir" \
    109   list
    110 
    111 ##############################################################################
    112 
    113 mkdir -p "$TESTROOT/storage/music"
    114 mkdir -p "$TESTROOT/storage/poetry"
    115 
    116 printf 'music\n' > "$TESTROOT/storage/music/song.mp3"
    117 printf 'poetry\n' > "$TESTROOT/storage/poetry/poem.txt"
    118 
    119 check_body \
    120   "music repository" \
    121   "song.mp3" \
    122   list_repo music
    123 
    124 check_not_body \
    125   "music excludes poetry" \
    126   "poem.txt" \
    127   list_repo music
    128 
    129 check_body \
    130   "poetry repository" \
    131   "poem.txt" \
    132   list_repo poetry
    133 
    134 check_not_body \
    135   "poetry excludes music" \
    136   "song.mp3" \
    137   list_repo poetry
    138 
    139 ##############################################################################
    140 
    141 mkdir -p "$TESTROOT/secret"
    142 
    143 printf 'secret\n' > "$TESTROOT/secret/password.txt"
    144 
    145 check_not_body \
    146   "reject repository traversal" \
    147   "password.txt" \
    148   list_repo "../secret"
    149 
    150 ##############################################################################
    151 
    152 # Test HTML escaping of filenames
    153 
    154 escaped_filename='&lt;test&gt;&amp;file.txt'
    155 raw_filename='<test>&file.txt'
    156 
    157 printf 'dummy\n' > "$TESTROOT/storage/default/$raw_filename"
    158 
    159 check_body \
    160   "escape filename in html" \
    161   "$escaped_filename" \
    162   list
    163 
    164 check_body \
    165   "url encode filename" \
    166   "download.cgi?file=%3Ctest%3E%26file.txt" \
    167   list
    168 
    169 ##############################################################################
    170 
    171 printf 'QUOTA=1024\n' > "$TESTROOT/storage/default/.config"
    172 
    173 check_not_body \
    174   "hide .config" \
    175   ".config" \
    176   list
    177 
    178 ##############################################################################
    179 #
    180 # Read-only repository
    181 #
    182 
    183 reset_testroot
    184 
    185 printf 'READ_ONLY=1\n' > "$TESTROOT/storage/default/.config"
    186 printf 'hello\n' > "$TESTROOT/storage/default/file1.txt"
    187 
    188 check_body \
    189   "readonly list still shows files" \
    190   "file1.txt" \
    191   list
    192 
    193 check_not_body \
    194   "readonly list hides upload link" \
    195   "upload.cgi" \
    196   list
    197 
    198 check_not_body \
    199   "readonly list hides delete link" \
    200   "delete.cgi" \
    201   list
    202 
    203 ####################################################
    204 #
    205 # Authentication-aware access control
    206 #
    207 
    208 # 1 Anonymous access is rejected by default
    209 
    210 reset_testroot
    211 
    212 write_default_repo_config ""
    213 
    214 printf '%s' 'list content' \
    215 	> "$TESTROOT/storage/default/file.txt"
    216 
    217 check_status \
    218 	"anonymous listing rejected by default" \
    219 	"403 Forbidden" \
    220 	list_no_user
    221 
    222 # 2 Anonymous listing is allowed when explicitly set
    223 
    224 reset_testroot
    225 
    226 write_default_repo_config ""
    227 
    228 printf '%s' 'list content' \
    229 	> "$TESTROOT/storage/default/file.txt"
    230 
    231 write_global_config "ANONYMOUS_READ=1"
    232 
    233 check_status \
    234 	"anonymous listing allowed with ANONYMOUS_READ" \
    235 	"200 OK" \
    236 	list_no_user
    237 
    238 check_body \
    239 	"anonymous listing with ANONYMOUS_READ succeeds" \
    240 	"file.txt" \
    241 	list_no_user
    242 
    243 check_not_body \
    244 	"anonymous listing allowed hides upload link" \
    245 	"upload.cgi" \
    246 	list_no_user
    247 
    248 check_not_body \
    249 	"anonymous listing allowed hides delete link" \
    250 	"delete.cgi?file=file.txt" \
    251 	list_no_user
    252 
    253 # 3 Authenticated non-admin listing remains allowed
    254 
    255 reset_testroot
    256 
    257 write_default_repo_config ""
    258 
    259 printf '%s' 'list content' \
    260 	> "$TESTROOT/storage/default/file.txt"
    261 
    262 check_status \
    263 	"authenticated listing allowed without ADMIN_USER" \
    264 	"200 OK" \
    265 	list_user \
    266 	"alice"
    267 
    268 check_body \
    269 	"authenticated listing without ADMIN_USER succeeds" \
    270 	"file.txt" \
    271 	list_user \
    272 	"alice"
    273 
    274 check_not_body \
    275 	"non-admin listing hides upload link" \
    276 	"upload.cgi" \
    277 	list_user \
    278 	"alice"
    279 
    280 check_not_body \
    281 	"non-admin listing hides delete link" \
    282 	"delete.cgi?file=file.txt" \
    283 	list_user \
    284 	"alice"
    285 
    286 # 4 Matching admin user is allowed
    287 
    288 reset_testroot
    289 
    290 write_default_repo_config "ADMIN_USER=bob"
    291 
    292 printf '%s' 'list content' \
    293 	> "$TESTROOT/storage/default/file.txt"
    294 
    295 check_status \
    296 	"admin user allowed to list" \
    297 	"200 OK" \
    298 	list_user \
    299 	"bob"
    300 
    301 check_body \
    302 	"admin listing succeeds" \
    303 	"file.txt" \
    304 	list_user \
    305 	"bob"
    306 
    307 check_body \
    308 	"admin listing shows upload link" \
    309 	"upload.cgi" \
    310 	list_user \
    311 	"bob"
    312 
    313 check_body \
    314 	"admin listing shows delete link" \
    315 	"delete.cgi?file=file.txt" \
    316 	list_user \
    317 	"bob"
    318 
    319 # 5 Non-admin authenticated user can read but cannot write
    320 
    321 reset_testroot
    322 
    323 write_default_repo_config "ADMIN_USER=bob"
    324 
    325 printf '%s' 'list content' \
    326 	> "$TESTROOT/storage/default/file.txt"
    327 
    328 check_status \
    329 	"non-admin user allowed to list" \
    330 	"200 OK" \
    331 	list_user \
    332 	"alice"
    333 
    334 check_body \
    335 	"non-admin listing succeeds" \
    336 	"file.txt" \
    337 	list_user \
    338 	"alice"
    339 
    340 check_not_body \
    341 	"non-admin listing hides upload link" \
    342 	"upload.cgi" \
    343 	list_user \
    344 	"alice"
    345 
    346 check_not_body \
    347 	"non-admin listing hides delete link" \
    348 	"delete.cgi?file=file.txt" \
    349 	list_user \
    350 	"alice"
    351 
    352 # 6 ANONYMOUS_READ allows anonymous access even when ADMIN_USER is configured
    353 
    354 reset_testroot
    355 
    356 write_default_repo_config "ADMIN_USER=bob"
    357 
    358 printf '%s' 'list content' \
    359 	> "$TESTROOT/storage/default/file.txt"
    360 
    361 write_global_config "ANONYMOUS_READ=1"
    362 
    363 check_status \
    364 	"anonymous listing allowed with ADMIN_USER and ANONYMOUS_READ" \
    365 	"200 OK" \
    366 	list_no_user
    367 
    368 check_body \
    369 	"anonymous listing succeeds with ADMIN_USER and ANONYMOUS_READ" \
    370 	"file.txt" \
    371 	list_no_user
    372 
    373 check_not_body \
    374 	"anonymous listing hides upload link" \
    375 	"upload.cgi" \
    376 	list_no_user
    377 
    378 check_not_body \
    379 	"anonymous listing hides delete link" \
    380 	"delete.cgi?file=file.txt" \
    381 	list_no_user
    382 
    383 #
    384 # Response generation
    385 #
    386 
    387 reset_testroot
    388 
    389 write_default_repo_config ""
    390 write_global_config "ANONYMOUS_READ=1"
    391 
    392 printf 'hello\n' > "$TESTROOT/storage/default/file1.txt"
    393 
    394 mkdir -p "$TESTROOT/html"
    395 printf '{{UNKNOWN_VARIABLE}}' > "$TESTROOT/html/list.html"
    396 
    397 check_status \
    398   "template failure returns 500" \
    399   "500 Internal Server Error" \
    400   list_no_user_root \
    401   "$TESTROOT/html"
    402 
    403 test_result