Skip to content

Commit a50e999

Browse files
Introduce Cip0134Uri type
1 parent d911863 commit a50e999

File tree

4 files changed

+105
-35
lines changed

4 files changed

+105
-35
lines changed

rust/rbac-registration/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@ workspace = true
2121
hex = "0.4.3"
2222
anyhow = "1.0.89"
2323
strum_macros = "0.26.4"
24-
regex = "1.11.0"
2524
minicbor = { version = "0.25.1", features = ["alloc", "derive", "half"] }
2625
brotli = "7.0.0"
2726
zstd = "0.13.2"
2827
x509-cert = "0.2.5"
2928
der-parser = "9.0.0"
30-
bech32 = "0.11.0"
3129
dashmap = "6.1.0"
3230
blake2b_simd = "1.0.2"
3331
tracing = "0.1.40"

rust/rbac-registration/src/cardano/cip509/utils/cip134.rs

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,87 @@
11
//! Utility functions for CIP-0134 address.
22
3+
// Ignore URIs that are used in tests and doc-examples.
4+
// cSpell:ignoreRegExp web\+cardano:.+
5+
6+
use std::fmt::{Display, Formatter};
7+
38
use anyhow::{anyhow, Context, Result};
49
use pallas::ledger::addresses::Address;
510

6-
/// Parses CIP-0134 URI and returns an address.
7-
///
8-
/// # Errors
9-
/// - Invalid URI.
11+
/// An URI in the CIP-0134 format.
1012
///
11-
/// # Examples
13+
/// See the [proposal] for more details.
1214
///
13-
/// ```
14-
/// use pallas::ledger::addresses::{Address, Network};
15-
/// use rbac_registration::cardano::cip509::utils::parse_cip0134_uri;
16-
///
17-
/// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
18-
/// let Address::Stake(address) = parse_cip0134_uri(uri).unwrap() else {
19-
/// panic!("Unexpected address type");
20-
/// };
21-
/// assert_eq!(address.network(), Network::Mainnet);
22-
/// ```
23-
pub fn parse_cip0134_uri(uri: &str) -> Result<Address> {
24-
let bech32 = uri
25-
.strip_prefix("web+cardano://addr/")
26-
.ok_or_else(|| anyhow!("Missing schema part of URI"))?;
27-
Address::from_bech32(bech32).context("Unable to parse bech32 part of URI")
15+
/// [proposal]: https://github.com/cardano-foundation/CIPs/pull/888
16+
#[derive(Debug)]
17+
pub struct Cip0134Uri {
18+
uri: String,
19+
address: Address,
20+
}
21+
22+
impl Cip0134Uri {
23+
/// Creates a new `Cip0134Uri` instance by parsing the given URI.
24+
///
25+
/// # Errors
26+
/// - Invalid URI.
27+
///
28+
/// # Examples
29+
///
30+
/// ```
31+
/// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
32+
///
33+
/// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
34+
/// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
35+
/// ```
36+
pub fn parse(uri: &str) -> Result<Self> {
37+
let bech32 = uri
38+
.strip_prefix("web+cardano://addr/")
39+
.ok_or_else(|| anyhow!("Missing schema part of URI"))?;
40+
let address = Address::from_bech32(bech32).context("Unable to parse bech32 part of URI")?;
41+
42+
Ok(Self {
43+
uri: uri.to_owned(),
44+
address,
45+
})
46+
}
47+
48+
/// Returns a URI string.
49+
///
50+
/// # Examples
51+
///
52+
/// ```
53+
/// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
54+
///
55+
/// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
56+
/// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
57+
/// assert_eq!(cip0134_uri.uri(), uri);
58+
pub fn uri(&self) -> &str {
59+
&self.uri
60+
}
61+
62+
/// Returns a URI string.
63+
///
64+
/// # Examples
65+
///
66+
/// ```
67+
/// use pallas::ledger::addresses::{Address, Network};
68+
/// use rbac_registration::cardano::cip509::utils::Cip0134Uri;
69+
///
70+
/// let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
71+
/// let cip0134_uri = Cip0134Uri::parse(uri).unwrap();
72+
/// let Address::Stake(address) = cip0134_uri.address() else {
73+
/// panic!("Unexpected address type");
74+
/// };
75+
/// assert_eq!(address.network(), Network::Mainnet);
76+
pub fn address(&self) -> &Address {
77+
&self.address
78+
}
79+
}
80+
81+
impl Display for Cip0134Uri {
82+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83+
write!(f, "{}", self.uri())
84+
}
2885
}
2986

