mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 01:07:57 +00:00
crypto: lazy_static removed, light parser for address URI added (#2250)
The `lazy_static` package does not work well in `no-std`: it requires `spin_no_std` feature, which also will propagate into `std` if enabled. This is not what we want. This PR provides simple address uri parser which allows to get rid of _regex_ which was used to parse the address uri, what in turns allows to remove lazy_static. Three regular expressions (`SS58_REGEX`,`SECRET_PHRASE_REGEX`,`JUNCTION_REGEX`) were replaced with the parser which unifies all of them. The new parser does not support Unicode, it is ASCII only. Related to: #2044 --------- Co-authored-by: Bastian Köcher <git@kchr.de> Co-authored-by: Koute <koute@users.noreply.github.com> Co-authored-by: command-bot <>
This commit is contained in:
committed by
GitHub
parent
3ab2bc9ff3
commit
5007e2dd5c
@@ -25,8 +25,6 @@ use codec::{Decode, Encode, MaxEncodedLen};
|
||||
use itertools::Itertools;
|
||||
#[cfg(feature = "std")]
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
#[cfg(feature = "std")]
|
||||
use regex::Regex;
|
||||
use scale_info::TypeInfo;
|
||||
#[cfg(feature = "std")]
|
||||
pub use secrecy::{ExposeSecret, SecretString};
|
||||
@@ -43,6 +41,11 @@ pub use ss58_registry::{from_known_address_format, Ss58AddressFormat, Ss58Addres
|
||||
/// Trait to zeroize a memory buffer.
|
||||
pub use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
pub use crate::address_uri::AddressUri;
|
||||
#[cfg(any(feature = "std", feature = "full_crypto"))]
|
||||
pub use crate::address_uri::Error as AddressUriError;
|
||||
|
||||
/// The root phrase for our publicly known keys.
|
||||
pub const DEV_PHRASE: &str =
|
||||
"bottom drive obey lake curtain smoke basket hold race lonely fit walk";
|
||||
@@ -82,8 +85,8 @@ impl<S, T: UncheckedFrom<S>> UncheckedInto<T> for S {
|
||||
#[cfg(feature = "full_crypto")]
|
||||
pub enum SecretStringError {
|
||||
/// The overall format was invalid (e.g. the seed phrase contained symbols).
|
||||
#[cfg_attr(feature = "std", error("Invalid format"))]
|
||||
InvalidFormat,
|
||||
#[cfg_attr(feature = "std", error("Invalid format {0}"))]
|
||||
InvalidFormat(AddressUriError),
|
||||
/// The seed phrase provided is not a valid BIP39 phrase.
|
||||
#[cfg_attr(feature = "std", error("Invalid phrase"))]
|
||||
InvalidPhrase,
|
||||
@@ -101,6 +104,13 @@ pub enum SecretStringError {
|
||||
InvalidPath,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "std", feature = "full_crypto"))]
|
||||
impl From<AddressUriError> for SecretStringError {
|
||||
fn from(e: AddressUriError) -> Self {
|
||||
Self::InvalidFormat(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// An error when deriving a key.
|
||||
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
@@ -208,7 +218,7 @@ impl<T: AsRef<str>> From<T> for DeriveJunction {
|
||||
/// An error type for SS58 decoding.
|
||||
#[cfg_attr(feature = "std", derive(thiserror::Error))]
|
||||
#[cfg_attr(not(feature = "std"), derive(Debug))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
#[derive(Clone, Eq, PartialEq)]
|
||||
#[allow(missing_docs)]
|
||||
#[cfg(any(feature = "full_crypto", feature = "serde"))]
|
||||
pub enum PublicError {
|
||||
@@ -235,6 +245,11 @@ pub enum PublicError {
|
||||
InvalidPath,
|
||||
#[cfg_attr(feature = "std", error("Disallowed SS58 Address Format for this datatype."))]
|
||||
FormatNotAllowed,
|
||||
#[cfg_attr(feature = "std", error("Password not allowed."))]
|
||||
PasswordNotAllowed,
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg_attr(feature = "std", error("Incorrect URI syntax {0}."))]
|
||||
MalformedUri(#[from] AddressUriError),
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
@@ -414,47 +429,40 @@ pub fn set_default_ss58_version(new_default: Ss58AddressFormat) {
|
||||
DEFAULT_VERSION.store(new_default.into(), core::sync::atomic::Ordering::Relaxed);
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
lazy_static::lazy_static! {
|
||||
static ref SS58_REGEX: Regex = Regex::new(r"^(?P<ss58>[\w\d ]+)?(?P<path>(//?[^/]+)*)$")
|
||||
.expect("constructed from known-good static value; qed");
|
||||
static ref SECRET_PHRASE_REGEX: Regex = Regex::new(r"^(?P<phrase>[\d\w ]+)?(?P<path>(//?[^/]+)*)(///(?P<password>.*))?$")
|
||||
.expect("constructed from known-good static value; qed");
|
||||
static ref JUNCTION_REGEX: Regex = Regex::new(r"/(/?[^/]+)")
|
||||
.expect("constructed from known-good static value; qed");
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<T: Sized + AsMut<[u8]> + AsRef<[u8]> + Public + Derive> Ss58Codec for T {
|
||||
fn from_string(s: &str) -> Result<Self, PublicError> {
|
||||
let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?;
|
||||
let s = cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS);
|
||||
let cap = AddressUri::parse(s)?;
|
||||
if cap.pass.is_some() {
|
||||
return Err(PublicError::PasswordNotAllowed);
|
||||
}
|
||||
let s = cap.phrase.unwrap_or(DEV_ADDRESS);
|
||||
let addr = if let Some(stripped) = s.strip_prefix("0x") {
|
||||
let d = array_bytes::hex2bytes(stripped).map_err(|_| PublicError::InvalidFormat)?;
|
||||
Self::from_slice(&d).map_err(|()| PublicError::BadLength)?
|
||||
} else {
|
||||
Self::from_ss58check(s)?
|
||||
};
|
||||
if cap["path"].is_empty() {
|
||||
if cap.paths.is_empty() {
|
||||
Ok(addr)
|
||||
} else {
|
||||
let path =
|
||||
JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
|
||||
addr.derive(path).ok_or(PublicError::InvalidPath)
|
||||
addr.derive(cap.paths.iter().map(DeriveJunction::from))
|
||||
.ok_or(PublicError::InvalidPath)
|
||||
}
|
||||
}
|
||||
|
||||
fn from_string_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
|
||||
let cap = SS58_REGEX.captures(s).ok_or(PublicError::InvalidFormat)?;
|
||||
let (addr, v) = Self::from_ss58check_with_version(
|
||||
cap.name("ss58").map(|r| r.as_str()).unwrap_or(DEV_ADDRESS),
|
||||
)?;
|
||||
if cap["path"].is_empty() {
|
||||
let cap = AddressUri::parse(s)?;
|
||||
if cap.pass.is_some() {
|
||||
return Err(PublicError::PasswordNotAllowed);
|
||||
}
|
||||
let (addr, v) = Self::from_ss58check_with_version(cap.phrase.unwrap_or(DEV_ADDRESS))?;
|
||||
if cap.paths.is_empty() {
|
||||
Ok((addr, v))
|
||||
} else {
|
||||
let path =
|
||||
JUNCTION_REGEX.captures_iter(&cap["path"]).map(|f| DeriveJunction::from(&f[1]));
|
||||
addr.derive(path).ok_or(PublicError::InvalidPath).map(|a| (a, v))
|
||||
addr.derive(cap.paths.iter().map(DeriveJunction::from))
|
||||
.ok_or(PublicError::InvalidPath)
|
||||
.map(|a| (a, v))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -817,22 +825,15 @@ impl sp_std::str::FromStr for SecretUri {
|
||||
type Err = SecretStringError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let cap = SECRET_PHRASE_REGEX.captures(s).ok_or(SecretStringError::InvalidFormat)?;
|
||||
|
||||
let junctions = JUNCTION_REGEX
|
||||
.captures_iter(&cap["path"])
|
||||
.map(|f| DeriveJunction::from(&f[1]))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let phrase = cap.name("phrase").map(|r| r.as_str()).unwrap_or(DEV_PHRASE);
|
||||
let password = cap.name("password");
|
||||
let cap = AddressUri::parse(s)?;
|
||||
let phrase = cap.phrase.unwrap_or(DEV_PHRASE);
|
||||
|
||||
Ok(Self {
|
||||
phrase: SecretString::from_str(phrase).expect("Returns infallible error; qed"),
|
||||
password: password.map(|v| {
|
||||
SecretString::from_str(v.as_str()).expect("Returns infallible error; qed")
|
||||
}),
|
||||
junctions,
|
||||
password: cap
|
||||
.pass
|
||||
.map(|v| SecretString::from_str(v).expect("Returns infallible error; qed")),
|
||||
junctions: cap.paths.iter().map(DeriveJunction::from).collect::<Vec<_>>(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user