identifiers: Make KeyId a DST

This commit is contained in:
Jonas Platte 2021-11-25 22:31:57 +01:00
parent 3ce578f384
commit 5852658da5
No known key found for this signature in database
GPG Key ID: 7D261D771D915378
14 changed files with 187 additions and 126 deletions

View File

@ -34,7 +34,7 @@ pub struct ThirdPartySigned<'a> {
pub token: &'a str, pub token: &'a str,
/// A signatures object containing a signature of the entire signed object. /// A signatures object containing a signature of the entire signed object.
pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
} }
impl<'a> ThirdPartySigned<'a> { impl<'a> ThirdPartySigned<'a> {
@ -44,7 +44,7 @@ impl<'a> ThirdPartySigned<'a> {
sender: &'a UserId, sender: &'a UserId,
mxid: &'a UserId, mxid: &'a UserId,
token: &'a str, token: &'a str,
signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
) -> Self { ) -> Self {
Self { sender, mxid, token, signatures } Self { sender, mxid, token, signatures }
} }

View File

@ -89,7 +89,7 @@ pub struct RoomV1Pdu {
pub hashes: EventHash, pub hashes: EventHash,
/// Signatures for the PDU. /// Signatures for the PDU.
pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
} }
/// A 'persistent data unit' (event) for room versions 3 and beyond. /// A 'persistent data unit' (event) for room versions 3 and beyond.
@ -146,7 +146,7 @@ pub struct RoomV3Pdu {
pub hashes: EventHash, pub hashes: EventHash,
/// Signatures for the PDU. /// Signatures for the PDU.
pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
} }
/// Content hashes of a PDU. /// Content hashes of a PDU.

View File

