The Windows UI needs current winsafe, whose real minimum is 1.89 (its manifest
under-declares 1.87 while it uses NonNull::from_ref). Rather than stop at the
minimum, this goes to current stable and fixes what that costs.
The counter-intuitive result: 1.97 is CHEAPER than 1.89. libfreemkv had 54
clippy errors at 1.89 and 6 at 1.97, because clippy tightened the noisy
collapsible_if lint in between. Stopping at the minimum would have been the most
expensive choice available.
Roughly 47 lints across the eight repos, the large majority auto-fixed:
libfreemkv 6, freemkv-engine 14, bdemu 8, freemkv-keysources 7, autorip 6,
freemkv-unlock 3, freemkv-i18n 3. The hand-fixed ones are a descending sort to
sort_by_key(Reverse), four manual checked-division sites, a loop counter replaced
by enumerate, and a loop whose first let-else became a while-let.
Worth recording for whoever bumps next: clippy is MSRV-AWARE. Those 54 lints only
appear once the crate DECLARES 1.89 or later, because let-chains become
available. A bare `cargo +1.89 clippy` against a manifest still pinned at 1.87
reports clean and is meaningless — gate with the real precommit script, which is
also the only thing that covers build scripts.
The pin still sits below the Mac default, so it keeps doing its job: catching
lint drift locally before CI sees it.
The Windows UI needs winsafe, whose current release requires rustc 1.87. The
alternative was pinning winsafe back to an older release, which would bake a
stale API surface into a brand-new UI permanently to dodge one minor version.
The pin's purpose is to sit BELOW the Mac default so clippy drift is caught
locally before CI, not to stay on 1.86 specifically, so 1.87 preserves the
discipline exactly.
Verified before moving anything, not after: `cargo +1.87 clippy -- -D warnings`
and `cargo +1.87 fmt --check` are clean across all eight repos, and the full
precommit gate (fmt + clippy + tests) passes on libfreemkv, autorip, bdemu,
freemkv-engine and freemkv-keysources. Zero new lints, zero formatting drift.
Bump to 1.6.0 (workspace sync, no source change). Fix stale get_uk ->
get_unit_keys references in the crate description + comments, correct the
libfreemkv version note, and drop a phantom Mapfile mention from the tests.
keysources deps libfreemkv, now git-only, so keysources follows it off
crates.io. A committed [patch.crates-io] redirects the bare libfreemkv version
req to the git tag (local dev overrides to a path via the gitignored config).
Move the keydb save/validation/atomic-write path out of libfreemkv onto
KeydbSource. New KeydbSource::save(bytes) validates + decompresses (zip /
gz / plain, decompressed-size capped) and crash-safely writes to the
source's OWN path (sibling-temp + fsync + rename + parent-dir fsync) —
not a hardcoded default, so the caller chooses the destination.
KeydbSource::update(fetch, url) calls an INJECTED fetch closure then
save, keeping this crate transport-agnostic on the update path (the app
supplies its own TLS / SSRF-guarded transport). UpdateResult moves here
and is re-exported. Add flate2 + zip (already in the resolved graph via
libfreemkv) for decompression; no new HTTP stack.
unit_keys_from now resolves the Media Key in order: stored per-disc MK
-> keydb Processing Key pool (mk_from_pk vs this disc's own MKB) ->
device-key pool (mk_from_dk), then MK+VID -> VUK -> UK. MK/VUK entries
still honored directly; cross-disc MK-pool brute stays retired. Fixes the
factually-wrong justifying comment + adds PK-pool KATs.
OnlineSource::query() now includes the disc's volume_label (UDF/ISO volume id)
as a plain-text `title` field in the /decode POST, so the key service can build
a disc_hash → title catalog from real rips. Depends on libfreemkv 0.30.
OnlineSource: the remote key-service client (moved out of autorip), posting the
disc's Unit_Key_RO.inf + MKB + Volume ID + encrypted content samples to the
service and returning the resolved unit key as a terminal Key::Unit candidate.
Kept out of libfreemkv so the library stays network-free. Source-internal
failures (unreachable / status / parse) are logged and surface as "no
candidate" so the next source is tried.
MapfileSource: reads a rip mapfile's persisted unit keys (the resume / deferred-
mux fast path) and offers them as a Key::Unit candidate. Keyed by mapfile path.
DiscInputs gained an app-populated `samples` field for sources that validate
against ciphertext server-side (OnlineSource); local sources ignore it.
The published key-source layer for libfreemkv. libfreemkv does no lookup; it
is handed a Key and derives down. This crate provides the KeySource impls that
do the lookup and hand a Key in. Applications choose and order the sources.
This first cut ships:
- KeydbSource: parses a local keydb.cfg and enumerates its material as ordered
candidate keys (per-disc VUK/unit/media first, then the universal device-key,
processing-key, and media-key pools). It does no derivation — the library
walks the MKB and verifies media keys. Candidate ordering lets the library
try each path a keydb can satisfy.
- resolve_first: tries each source's candidates in order and returns the first
the caller's validator accepts (validate-before-return), so a stale entry
falls through to the next source.
OnlineSource (remote key service) and MapfileSource (cached unit key) land with
the application wiring, where the sample-read and mapfile paths already live.