emerald_hwkey/ledger/connect/
mod.rs1use std::sync::{Arc, Mutex};
2use crate::errors::HWKeyError;
3use crate::ledger::apdu::APDU;
4use crate::ledger::comm::{sendrecv_timeout, LedgerTransport};
5use direct::AppDetails;
6use crate::ledger::app::LedgerApp;
7
8pub mod direct;
9pub mod shared;
10#[cfg(feature = "speculos")]
11mod speculos;
12#[cfg(feature = "speculos")]
13pub mod speculos_api;
14#[cfg(test)]
15pub mod mock;
16
17pub use {
18 direct::LedgerHidKey,
19 shared::LedgerKeyShared,
20};
21
22#[cfg(feature = "speculos")]
23pub use {
24 speculos::LedgerSpeculosKey,
25};
26use crate::ledger::connect::direct::LedgerDetails;
27
28pub trait LedgerKey {
29
30 type Transport: LedgerTransport;
31
32 fn create() -> Result<Self, HWKeyError> where Self: Sized;
33
34 fn connect(&mut self) -> Result<(), HWKeyError>;
40
41 fn get_app_details(&self) -> Result<AppDetails, HWKeyError> {
45 let apdu = APDU {
46 cla: 0xb0,
47 ins: 0x01,
48 ..APDU::default()
49 };
50 let device = self.open_exclusive()?;
51 let conn = device.lock()
52 .map_err(|_| HWKeyError::Unavailable)?;
53 match sendrecv_timeout(&*conn, &apdu, 100) {
54 Err(e) => match e {
55 HWKeyError::EmptyResponse => Ok(AppDetails::default()),
56 _ => Err(e),
57 }
58 Ok(resp) => AppDetails::try_from(resp)
59 }
60 }
61
62 fn open_exclusive(&self) -> Result<Arc<Mutex<Self::Transport>>, HWKeyError>;
63
64 fn access<A>(&self) -> Result<A, HWKeyError> where A: LedgerApp, Self::Transport: 'static {
67 let conn = self.open_exclusive()?;
68 Ok(A::new(conn))
69 }
70
71 fn get_ledger_version(&self) -> Result<LedgerDetails, HWKeyError> {
75 let apdu = APDU {
76 cla: 0xe0,
77 ins: 0x01,
78 ..APDU::default()
79 };
80 let device = self.open_exclusive()?;
81 let conn = device.lock()
82 .map_err(|_| HWKeyError::Unavailable)?;
83 let resp = sendrecv_timeout(&*conn, &apdu, 100)?;
84 LedgerDetails::try_from(resp)
85 }
86}