@ -178,7 +178,7 @@ pub struct SignedContent {
/// A single signature from the verifying server, in the format specified by the Signing Events /// A single signature from the verifying server, in the format specified by the Signing Events
/// section of the server-server API. /// section of the server-server API.
pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
/// The token property of the containing `third_party_invite` object. /// The token property of the containing `third_party_invite` object.
pub token: String, pub token: String,
@ -188,7 +188,7 @@ impl SignedContent {
/// Creates a new `SignedContent` with the given mxid, signature and token. /// Creates a new `SignedContent` with the given mxid, signature and token.
pub fn new( pub fn new(
mxid: Box<UserId>, mxid: Box<UserId>,
signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
token: String, token: String,
) -> Self { ) -> Self {
Self { mxid, signatures, token } Self { mxid, signatures, token }
@ -495,7 +495,7 @@ mod tests {
&& mxid == "@alice:example.org" && mxid == "@alice:example.org"
&& signatures == btreemap! { && signatures == btreemap! {
server_name!("magic.forest") => btreemap! { server_name!("magic.forest") => btreemap! {
server_signing_key_id!("ed25519:3") => "foobar".to_owned() server_signing_key_id!("ed25519:3").to_owned() => "foobar".to_owned()
} }
} }
&& token == "abc123" && token == "abc123"
@ -580,7 +580,7 @@ mod tests {
&& mxid == "@alice:example.org" && mxid == "@alice:example.org"
&& signatures == btreemap! { && signatures == btreemap! {
server_name!("magic.forest") => btreemap! { server_name!("magic.forest") => btreemap! {
server_signing_key_id!("ed25519:3") => "foobar".to_owned() server_signing_key_id!("ed25519:3").to_owned() => "foobar".to_owned()
} }
} }
&& token == "abc123" && token == "abc123"
@ -654,7 +654,7 @@ mod tests {
&& mxid == "@alice:example.org" && mxid == "@alice:example.org"
&& signatures == btreemap! { && signatures == btreemap! {
server_name!("magic.forest") => btreemap! { server_name!("magic.forest") => btreemap! {
server_signing_key_id!("ed25519:3") => "foobar".to_owned() server_signing_key_id!("ed25519:3").to_owned() => "foobar".to_owned()
} }
} }
&& token == "abc123" && token == "abc123"

View File

@ -18,7 +18,7 @@ fn serialize_pdu_as_v1() {
let mut signatures = BTreeMap::new(); let mut signatures = BTreeMap::new();
let mut inner_signature = BTreeMap::new(); let mut inner_signature = BTreeMap::new();
inner_signature.insert( inner_signature.insert(
server_signing_key_id!("ed25519:key_version"), server_signing_key_id!("ed25519:key_version").to_owned(),
"86BytesOfSignatureOfTheRedactedEvent".into(), "86BytesOfSignatureOfTheRedactedEvent".into(),
); );
signatures.insert(server_name!("example.com"), inner_signature); signatures.insert(server_name!("example.com"), inner_signature);
@ -85,7 +85,7 @@ fn serialize_pdu_as_v3() {
let mut signatures = BTreeMap::new(); let mut signatures = BTreeMap::new();
let mut inner_signature = BTreeMap::new(); let mut inner_signature = BTreeMap::new();
inner_signature.insert( inner_signature.insert(
server_signing_key_id!("ed25519:key_version"), server_signing_key_id!("ed25519:key_version").to_owned(),
"86BytesOfSignatureOfTheRedactedEvent".into(), "86BytesOfSignatureOfTheRedactedEvent".into(),
); );
signatures.insert(server_name!("example.com"), inner_signature); signatures.insert(server_name!("example.com"), inner_signature);

View File

@ -54,15 +54,15 @@ pub struct ServerSigningKeys {
pub server_name: Box<ServerName>, pub server_name: Box<ServerName>,
/// Public keys of the homeserver for verifying digital signatures. /// Public keys of the homeserver for verifying digital signatures.
pub verify_keys: BTreeMap<ServerSigningKeyId, VerifyKey>, pub verify_keys: BTreeMap<Box<ServerSigningKeyId>, VerifyKey>,
/// Public keys that the homeserver used to use and when it stopped using them. /// Public keys that the homeserver used to use and when it stopped using them.
pub old_verify_keys: BTreeMap<ServerSigningKeyId, OldVerifyKey>, pub old_verify_keys: BTreeMap<Box<ServerSigningKeyId>, OldVerifyKey>,
/// Digital signatures of this object signed using the verify_keys. /// Digital signatures of this object signed using the verify_keys.
/// ///
/// Map of server name to keys by key ID. /// Map of server name to keys by key ID.
pub signatures: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signatures: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
/// Timestamp when the keys should be refreshed. /// Timestamp when the keys should be refreshed.
/// ///

View File

@ -28,7 +28,7 @@ ruma_api! {
/// notary server must return an empty server_keys array in the response. /// notary server must return an empty server_keys array in the response.
/// ///
/// The notary server may return multiple keys regardless of the Key IDs given. /// The notary server may return multiple keys regardless of the Key IDs given.
pub server_keys: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, QueryCriteria>>, pub server_keys: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, QueryCriteria>>,
} }
@ -41,7 +41,7 @@ ruma_api! {
impl Request { impl Request {
/// Creates a new `Request` with the given query criteria. /// Creates a new `Request` with the given query criteria.
pub fn new( pub fn new(
server_keys: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, QueryCriteria>>, server_keys: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, QueryCriteria>>,
) -> Self { ) -> Self {
Self { server_keys } Self { server_keys }
} }

View File

@ -77,7 +77,7 @@ pub struct ThirdPartyInvite {
pub sender: Box<UserId>, pub sender: Box<UserId>,
/// Signature from the identity server using a long-term private key. /// Signature from the identity server using a long-term private key.
pub signed: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, pub signed: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
} }
impl ThirdPartyInvite { impl ThirdPartyInvite {
@ -87,7 +87,7 @@ impl ThirdPartyInvite {
mxid: Box<UserId>, mxid: Box<UserId>,
room_id: Box<RoomId>, room_id: Box<RoomId>,
sender: Box<UserId>, sender: Box<UserId>,
signed: BTreeMap<Box<ServerName>, BTreeMap<ServerSigningKeyId, String>>, signed: BTreeMap<Box<ServerName>, BTreeMap<Box<ServerSigningKeyId>, String>>,
) -> Self { ) -> Self {
Self { medium: Medium::Email, address, mxid, room_id, sender, signed } Self { medium: Medium::Email, address, mxid, room_id, sender, signed }
} }

View File

@ -91,7 +91,7 @@ pub fn server_signing_key_id(input: TokenStream) -> TokenStream {
assert!(key_id::validate(&id.value()).is_ok(), "Invalid server_signing_key_id"); assert!(key_id::validate(&id.value()).is_ok(), "Invalid server_signing_key_id");
let output = quote! { let output = quote! {
<#dollar_crate::ServerSigningKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap() <&#dollar_crate::ServerSigningKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
}; };
output.into() output.into()

View File

@ -16,8 +16,6 @@ pub mod server_name;
pub mod session_id; pub mod session_id;
pub mod user_id; pub mod user_id;
use std::num::NonZeroU8;
pub use error::Error; pub use error::Error;
/// All identifiers must be 255 bytes or less. /// All identifiers must be 255 bytes or less.
@ -36,13 +34,12 @@ fn validate_id(id: &str, valid_sigils: &[char]) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Checks an identifier that contains a localpart and hostname for validity, /// Checks an identifier that contains a localpart and hostname for validity.
/// and returns the index of the colon that separates the two. fn parse_id(id: &str, valid_sigils: &[char]) -> Result<usize, Error> {
fn parse_id(id: &str, valid_sigils: &[char]) -> Result<NonZeroU8, Error> {
validate_id(id, valid_sigils)?; validate_id(id, valid_sigils)?;
let colon_idx = id.find(':').ok_or(Error::MissingDelimiter)?; let colon_idx = id.find(':').ok_or(Error::MissingDelimiter)?;
server_name::validate(&id[colon_idx + 1..])?; server_name::validate(&id[colon_idx + 1..])?;
Ok(NonZeroU8::new(colon_idx as u8).unwrap()) Ok(colon_idx)
} }
/// Checks an identifier that contains a localpart and hostname for validity. /// Checks an identifier that contains a localpart and hostname for validity.

View File

@ -1,13 +1,11 @@
use std::num::NonZeroU8;
use crate::{parse_id, Error}; use crate::{parse_id, Error};
pub fn validate(s: &str) -> Result<(NonZeroU8, bool), Error> { pub fn validate(s: &str) -> Result<(), Error> {
let colon_idx = parse_id(s, &['@'])?; let colon_idx = parse_id(s, &['@'])?;
let localpart = &s[1..colon_idx.get() as usize]; let localpart = &s[1..colon_idx];
let is_historical = localpart_is_fully_conforming(localpart)?; let _ = localpart_is_fully_conforming(localpart)?;
Ok((colon_idx, is_historical)) Ok(())
} }
/// Check whether the given user id localpart is valid and fully conforming /// Check whether the given user id localpart is valid and fully conforming

View File

@ -1,25 +1,21 @@
use std::{ use std::{
cmp::Ordering, cmp::Ordering,
convert::{TryFrom, TryInto}, convert::TryFrom,
fmt, fmt,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
marker::PhantomData, marker::PhantomData,
num::NonZeroU8,
str::FromStr, str::FromStr,
}; };
use crate::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName}; use crate::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName};
/// A key algorithm and key name delimited by a colon /// A key algorithm and key name delimited by a colon.
pub struct KeyId<A, K: ?Sized> { #[repr(transparent)]
full_id: Box<str>, pub struct KeyId<A, K: ?Sized>(PhantomData<(A, K)>, str);
colon_idx: NonZeroU8,
_phantom: PhantomData<(A, K)>,
}
impl<A, K: ?Sized> KeyId<A, K> { impl<A, K: ?Sized> KeyId<A, K> {
/// Creates a new `KeyId` from an algorithm and key name. /// Creates a new `KeyId` from an algorithm and key name.
pub fn from_parts(algorithm: A, key_name: &K) -> Self pub fn from_parts(algorithm: A, key_name: &K) -> Box<Self>
where where
A: AsRef<str>, A: AsRef<str>,
K: AsRef<str>, K: AsRef<str>,
@ -32,11 +28,7 @@ impl<A, K: ?Sized> KeyId<A, K> {
res.push(':'); res.push(':');
res.push_str(key_name); res.push_str(key_name);
let colon_idx = Self::from_owned(res.into())
NonZeroU8::new(algorithm.len().try_into().expect("no algorithm name len > 255"))
.expect("no empty algorithm name");
KeyId { full_id: res.into(), colon_idx, _phantom: PhantomData }
} }
/// Returns key algorithm of the key ID. /// Returns key algorithm of the key ID.
@ -44,8 +36,7 @@ impl<A, K: ?Sized> KeyId<A, K> {
where where
A: FromStr, A: FromStr,
{ {
A::from_str(&self.full_id[..self.colon_idx.get() as usize]) A::from_str(&self.as_str()[..self.colon_idx()]).unwrap_or_else(|_| unreachable!())
.unwrap_or_else(|_| unreachable!())
} }
/// Returns the key name of the key ID. /// Returns the key name of the key ID.
@ -53,33 +44,105 @@ impl<A, K: ?Sized> KeyId<A, K> {
where where
&'a K: From<&'a str>, &'a K: From<&'a str>,
{ {
self.full_id[self.colon_idx.get() as usize + 1..].into() self.as_str()[self.colon_idx() + 1..].into()
} }
}
fn try_from<S, A, K: ?Sized>(key_identifier: S) -> Result<KeyId<A, K>, crate::Error> /// Creates a string slice from this `KeyId`.
where
S: AsRef<str> + Into<Box<str>>,
{
let colon_idx = ruma_identifiers_validation::key_id::validate(key_identifier.as_ref())?;
Ok(KeyId { full_id: key_identifier.into(), colon_idx, _phantom: PhantomData })
}
impl<A, K: ?Sized> KeyId<A, K> {
/// Creates a string slice from this `KeyId<A, K>`
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
&self.full_id &self.1
} }
/// Creates a byte slice from this `KeyId<A, K>` /// Creates a byte slice from this `KeyId`.
pub fn as_bytes(&self) -> &[u8] { pub fn as_bytes(&self) -> &[u8] {
self.full_id.as_bytes() self.1.as_bytes()
}
fn from_borrowed(s: &str) -> &Self {
unsafe { std::mem::transmute(s) }
}
fn from_owned(s: Box<str>) -> Box<Self> {
unsafe { Box::from_raw(Box::into_raw(s) as _) }
}
fn into_owned(self: Box<Self>) -> Box<str> {
unsafe { Box::from_raw(Box::into_raw(self) as _) }
}
fn colon_idx(&self) -> usize {
self.as_str().find(':').unwrap()
} }
} }
impl<A, K: ?Sized> Clone for KeyId<A, K> { /// Algorithm + key name for signing keys.
pub type SigningKeyId<K> = KeyId<SigningKeyAlgorithm, K>;
/// Algorithm + key name for homeserver signing keys.
pub type ServerSigningKeyId = SigningKeyId<KeyName>;
/// Algorithm + key name for device keys.
pub type DeviceSigningKeyId = SigningKeyId<DeviceId>;
impl<A, K: ?Sized> Clone for Box<KeyId<A, K>> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { full_id: self.full_id.clone(), colon_idx: self.colon_idx, _phantom: PhantomData } (**self).to_owned()
}
}
impl<A, K: ?Sized> ToOwned for KeyId<A, K> {
type Owned = Box<KeyId<A, K>>;
fn to_owned(&self) -> Self::Owned {
Self::from_owned(self.1.into())
}
}
impl<A, K: ?Sized> From<&KeyId<A, K>> for Box<KeyId<A, K>> {
fn from(id: &KeyId<A, K>) -> Self {
id.to_owned()
}
}
impl<A, K: ?Sized> AsRef<str> for Box<KeyId<A, K>> {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl<A, K: ?Sized> From<&KeyId<A, K>> for std::rc::Rc<KeyId<A, K>> {
fn from(s: &KeyId<A, K>) -> std::rc::Rc<KeyId<A, K>> {
let rc = std::rc::Rc::<str>::from(s.as_str());
unsafe { std::rc::Rc::from_raw(std::rc::Rc::into_raw(rc) as *const KeyId<A, K>) }
}
}
impl<A, K: ?Sized> From<&KeyId<A, K>> for std::sync::Arc<KeyId<A, K>> {
fn from(s: &KeyId<A, K>) -> std::sync::Arc<KeyId<A, K>> {
let arc = std::sync::Arc::<str>::from(s.as_str());
unsafe { std::sync::Arc::from_raw(std::sync::Arc::into_raw(arc) as *const KeyId<A, K>) }
}
}
impl<A, K: ?Sized> PartialEq<KeyId<A, K>> for Box<KeyId<A, K>> {
fn eq(&self, other: &KeyId<A, K>) -> bool {
self.as_str() == other.as_str()
}
}
impl<A, K: ?Sized> PartialEq<&'_ KeyId<A, K>> for Box<KeyId<A, K>> {
fn eq(&self, other: &&KeyId<A, K>) -> bool {
self.as_str() == other.as_str()
}
}
impl<A, K: ?Sized> PartialEq<Box<KeyId<A, K>>> for KeyId<A, K> {
fn eq(&self, other: &Box<KeyId<A, K>>) -> bool {
self.as_str() == other.as_str()
}
}
impl<A, K: ?Sized> PartialEq<Box<KeyId<A, K>>> for &'_ KeyId<A, K> {
fn eq(&self, other: &Box<KeyId<A, K>>) -> bool {
self.as_str() == other.as_str()
} }
} }
@ -89,54 +152,15 @@ impl<A, K: ?Sized> AsRef<str> for KeyId<A, K> {
} }
} }
impl<A, K: ?Sized> From<KeyId<A, K>> for String { impl<A, K: ?Sized> fmt::Display for KeyId<A, K> {
fn from(id: KeyId<A, K>) -> Self { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
id.full_id.into() self.as_str().fmt(f)
}
}
impl<A, K: ?Sized> FromStr for KeyId<A, K> {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
try_from(s)
}
}
impl<A, K: ?Sized> TryFrom<&str> for KeyId<A, K> {
type Error = crate::Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
try_from(s)
}
}
impl<A, K: ?Sized> TryFrom<String> for KeyId<A, K>
where
A: FromStr,
K: From<String>,
{
type Error = crate::Error;
fn try_from(s: String) -> Result<Self, Self::Error> {
try_from(s)
} }
} }
impl<A, K: ?Sized> fmt::Debug for KeyId<A, K> { impl<A, K: ?Sized> fmt::Debug for KeyId<A, K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Using struct debug format for consistency with other ID types. self.as_str().fmt(f)
// FIXME: Change all ID types to have just a string debug format?
f.debug_struct("KeyId")
.field("full_id", &self.full_id)
.field("colon_idxs", &self.colon_idx)
.finish()
}
}
impl<A, K: ?Sized> fmt::Display for KeyId<A, K> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
} }
} }
@ -150,13 +174,13 @@ impl<A, K: ?Sized> Eq for KeyId<A, K> {}
impl<A, K: ?Sized> PartialOrd for KeyId<A, K> { impl<A, K: ?Sized> PartialOrd for KeyId<A, K> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.as_str().partial_cmp(other.as_str()) PartialOrd::partial_cmp(self.as_str(), other.as_str())
} }
} }
impl<A, K: ?Sized> Ord for KeyId<A, K> { impl<A, K: ?Sized> Ord for KeyId<A, K> {
fn cmp(&self, other: &Self) -> Ordering { fn cmp(&self, other: &Self) -> Ordering {
self.as_str().cmp(other.as_str()) Ord::cmp(self.as_str(), other.as_str())
} }
} }
@ -165,7 +189,6 @@ impl<A, K: ?Sized> Hash for KeyId<A, K> {
self.as_str().hash(state); self.as_str().hash(state);
} }
} }
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl<A, K: ?Sized> serde::Serialize for KeyId<A, K> { impl<A, K: ?Sized> serde::Serialize for KeyId<A, K> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
@ -176,24 +199,63 @@ impl<A, K: ?Sized> serde::Serialize for KeyId<A, K> {
} }
} }
impl<A, K: ?Sized> From<Box<KeyId<A, K>>> for String {
fn from(id: Box<KeyId<A, K>>) -> Self {
id.into_owned().into()
}
}
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
impl<'de, A, K: ?Sized> serde::Deserialize<'de> for KeyId<A, K> { impl<'de, A, K: ?Sized> serde::Deserialize<'de> for Box<KeyId<A, K>> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
D: serde::Deserializer<'de>, D: serde::Deserializer<'de>,
{ {
crate::deserialize_id(deserializer, "Key name with algorithm and key identifier") use serde::de::Error;
let s = String::deserialize(deserializer)?;
match try_from(s) {
Ok(o) => Ok(o),
Err(e) => Err(D::Error::custom(e)),
}
}
}
fn try_from<S, A, K: ?Sized>(s: S) -> Result<Box<KeyId<A, K>>, crate::Error>
where
S: AsRef<str> + Into<Box<str>>,
{
ruma_identifiers_validation::key_id::validate(s.as_ref())?;
Ok(KeyId::from_owned(s.into()))
}
impl<'a, A, K: ?Sized> TryFrom<&'a str> for &'a KeyId<A, K> {
type Error = crate::Error;
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
(ruma_identifiers_validation::key_id::validate)(s)?;
Ok(KeyId::from_borrowed(s))
}
}
impl<A, K: ?Sized> FromStr for Box<KeyId<A, K>> {
type Err = crate::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
try_from(s)
}
}
impl<A, K: ?Sized> TryFrom<&str> for Box<KeyId<A, K>> {
type Error = crate::Error;
fn try_from(s: &str) -> Result<Self, Self::Error> {
try_from(s)
}
}
impl<A, K: ?Sized> TryFrom<String> for Box<KeyId<A, K>> {
type Error = crate::Error;
fn try_from(s: String) -> Result<Self, Self::Error> {
try_from(s)
} }
} }
#[rustfmt::skip] #[rustfmt::skip]
partial_eq_string!(KeyId<A, K> [A, K]); partial_eq_string!(KeyId<A, K> [A, K]);
/// Algorithm + key name for signing keys.
pub type SigningKeyId<K> = KeyId<SigningKeyAlgorithm, K>;
/// Algorithm + key name for homeserver signing keys.
pub type ServerSigningKeyId = SigningKeyId<KeyName>;
/// Algorithm + key name for device keys.
pub type DeviceSigningKeyId = SigningKeyId<DeviceId>;

