Skip to content

Commit

Permalink
remote-wallet: Plumb Locator into RemoteWalletInfo
Browse files Browse the repository at this point in the history
  • Loading branch information
t-nelson committed Apr 27, 2021
1 parent 64fcb79 commit 3d12be2
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 76 deletions.
11 changes: 6 additions & 5 deletions remote-wallet/src/ledger.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use {
crate::{
ledger_error::LedgerError,
remote_wallet::{RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager},
remote_wallet::{
Manufacturer, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
},
},
console::Emoji,
dialoguer::{theme::ColorfulTheme, Select},
log::*,
num_traits::FromPrimitive,
semver::Version as FirmwareVersion,
solana_sdk::{derivation_path::DerivationPath, pubkey::Pubkey, signature::Signature},
std::{cmp::min, fmt, sync::Arc},
std::{cmp::min, convert::TryFrom, fmt, sync::Arc},
};

static CHECK_MARK: Emoji = Emoji("✅ ", "");
Expand Down Expand Up @@ -363,9 +365,8 @@ impl RemoteWallet for LedgerWallet {
) -> Result<RemoteWalletInfo, RemoteWalletError> {
let manufacturer = dev_info
.manufacturer_string()
.unwrap_or("Unknown")
.to_lowercase()
.replace(" ", "-");
.and_then(|s| Manufacturer::try_from(s).ok())
.unwrap_or_default();
let model = dev_info
.product_string()
.unwrap_or("Unknown")
Expand Down
4 changes: 2 additions & 2 deletions remote-wallet/src/remote_keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
ledger::get_ledger_from_info,
remote_wallet::{
RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
Manufacturer, RemoteWallet, RemoteWalletError, RemoteWalletInfo, RemoteWalletManager,
RemoteWalletType,
},
},
Expand Down Expand Up @@ -61,7 +61,7 @@ pub fn generate_remote_keypair(
keypair_name: &str,
) -> Result<RemoteKeypair, RemoteWalletError> {
let (remote_wallet_info, derivation_path) = RemoteWalletInfo::parse_path(path)?;
if remote_wallet_info.manufacturer == "ledger" {
if remote_wallet_info.manufacturer == Manufacturer::Ledger {
let ledger = get_ledger_from_info(remote_wallet_info, keypair_name, wallet_manager)?;
let path = format!("{}{}", ledger.pretty_path, derivation_path.get_query());
Ok(RemoteKeypair::new(
Expand Down
97 changes: 28 additions & 69 deletions remote-wallet/src/remote_wallet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ pub enum RemoteWalletError {

#[error("remote wallet operation rejected by the user")]
UserCancel,

#[error(transparent)]
LocatorError(#[from] LocatorError),
}

impl From<hidapi::HidError> for RemoteWalletError {
Expand Down Expand Up @@ -240,7 +243,7 @@ pub struct RemoteWalletInfo {
/// RemoteWallet device model
pub model: String,
/// RemoteWallet device manufacturer
pub manufacturer: String,
pub manufacturer: Manufacturer,
/// RemoteWallet device serial number
pub serial: String,
/// RemoteWallet host device path
Expand Down Expand Up @@ -444,63 +447,19 @@ impl Locator {

impl RemoteWalletInfo {
pub fn parse_path(path: String) -> Result<(Self, DerivationPath), RemoteWalletError> {
let wallet_path = Url::parse(&path).map_err(|e| {
Into::<RemoteWalletError>::into(DerivationPathError::InvalidDerivationPath(format!(
"parse error: {:?}",
e
)))
})?;

if wallet_path.host_str().is_none() {
return Err(DerivationPathError::InvalidDerivationPath(
"missing remote wallet type".to_string(),
)
.into());
}

let mut wallet_info = RemoteWalletInfo {
manufacturer: wallet_path.host_str().unwrap().to_string(),
..RemoteWalletInfo::default()
};

if let Some(wallet_id) = wallet_path.path_segments().map(|c| c.collect::<Vec<_>>()) {
if !wallet_id[0].is_empty() {
wallet_info.pubkey = Pubkey::from_str(wallet_id[0]).map_err(|e| {
Into::<RemoteWalletError>::into(DerivationPathError::InvalidDerivationPath(
format!("pubkey from_str error: {:?}", e),
))
})?;
}
}

let mut derivation_path = DerivationPath::default();
let mut query_pairs = wallet_path.query_pairs();
if query_pairs.count() > 0 {
for _ in 0..query_pairs.count() {
if let Some(mut pair) = query_pairs.next() {
if pair.0 == "key" {
let key_path = pair.1.to_mut();
if key_path.ends_with('/') {
key_path.pop();
}
derivation_path = DerivationPath::from_key_str(key_path)?;
} else {
return Err(DerivationPathError::InvalidDerivationPath(format!(
"invalid query string `{}={}`, only `key` supported",
pair.0, pair.1
))
.into());
}
}
if query_pairs.next().is_some() {
return Err(DerivationPathError::InvalidDerivationPath(
"invalid query string, extra fields not supported".to_string(),
)
.into());
}
}
}
Ok((wallet_info, derivation_path))
let Locator {
manufacturer,
pubkey,
derivation_path,
} = Locator::new_from_path(path)?;
Ok((
RemoteWalletInfo {
manufacturer,
pubkey: pubkey.unwrap_or_default(),
..RemoteWalletInfo::default()
},
derivation_path.unwrap_or_default(),
))
}

pub fn get_pretty_path(&self) -> String {
Expand Down Expand Up @@ -548,7 +507,7 @@ mod tests {
RemoteWalletInfo::parse_path(format!("usb://ledger/{:?}?key=1/2", pubkey)).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand All @@ -559,7 +518,7 @@ mod tests {
RemoteWalletInfo::parse_path(format!("usb://ledger/{:?}?key=1'/2'", pubkey)).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand All @@ -570,7 +529,7 @@ mod tests {
RemoteWalletInfo::parse_path(format!("usb://ledger/{:?}?key=1\'/2\'", pubkey)).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand All @@ -581,7 +540,7 @@ mod tests {
RemoteWalletInfo::parse_path(format!("usb://ledger/{:?}?key=1/2/", pubkey)).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Vendor::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand All @@ -592,7 +551,7 @@ mod tests {
RemoteWalletInfo::parse_path(format!("usb://ledger/{:?}?key=1/", pubkey)).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Vendor::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand All @@ -605,7 +564,7 @@ mod tests {
RemoteWalletInfo::parse_path("usb://ledger?key=1".to_string()).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey: Pubkey::default(),
Expand All @@ -616,7 +575,7 @@ mod tests {
RemoteWalletInfo::parse_path("usb://ledger/?key=1/2".to_string()).unwrap();
assert!(wallet_info.matches(&RemoteWalletInfo {
model: "".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey: Pubkey::default(),
Expand Down Expand Up @@ -644,19 +603,19 @@ mod tests {
fn test_remote_wallet_info_matches() {
let pubkey = solana_sdk::pubkey::new_rand();
let info = RemoteWalletInfo {
manufacturer: "Ledger".to_string(),
manufacturer: Manufacturer::Ledger,
model: "Nano S".to_string(),
serial: "0001".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
error: None,
};
let mut test_info = RemoteWalletInfo {
manufacturer: "Not Ledger".to_string(),
manufacturer: Manufacturer::Unknown,
..RemoteWalletInfo::default()
};
assert!(!info.matches(&test_info));
test_info.manufacturer = "Ledger".to_string();
test_info.manufacturer = Manufacturer::Ledger;
assert!(info.matches(&test_info));
test_info.model = "Other".to_string();
assert!(info.matches(&test_info));
Expand All @@ -677,7 +636,7 @@ mod tests {
let pubkey_str = pubkey.to_string();
let remote_wallet_info = RemoteWalletInfo {
model: "nano-s".to_string(),
manufacturer: "ledger".to_string(),
manufacturer: Manufacturer::Ledger,
serial: "".to_string(),
host_device_path: "/host/device/path".to_string(),
pubkey,
Expand Down

0 comments on commit 3d12be2

Please sign in to comment.