Skip to main content

Security model

In Home Keeper Library, an admin manages the library. Each signed-in user keeps the reading of their own person. Admins manage the locations, the books and their copies, the loans and the wishlist. A non-admin user sets the reading status, the rating and the notes of their own person, and reads what the projections allow.

The rule​

A Home Assistant instance usually has 1 or 2 admins and a few users, such as a partner, children, a housemate or a guest account on a wall tablet. The library follows the rule of Home Assistant itself: a user who is not an admin cannot change the setup of the home. For the library, a guest account must not:

  • delete books or move copies;
  • read the price and the value of a copy, or the names of the people who borrowed a book;
  • read the private notes of another person;
  • read the reading status of a person who does not share it.

The admin UI is the Library tab of the Home Keeper panel, and that panel is admin-only. Every user can use the card and the entities. Every user can also call the services that this page lists as open.

The caller​

The library finds the person of a caller from the Home Assistant user: the person whose user is the caller. A user with no person can read the library. An operation that acts for a person gives that user the error no_person. The library trusts a call with no user, as Home Assistant does. An automation makes that kind of call.

Services​

ServiceAccess
add_room, update_room, delete_roomAdmin
add_bookcase, update_bookcase, delete_bookcaseAdmin
add_shelf, update_shelf, delete_shelfAdmin
lookup_isbn, add_book, update_book, delete_book, refresh_bookAdmin
scan_isbn, add_copy, update_copy, move_copy, delete_copy, set_coverAdmin
lend_book, borrow_book, return_loan, update_loan, delete_loanAdmin
add_to_wishlist, update_wishlist, remove_from_wishlist, got_wishlist_bookAdmin
set_settings, import_csv, export_csvAdmin
send_to_catalog, link_catalog, skip_catalog, disconnect_catalogAdmin
export_data, import_dataAdmin
set_readingOpen, for the caller's own person. An admin can name any person.
set_person_settingsOpen, for the caller's own person, with no wishlist_todo. An admin can set each field of any person.
list_books, get_book, list_locations, list_loans, list_peopleOpen, projected

wishlist_todo is admin-only because it sends book titles to a to-do list. Import and export are admin-only because they read or write the whole library. send_to_catalog is admin-only because it sends book details to a public website as the household account.

Open Library account​

An admin can connect an Open Library account to send books (open-library-contribute).

  • The 2 Archive.org S3 keys come in only through the openlibrary step of the options flow. Home Assistant lets only an admin run an options flow. The keys are not a service field, so no call_service event or recorder row holds them.
  • The keys stay in the config entry data. No reply, event or diagnostics file shows them. get_state gives an admin only catalog_accounts: for each catalog, if an account is connected, and its user name. A non-admin user gets no catalog_accounts.
  • The library signs in for each send and keeps the session cookie only for that send.
  • A send goes only to the Open Library base URL, with the same limit of 1 request a second as the lookups. It sends the title, the first author and the fields that the admin selects. It never sends notes, prices, values, loans, shelves or reading status.

Websocket commands​

CommandAccess
home_keeper_library/get_stateOpen, projected
home_keeper_library/subscribeOpen. It sends only a revision number.
home_keeper_library/list_todo_entitiesAdmin
home_keeper_library/<service>The same access as the service of the same name

Each command with the name of a service runs the same code and the same check as the service. A gate on the command alone would be no gate, because a user can call the service directly.

HTTP views​

Method and pathAccess
GET /home_keeper_library_static/...Public. It holds only the built bundles.
GET /api/home_keeper_library/cover/{book_id}Each signed-in user. Covers are not private.
POST /api/home_keeper_library/uploadAdmin, as a real user. At most 10 MB. JPEG, PNG or WebP.

Home Assistant serves a static path before authentication, so the static path holds only frontend/dist/. The upload view reads the image type from the first bytes of the file, and stores only a JPEG that it writes again. A signed URL is accepted only for GET and HEAD, so a signed URL cannot upload.

Projections​

An admin reads the full library. For a non-admin user, every reply goes through the projection:

RecordHidden from a non-admin user
Copyprice, value, acquired_from
Loanparty
Reading row of another personThe whole row if that person has share_reading: false, else private_notes
Settings of another personwishlist_todo
Wishlist entry of another persontodo_entity, todo_uid

The book records, the shared notes and the covers are open to every user. Only an admin can download the diagnostics. The download redacts the loan parties, the notes and acquired_from. It has no Open Library key, only a mark that shows if an account is connected.

Entities​

Home Assistant shows each entity to each user, and lets each user call the todo services on each to-do list. So the per-person entities apply the privacy rules of the library:

  • The To read list of a person takes a change only from the user of that person or from an admin user. A call with no user, such as an automation, is trusted. A change from another user fails with the error todo_not_allowed.
  • If a person has share_reading: false, the 3 entities of that person are unavailable: the To read list and the sensors that show the books read this year and the books that the person reads now. The list gives no items, also over the todo/item/list websocket command. They come back when the person shares the reading again.

The library sensors show only counts, with no title and no person.

Events​

The payload of a bus event holds the book title, the person id and, for a loan, the party. Home Assistant lets only an admin subscribe to these events over the websocket API. An automation that copies an event to a notification sends that data to the place that the automation names.

Add a surface​

Each PR lists the surfaces that it adds or changes in its Security section. The rules that decide if an operation is admin-only or open are in the architecture rules.