2020-02-21 14:55:53 -07:00
|
|
|
use crate::keypair::{parse_keypair_path, KeypairUrl, ASK_KEYWORD};
|
2019-12-30 22:57:47 -07:00
|
|
|
use chrono::DateTime;
|
2020-02-07 11:26:56 -07:00
|
|
|
use solana_sdk::{
|
2020-03-02 11:47:58 -07:00
|
|
|
clock::Slot,
|
2020-02-07 11:26:56 -07:00
|
|
|
hash::Hash,
|
|
|
|
pubkey::Pubkey,
|
|
|
|
signature::{read_keypair_file, Signature},
|
|
|
|
};
|
2019-11-25 21:09:57 -08:00
|
|
|
use std::str::FromStr;
|
2019-09-03 10:38:12 -07:00
|
|
|
|
|
|
|
// Return an error if a pubkey cannot be parsed.
|
|
|
|
pub fn is_pubkey(string: String) -> Result<(), String> {
|
|
|
|
match string.parse::<Pubkey>() {
|
|
|
|
Ok(_) => Ok(()),
|
2020-03-13 00:20:49 -06:00
|
|
|
Err(err) => Err(format!("{}", err)),
|
2019-09-03 10:38:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 21:09:57 -08:00
|
|
|
// Return an error if a hash cannot be parsed.
|
|
|
|
pub fn is_hash(string: String) -> Result<(), String> {
|
|
|
|
match string.parse::<Hash>() {
|
|
|
|
Ok(_) => Ok(()),
|
2020-03-13 00:20:49 -06:00
|
|
|
Err(err) => Err(format!("{}", err)),
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 10:38:12 -07:00
|
|
|
// Return an error if a keypair file cannot be parsed.
|
|
|
|
pub fn is_keypair(string: String) -> Result<(), String> {
|
2019-10-10 17:01:03 -06:00
|
|
|
read_keypair_file(&string)
|
2019-09-03 10:38:12 -07:00
|
|
|
.map(|_| ())
|
2020-03-13 00:20:49 -06:00
|
|
|
.map_err(|err| format!("{}", err))
|
2019-09-03 10:38:12 -07:00
|
|
|
}
|
|
|
|
|
2019-11-23 11:55:43 -05:00
|
|
|
// Return an error if a keypair file cannot be parsed
|
|
|
|
pub fn is_keypair_or_ask_keyword(string: String) -> Result<(), String> {
|
|
|
|
if string.as_str() == ASK_KEYWORD {
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
read_keypair_file(&string)
|
|
|
|
.map(|_| ())
|
2020-03-13 00:20:49 -06:00
|
|
|
.map_err(|err| format!("{}", err))
|
2019-11-23 11:55:43 -05:00
|
|
|
}
|
|
|
|
|
2019-09-03 10:38:12 -07:00
|
|
|
// Return an error if string cannot be parsed as pubkey string or keypair file location
|
|
|
|
pub fn is_pubkey_or_keypair(string: String) -> Result<(), String> {
|
|
|
|
is_pubkey(string.clone()).or_else(|_| is_keypair(string))
|
|
|
|
}
|
|
|
|
|
2020-03-16 16:17:13 -06:00
|
|
|
// Return an error if string cannot be parsed as a pubkey string, or a valid Signer that can
|
|
|
|
// produce a pubkey()
|
|
|
|
pub fn is_valid_pubkey(string: String) -> Result<(), String> {
|
2020-02-21 14:55:53 -07:00
|
|
|
match parse_keypair_path(&string) {
|
|
|
|
KeypairUrl::Filepath(path) => is_keypair(path),
|
|
|
|
_ => Ok(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-16 16:17:13 -06:00
|
|
|
// Return an error if string cannot be parsed as a valid Signer. This is an alias of
|
|
|
|
// `is_valid_pubkey`, and does accept pubkey strings, even though a Pubkey is not by itself
|
|
|
|
// sufficient to sign a transaction.
|
|
|
|
//
|
|
|
|
// In the current offline-signing implementation, a pubkey is the valid input for a signer field
|
|
|
|
// when paired with an offline `--signer` argument to provide a Presigner (pubkey + signature).
|
|
|
|
// Clap validators can't check multiple fields at once, so the verification that a `--signer` is
|
|
|
|
// also provided and correct happens in parsing, not in validation.
|
|
|
|
pub fn is_valid_signer(string: String) -> Result<(), String> {
|
|
|
|
is_valid_pubkey(string)
|
|
|
|
}
|
|
|
|
|
2019-11-25 21:09:57 -08:00
|
|
|
// Return an error if string cannot be parsed as pubkey=signature string
|
|
|
|
pub fn is_pubkey_sig(string: String) -> Result<(), String> {
|
|
|
|
let mut signer = string.split('=');
|
|
|
|
match Pubkey::from_str(
|
|
|
|
signer
|
|
|
|
.next()
|
|
|
|
.ok_or_else(|| "Malformed signer string".to_string())?,
|
|
|
|
) {
|
|
|
|
Ok(_) => {
|
|
|
|
match Signature::from_str(
|
|
|
|
signer
|
|
|
|
.next()
|
|
|
|
.ok_or_else(|| "Malformed signer string".to_string())?,
|
|
|
|
) {
|
|
|
|
Ok(_) => Ok(()),
|
2020-03-13 00:20:49 -06:00
|
|
|
Err(err) => Err(format!("{}", err)),
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
}
|
2020-03-13 00:20:49 -06:00
|
|
|
Err(err) => Err(format!("{}", err)),
|
2019-11-25 21:09:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-03 10:38:12 -07:00
|
|
|
// Return an error if a url cannot be parsed.
|
|
|
|
pub fn is_url(string: String) -> Result<(), String> {
|
|
|
|
match url::Url::parse(&string) {
|
|
|
|
Ok(url) => {
|
|
|
|
if url.has_host() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err("no host provided".to_string())
|
|
|
|
}
|
|
|
|
}
|
2020-03-13 00:20:49 -06:00
|
|
|
Err(err) => Err(format!("{}", err)),
|
2019-09-03 10:38:12 -07:00
|
|
|
}
|
|
|
|
}
|
2019-11-12 09:42:08 +09:00
|
|
|
|
2020-03-02 11:47:58 -07:00
|
|
|
pub fn is_slot(slot: String) -> Result<(), String> {
|
|
|
|
slot.parse::<Slot>()
|
|
|
|
.map(|_| ())
|
2020-03-13 00:20:49 -06:00
|
|
|
.map_err(|e| format!("{}", e))
|
2020-03-02 11:47:58 -07:00
|
|
|
}
|
|
|
|
|
2019-11-20 15:21:34 -07:00
|
|
|
pub fn is_port(port: String) -> Result<(), String> {
|
|
|
|
port.parse::<u16>()
|
|
|
|
.map(|_| ())
|
2020-03-13 00:20:49 -06:00
|
|
|
.map_err(|e| format!("{}", e))
|
2019-11-20 15:21:34 -07:00
|
|
|
}
|
2019-12-04 00:54:01 +05:30
|
|
|
|
|
|
|
pub fn is_valid_percentage(percentage: String) -> Result<(), String> {
|
|
|
|
percentage
|
|
|
|
.parse::<u8>()
|
|
|
|
.map_err(|e| {
|
|
|
|
format!(
|
2020-03-13 00:20:49 -06:00
|
|
|
"Unable to parse input percentage, provided: {}, err: {}",
|
2019-12-04 00:54:01 +05:30
|
|
|
percentage, e
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.and_then(|v| {
|
|
|
|
if v > 100 {
|
|
|
|
Err(format!(
|
|
|
|
"Percentage must be in range of 0 to 100, provided: {}",
|
|
|
|
v
|
|
|
|
))
|
|
|
|
} else {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2019-12-10 00:24:44 -08:00
|
|
|
|
|
|
|
pub fn is_amount(amount: String) -> Result<(), String> {
|
2019-12-10 11:29:17 -07:00
|
|
|
if amount.parse::<u64>().is_ok() || amount.parse::<f64>().is_ok() {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
|
|
|
Err(format!(
|
|
|
|
"Unable to parse input amount as integer or float, provided: {}",
|
|
|
|
amount
|
|
|
|
))
|
|
|
|
}
|
2019-12-10 00:24:44 -08:00
|
|
|
}
|
2019-12-30 22:57:47 -07:00
|
|
|
|
|
|
|
pub fn is_rfc3339_datetime(value: String) -> Result<(), String> {
|
|
|
|
DateTime::parse_from_rfc3339(&value)
|
|
|
|
.map(|_| ())
|
2020-03-13 00:20:49 -06:00
|
|
|
.map_err(|e| format!("{}", e))
|
2019-12-30 22:57:47 -07:00
|
|
|
}
|
2020-02-07 11:26:56 -07:00
|
|
|
|
|
|
|
pub fn is_derivation(value: String) -> Result<(), String> {
|
|
|
|
let value = value.replace("'", "");
|
|
|
|
let mut parts = value.split('/');
|
|
|
|
let account = parts.next().unwrap();
|
|
|
|
account
|
2020-02-25 17:41:21 -07:00
|
|
|
.parse::<u32>()
|
2020-02-07 11:26:56 -07:00
|
|
|
.map_err(|e| {
|
|
|
|
format!(
|
2020-03-13 00:20:49 -06:00
|
|
|
"Unable to parse derivation, provided: {}, err: {}",
|
2020-02-07 11:26:56 -07:00
|
|
|
account, e
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.and_then(|_| {
|
|
|
|
if let Some(change) = parts.next() {
|
2020-02-25 17:41:21 -07:00
|
|
|
change.parse::<u32>().map_err(|e| {
|
2020-02-07 11:26:56 -07:00
|
|
|
format!(
|
2020-03-13 00:20:49 -06:00
|
|
|
"Unable to parse derivation, provided: {}, err: {}",
|
2020-02-07 11:26:56 -07:00
|
|
|
change, e
|
|
|
|
)
|
|
|
|
})
|
|
|
|
} else {
|
|
|
|
Ok(0)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.map(|_| ())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_is_derivation() {
|
|
|
|
assert_eq!(is_derivation("2".to_string()), Ok(()));
|
|
|
|
assert_eq!(is_derivation("0".to_string()), Ok(()));
|
2020-02-25 17:41:21 -07:00
|
|
|
assert_eq!(is_derivation("65537".to_string()), Ok(()));
|
2020-02-07 11:26:56 -07:00
|
|
|
assert_eq!(is_derivation("0/2".to_string()), Ok(()));
|
|
|
|
assert_eq!(is_derivation("0'/2'".to_string()), Ok(()));
|
|
|
|
assert!(is_derivation("a".to_string()).is_err());
|
2020-02-25 17:41:21 -07:00
|
|
|
assert!(is_derivation("4294967296".to_string()).is_err());
|
2020-02-07 11:26:56 -07:00
|
|
|
assert!(is_derivation("a/b".to_string()).is_err());
|
2020-02-25 17:41:21 -07:00
|
|
|
assert!(is_derivation("0/4294967296".to_string()).is_err());
|
2020-02-07 11:26:56 -07:00
|
|
|
}
|
|
|
|
}
|