# ProjectSend r2098

## New Features

- **Generic OIDC single sign-on** — Any OpenID Connect provider can now be used to sign in, including Keycloak, Authentik and Authelia, alongside the existing social providers.
- **Create own folders permission** — A new per-role permission controls who can create their own folders. It is enabled for the Client role by default, so nothing changes unless you turn it off.
- **LiteSpeed download support** — LiteSpeed servers can now serve downloads directly through an internal redirect, the same way X-Accel and XSendFile already did.
- **Reset a lost authenticator app** — When someone loses their authenticator and their backup codes, whoever can edit that account can now clear the app so they can enroll again on the next log in.

## Security Updates

- **Fix a two factor authentication bypass** — The email and TOTP methods shared one table, and the marker stored for TOTP rows was a value the email verifier accepted, so a TOTP challenge could be completed with no code at all. Each verifier now only accepts a token minted for its own method. Reported by Infinit3i.
- **Stop a TOTP challenge from being traded for an email code** — The same token could be handed to the "send me another code" action and downgraded to email.
- **Enforce two factor enrollment everywhere** — When two factor is required, accounts that had not enrolled yet could still reach endpoints that render no HTML, including the upload and ajax handlers.
- **Fix stored cross site scripting in the custom footer** — Footer content was filtered with `strip_tags()`, which leaves attributes on the tags it keeps, so an event handler survived and ran on every page including the log in form. Reported by Venkata Karthik Kakarla.
- **Fix stored cross site scripting on folder rename** — Renaming a folder stored the name unfiltered, and three places rendered it without escaping.
- **Fix reflected cross site scripting** — The date filter parameters on the thumbnail regeneration page were echoed back unescaped.
- **Escape names in the side modal title** — A name containing markup was inserted into the document rather than shown as text.
- **Require the upload permission where the file actually arrives** — The upload form checked the permission but the endpoint receiving the chunks only checked for a session, so files could be written to storage without it. Reported by Zeliang Yu.
- **Stop the e-mail templates page from writing any option** — It saved every field it was posted, so the permission to edit e-mail copy was enough to change any setting in the system, including the allowed upload extensions. Reported by Kery Qi.
- **Fix an insecure direct object reference** — Download permission checks granted access to any staff role rather than the intended one.
- **Close direct file access on Nginx** — Uploaded files could be fetched straight from the uploads directory, and the static asset rule served blocked uploads.
- **Close CSRF gaps** — The token check only ran when a form body was present, so requests with an empty or JSON body skipped it. Logging out and changing the language are also covered now.
- **Escape the address used in the LDAP search filter** — The e-mail was placed into the filter without escaping.
- **Require a verified e-mail from the generic OIDC provider** — An unverified address was accepted at sign in.

## Improvements

- **Numbered files sort in the order people expect** — Sorting by a text column compared it character by character, so `img10` came before `img2`. Applies to every list, not just files.
- **Encryption settings are honoured on upload** — Files were encrypted whenever the feature was on, ignoring the per upload choice, and the maximum size in the options was never read at all.
- **Decrypted temporary files are cleaned by the cron system** — The cleanup used to run on every admin page load.
- **Cron cleans up orphan files** — The cron option now targets orphan files rather than expired ones.
- **HybridAuth upgraded to 3.13.0** — Includes the migration from Twitter to X.

## Bug Fixes

- Public download buttons work for visitors who are not logged in (#1431).
- Large downloads are no longer cut off part way through.
- Decrypted files are no longer deleted before they finish being served on X-Accel, XSendFile and LiteSpeed.
- LDAP accounts can be created automatically again (#1545).
- Two factor setup no longer fails on installations upgraded from older versions (#1546).
- Two factor no longer redirects to the setup page when it is not required.
- Permission changes on custom roles save instead of failing silently (#1597).
- The single file editor no longer crashes on a missing value.
- CKEditor loads correctly on release builds.
- The public group link points at the group rather than the file list.
- Files with no description no longer log a warning on every page that lists them.
- The ajax actions answer with the field they are missing instead of a bare error.

## Maintenance

- Static analysis runs again: the lock file pinned a PHPStan release whose download no longer resolved, so every build failed before it could analyse anything.
- PHPStan baseline regenerated, now covering the files added since it was last written.
- Dependencies updated, including aws-sdk-php, axios, guzzle, immutable, picomatch and sjcl.
- The minify tasks no longer re-minify their own output.
- Translation templates regenerated so the strings added in this release are available to translators.
