The /api/fetchRes proxy endpoint accepted an arbitrary URL from the
request body and passed it directly to fetch(), returning the response
to the caller. Any user with the site auth code could use it to reach
internal services (cloud metadata endpoints, RFC1918 hosts, loopback,
non-http(s) schemes) — a classic CWE-918 SSRF primitive.
The endpoint now:
- rejects non-http(s) schemes
- rejects URLs containing embedded credentials
- rejects hostnames resolving to loopback/private/link-local/CGNAT/
multicast/reserved ranges, IPv6 ULA/link-local, IPv4-mapped variants
and well-known cloud metadata hostnames
- follows redirects manually and re-validates each hop (max 5)
Chunked upload (uploadLargeFileToTelegram) and chunk merge responses
now also include publicUrl field when urlPrefix is configured, matching
the behavior of regular uploads.
When urlPrefix is configured in page settings, the upload API now
returns a `publicUrl` field in addition to the existing `src` field,
allowing clients to directly access files via the configured public
domain (e.g. R2 custom domain) without needing to reconstruct the URL.
- File size: prefer FileSizeBytes, fall back to FileSize (MB) * 1024^2
for files uploaded before FileSizeBytes was added
- Timestamps: use TimeStamp from metadata instead of current time,
so clients show the actual upload date, not the PROPFIND request time
Read FileType from metadata to populate D:getcontenttype (e.g.
image/jpeg), enabling WebDAV clients like Alist to identify file
types and show image previews.
- Read FileSizeBytes instead of non-existent File-Size metadata field,
so getcontentlength reports actual bytes instead of always 0
- Add /dav prefix to file href so WebDAV clients can GET files at the
correct path
Fixes files showing as 0B and being unopenable in RaiDrive, Cyberduck,
and Windows mapped drives.