identifiers: Allow to validate KeyId with any key name type
Use new trait bounds for KeyId to only allow specific types. Change the KeyId validation to be generic over the key name type. Remove the KeyName type and replace it with the more specific ServerSigningKeyVersion.
This commit is contained in:
parent
f47733b49d
commit
ae3897cad8
@ -15,6 +15,16 @@ Breaking changes:
|
||||
with `serde_html_form`.
|
||||
- The `header` attribute for the `request` and `response` macros accepts any
|
||||
type that implements `ToString` and `FromStr`.
|
||||
- The `compat-key-id` cargo feature was renamed to
|
||||
`compat-server-signing-key-version`.
|
||||
- `(Owned)KeyName` was renamed to `(Owned)ServerSigningKeyVersion` and is now
|
||||
validated according to the set of allowed characters defined in the docs,
|
||||
unless the `compat-server-signing-key-version` cargo feature is enabled.
|
||||
- The bounds on `KeyId` changed. The algorithm part must implement
|
||||
`KeyAlgorithm` and the key name part must implement `KeyName`.
|
||||
- The `(owned_)server_signing_key_id` macros were removed. For compile-time
|
||||
validated construction, use `ServerSigningKeyId::from_parts` with a
|
||||
`SigningKeyAlgorithm` and the `server_signing_key_version` macro.
|
||||
|
||||
Improvements:
|
||||
|
||||
|
@ -38,8 +38,8 @@ compat-arbitrary-length-ids = [
|
||||
"ruma-identifiers-validation/compat-arbitrary-length-ids",
|
||||
]
|
||||
|
||||
# Don't validate the version part in `KeyId`.
|
||||
compat-key-id = ["ruma-identifiers-validation/compat-key-id"]
|
||||
# Don't validate `ServerSigningKeyVersion`.
|
||||
compat-server-signing-key-version = ["ruma-identifiers-validation/compat-server-signing-key-version"]
|
||||
|
||||
# Allow some user IDs that are invalid even with the specified historical
|
||||
# user ID scheme.
|
||||
|
@ -5,9 +5,12 @@
|
||||
#![allow(unused_qualifications)]
|
||||
|
||||
#[doc(inline)]
|
||||
pub use ruma_identifiers_validation::error::{
|
||||
Error as IdParseError, MatrixIdError, MatrixToError, MatrixUriError, MxcUriError,
|
||||
VoipVersionIdError,
|
||||
pub use ruma_identifiers_validation::{
|
||||
error::{
|
||||
Error as IdParseError, MatrixIdError, MatrixToError, MatrixUriError, MxcUriError,
|
||||
VoipVersionIdError,
|
||||
},
|
||||
KeyName,
|
||||
};
|
||||
use serde::de::{self, Deserializer, Unexpected};
|
||||
|
||||
@ -21,10 +24,9 @@ pub use self::{
|
||||
device_key_id::{DeviceKeyId, OwnedDeviceKeyId},
|
||||
event_id::{EventId, OwnedEventId},
|
||||
key_id::{
|
||||
DeviceSigningKeyId, KeyId, OwnedDeviceSigningKeyId, OwnedKeyId, OwnedServerSigningKeyId,
|
||||
OwnedSigningKeyId, ServerSigningKeyId, SigningKeyId,
|
||||
DeviceSigningKeyId, KeyAlgorithm, KeyId, OwnedDeviceSigningKeyId, OwnedKeyId,
|
||||
OwnedServerSigningKeyId, OwnedSigningKeyId, ServerSigningKeyId, SigningKeyId,
|
||||
},
|
||||
key_name::{KeyName, OwnedKeyName},
|
||||
matrix_uri::{MatrixToUri, MatrixUri},
|
||||
mxc_uri::{Mxc, MxcUri, OwnedMxcUri},
|
||||
room_alias_id::{OwnedRoomAliasId, RoomAliasId},
|
||||
@ -32,6 +34,7 @@ pub use self::{
|
||||
room_or_alias_id::{OwnedRoomOrAliasId, RoomOrAliasId},
|
||||
room_version_id::RoomVersionId,
|
||||
server_name::{OwnedServerName, ServerName},
|
||||
server_signing_key_version::{OwnedServerSigningKeyVersion, ServerSigningKeyVersion},
|
||||
session_id::{OwnedSessionId, SessionId},
|
||||
signatures::{DeviceSignatures, EntitySignatures, ServerSignatures, Signatures},
|
||||
transaction_id::{OwnedTransactionId, TransactionId},
|
||||
@ -49,13 +52,13 @@ mod device_id;
|
||||
mod device_key_id;
|
||||
mod event_id;
|
||||
mod key_id;
|
||||
mod key_name;
|
||||
mod mxc_uri;
|
||||
mod room_alias_id;
|
||||
mod room_id;
|
||||
mod room_or_alias_id;
|
||||
mod room_version_id;
|
||||
mod server_name;
|
||||
mod server_signing_key_version;
|
||||
mod session_id;
|
||||
mod signatures;
|
||||
mod transaction_id;
|
||||
@ -107,7 +110,7 @@ macro_rules! owned_device_id {
|
||||
pub mod __private_macros {
|
||||
pub use ruma_macros::{
|
||||
device_key_id, event_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
|
||||
server_signing_key_id, user_id,
|
||||
server_signing_key_version, user_id,
|
||||
};
|
||||
}
|
||||
|
||||
@ -183,19 +186,19 @@ macro_rules! room_version_id {
|
||||
};
|
||||
}
|
||||
|
||||
/// Compile-time checked [`ServerSigningKeyId`] construction.
|
||||
/// Compile-time checked [`ServerSigningKeyVersion`] construction.
|
||||
#[macro_export]
|
||||
macro_rules! server_signing_key_id {
|
||||
macro_rules! server_signing_key_version {
|
||||
($s:literal) => {
|
||||
$crate::__private_macros::server_signing_key_id!($crate, $s)
|
||||
$crate::__private_macros::server_signing_key_version!($crate, $s)
|
||||
};
|
||||
}
|
||||
|
||||
/// Compile-time checked [`OwnedServerSigningKeyId`] construction.
|
||||
/// Compile-time checked [`OwnedServerSigningKeyVersion`] construction.
|
||||
#[macro_export]
|
||||
macro_rules! owned_server_signing_key_id {
|
||||
macro_rules! owned_server_signing_key_version {
|
||||
($s:literal) => {
|
||||
$crate::server_signing_key_id!($s).to_owned()
|
||||
$crate::server_signing_key_version!($s).to_owned()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2,8 +2,9 @@ use ruma_macros::IdZst;
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
use super::generate_localpart;
|
||||
use super::{IdParseError, KeyName};
|
||||
|
||||
/// A Matrix key ID.
|
||||
/// A Matrix device ID.
|
||||
///
|
||||
/// Device identifiers in Matrix are completely opaque character sequences. This type is provided
|
||||
/// simply for its semantic value.
|
||||
@ -40,6 +41,18 @@ impl DeviceId {
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyName for DeviceId {
|
||||
fn validate(_s: &str) -> Result<(), IdParseError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyName for OwnedDeviceId {
|
||||
fn validate(_s: &str) -> Result<(), IdParseError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::{DeviceId, OwnedDeviceId};
|
||||
|
@ -2,26 +2,23 @@ use std::{
|
||||
cmp::Ordering,
|
||||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
use ruma_macros::IdZst;
|
||||
|
||||
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName};
|
||||
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName, ServerSigningKeyVersion};
|
||||
|
||||
/// A key algorithm and key name delimited by a colon.
|
||||
#[repr(transparent)]
|
||||
#[derive(IdZst)]
|
||||
#[ruma_id(validate = ruma_identifiers_validation::key_id::validate)]
|
||||
pub struct KeyId<A, K: ?Sized>(PhantomData<(A, K)>, str);
|
||||
#[ruma_id(
|
||||
validate = ruma_identifiers_validation::key_id::validate::<K>,
|
||||
)]
|
||||
pub struct KeyId<A: KeyAlgorithm, K: KeyName + ?Sized>(PhantomData<(A, K)>, str);
|
||||
|
||||
impl<A, K: ?Sized> KeyId<A, K> {
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> KeyId<A, K> {
|
||||
/// Creates a new `KeyId` from an algorithm and key name.
|
||||
pub fn from_parts(algorithm: A, key_name: &K) -> OwnedKeyId<A, K>
|
||||
where
|
||||
A: AsRef<str>,
|
||||
K: AsRef<str>,
|
||||
{
|
||||
pub fn from_parts(algorithm: A, key_name: &K) -> OwnedKeyId<A, K> {
|
||||
let algorithm = algorithm.as_ref();
|
||||
let key_name = key_name.as_ref();
|
||||
|
||||
@ -34,19 +31,16 @@ impl<A, K: ?Sized> KeyId<A, K> {
|
||||
}
|
||||
|
||||
/// Returns key algorithm of the key ID.
|
||||
pub fn algorithm(&self) -> A
|
||||
where
|
||||
A: FromStr,
|
||||
{
|
||||
A::from_str(&self.as_str()[..self.colon_idx()]).unwrap_or_else(|_| unreachable!())
|
||||
pub fn algorithm(&self) -> A {
|
||||
A::from(&self.as_str()[..self.colon_idx()])
|
||||
}
|
||||
|
||||
/// Returns the key name of the key ID.
|
||||
pub fn key_name<'a>(&'a self) -> &'a K
|
||||
where
|
||||
&'a K: From<&'a str>,
|
||||
&'a K: TryFrom<&'a str>,
|
||||
{
|
||||
self.as_str()[self.colon_idx() + 1..].into()
|
||||
<&'a K>::try_from(&self.as_str()[..self.colon_idx()]).unwrap_or_else(|_| unreachable!())
|
||||
}
|
||||
|
||||
fn colon_idx(&self) -> usize {
|
||||
@ -61,10 +55,10 @@ pub type SigningKeyId<K> = KeyId<SigningKeyAlgorithm, K>;
|
||||
pub type OwnedSigningKeyId<K> = OwnedKeyId<SigningKeyAlgorithm, K>;
|
||||
|
||||
/// Algorithm + key name for homeserver signing keys.
|
||||
pub type ServerSigningKeyId = SigningKeyId<KeyName>;
|
||||
pub type ServerSigningKeyId = SigningKeyId<ServerSigningKeyVersion>;
|
||||
|
||||
/// Algorithm + key name for homeserver signing keys.
|
||||
pub type OwnedServerSigningKeyId = OwnedSigningKeyId<KeyName>;
|
||||
pub type OwnedServerSigningKeyId = OwnedSigningKeyId<ServerSigningKeyVersion>;
|
||||
|
||||
/// Algorithm + key name for device keys.
|
||||
pub type DeviceSigningKeyId = SigningKeyId<DeviceId>;
|
||||
@ -74,28 +68,33 @@ pub type OwnedDeviceSigningKeyId = OwnedSigningKeyId<DeviceId>;
|
||||
|
||||
// The following impls are usually derived using the std macros.
|
||||
// They are implemented manually here to avoid unnecessary bounds.
|
||||
impl<A, K: ?Sized> PartialEq for KeyId<A, K> {
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> PartialEq for KeyId<A, K> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_str() == other.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> Eq for KeyId<A, K> {}
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> Eq for KeyId<A, K> {}
|
||||
|
||||
impl<A, K: ?Sized> PartialOrd for KeyId<A, K> {
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> PartialOrd for KeyId<A, K> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> Ord for KeyId<A, K> {
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> Ord for KeyId<A, K> {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
Ord::cmp(self.as_str(), other.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, K: ?Sized> Hash for KeyId<A, K> {
|
||||
impl<A: KeyAlgorithm, K: KeyName + ?Sized> Hash for KeyId<A, K> {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.as_str().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// The algorithm of a key.
|
||||
pub trait KeyAlgorithm: for<'a> From<&'a str> + AsRef<str> {}
|
||||
|
||||
impl KeyAlgorithm for SigningKeyAlgorithm {}
|
||||
|
@ -1,9 +0,0 @@
|
||||
use ruma_macros::IdZst;
|
||||
|
||||
/// A Matrix key identifier.
|
||||
///
|
||||
/// Key identifiers in Matrix are opaque character sequences of `[a-zA-Z_]`. This type is
|
||||
/// provided simply for its semantic value.
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
|
||||
pub struct KeyName(str);
|
@ -0,0 +1,31 @@
|
||||
use ruma_macros::IdZst;
|
||||
|
||||
use super::{IdParseError, KeyName};
|
||||
|
||||
/// The version of a [homeserver signing key].
|
||||
///
|
||||
/// This is an opaque character sequences of `[a-zA-Z0-9_]`. This type is provided simply for its
|
||||
/// semantic value.
|
||||
///
|
||||
/// With the `compat-server-signing-key-version` cargo feature, the validation of this type is
|
||||
/// relaxed to accept any string.
|
||||
///
|
||||
/// [homeserver signing key]: https://spec.matrix.org/latest/server-server-api/#retrieving-server-keys
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
|
||||
#[ruma_id(
|
||||
validate = ruma_identifiers_validation::server_signing_key_version::validate,
|
||||
)]
|
||||
pub struct ServerSigningKeyVersion(str);
|
||||
|
||||
impl KeyName for ServerSigningKeyVersion {
|
||||
fn validate(s: &str) -> Result<(), IdParseError> {
|
||||
ruma_identifiers_validation::server_signing_key_version::validate(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl KeyName for OwnedServerSigningKeyVersion {
|
||||
fn validate(s: &str) -> Result<(), IdParseError> {
|
||||
ruma_identifiers_validation::server_signing_key_version::validate(s)
|
||||
}
|
||||
}
|
@ -2,7 +2,10 @@ use std::{borrow::Borrow, collections::BTreeMap};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::{OwnedDeviceId, OwnedKeyName, OwnedServerName, OwnedSigningKeyId, OwnedUserId};
|
||||
use super::{
|
||||
KeyName, OwnedDeviceId, OwnedServerName, OwnedServerSigningKeyVersion, OwnedSigningKeyId,
|
||||
OwnedUserId,
|
||||
};
|
||||
|
||||
/// Map of key identifier to signature values.
|
||||
pub type EntitySignatures<K> = BTreeMap<OwnedSigningKeyId<K>, String>;
|
||||
@ -10,8 +13,11 @@ pub type EntitySignatures<K> = BTreeMap<OwnedSigningKeyId<K>, String>;
|
||||
/// Map of all signatures, grouped by entity
|
||||
///
|
||||
/// ```
|
||||
/// # use ruma_common::{server_name, KeyId, Signatures, SigningKeyAlgorithm};
|
||||
/// let key_identifier = KeyId::from_parts(SigningKeyAlgorithm::Ed25519, "1");
|
||||
/// # use ruma_common::{server_name, server_signing_key_version, ServerSigningKeyId, Signatures, SigningKeyAlgorithm};
|
||||
/// let key_identifier = ServerSigningKeyId::from_parts(
|
||||
/// SigningKeyAlgorithm::Ed25519,
|
||||
/// server_signing_key_version!("1")
|
||||
/// );
|
||||
/// let mut signatures = Signatures::new();
|
||||
/// let server_name = server_name!("example.org");
|
||||
/// let signature =
|
||||
@ -20,9 +26,9 @@ pub type EntitySignatures<K> = BTreeMap<OwnedSigningKeyId<K>, String>;
|
||||
/// ```
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct Signatures<E: Ord, K: ?Sized>(BTreeMap<E, EntitySignatures<K>>);
|
||||
pub struct Signatures<E: Ord, K: KeyName + ?Sized>(BTreeMap<E, EntitySignatures<K>>);
|
||||
|
||||
impl<E: Ord, K: ?Sized> Signatures<E, K> {
|
||||
impl<E: Ord, K: KeyName + ?Sized> Signatures<E, K> {
|
||||
/// Creates an empty signature map.
|
||||
pub fn new() -> Self {
|
||||
Self(BTreeMap::new())
|
||||
@ -51,7 +57,7 @@ impl<E: Ord, K: ?Sized> Signatures<E, K> {
|
||||
}
|
||||
|
||||
/// Map of server signatures for an event, grouped by server.
|
||||
pub type ServerSignatures = Signatures<OwnedServerName, OwnedKeyName>;
|
||||
pub type ServerSignatures = Signatures<OwnedServerName, OwnedServerSigningKeyVersion>;
|
||||
|
||||
/// Map of device signatures for an event, grouped by user.
|
||||
pub type DeviceSignatures = Signatures<OwnedUserId, OwnedDeviceId>;
|
||||
|
@ -7,7 +7,7 @@ fn main() {
|
||||
_ = ruma_common::room_id!("!1234567890:matrix.org");
|
||||
_ = ruma_common::room_version_id!("1");
|
||||
_ = ruma_common::room_version_id!("1-custom");
|
||||
_ = ruma_common::server_signing_key_id!("ed25519:Abc_1");
|
||||
_ = ruma_common::server_signing_key_version!("Abc_1");
|
||||
_ = ruma_common::server_name!("myserver.fish");
|
||||
_ = ruma_common::user_id!("@user:ruma.io");
|
||||
|
||||
|
@ -581,8 +581,8 @@ mod tests {
|
||||
use js_int::uint;
|
||||
use maplit::btreemap;
|
||||
use ruma_common::{
|
||||
mxc_uri, owned_server_signing_key_id, serde::CanBeEmpty, server_name, user_id,
|
||||
MilliSecondsSinceUnixEpoch,
|
||||
mxc_uri, serde::CanBeEmpty, server_name, server_signing_key_version, user_id,
|
||||
MilliSecondsSinceUnixEpoch, ServerSigningKeyId, SigningKeyAlgorithm,
|
||||
};
|
||||
use serde_json::{from_value as from_json_value, json};
|
||||
|
||||
@ -710,7 +710,10 @@ mod tests {
|
||||
third_party_invite.signed.signatures,
|
||||
btreemap! {
|
||||
server_name!("magic.forest").to_owned() => btreemap! {
|
||||
owned_server_signing_key_id!("ed25519:3") => "foobar".to_owned()
|
||||
ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
server_signing_key_version!("3")
|
||||
) => "foobar".to_owned()
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -780,7 +783,10 @@ mod tests {
|
||||
third_party_invite.signed.signatures,
|
||||
btreemap! {
|
||||
server_name!("magic.forest").to_owned() => btreemap! {
|
||||
owned_server_signing_key_id!("ed25519:3") => "foobar".to_owned()
|
||||
ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
server_signing_key_version!("3")
|
||||
) => "foobar".to_owned()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -4,8 +4,9 @@ use std::collections::BTreeMap;
|
||||
|
||||
use js_int::uint;
|
||||
use ruma_common::{
|
||||
event_id, owned_event_id, owned_room_id, owned_server_signing_key_id, owned_user_id,
|
||||
server_name, MilliSecondsSinceUnixEpoch,
|
||||
event_id, owned_event_id, owned_room_id, owned_user_id, server_name,
|
||||
server_signing_key_version, MilliSecondsSinceUnixEpoch, ServerSigningKeyId,
|
||||
SigningKeyAlgorithm,
|
||||
};
|
||||
use ruma_events::{
|
||||
pdu::{EventHash, Pdu, RoomV1Pdu, RoomV3Pdu},
|
||||
@ -21,7 +22,10 @@ fn serialize_pdu_as_v1() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
owned_server_signing_key_id!("ed25519:key_version"),
|
||||
ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
server_signing_key_version!("key_version"),
|
||||
),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".into(),
|
||||
);
|
||||
signatures.insert(server_name!("example.com").to_owned(), inner_signature);
|
||||
@ -86,7 +90,10 @@ fn serialize_pdu_as_v3() {
|
||||
let mut signatures = BTreeMap::new();
|
||||
let mut inner_signature = BTreeMap::new();
|
||||
inner_signature.insert(
|
||||
owned_server_signing_key_id!("ed25519:key_version"),
|
||||
ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
server_signing_key_version!("key_version"),
|
||||
),
|
||||
"86BytesOfSignatureOfTheRedactedEvent".into(),
|
||||
);
|
||||
signatures.insert(server_name!("example.com").to_owned(), inner_signature);
|
||||
|
@ -1,5 +1,17 @@
|
||||
# [unreleased]
|
||||
|
||||
Breaking changes:
|
||||
|
||||
- `key_id::validate` takes a generic parameter that implements the new `KeyName`
|
||||
trait to validate the key name part. This allows to validate key names that
|
||||
are not only server signing key versions.
|
||||
- The `compat-key-id` cargo feature was renamed to
|
||||
`compat-server-signing-key-version`.
|
||||
|
||||
Improvements:
|
||||
|
||||
- Add `server_signing_key_version::validate`.
|
||||
|
||||
# 0.9.5
|
||||
|
||||
Bug fixes:
|
||||
|
@ -15,8 +15,8 @@ all-features = true
|
||||
# Allow IDs to exceed 255 bytes.
|
||||
compat-arbitrary-length-ids = []
|
||||
|
||||
# Don't validate the version part in `key_id::validate`.
|
||||
compat-key-id = []
|
||||
# Don't validate the version in `server_signing_key_version::validate`.
|
||||
compat-server-signing-key-version = []
|
||||
|
||||
# Allow some user IDs that are invalid even with the specified historical
|
||||
# user ID scheme.
|
||||
|
@ -1,24 +1,12 @@
|
||||
use std::num::NonZeroU8;
|
||||
|
||||
use crate::Error;
|
||||
use crate::{Error, KeyName};
|
||||
|
||||
pub fn validate(s: &str) -> Result<NonZeroU8, Error> {
|
||||
pub fn validate<K: KeyName + ?Sized>(s: &str) -> Result<NonZeroU8, Error> {
|
||||
let colon_idx =
|
||||
NonZeroU8::new(s.find(':').ok_or(Error::MissingColon)? as u8).ok_or(Error::MissingColon)?;
|
||||
|
||||
#[cfg(not(feature = "compat-key-id"))]
|
||||
validate_version(&s[colon_idx.get() as usize + 1..])?;
|
||||
K::validate(&s[colon_idx.get() as usize + 1..])?;
|
||||
|
||||
Ok(colon_idx)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "compat-key-id"))]
|
||||
fn validate_version(version: &str) -> Result<(), Error> {
|
||||
if version.is_empty() {
|
||||
return Err(Error::Empty);
|
||||
} else if !version.chars().all(|c| c.is_alphanumeric() || c == '_') {
|
||||
return Err(Error::InvalidCharacters);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ pub mod room_id;
|
||||
pub mod room_id_or_alias_id;
|
||||
pub mod room_version_id;
|
||||
pub mod server_name;
|
||||
pub mod server_signing_key_version;
|
||||
pub mod user_id;
|
||||
pub mod voip_version_id;
|
||||
|
||||
@ -48,3 +49,9 @@ fn validate_delimited_id(id: &str, first_byte: u8) -> Result<(), Error> {
|
||||
parse_id(id, first_byte)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Helper trait to validate the name of a key.
|
||||
pub trait KeyName: AsRef<str> {
|
||||
/// Validate the given string for this name.
|
||||
fn validate(s: &str) -> Result<(), Error>;
|
||||
}
|
||||
|
@ -0,0 +1,15 @@
|
||||
use crate::Error;
|
||||
|
||||
#[cfg_attr(feature = "compat-server-signing-key-version", allow(unused_variables))]
|
||||
pub fn validate(s: &str) -> Result<(), Error> {
|
||||
#[cfg(not(feature = "compat-server-signing-key-version"))]
|
||||
{
|
||||
if s.is_empty() {
|
||||
return Err(Error::Empty);
|
||||
} else if !s.chars().all(|c| c.is_alphanumeric() || c == '_') {
|
||||
return Err(Error::InvalidCharacters);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
@ -15,8 +15,8 @@ use proc_macro::TokenStream;
|
||||
use proc_macro2 as pm2;
|
||||
use quote::quote;
|
||||
use ruma_identifiers_validation::{
|
||||
device_key_id, event_id, key_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
|
||||
user_id,
|
||||
device_key_id, event_id, mxc_uri, room_alias_id, room_id, room_version_id, server_name,
|
||||
server_signing_key_version, user_id,
|
||||
};
|
||||
use syn::{parse_macro_input, DeriveInput, ItemEnum, ItemStruct};
|
||||
|
||||
@ -211,14 +211,17 @@ pub fn room_version_id(input: TokenStream) -> TokenStream {
|
||||
output.into()
|
||||
}
|
||||
|
||||
/// Compile-time checked `ServerSigningKeyId` construction.
|
||||
/// Compile-time checked `ServerSigningKeyVersion` construction.
|
||||
#[proc_macro]
|
||||
pub fn server_signing_key_id(input: TokenStream) -> TokenStream {
|
||||
pub fn server_signing_key_version(input: TokenStream) -> TokenStream {
|
||||
let IdentifierInput { dollar_crate, id } = parse_macro_input!(input as IdentifierInput);
|
||||
assert!(key_id::validate(&id.value()).is_ok(), "Invalid server_signing_key_id");
|
||||
assert!(
|
||||
server_signing_key_version::validate(&id.value()).is_ok(),
|
||||
"Invalid server_signing_key_version"
|
||||
);
|
||||
|
||||
let output = quote! {
|
||||
<&#dollar_crate::ServerSigningKeyId as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
|
||||
<&#dollar_crate::ServerSigningKeyVersion as ::std::convert::TryFrom<&str>>::try_from(#id).unwrap()
|
||||
};
|
||||
|
||||
output.into()
|
||||
|
@ -1003,7 +1003,7 @@ mod tests {
|
||||
let encoded_public_key = Base64::new(newly_generated_key_pair.public_key().to_vec());
|
||||
let version = ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
key_pair_sender.version().into(),
|
||||
key_pair_sender.version().try_into().unwrap(),
|
||||
);
|
||||
sender_key_map.insert(version.to_string(), encoded_public_key);
|
||||
public_key_map.insert("domain-sender".to_owned(), sender_key_map);
|
||||
@ -1177,8 +1177,10 @@ mod tests {
|
||||
fn add_key_to_map(public_key_map: &mut PublicKeyMap, name: &str, pair: &Ed25519KeyPair) {
|
||||
let sender_key_map = public_key_map.entry(name.to_owned()).or_default();
|
||||
let encoded_public_key = Base64::new(pair.public_key().to_vec());
|
||||
let version =
|
||||
ServerSigningKeyId::from_parts(SigningKeyAlgorithm::Ed25519, pair.version().into());
|
||||
let version = ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
pair.version().try_into().unwrap(),
|
||||
);
|
||||
|
||||
sender_key_map.insert(version.to_string(), encoded_public_key);
|
||||
}
|
||||
@ -1192,7 +1194,7 @@ mod tests {
|
||||
let encoded_public_key = Base64::new(pair.public_key().to_vec());
|
||||
let version = ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::from("an-unknown-algorithm"),
|
||||
pair.version().into(),
|
||||
pair.version().try_into().unwrap(),
|
||||
);
|
||||
|
||||
sender_key_map.insert(version.to_string(), encoded_public_key);
|
||||
|
@ -8,8 +8,10 @@ static PKCS8_ED25519_DER: &[u8] = include_bytes!("./keys/ed25519.der");
|
||||
fn add_key_to_map(public_key_map: &mut PublicKeyMap, name: &str, pair: &Ed25519KeyPair) {
|
||||
let sender_key_map = public_key_map.entry(name.to_owned()).or_default();
|
||||
let encoded_public_key = Base64::new(pair.public_key().to_vec());
|
||||
let version =
|
||||
ServerSigningKeyId::from_parts(SigningKeyAlgorithm::Ed25519, pair.version().into());
|
||||
let version = ServerSigningKeyId::from_parts(
|
||||
SigningKeyAlgorithm::Ed25519,
|
||||
pair.version().try_into().unwrap(),
|
||||
);
|
||||
|
||||
sender_key_map.insert(version.to_string(), encoded_public_key);
|
||||
}
|
||||
|
@ -1,5 +1,8 @@
|
||||
# [unreleased]
|
||||
|
||||
- The `compat-key-id` cargo feature was renamed to
|
||||
`compat-server-signing-key-version`.
|
||||
|
||||
# 0.10.1
|
||||
|
||||
Upgrade `ruma-events` to 0.28.1.
|
||||
|
@ -133,7 +133,7 @@ full = [
|
||||
|
||||
# Enable all compatibility hacks. Deprecated.
|
||||
compat = [
|
||||
"compat-key-id",
|
||||
"compat-server-signing-key-version",
|
||||
"compat-user-id",
|
||||
"compat-empty-string-null",
|
||||
"compat-null",
|
||||
@ -147,8 +147,8 @@ compat = [
|
||||
# Allow IDs to exceed 255 bytes.
|
||||
compat-arbitrary-length-ids = ["ruma-common/compat-arbitrary-length-ids"]
|
||||
|
||||
# Don't validate the version part in `KeyId`.
|
||||
compat-key-id = ["ruma-common/compat-key-id"]
|
||||
# Don't validate `ServerSigningKeyVersion`.
|
||||
compat-server-signing-key-version = ["ruma-common/compat-server-signing-key-version"]
|
||||
|
||||
# Allow some user IDs that are invalid even with the specified historical
|
||||
# user ID scheme.
|
||||
|
Loading…
x
Reference in New Issue
Block a user