From 619c24e1e92910c4676f2619922db83a91f5f303 Mon Sep 17 00:00:00 2001 From: Edouard Vanbelle Date: Wed, 17 Jun 2026 09:32:37 +0200 Subject: [PATCH] test(api): unpin folder-share file fetch; assert in/out-of-scope MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The KNOWN BUG pin for `GET /api/s/{folder-token}/file/{file_id}` was stale — the route now returns 200 + body for files inside the share's subtree and 404 for anything outside it. Replaces the sidestep comment with two positive assertions: - in-share: 200 + Content-Disposition references the file name - out-of-share (caller-owned file in a different folder): 404, matching "no such file" so the response can't be used to enumerate foreign file ids Coverage now exercises the actual recipient-side download path that NC desktop and web clients use; the file-share variant (item_type=file) moves down to test 8b. Adds a teardown DELETE for the outsider hello.txt so the next test in the runner (permissions.hurl) can re-upload its own hello.txt into admin's home folder without hitting the live-name unique index. --- tests/api/public_shares.hurl | 56 ++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/tests/api/public_shares.hurl b/tests/api/public_shares.hurl index 34f49657..81b02edc 100644 --- a/tests/api/public_shares.hurl +++ b/tests/api/public_shares.hurl @@ -136,15 +136,45 @@ body contains "{{shared_file_id}}" # ───────────────────────────────────────────────────────────── -# 8 — Direct file share: mint a share on the FILE itself -# (item_type=file) and access it via /api/s/{token}. -# -# KNOWN BUG: GET /api/s/{folder-token}/file/{file_id} (the -# "fetch a file from inside a shared folder" route at -# share_handler.rs:653) currently returns 500. We sidestep -# it here by sharing the file directly. When the folder-file -# path is fixed, add a new scenario asserting it returns -# 200 + body, and back-link this comment. +# 8 — Fetch a file from inside the FOLDER share via +# /api/s/{folder-token}/file/{file_id}. This is the path NC +# desktop and web clients use to download a single file out +# of a shared folder without zipping the whole tree. The +# handler must (a) accept the file_id only when the file +# lives in the share's subtree, and (b) refuse with 404 for +# any file outside the subtree (anti-enumeration: the same +# status as "file doesn't exist", so the caller can't probe +# for foreign file ids). +# ───────────────────────────────────────────────────────────── +GET {{base_url}}/api/s/{{share_token}}/file/{{shared_file_id}} + +HTTP 200 +[Asserts] +header "Content-Disposition" contains "hello.txt" + + +# A file the caller owns but that isn't inside the shared +# folder MUST 404 — same shape as "no such file", so the +# response can't be used to enumerate file ids. +POST {{base_url}}/api/files/upload +Authorization: Bearer {{admin_token}} +[MultipartFormData] +folder_id: {{admin_home_id}} +file: file,fixtures/hello.txt; text/plain + +HTTP 201 +[Captures] +outsider_file_id: jsonpath "$.id" + + +GET {{base_url}}/api/s/{{share_token}}/file/{{outsider_file_id}} + +HTTP 404 + + +# ───────────────────────────────────────────────────────────── +# 8b — Direct file share: mint a share on the FILE itself +# (item_type=file) and access it via /api/s/{token}. # ───────────────────────────────────────────────────────────── POST {{base_url}}/api/shares Authorization: Bearer {{admin_token}} @@ -256,6 +286,14 @@ DELETE {{base_url}}/api/shares/{{file_share_id}} Authorization: Bearer {{admin_token}} HTTP 204 +# The "outsider" hello.txt sits in admin's home folder, not under the +# shared subtree — delete it explicitly so the next test in the +# runner (permissions.hurl) can upload its own hello.txt to the same +# folder without hitting the live-name unique index (409). +DELETE {{base_url}}/api/files/{{outsider_file_id}} +Authorization: Bearer {{admin_token}} +HTTP 204 + DELETE {{base_url}}/api/folders/{{share_folder_id}} Authorization: Bearer {{admin_token}} HTTP 204