How access works¶
Files are served only by File Share¶
Shared files are served from /share/{id}/file/{n} and nowhere else. File Share does not implement hook_file_download(), so the core path /system/files/... behaves as before. A share neither opens it nor closes it.
Every request is checked¶
Each request to a share or its files goes through these checks in order. The first that fails ends the request and is logged with its reason.
- The share exists, is not revoked, and has not expired.
- The requester is identified:
- A logged-in account matches a recipient by account, by its email address, or by its address's domain.
- Otherwise the sign-in session gives an address, matched against addresses and domains.
- An address that belongs to an account, active or blocked, must log in instead.
- The item resolves to a file. A media item resolves to its current source file.
- The issuer can still download it: view access to the media item, then
$file->access('download', $issuer).
For a file referenced through a file field, core checks view access to the referencing entity and field as the issuer. A file that nothing references falls back to ownership. Files uploaded into a share are recorded as used by File Share, which core's file reference resolver does not count, so they pass for their owner, the issuer.
Access granted only by hook_file_download()
Modules that grant access to private files only through hook_file_download(), such as per-directory rules, are not consulted by the issuer check.
Sign-in tokens¶
- Codes and links are stored only as HMAC hashes.
- A token is consumed by
UPDATE … WHERE used IS NULL, and only a request that changes the row succeeds. Two requests racing with the same code or link cannot both sign in. - Opening a link only shows a Continue button; the POST from that page consumes it.
- Code requests, code checks and link checks are rate-limited with Drupal's Flood service.
Sessions¶
Recipients signed in by email get File Share's own session, not a Drupal session.
- The cookie,
SESSfileshare, holds a random value. Only its SHA-256 hash is stored. - It is set with
Path=/share,HttpOnly,SameSite=Lax, andSecureon HTTPS. - Pantheon's edge forwards cookies named
SESSfollowed by letters and digits to Drupal and does not cache those requests. The name was chosen for that. - Because no Drupal session is started, anonymous page caching elsewhere on the site is unaffected.
Caching and headers¶
Every /share route sets no_cache, so neither page cache stores it. Responses also carry these headers:
Cache-Control: private, no-storeX-Robots-Tag: noindex, nofollowReferrer-Policy: no-referrer
Files also carry X-Content-Type-Options: nosniff.
What the module stores¶
| Store | Holds |
|---|---|
file_share entity |
Title, message, items, issuer, expiry, revocation, invite and notification settings |
file_share_recipient |
Recipients, who added or invited them, and when they were removed |
file_share_token |
Hashed sign-in codes and links, with expiry and attempts |
file_share_session |
Hashed session IDs, email, last use and expiry |
file_share_log |
Sign-ins, downloads and refusals, with IP address and user agent |
Activity is purged after 90 days by default.