Skip to content

Commit 6e743dc

Browse files
committed
update CatalystId type with admin functionality
1 parent c0d45dd commit 6e743dc

File tree

2 files changed

+82
-55
lines changed

2 files changed

+82
-55
lines changed

rust/catalyst-types/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ num-traits = "0.2.19"
2424
orx-concurrent-vec = { version = "3.6.0", features = ["serde"] }
2525
serde = { version = "1.0.217", features = ["derive", "rc"] }
2626
thiserror = "2.0.11"
27-
base64-url = "3.0.0"
27+
base64-url = "=3.0.0"
2828
uuid = { version = "1.12.0", features = ["v4", "v7", "serde"] }
2929
chrono = "0.4.39"
3030
tracing = "0.1.41"

rust/catalyst-types/src/catalyst_id/mod.rs

Lines changed: 81 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,27 @@ struct CatalystIdInner {
6363
/// - `true`: The key is used for encryption.
6464
/// - `false`: The key is used for signing (signature key).
6565
encryption: bool,
66-
/// Indicates if this is an `id` type, or a `uri` type.
66+
/// Indicates if this is an `id` type, or a `uri` type o.
6767
/// Used by the serialization functions.
6868
/// `true` = format as an `Id`
6969
/// `false` = format as a `Uri`
70-
id: bool,
70+
r#type: CatalysIdType,
71+
}
72+
73+
#[derive(Debug, Clone, Default)]
74+
enum CatalysIdType {
75+
/// format as an `Id`
76+
Id,
77+
/// format as a `Uri`
78+
#[default]
79+
Uri,
80+
/// format as a admin `Uri`
81+
AdminUri,
7182
}
7283

7384
impl CatalystId {
85+
/// Admin URI scheme for Catalyst
86+
pub const ADMIN_SCHEME: &Scheme = Scheme::new_or_panic("admin.catalyst");
7487
/// Encryption Key Identifier Fragment
7588
const ENCRYPTION_FRAGMENT: &EStr<Fragment> = EStr::new_or_panic("encrypt");
7689
/// Maximum allowable Nonce Value
@@ -140,7 +153,7 @@ impl CatalystId {
140153
role: RoleId::default(), // Defaulted, use `with_role()` to change it.
141154
rotation: KeyRotation::default(), // Defaulted, use `with_rotation()` to change it.
142155
encryption: false, // Defaulted, use `with_encryption()` to change it.
143-
id: false, // Default to `URI` formatted.
156+
r#type: CatalysIdType::default(), // Default to `URI` formatted.
144157
});
145158

