Expand description
day-part-keychain: small secrets in the platform’s own secure store, by key. No UI; any Rust code can depend on this crate and keep a session token, a password or a key where the OS keeps its own.
use day_part_keychain::{Protection, Secret};
day_part_keychain::set("session", &Secret::from("eyJhbGciOi…"), Protection::WhenUnlocked)?;
let token = day_part_keychain::get("session")?;
println!("{} bytes", token.len());Platform selection is #[cfg(target_os)]: the data protection keychain on iOS and macOS, the
Android Keystore over files in the app’s no-backup directory, DPAPI over files under
%LOCALAPPDATA% on Windows, the Secret Service (GNOME Keyring, KDE’s ksecretd, KeePassXC)
through libsecret on desktop Linux, and the Universal Keystore over files in the app sandbox
on HarmonyOS. The web has no store a page may rely on for a secret, so support reports
Unsupported there and every call fails with KeychainError::Unsupported.
§What an item is
An item is a key (a short string the app chooses) and a Secret (up to MAX_SECRET_LEN
bytes), stored for this app on this device under a Protection level. Items belong to the
app that wrote them: each platform scopes them by the app’s identity (the bundle, the package,
the user’s profile and the app id). They survive a reinstall where the platform keeps keychain
data across one (Apple) and are removed with the app elsewhere; none of them is backed up or
synchronized, because the keys that encrypt them never leave the device.
§Reading an item that needs the person
A Protection::UserPresence item is readable only after the device verifies the person: a
biometric or the device credential, in the OS’s own dialog. get is synchronous and never
shows that dialog; on such an item it returns KeychainError::NeedsPresence, and the app
calls get_async or get_future, which show the dialog and resolve with the secret. The
other protection levels resolve without a dialog in either form.
§Threads
The synchronous calls run on the caller’s thread and finish in milliseconds on every platform
but Linux, where a locked keyring makes the Secret Service show its unlock dialog during the
call; UI code there prefers get_async, which works on a thread of its own. Completions run
where the platform delivers them (a worker thread, an Android executor, the HarmonyOS JS
thread), which is why the callback is Send; get_future awaited under day::task
resumes on the UI thread. Nothing here posts to a main loop, so the crate works in a plain
main and under cargo test (docs/async.md rule 3).
Structs§
Enums§
- Keychain
Error - Why a call did not do what it was asked.
- Protection
- When an item may be read.
- Support
Constants§
- MAX_
KEY_ LEN - The longest key, in UTF-8 bytes. Long enough for a reverse-DNS name with an account after it, short enough for every platform’s identifier and file-name limits.
- MAX_
SECRET_ LEN - The largest secret, in bytes. A keychain holds credentials, not documents: tokens, passwords, keys and the occasional certificate all fit, and every platform store below stays fast at this size.
Functions§
- backend
- The store selected for this process, as a short name for diagnostics and support notes:
data-protection-keychain,login-keychain,android-keystore,dpapi,secret-service,huks, ornone. - contains
- Whether an item exists under
key, without reading it and without a dialog. - entries
- Every item this app stored, with its level, without the secrets and without a dialog.
- get
- The item under
key, without a dialog. AProtection::UserPresenceitem answersKeychainError::NeedsPresence; useget_asyncorget_futurefor it. - get_
async - The item under
key, showing the OS’s verification dialog withreasonwhen the item needs the person present, and answering exactly once, on the platform’s thread. An item at another level resolves without a dialog. - get_
future get_asyncas a future.- protection_
support - Whether one
Protectionlevel is realized here:Nativewhere the OS binds the item to it,Emulatedwhere the crate gates the read without a binding (Windows user presence),Unsupportedwhere nothing can honor it (Linux user presence, every level on the web). - remove
- Remove the item under
key.KeychainError::NotFoundwhen there is none. - set
- Store
secretunderkeyatprotection, replacing any item with that key (whatever its level). Never shows a dialog. - support
- What this target’s store promises:
Nativewhere the platform keeps the secret in its own store,Emulatedwhere the store is a stand-in with weaker guarantees (an unsigned macOS development build’s login keychain),Unsupportedwhere there is none (the web, a Linux session with no Secret Service).