Multi user hardening from a review of how separate libraries are kept apart, an ebook import that no longer lands in another book's folder, a guide to naming templates, and dependency updates. If you run Bindery with BINDERY_ENFORCE_TENANCY on and more than one account, please update.
Added
- File naming guide (#3568). A new docs page, File Naming, covers every naming token, conditional groups, how empty folder levels drop, name cleaning, length limits, recipes for common layouts and the usual mistakes. Every example in it was rendered by Bindery's own renamer. Thanks to robrowald for asking in Discussion #1311.
Changed
- Web dependencies updated (#3583). i18next, react-i18next, react-router and a few build tools move to their latest minor or patch releases. Nothing changes in how Bindery behaves.
- Refreshed base images and CI tooling (#3571, #3572, #3580, #3581, #3582, #3584, #3585, #3573 to #3578, #3588). The Go, Node and distroless image digests and the CI actions were updated, and the CodeQL steps now always run the same release.
Fixed
- Ebook import no longer lands inside another book's tracked folder (#3556, #3570). When an ebook would be written below a folder another book tracks (an audiobook's folder, for example), the import is now blocked with a reason instead of placing the file where a later Reorganize of that folder would carry it away. The block tells you to remove the duplicate book or change the naming template. Reorganize itself can still move a file into another book's folder; that half is tracked in #3599. Thanks to pujitha24 for the fix.
Security
- Shared authors and books can only be changed by an admin when tenancy is on (#3587). With
BINDERY_ENFORCE_TENANCYset, a user who was not an admin could delete, merge, edit or refresh an author or book that had no owner, and act on automatic downloads and pending releases for such books. Because a shared author can hold books from several libraries, that let one user delete other users' books (and their files), move them under their own author, or change their monitoring and root folders. Adding an author or a book could also rewrite a shared author or adopt a shared book. Rows with no owner are still visible to every user, but only an admin can change them now, whether directly or through an add, and a user can no longer delete or merge one of their own authors while it holds a book from someone else's library. Tenancy off and admin accounts behave as before. - A download grabbed without a book now only lands in a book its owner can see (#3587). With
BINDERY_ENFORCE_TENANCYon, a release a user grabbed from the Search page without picking a book could be matched, once it finished, to a book in another user's library and imported there. Bindery now matches such a download only against the owner's own books and books nobody owns. If nothing there matches, it stays in the queue as unmatched, as it always has when nothing matches. Downloads grabbed by an admin, automatic grabs, and installs with tenancy off match against the whole library as before. - History, Refresh all and recommendations stay within each user's library (#3587). With
BINDERY_ENFORCE_TENANCYon, deleting a book used to leave its history (release names, indexers and import paths) visible to every user, and any user could delete those entries or blocklist their releases. History entries now belong to an account and stay with it after the book is gone; entries with no owner and no book are admin only. A user who is not an admin could also run Refresh all over every account's authors and read the instance's author count, and their Discover recommendations were built from, and could name, other users' books and the admin's Hardcover want to read list. Refresh all now covers only that user's own authors and reports only their run, and recommendations use only their own and shared books. Adds database migration 117, which gives existing history entries an owner where it can tell. Recommendations saved before upgrading are cleared once for every account that is not an admin and rebuilt on the next refresh; dismissed books and excluded authors are kept. Otherwise admins and installs with tenancy off are unchanged. - An audiobook folder download only contains that audiobook (#3587). Downloading an audiobook as a zip, from the web app or over OPDS, packed every file in its folder, so a file another book tracks inside that folder (with separate libraries per user, possibly another user's ebook) came along with it. Files and folders another book tracks are now left out, also when the two are spelled in different case. Cover art, cue sheets and other untracked files in the folder are still included.
- Download client errors are only shown in full to admins (#3587). When a download client could not be reached, or refused a release, the queue and History showed every account the client's own error, which names its address. Accounts that are not admins now see the client's name and a short message instead, including for older entries. Admins still get the full error in the queue and the log. New History entries and failure notifications carry the short message for everyone.
- An import blocked by another user's book no longer names it (#3587). With
BINDERY_ENFORCE_TENANCYon, a download whose destination is already tracked by a book that belongs to someone else now says another book in the library uses that path, without that book's title or id. The import is still blocked as before.