3087
#[cfg(test)]
@@ -35,23 +92,25 @@ mod tests {
3592

3693
#[test]
3794
fn invalid_prefix() {
95+
// cSpell:disable
3896
let test_uris = [
3997
"addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x",
4098
"//addr/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x",
4199
"web+cardano:/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x",
42100
"somthing+unexpected://addr/addr1qx2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgse35a3x",
43101
];
102+
// cSpell:enable
44103

45104
for uri in test_uris {
46-
let err = format!("{:?}", parse_cip0134_uri(uri).expect_err(&format!("{uri}")));
105+
let err = format!("{:?}", Cip0134Uri::parse(uri).expect_err(&format!("{uri}")));
47106
assert_eq!("Missing schema part of URI", err);
48107
}
49108
}
50109

51110
#[test]
52111
fn invalid_bech32() {
53112
let uri = "web+cardano://addr/adr1qx2fxv2umyh";
54-
let err = format!("{:?}", parse_cip0134_uri(uri).unwrap_err());
113+
let err = format!("{:?}", Cip0134Uri::parse(uri).unwrap_err());
55114
assert!(err.starts_with("Unable to parse bech32 part of URI"));
56115
}
57116

@@ -76,7 +135,8 @@ mod tests {
76135
];
77136

78137
for (uri, network, payload) in test_data {
79-
let Address::Stake(address) = parse_cip0134_uri(uri).unwrap() else {
138+
let cip0134_uri = Cip0134Uri::parse(uri).expect(&format!("{uri}"));
139+
let Address::Stake(address) = cip0134_uri.address else {
80140
panic!("Unexpected address type ({uri})");
81141
};
82142
assert_eq!(network, address.network());
@@ -102,10 +162,19 @@ mod tests {
102162
];
103163

104164
for (uri, network) in test_data {
105-
let Address::Shelley(address) = parse_cip0134_uri(uri).unwrap() else {
165+
let cip0134_uri = Cip0134Uri::parse(uri).expect(&format!("{uri}"));
166+
let Address::Shelley(address) = cip0134_uri.address else {
106167
panic!("Unexpected address type ({uri})");
107168
};
108169
assert_eq!(network, address.network());
109170
}
110171
}
172+
173+
// The Display should return the original URI.
174+
#[test]
175+
fn display() {
176+
let uri = "web+cardano://addr/stake1uyehkck0lajq8gr28t9uxnuvgcqrc6070x3k9r8048z8y5gh6ffgw";
177+
let cip0134_uri = Cip0134Uri::parse(uri).expect(&format!("{uri}"));
178+
assert_eq!(uri, cip0134_uri.to_string());
179+
}
111180
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Utility functions for CIP-509
22
33
pub mod cip19;
4-
pub use cip134::parse_cip0134_uri;
4+
pub use cip134::Cip0134Uri;
55

66
mod cip134;

rust/rbac-registration/src/cardano/cip509/validation.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ use super::{
4040
},
4141
utils::{
4242
cip19::{compare_key_hash, extract_key_hash},
43-
parse_cip0134_uri,
43+
Cip0134Uri,
4444
},
4545
Cip509, TxInputHash, TxWitness,
4646
};
@@ -169,11 +169,12 @@ pub(crate) fn validate_stake_public_key(
169169

170170
// Extract the CIP19 hash and push into
171171
// array
172-
if let Ok(Address::Stake(a)) =
173-
parse_cip0134_uri(&addr)
174-
{
175-
pk_addrs
176-
.push(a.payload().as_hash().to_vec());
172+
if let Ok(uri) = Cip0134Uri::parse(&addr) {
173+
if let Address::Stake(a) = uri.address() {
174+
pk_addrs.push(
175+
a.payload().as_hash().to_vec(),
176+
);
177+
}
177178
}
178179
},
179180
Err(e) => {
@@ -222,8 +223,10 @@ pub(crate) fn validate_stake_public_key(
222223
if name.gn_type() == &c509_certificate::general_names::general_name::GeneralNameTypeRegistry::UniformResourceIdentifier {
223224
match name.gn_value() {
224225
GeneralNameValue::Text(s) => {
225-
if let Ok(Address::Stake(a)) = parse_cip0134_uri(s) {
226-
pk_addrs.push(a.payload().as_hash().to_vec());
226+
if let Ok(uri) = Cip0134Uri::parse(s) {
227+
if let Address::Stake(a) = uri.address() {
228+
pk_addrs.push(a.payload().as_hash().to_vec());
229+
}
227230
}
228231
},
229232
_ => {

0 commit comments

Comments
 (0)