Skip to content

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.

  1. The share exists, is not revoked, and has not expired.
  2. 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.
  3. The item resolves to a file. A media item resolves to its current source file.
  4. 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, and Secure on HTTPS.
  • Pantheon's edge forwards cookies named SESS followed 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-store
  • X-Robots-Tag: noindex, nofollow
  • Referrer-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.