diff --git a/src/lib.rs b/src/lib.rs index 8ab414a50d..c41a2c231e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,6 +114,7 @@ mod inscriptions; mod object; pub mod options; pub mod outgoing; +mod re; mod representation; pub mod runes; mod server_config; diff --git a/src/outgoing.rs b/src/outgoing.rs index 72d00a1064..fef42322b8 100644 --- a/src/outgoing.rs +++ b/src/outgoing.rs @@ -24,8 +24,6 @@ impl FromStr for Outgoing { fn from_str(s: &str) -> Result { lazy_static! { - static ref SATPOINT: Regex = Regex::new(r"^[[:xdigit:]]{64}:\d+:\d+$").unwrap(); - static ref INSCRIPTION_ID: Regex = Regex::new(r"^[[:xdigit:]]{64}i\d+$").unwrap(); static ref AMOUNT: Regex = Regex::new( r"(?x) ^ @@ -63,9 +61,9 @@ impl FromStr for Outgoing { .unwrap(); } - Ok(if SATPOINT.is_match(s) { + Ok(if re::SATPOINT.is_match(s) { Self::SatPoint(s.parse()?) - } else if INSCRIPTION_ID.is_match(s) { + } else if re::INSCRIPTION_ID.is_match(s) { Self::InscriptionId(s.parse()?) } else if AMOUNT.is_match(s) { Self::Amount(s.parse()?) diff --git a/src/re.rs b/src/re.rs new file mode 100644 index 0000000000..f1cdba04a5 --- /dev/null +++ b/src/re.rs @@ -0,0 +1,16 @@ +use super::*; + +fn re(s: &'static str) -> Regex { + Regex::new(&format!("^{s}$")).unwrap() +} + +lazy_static! { + pub(crate) static ref HASH: Regex = re(r"[[:xdigit:]]{64}"); + pub(crate) static ref INSCRIPTION_ID: Regex = re(r"[[:xdigit:]]{64}i\d+"); + pub(crate) static ref INSCRIPTION_NUMBER: Regex = re(r"-?[0-9]+"); + pub(crate) static ref OUTPOINT: Regex = re(r"[[:xdigit:]]{64}:\d+"); + pub(crate) static ref RUNE_ID: Regex = re(r"[0-9]+:[0-9]+"); + pub(crate) static ref SATPOINT: Regex = re(r"[[:xdigit:]]{64}:\d+:\d+"); + pub(crate) static ref SAT_NAME: Regex = re(r"[a-z]+"); + pub(crate) static ref SPACED_RUNE: Regex = re(r"[A-Z•.]+"); +} diff --git a/src/subcommand/server.rs b/src/subcommand/server.rs index 5d467bff2a..3b4155ec7e 100644 --- a/src/subcommand/server.rs +++ b/src/subcommand/server.rs @@ -940,29 +940,21 @@ impl Server { async fn search_inner(index: Arc, query: String) -> ServerResult { task::block_in_place(|| { - lazy_static! { - static ref HASH: Regex = Regex::new(r"^[[:xdigit:]]{64}$").unwrap(); - static ref INSCRIPTION_ID: Regex = Regex::new(r"^[[:xdigit:]]{64}i\d+$").unwrap(); - static ref OUTPOINT: Regex = Regex::new(r"^[[:xdigit:]]{64}:\d+$").unwrap(); - static ref RUNE: Regex = Regex::new(r"^[A-Z•.]+$").unwrap(); - static ref RUNE_ID: Regex = Regex::new(r"^[0-9]+:[0-9]+$").unwrap(); - } - let query = query.trim(); - if HASH.is_match(query) { + if re::HASH.is_match(query) { if index.block_header(query.parse().unwrap())?.is_some() { Ok(Redirect::to(&format!("/block/{query}"))) } else { Ok(Redirect::to(&format!("/tx/{query}"))) } - } else if OUTPOINT.is_match(query) { + } else if re::OUTPOINT.is_match(query) { Ok(Redirect::to(&format!("/output/{query}"))) - } else if INSCRIPTION_ID.is_match(query) { + } else if re::INSCRIPTION_ID.is_match(query) { Ok(Redirect::to(&format!("/inscription/{query}"))) - } else if RUNE.is_match(query) { + } else if re::SPACED_RUNE.is_match(query) { Ok(Redirect::to(&format!("/rune/{query}"))) - } else if RUNE_ID.is_match(query) { + } else if re::RUNE_ID.is_match(query) { let id = query .parse::() .map_err(|err| ServerError::BadRequest(err.to_string()))?; @@ -4206,10 +4198,19 @@ mod tests { server.assert_response_regex( format!("/inscription/{}", Sat(5000000000).name()), StatusCode::OK, - r".*Inscription 0</title.*", + ".*<title>Inscription 0</title.*", ); } + #[test] + fn inscriptions_can_be_looked_up_by_sat_name_with_letter_i() { + let server = TestServer::builder() + .chain(Chain::Regtest) + .index_sats() + .build(); + server.assert_response_regex("/inscription/i", StatusCode::NOT_FOUND, ".*"); + } + #[test] fn inscription_page_does_not_have_sat_when_sats_are_not_tracked() { let server = TestServer::builder().chain(Chain::Regtest).build(); diff --git a/src/subcommand/server/query.rs b/src/subcommand/server/query.rs index 52286756ff..3acdc5e940 100644 --- a/src/subcommand/server/query.rs +++ b/src/subcommand/server/query.rs @@ -28,13 +28,15 @@ impl FromStr for Inscription { type Err = Error; fn from_str(s: &str) -> Result<Self, Self::Err> { - Ok(if s.contains('i') { - Self::Id(s.parse()?) - } else if s.chars().all(|c| c.is_ascii_lowercase()) { - Self::Sat(s.parse()?) + if re::INSCRIPTION_ID.is_match(s) { + Ok(Self::Id(s.parse()?)) + } else if re::INSCRIPTION_NUMBER.is_match(s) { + Ok(Self::Number(s.parse()?)) + } else if re::SAT_NAME.is_match(s) { + Ok(Self::Sat(s.parse()?)) } else { - Self::Number(s.parse()?) - }) + Err(anyhow!("bad inscription query {s}")) + } } }