mirror of
https://github.com/logos-blockchain/lssa.git
synced 2026-08-11 09:23:20 +00:00
* refactor(keycard_wallet): replace keycard-py (pyo3) with native keycard-rs Rewrites the Keycard integration to talk to the LEE-flavored applet directly from Rust via keycard-rs (pinned git dependency), dropping the pyo3 shim, python_path.rs, and the vendored keycard-py Python library entirely. Verified end-to-end against real hardware: pairing, PIN verification, mnemonic loading, BIP340 Schnorr signing, and transfers between keycard and public/private accounts. Also cleans up the pyo3 usage that had leaked into wallet's signing path (signing.rs, account_manager.rs) beyond the keycard CLI itself, and trims wallet_with_keycard.sh's Python setup down to just pyscard, which is only needed by the force_unpower.py test helper now. * Updated to v2 secure communication * ci: install libpcsclite-dev for pcsc crate builds * docs(keycard): clarify personalization is mandatory and document default CA Reinstalling the applet via `./gradlew install` wipes any existing personalization regardless of firmware source, which wasn't previously called out and is a common source of "card not available" confusion. Also state plainly that personalization is required before any command works, and document keycard-rs's actual baked-in default CA public key instead of only describing the override mechanism. Export KEYCARD_CA_PUBLIC_KEY in all keycard test scripts so they work against the dev/test-CA personalization flow they rely on. * fix(keycard): address PR #595 review comments - Propagate the load_mnemonic error instead of swallowing it behind is_ok(), matching every other command handler in this file. - Add deny.toml allowing the keycard-rs git source, fixing the source-not-allowed failure in `cargo deny check`. Licenses and advisories checks still have pre-existing, separate failures not addressed here. - Drop the pinned rev for the keycard-rs git dependency so it tracks the upstream default branch instead. * chore(deny): trim deny.toml to essentials and allow all in-use licenses Replace the full cargo-deny init template with just the two sections that matter: the keycard-rs git-source allowance, and an explicit license allow-list covering every license currently in the dependency tree. cargo deny check now passes on sources, bans, and licenses; advisories still fails on a pre-existing, unrelated RUSTSEC advisory. * fix(deny): remove second config and add source to the original one * chore: pin keycard-rs dependency and fix factory-reset debug-gate doc * chore: regenerate test fixture and lockfile after rebase onto dev --------- Co-authored-by: Daniil Polyakov <arjentix@gmail.com>
53 lines
1.8 KiB
Rust
53 lines
1.8 KiB
Rust
#![expect(
|
|
clippy::print_stdout,
|
|
reason = "This is a CLI test helper, printing to stdout is expected and convenient"
|
|
)]
|
|
|
|
//! Forces the card in the first available reader into the unpowered state via PC/SC
|
|
//! `SCARD_UNPOWER_CARD`. Run immediately before a wallet command to simulate the power-loss
|
|
//! condition reported on some USB reader/driver combinations.
|
|
//!
|
|
//! Either:
|
|
//! - pcscd re-powers the card on the next `SCardConnect`, so wallet commands will succeed without
|
|
//! triggering the retry path.
|
|
//! - the card stays unpowered, triggering a PC/SC transport error (`keycard_rs::Error::Io`) and
|
|
//! exercising the reconnect-and-retry wrapper in `KeycardWallet::connect()`.
|
|
|
|
fn main() {
|
|
let context = match pcsc::Context::establish(pcsc::Scope::User) {
|
|
Ok(context) => context,
|
|
Err(e) => {
|
|
println!("force_unpower: failed to establish PC/SC context ({e}), skipping.");
|
|
return;
|
|
}
|
|
};
|
|
|
|
let readers = match context.list_readers_owned() {
|
|
Ok(readers) => readers,
|
|
Err(e) => {
|
|
println!("force_unpower: failed to list readers ({e}), skipping.");
|
|
return;
|
|
}
|
|
};
|
|
|
|
let Some(reader) = readers.first() else {
|
|
println!("force_unpower: no readers found, skipping.");
|
|
return;
|
|
};
|
|
|
|
let card = match context.connect(reader, pcsc::ShareMode::Shared, pcsc::Protocols::ANY) {
|
|
Ok(card) => card,
|
|
Err(e) => {
|
|
println!("force_unpower: connect failed ({e}), skipping.");
|
|
return;
|
|
}
|
|
};
|
|
|
|
if let Err((_card, e)) = card.disconnect(pcsc::Disposition::UnpowerCard) {
|
|
println!("force_unpower: disconnect failed ({e}), skipping.");
|
|
return;
|
|
}
|
|
|
|
println!("force_unpower: card powered down.");
|
|
}
|