remote-wallet: Select hardware wallets based on host device path

This commit is contained in:
Trent Nelson
2020-10-07 20:02:02 -06:00
committed by Trent Nelson
parent 2c38865e70
commit 8e3353d9ef
2 changed files with 27 additions and 9 deletions

View File

@ -339,6 +339,7 @@ impl RemoteWallet for LedgerWallet {
.clone() .clone()
.unwrap_or("Unknown") .unwrap_or("Unknown")
.to_string(); .to_string();
let host_device_path = dev_info.path().to_string_lossy().to_string();
let version = self.get_firmware_version()?; let version = self.get_firmware_version()?;
self.version = version; self.version = version;
let pubkey_result = self.get_pubkey(&DerivationPath::default(), false); let pubkey_result = self.get_pubkey(&DerivationPath::default(), false);
@ -350,6 +351,7 @@ impl RemoteWallet for LedgerWallet {
model, model,
manufacturer, manufacturer,
serial, serial,
host_device_path,
pubkey, pubkey,
error, error,
}) })
@ -521,17 +523,17 @@ pub fn get_ledger_from_info(
return Err(device.error.clone().unwrap()); return Err(device.error.clone().unwrap());
} }
} }
let mut matches: Vec<(Pubkey, String)> = matches let mut matches: Vec<(String, String)> = matches
.filter(|&device_info| device_info.error.is_none()) .filter(|&device_info| device_info.error.is_none())
.map(|device_info| (device_info.pubkey, device_info.get_pretty_path())) .map(|device_info| (device_info.host_device_path.clone(), device_info.get_pretty_path()))
.collect(); .collect();
if matches.is_empty() { if matches.is_empty() {
return Err(RemoteWalletError::NoDeviceFound); return Err(RemoteWalletError::NoDeviceFound);
} }
matches.sort_by(|a, b| a.1.cmp(&b.1)); matches.sort_by(|a, b| a.1.cmp(&b.1));
let (pubkeys, device_paths): (Vec<Pubkey>, Vec<String>) = matches.into_iter().unzip(); let (host_device_paths, device_paths): (Vec<Pubkey>, Vec<String>) = matches.into_iter().unzip();
let wallet_base_pubkey = if pubkeys.len() > 1 { let wallet_host_device_path = if host_device_paths.len() > 1 {
let selection = Select::with_theme(&ColorfulTheme::default()) let selection = Select::with_theme(&ColorfulTheme::default())
.with_prompt(&format!( .with_prompt(&format!(
"Multiple hardware wallets found. Please select a device for {:?}", "Multiple hardware wallets found. Please select a device for {:?}",
@ -541,11 +543,11 @@ pub fn get_ledger_from_info(
.items(&device_paths[..]) .items(&device_paths[..])
.interact() .interact()
.unwrap(); .unwrap();
pubkeys[selection] &host_device_paths[selection]
} else { } else {
pubkeys[0] &host_device_paths[0]
}; };
wallet_manager.get_ledger(&wallet_base_pubkey) wallet_manager.get_ledger(wallet_host_device_path)
} }
// //

View File

@ -152,11 +152,14 @@ impl RemoteWalletManager {
/// Get a particular wallet /// Get a particular wallet
#[allow(unreachable_patterns)] #[allow(unreachable_patterns)]
pub fn get_ledger(&self, pubkey: &Pubkey) -> Result<Arc<LedgerWallet>, RemoteWalletError> { pub fn get_ledger(
&self,
host_device_path: &str,
) -> Result<Arc<LedgerWallet>, RemoteWalletError> {
self.devices self.devices
.read() .read()
.iter() .iter()
.find(|device| &device.info.pubkey == pubkey) .find(|device| device.info.host_device_path == host_device_path)
.ok_or(RemoteWalletError::PubkeyNotFound) .ok_or(RemoteWalletError::PubkeyNotFound)
.and_then(|device| match &device.wallet_type { .and_then(|device| match &device.wallet_type {
RemoteWalletType::Ledger(ledger) => Ok(ledger.clone()), RemoteWalletType::Ledger(ledger) => Ok(ledger.clone()),
@ -237,6 +240,8 @@ pub struct RemoteWalletInfo {
pub manufacturer: String, pub manufacturer: String,
/// RemoteWallet device serial number /// RemoteWallet device serial number
pub serial: String, pub serial: String,
/// RemoteWallet host device path
pub host_device_path: String,
/// Base pubkey of device at Solana derivation path /// Base pubkey of device at Solana derivation path
pub pubkey: Pubkey, pub pubkey: Pubkey,
/// Initial read error /// Initial read error
@ -449,6 +454,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
})); }));
@ -465,6 +471,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
})); }));
@ -481,6 +488,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
})); }));
@ -497,6 +505,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
})); }));
@ -513,6 +522,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
})); }));
@ -531,6 +541,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey: Pubkey::default(), pubkey: Pubkey::default(),
error: None, error: None,
})); }));
@ -547,6 +558,7 @@ mod tests {
model: "".to_string(), model: "".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey: Pubkey::default(), pubkey: Pubkey::default(),
error: None, error: None,
})); }));
@ -581,6 +593,7 @@ mod tests {
manufacturer: "Ledger".to_string(), manufacturer: "Ledger".to_string(),
model: "Nano S".to_string(), model: "Nano S".to_string(),
serial: "0001".to_string(), serial: "0001".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
}; };
@ -593,6 +606,8 @@ mod tests {
assert!(info.matches(&test_info)); assert!(info.matches(&test_info));
test_info.model = "Nano S".to_string(); test_info.model = "Nano S".to_string();
assert!(info.matches(&test_info)); assert!(info.matches(&test_info));
test_info.host_device_path = "/host/device/path".to_string();
assert!(info.matches(&test_info));
let another_pubkey = Pubkey::new_rand(); let another_pubkey = Pubkey::new_rand();
test_info.pubkey = another_pubkey; test_info.pubkey = another_pubkey;
assert!(!info.matches(&test_info)); assert!(!info.matches(&test_info));
@ -608,6 +623,7 @@ mod tests {
model: "nano-s".to_string(), model: "nano-s".to_string(),
manufacturer: "ledger".to_string(), manufacturer: "ledger".to_string(),
serial: "".to_string(), serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey, pubkey,
error: None, error: None,
}; };