View File

@ -3,7 +3,7 @@ use std::{borrow::Borrow, collections::BTreeMap};
use crate::{DeviceId, KeyName, ServerName, SigningKeyId, UserId}; use crate::{DeviceId, KeyName, ServerName, SigningKeyId, UserId};
/// Map of key identifier to signature values. /// Map of key identifier to signature values.
pub type EntitySignatures<K> = BTreeMap<SigningKeyId<K>, String>; pub type EntitySignatures<K> = BTreeMap<Box<SigningKeyId<K>>, String>;
/// Map of all signatures, grouped by entity /// Map of all signatures, grouped by entity
/// ///
@ -35,7 +35,7 @@ impl<E: Ord, K: ?Sized> Signatures<E, K> {
pub fn insert( pub fn insert(
&mut self, &mut self,
entity: E, entity: E,
key_identifier: SigningKeyId<K>, key_identifier: Box<SigningKeyId<K>>,
value: String, value: String,
) -> Option<String> { ) -> Option<String> {
self.0.entry(entity).or_insert_with(Default::default).insert(key_identifier, value) self.0.entry(entity).or_insert_with(Default::default).insert(key_identifier, value)

View File

@ -16,7 +16,7 @@ ruma_api! {
request: { request: {
/// The ID of the key. /// The ID of the key.
#[ruma_api(path)] #[ruma_api(path)]
pub key_id: ServerSigningKeyId, pub key_id: &'a ServerSigningKeyId,
} }
response: { response: {
@ -25,9 +25,9 @@ ruma_api! {
} }
} }
impl Request { impl<'a> Request<'a> {
/// Create a `Request` with the given key_id. /// Create a `Request` with the given key_id.
pub fn new(key_id: ServerSigningKeyId) -> Self { pub fn new(key_id: &'a ServerSigningKeyId) -> Self {
Self { key_id } Self { key_id }
} }
} }

View File

@ -262,7 +262,9 @@ fn strip_lifetimes(field_type: &mut Type) -> bool {
} else if last_seg.ident == "ClientSecret" } else if last_seg.ident == "ClientSecret"
|| last_seg.ident == "DeviceId" || last_seg.ident == "DeviceId"
|| last_seg.ident == "DeviceKeyId" || last_seg.ident == "DeviceKeyId"
|| last_seg.ident == "DeviceSigningKeyId"
|| last_seg.ident == "EventId" || last_seg.ident == "EventId"
|| last_seg.ident == "KeyId"
|| last_seg.ident == "MxcUri" || last_seg.ident == "MxcUri"
|| last_seg.ident == "ServerName" || last_seg.ident == "ServerName"
|| last_seg.ident == "SessionId" || last_seg.ident == "SessionId"
@ -271,6 +273,8 @@ fn strip_lifetimes(field_type: &mut Type) -> bool {
|| last_seg.ident == "RoomId" || last_seg.ident == "RoomId"
|| last_seg.ident == "RoomIdOrAliasId" || last_seg.ident == "RoomIdOrAliasId"
|| last_seg.ident == "RoomName" || last_seg.ident == "RoomName"
|| last_seg.ident == "ServerSigningKeyId"
|| last_seg.ident == "SigningKeyId"
|| last_seg.ident == "UserId" || last_seg.ident == "UserId"
{ {
// The identifiers that need to be boxed `Box<T>` since they are DST's. // The identifiers that need to be boxed `Box<T>` since they are DST's.