disc: unlocker_matrix reports 'did work this rip', not 'matched'
yes now means the unlocker actually ran and did its job: LibreDrive from the runtime firmware-unlock success, AACS host-cert only when LibreDrive didn't do the bus (stock-drive fallback), CSS from the crack succeeding. On a LibreDrive UHD that correctly reads LibreDrive: yes, AACS: no (LD removed the bus, the cert route never ran) instead of the misleading AACS: yes. Names stay registry-driven; runtime logic lives here.
This commit is contained in:
+31
-11
@@ -2270,19 +2270,39 @@ impl Disc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The unlocker matrix for this scanned disc on `drive`: each REGISTERED
|
/// The unlocker matrix for this scanned disc on `drive`: each REGISTERED
|
||||||
/// unlocker's name + whether it applies to this drive + disc. Registry-driven
|
/// unlocker's name + whether it actually **did work this rip** — i.e. ran and
|
||||||
/// (no hardcoded names) so the CLI and autorip render an identical, always-
|
/// accomplished its job, NOT merely "matched the disc kind". Registry-driven
|
||||||
/// current report. The disc's crypto kind is derived here (in the library) so
|
/// names (no hardcoding) so the CLI and autorip render an identical, always-
|
||||||
/// both apps agree.
|
/// current report; the per-unlocker runtime signal is computed here because
|
||||||
|
/// the library owns unlock semantics AND the disc/drive state.
|
||||||
|
///
|
||||||
|
/// The distinction matters: on a LibreDrive drive, LibreDrive's firmware route
|
||||||
|
/// removes the AACS bus and reads the VID, so the AACS host-cert unlocker
|
||||||
|
/// never runs — it "matched" (AACS disc) but did nothing. `did-work` reports
|
||||||
|
/// that honestly (`AACS: no`), and on a *stock* drive that fell back to the
|
||||||
|
/// cert route it reports `LibreDrive: no, AACS: yes` — the real diagnostic.
|
||||||
pub fn unlocker_matrix(&self, drive: &crate::Drive) -> Vec<(&'static str, bool)> {
|
pub fn unlocker_matrix(&self, drive: &crate::Drive) -> Vec<(&'static str, bool)> {
|
||||||
let kind = if self.aacs.is_some() || self.aacs_error.is_some() {
|
// LibreDrive firmware-unlocked the drive iff a drive unlocker actually
|
||||||
freemkv_unlock::DiscKind::Aacs
|
// succeeded at init (name recorded only on success).
|
||||||
} else if self.css.is_some() || self.css_error.is_some() {
|
let ld_worked = drive.unlocker_name().is_some();
|
||||||
freemkv_unlock::DiscKind::Css
|
crate::unlock_bridge::unlocker_names()
|
||||||
} else {
|
.into_iter()
|
||||||
freemkv_unlock::DiscKind::Unencrypted
|
.map(|name| {
|
||||||
|
let did_work = match name {
|
||||||
|
// The drive firmware unlock ran and succeeded.
|
||||||
|
"LibreDrive" => ld_worked,
|
||||||
|
// The AACS host-cert route removed the bus ONLY when LibreDrive
|
||||||
|
// didn't (stock drive) AND AACS state was actually obtained.
|
||||||
|
"AACS" => self.aacs.is_some() && !ld_worked,
|
||||||
|
// The CSS handshake/crack succeeded → title keys recovered.
|
||||||
|
"CSS" => self.css.is_some(),
|
||||||
|
// A newly-registered unlocker with no runtime signal wired
|
||||||
|
// here yet: report `no` rather than guess.
|
||||||
|
_ => false,
|
||||||
};
|
};
|
||||||
crate::unlock_bridge::unlocker_matrix(&drive.drive_id, kind)
|
(name, did_work)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The system-wide decrypt correctness gate.
|
/// The system-wide decrypt correctness gate.
|
||||||
|
|||||||
+7
-15
@@ -124,21 +124,13 @@ pub(crate) fn run_unlockers(
|
|||||||
Err(fu::UnlockError::NotApplicable)
|
Err(fu::UnlockError::NotApplicable)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Registry-driven unlocker matrix: each REGISTERED unlocker's name + whether it
|
/// The names of every REGISTERED unlocker, in dispatch order. Registry-driven —
|
||||||
/// applies to this drive + disc, in dispatch order. Dynamic — sourced from
|
/// sourced from `all_unlockers()`, so adding/removing an unlocker updates every
|
||||||
/// `all_unlockers()`, so adding/removing an unlocker updates every report with no
|
/// report with no other change (no hardcoded names). The per-unlocker "did it
|
||||||
/// other change (no hardcoded names). Apps render the yes/no English from this
|
/// run this rip" outcome is computed by the caller, which has the disc + drive
|
||||||
/// typed list. Report-only: uses `applies_to`, not the phase-gated `matches`.
|
/// runtime state this crate cannot see.
|
||||||
pub(crate) fn unlocker_matrix(
|
pub(crate) fn unlocker_names() -> Vec<&'static str> {
|
||||||
drive_id: &crate::identity::DriveId,
|
fu::all_unlockers().iter().map(|u| u.name()).collect()
|
||||||
kind: fu::DiscKind,
|
|
||||||
) -> Vec<(&'static str, bool)> {
|
|
||||||
let id = to_fu_drive_id(drive_id);
|
|
||||||
let ctx = fu::UnlockCtx::new(&id, kind, &[]);
|
|
||||||
fu::all_unlockers()
|
|
||||||
.iter()
|
|
||||||
.map(|u| (u.name(), u.applies_to(&ctx)))
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user