soroban_cli/config/
address.rs1use std::{
2 fmt::{self, Display, Formatter},
3 str::FromStr,
4};
5
6use crate::{
7 signer::{self, ledger},
8 xdr,
9};
10
11use super::{key, locator, secret};
12
13#[derive(Clone, Debug)]
15pub enum UnresolvedMuxedAccount {
16 Resolved(xdr::MuxedAccount),
17 AliasOrSecret(String),
18 Ledger(u32),
19}
20
21impl Default for UnresolvedMuxedAccount {
22 fn default() -> Self {
23 UnresolvedMuxedAccount::AliasOrSecret(String::default())
24 }
25}
26
27#[derive(thiserror::Error, Debug)]
28pub enum Error {
29 #[error(transparent)]
30 Locator(#[from] locator::Error),
31 #[error(transparent)]
32 Secret(#[from] secret::Error),
33 #[error(transparent)]
34 Signer(#[from] signer::Error),
35 #[error(transparent)]
36 Key(#[from] key::Error),
37 #[error("Address cannot be used to sign {0}")]
38 CannotSign(xdr::MuxedAccount),
39 #[error("Ledger cannot reveal private keys")]
40 LedgerPrivateKeyRevealNotSupported,
41 #[error("Invalid key name: {0}\n `ledger` is not allowed")]
42 LedgerIsInvalidKeyName(String),
43 #[error("Invalid key name: {0}\n only alphanumeric characters, underscores (_), and hyphens (-) are allowed.")]
44 InvalidKeyNameCharacters(String),
45 #[error("Invalid key name: {0}\n keys cannot exceed 250 characters")]
46 InvalidKeyNameLength(String),
47 #[error("Invalid key name: {0}\n keys cannot be the word \"ledger\"")]
48 InvalidKeyName(String),
49 #[error("Ledger not supported in this context")]
50 LedgerNotSupported,
51 #[error(transparent)]
52 Ledger(#[from] signer::ledger::Error),
53}
54
55impl FromStr for UnresolvedMuxedAccount {
56 type Err = Error;
57
58 fn from_str(value: &str) -> Result<Self, Self::Err> {
59 if value.starts_with("ledger") {
60 if let Some(ledger) = parse_ledger(value) {
61 return Ok(UnresolvedMuxedAccount::Ledger(ledger));
62 }
63 }
64 Ok(xdr::MuxedAccount::from_str(value).map_or_else(
65 |_| UnresolvedMuxedAccount::AliasOrSecret(value.to_string()),
66 UnresolvedMuxedAccount::Resolved,
67 ))
68 }
69}
70
71fn parse_ledger(value: &str) -> Option<u32> {
72 let vals: Vec<_> = value.split(':').collect();
73 if vals.len() > 2 {
74 return None;
75 }
76 if vals.len() == 1 {
77 return Some(0);
78 }
79 vals[1].parse().ok()
80}
81
82impl UnresolvedMuxedAccount {
83 pub async fn resolve_muxed_account(
84 &self,
85 locator: &locator::Args,
86 hd_path: Option<usize>,
87 ) -> Result<xdr::MuxedAccount, Error> {
88 match self {
89 UnresolvedMuxedAccount::Ledger(hd_path) => Ok(xdr::MuxedAccount::Ed25519(
90 ledger::new(*hd_path).await?.public_key().await?.0.into(),
91 )),
92 UnresolvedMuxedAccount::Resolved(_) | UnresolvedMuxedAccount::AliasOrSecret(_) => {
93 self.resolve_muxed_account_sync(locator, hd_path)
94 }
95 }
96 }
97
98 pub fn resolve_muxed_account_sync(
99 &self,
100 locator: &locator::Args,
101 hd_path: Option<usize>,
102 ) -> Result<xdr::MuxedAccount, Error> {
103 match self {
104 UnresolvedMuxedAccount::Resolved(muxed_account) => Ok(muxed_account.clone()),
105 UnresolvedMuxedAccount::AliasOrSecret(alias_or_secret) => {
106 Ok(locator.read_key(alias_or_secret)?.muxed_account(hd_path)?)
107 }
108 UnresolvedMuxedAccount::Ledger(_) => Err(Error::LedgerNotSupported),
109 }
110 }
111
112 pub fn resolve_secret(&self, locator: &locator::Args) -> Result<secret::Secret, Error> {
113 match &self {
114 UnresolvedMuxedAccount::Resolved(muxed_account) => {
115 Err(Error::CannotSign(muxed_account.clone()))
116 }
117 UnresolvedMuxedAccount::AliasOrSecret(alias_or_secret) => {
118 Ok(locator.read_key(alias_or_secret)?.try_into()?)
119 }
120 UnresolvedMuxedAccount::Ledger(_) => Err(Error::LedgerPrivateKeyRevealNotSupported),
121 }
122 }
123}
124
125#[derive(Clone, Debug)]
126pub struct KeyName(pub String);
127
128impl std::ops::Deref for KeyName {
129 type Target = str;
130 fn deref(&self) -> &Self::Target {
131 &self.0
132 }
133}
134
135impl std::str::FromStr for KeyName {
136 type Err = Error;
137 fn from_str(s: &str) -> Result<Self, Self::Err> {
138 if !s.chars().all(allowed_char) {
139 return Err(Error::InvalidKeyNameCharacters(s.to_string()));
140 }
141 if s == "ledger" {
142 return Err(Error::InvalidKeyName(s.to_string()));
143 }
144 if s.len() > 250 {
145 return Err(Error::InvalidKeyNameLength(s.to_string()));
146 }
147 Ok(KeyName(s.to_string()))
148 }
149}
150
151impl Display for KeyName {
152 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
153 write!(f, "{}", self.0)
154 }
155}
156
157fn allowed_char(c: char) -> bool {
158 c.is_ascii_alphanumeric() || c == '_' || c == '-'
159}