146159
Self { inner }
@@ -150,28 +163,51 @@ impl CatalystId {
150163
#[must_use]
151164
pub fn as_uri(self) -> Self {
152165
let inner = Arc::try_unwrap(self.inner).unwrap_or_else(|v| (*v).clone());
153-
let inner = Arc::new(CatalystIdInner { id: false, ..inner });
166+
let inner = Arc::new(CatalystIdInner {
167+
r#type: CatalysIdType::Uri,
168+
..inner
169+
});
154170
Self { inner }
155171
}
156172

157173
/// The `CatalystId` is formatted as a id.
158174
#[must_use]
159175
pub fn as_id(self) -> Self {
160176
let inner = Arc::try_unwrap(self.inner).unwrap_or_else(|v| (*v).clone());
161-
let inner = Arc::new(CatalystIdInner { id: true, ..inner });
177+
let inner = Arc::new(CatalystIdInner {
178+
r#type: CatalysIdType::Id,
179+
..inner
180+
});
181+
Self { inner }
182+
}
183+
184+
/// The `CatalystId` is formatted as a admin URI.
185+
#[must_use]
186+
pub fn as_admin(self) -> Self {
187+
let inner = Arc::try_unwrap(self.inner).unwrap_or_else(|v| (*v).clone());
188+
let inner = Arc::new(CatalystIdInner {
189+
r#type: CatalysIdType::AdminUri,
190+
..inner
191+
});
162192
Self { inner }
163193
}
164194

165195
/// Was `CatalystId` formatted as an id when it was parsed.
166196
#[must_use]
167197
pub fn is_id(&self) -> bool {
168-
self.inner.id
198+
matches!(self.inner.r#type, CatalysIdType::Id)
199+
}
200+
201+
/// Is `CatalystId` formatted as an Admin.
202+
#[must_use]
203+
pub fn is_admin(&self) -> bool {
204+
matches!(self.inner.r#type, CatalysIdType::AdminUri)
169205
}
170206

171207
/// Was `CatalystId` formatted as an uri when it was parsed.
172208
#[must_use]
173209
pub fn is_uri(&self) -> bool {
174-
!self.inner.id
210+
matches!(self.inner.r#type, CatalysIdType::Uri)
175211
}
176212

177213
/// Add or change the username in a Catalyst ID URI.
@@ -588,27 +624,26 @@ impl FromStr for CatalystId {
588624
/// This will parse a URI or a RAW ID.\
589625
/// The only difference between them is a URI has the scheme, a raw ID does not.
590626
fn from_str(s: &str) -> Result<Self, Self::Err> {
591-
// Did we serialize an ID?
592-
let mut id = false;
593-
594-
// Check if we have a scheme, and if not default it to the catalyst ID scheme.
595-
let raw_uri = {
627+
let (uri, r#type) = {
596628
if s.contains("://") {
597-
s.to_owned()
629+
let uri = Uri::parse(s.to_owned())?;
630+
// Check if its the correct scheme.
631+
let r#type = if uri.scheme() == Self::SCHEME {
632+
CatalysIdType::Uri
633+
} else if uri.scheme() == Self::ADMIN_SCHEME {
634+
CatalysIdType::AdminUri
635+
} else {
636+
return Err(errors::CatalystIdError::InvalidScheme);
637+
};
638+
(uri, r#type)
598639
} else {
599-
id = true;
600640
// It might be a RAW ID, so try and parse with the correct scheme.
601-
format!("{}://{}", CatalystId::SCHEME, s)
641+
let uri = Uri::parse(format!("{}://{}", Self::SCHEME, s))?;
642+
let r#type = CatalysIdType::Id;
643+
(uri, r#type)
602644
}
603645
};
604646

605-
let uri = Uri::parse(raw_uri)?;
606-
607-
// Check if its the correct scheme.
608-
if uri.scheme() != CatalystId::SCHEME {
609-
return Err(errors::CatalystIdError::InvalidScheme);
610-
}
611-
612647
// Decode the network and subnet
613648
let auth = uri
614649
.authority()
@@ -684,36 +719,26 @@ impl FromStr for CatalystId {
684719
}
685720
};
686721

687-
let cat_id = {
688-
let mut cat_id = Self::new(network, subnet, role0_pk)
689-
.with_role(role_index)
690-
.with_rotation(rotation);
691-
692-
if uri.has_fragment() {
693-
if uri.fragment() == Some(Self::ENCRYPTION_FRAGMENT) {
694-
cat_id = cat_id.with_encryption();
695-
} else {
696-
return Err(errors::CatalystIdError::InvalidEncryptionKeyFragment);
697-
}
698-
}
699-
700-
if let Some(username) = username {
701-
cat_id = cat_id.with_username(&username);
702-
}
703-
704-
if let Some(nonce) = nonce {
705-
cat_id = cat_id.with_specific_nonce(nonce);
706-
}
707-
708-
// Default to URI, so only set it as an ID if its not a URI.
709-
if id {
710-
cat_id = cat_id.as_id();
711-
}
712-
713-
cat_id
722+
let encryption = match uri.fragment() {
723+
None => false,
724+
Some(f) if f == Self::ENCRYPTION_FRAGMENT => true,
725+
Some(_) => return Err(errors::CatalystIdError::InvalidEncryptionKeyFragment),
714726
};
715727

716-
Ok(cat_id)
728+
let inner = CatalystIdInner {
729+
network: network.to_string(),
730+
subnet: subnet.map(ToString::to_string),
731+
role0_pk,
732+
r#type,
733+
rotation,
734+
role: role_index,
735+
username,
736+
nonce,
737+
encryption,
738+
}
739+
.into();
740+
741+
Ok(Self { inner })
717742
}
718743
}
719744

@@ -722,8 +747,10 @@ impl Display for CatalystId {
722747
&self,
723748
f: &mut Formatter<'_>,
724749
) -> Result<(), std::fmt::Error> {
725-
if !self.inner.id {
726-
write!(f, "{}://", Self::SCHEME.as_str())?;
750+
match self.inner.r#type {
751+
CatalysIdType::Uri => write!(f, "{}://", Self::SCHEME.as_str())?,
752+
CatalysIdType::AdminUri => write!(f, "{}://", Self::ADMIN_SCHEME.as_str())?,
753+
CatalysIdType::Id => {},
727754
}
728755

729756
let mut needs_at = false;
@@ -754,9 +781,9 @@ impl Display for CatalystId {
754781
)?;
755782

756783
// Role and Rotation are only serialized if its NOT and ID or they are not the defaults.
757-
if !self.inner.role.is_default() || !self.inner.rotation.is_default() || !self.inner.id {
784+
if !self.inner.role.is_default() || !self.inner.rotation.is_default() || !self.is_id() {
758785
write!(f, "/{}", self.inner.role)?;
759-
if !self.inner.rotation.is_default() || !self.inner.id {
786+
if !self.inner.rotation.is_default() || !self.is_id() {
760787
write!(f, "/{}", self.inner.rotation)?;
761788
}
762789
}

0 commit comments

Comments
 (0)