From ae3897cad85fe1855ab88295077dd16b8313e7e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Commaille?= Date: Tue, 8 Oct 2024 15:48:03 +0200 Subject: [PATCH] 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. --- crates/ruma-common/CHANGELOG.md | 12 ++++- crates/ruma-common/Cargo.toml | 4 +- crates/ruma-common/src/identifiers.rs | 31 ++++++------ .../ruma-common/src/identifiers/device_id.rs | 15 +++++- crates/ruma-common/src/identifiers/key_id.rs | 47 +++++++++---------- .../ruma-common/src/identifiers/key_name.rs | 9 ---- .../identifiers/server_signing_key_version.rs | 31 ++++++++++++ .../ruma-common/src/identifiers/signatures.rs | 18 ++++--- .../it/identifiers/ui/01-valid-id-macros.rs | 2 +- crates/ruma-events/src/room/member.rs | 14 ++++-- crates/ruma-events/tests/it/pdu.rs | 15 ++++-- .../ruma-identifiers-validation/CHANGELOG.md | 12 +++++ crates/ruma-identifiers-validation/Cargo.toml | 4 +- .../ruma-identifiers-validation/src/key_id.rs | 18 ++----- crates/ruma-identifiers-validation/src/lib.rs | 7 +++ .../src/server_signing_key_version.rs | 15 ++++++ crates/ruma-macros/src/lib.rs | 15 +++--- crates/ruma-signatures/src/functions.rs | 10 ++-- crates/ruma-signatures/tests/tests.rs | 6 ++- crates/ruma/CHANGELOG.md | 3 ++ crates/ruma/Cargo.toml | 6 +-- 21 files changed, 196 insertions(+), 98 deletions(-) delete mode 100644 crates/ruma-common/src/identifiers/key_name.rs create mode 100644 crates/ruma-common/src/identifiers/server_signing_key_version.rs create mode 100644 crates/ruma-identifiers-validation/src/server_signing_key_version.rs diff --git a/crates/ruma-common/CHANGELOG.md b/crates/ruma-common/CHANGELOG.md index 12999062..612b2ff2 100644 --- a/crates/ruma-common/CHANGELOG.md +++ b/crates/ruma-common/CHANGELOG.md @@ -14,7 +14,17 @@ Breaking changes: query parameters. Note that the (de)serialization of the type used must work with `serde_html_form`. - The `header` attribute for the `request` and `response` macros accepts any - type that implements `ToString` and `FromStr`. + 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: diff --git a/crates/ruma-common/Cargo.toml b/crates/ruma-common/Cargo.toml index ffa9b112..c0637102 100644 --- a/crates/ruma-common/Cargo.toml +++ b/crates/ruma-common/Cargo.toml @@ -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. diff --git a/crates/ruma-common/src/identifiers.rs b/crates/ruma-common/src/identifiers.rs index d2fdbecf..7bbe2609 100644 --- a/crates/ruma-common/src/identifiers.rs +++ b/crates/ruma-common/src/identifiers.rs @@ -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() }; } diff --git a/crates/ruma-common/src/identifiers/device_id.rs b/crates/ruma-common/src/identifiers/device_id.rs index c8babb18..d6e7bdea 100644 --- a/crates/ruma-common/src/identifiers/device_id.rs +++ b/crates/ruma-common/src/identifiers/device_id.rs @@ -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}; diff --git a/crates/ruma-common/src/identifiers/key_id.rs b/crates/ruma-common/src/identifiers/key_id.rs index f799fa01..8dcea5d5 100644 --- a/crates/ruma-common/src/identifiers/key_id.rs +++ b/crates/ruma-common/src/identifiers/key_id.rs @@ -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(PhantomData<(A, K)>, str); +#[ruma_id( + validate = ruma_identifiers_validation::key_id::validate::, +)] +pub struct KeyId(PhantomData<(A, K)>, str); -impl KeyId { +impl KeyId { /// Creates a new `KeyId` from an algorithm and key name. - pub fn from_parts(algorithm: A, key_name: &K) -> OwnedKeyId - where - A: AsRef, - K: AsRef, - { + pub fn from_parts(algorithm: A, key_name: &K) -> OwnedKeyId { let algorithm = algorithm.as_ref(); let key_name = key_name.as_ref(); @@ -34,19 +31,16 @@ impl KeyId { } /// 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 = KeyId; pub type OwnedSigningKeyId = OwnedKeyId; /// Algorithm + key name for homeserver signing keys. -pub type ServerSigningKeyId = SigningKeyId; +pub type ServerSigningKeyId = SigningKeyId; /// Algorithm + key name for homeserver signing keys. -pub type OwnedServerSigningKeyId = OwnedSigningKeyId; +pub type OwnedServerSigningKeyId = OwnedSigningKeyId; /// Algorithm + key name for device keys. pub type DeviceSigningKeyId = SigningKeyId; @@ -74,28 +68,33 @@ pub type OwnedDeviceSigningKeyId = OwnedSigningKeyId; // The following impls are usually derived using the std macros. // They are implemented manually here to avoid unnecessary bounds. -impl PartialEq for KeyId { +impl PartialEq for KeyId { fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() } } -impl Eq for KeyId {} +impl Eq for KeyId {} -impl PartialOrd for KeyId { +impl PartialOrd for KeyId { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } -impl Ord for KeyId { +impl Ord for KeyId { fn cmp(&self, other: &Self) -> Ordering { Ord::cmp(self.as_str(), other.as_str()) } } -impl Hash for KeyId { +impl Hash for KeyId { fn hash(&self, state: &mut H) { self.as_str().hash(state); } } + +/// The algorithm of a key. +pub trait KeyAlgorithm: for<'a> From<&'a str> + AsRef {} + +impl KeyAlgorithm for SigningKeyAlgorithm {} diff --git a/crates/ruma-common/src/identifiers/key_name.rs b/crates/ruma-common/src/identifiers/key_name.rs deleted file mode 100644 index 3b5ee994..00000000 --- a/crates/ruma-common/src/identifiers/key_name.rs +++ /dev/null @@ -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); diff --git a/crates/ruma-common/src/identifiers/server_signing_key_version.rs b/crates/ruma-common/src/identifiers/server_signing_key_version.rs new file mode 100644 index 00000000..4425d2df --- /dev/null +++ b/crates/ruma-common/src/identifiers/server_signing_key_version.rs @@ -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) + } +} diff --git a/crates/ruma-common/src/identifiers/signatures.rs b/crates/ruma-common/src/identifiers/signatures.rs index 05446363..167836f0 100644 --- a/crates/ruma-common/src/identifiers/signatures.rs +++ b/crates/ruma-common/src/identifiers/signatures.rs @@ -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 = BTreeMap, String>; @@ -10,8 +13,11 @@ pub type EntitySignatures = BTreeMap, 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 = BTreeMap, String>; /// ``` #[derive(Clone, Debug, Default, Serialize, Deserialize)] #[serde(transparent)] -pub struct Signatures(BTreeMap>); +pub struct Signatures(BTreeMap>); -impl Signatures { +impl Signatures { /// Creates an empty signature map. pub fn new() -> Self { Self(BTreeMap::new()) @@ -51,7 +57,7 @@ impl Signatures { } /// Map of server signatures for an event, grouped by server. -pub type ServerSignatures = Signatures; +pub type ServerSignatures = Signatures; /// Map of device signatures for an event, grouped by user. pub type DeviceSignatures = Signatures; diff --git a/crates/ruma-common/tests/it/identifiers/ui/01-valid-id-macros.rs b/crates/ruma-common/tests/it/identifiers/ui/01-valid-id-macros.rs index ea635b0d..9867c581 100644 --- a/crates/ruma-common/tests/it/identifiers/ui/01-valid-id-macros.rs +++ b/crates/ruma-common/tests/it/identifiers/ui/01-valid-id-macros.rs @@ -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"); diff --git a/crates/ruma-events/src/room/member.rs b/crates/ruma-events/src/room/member.rs index 4f34e631..0bd23808 100644 --- a/crates/ruma-events/src/room/member.rs +++ b/crates/ruma-events/src/room/member.rs @@ -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() } } ); diff --git a/crates/ruma-events/tests/it/pdu.rs b/crates/ruma-events/tests/it/pdu.rs index 9c078045..6945b015 100644 --- a/crates/ruma-events/tests/it/pdu.rs +++ b/crates/ruma-events/tests/it/pdu.rs @@ -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); diff --git a/crates/ruma-identifiers-validation/CHANGELOG.md b/crates/ruma-identifiers-validation/CHANGELOG.md index f8c9f623..079535d4 100644 --- a/crates/ruma-identifiers-validation/CHANGELOG.md +++ b/crates/ruma-identifiers-validation/CHANGELOG.md @@ -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: diff --git a/crates/ruma-identifiers-validation/Cargo.toml b/crates/ruma-identifiers-validation/Cargo.toml index a4cc6d60..05d9a5cf 100644 --- a/crates/ruma-identifiers-validation/Cargo.toml +++ b/crates/ruma-identifiers-validation/Cargo.toml @@ -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. diff --git a/crates/ruma-identifiers-validation/src/key_id.rs b/crates/ruma-identifiers-validation/src/key_id.rs index 8c5f7394..2845a0ca 100644 --- a/crates/ruma-identifiers-validation/src/key_id.rs +++ b/crates/ruma-identifiers-validation/src/key_id.rs @@ -1,24 +1,12 @@ use std::num::NonZeroU8; -use crate::Error; +use crate::{Error, KeyName}; -pub fn validate(s: &str) -> Result { +pub fn validate(s: &str) -> Result { 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(()) -} diff --git a/crates/ruma-identifiers-validation/src/lib.rs b/crates/ruma-identifiers-validation/src/lib.rs index 50f86d57..1d845c56 100644 --- a/crates/ruma-identifiers-validation/src/lib.rs +++ b/crates/ruma-identifiers-validation/src/lib.rs @@ -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 { + /// Validate the given string for this name. + fn validate(s: &str) -> Result<(), Error>; +} diff --git a/crates/ruma-identifiers-validation/src/server_signing_key_version.rs b/crates/ruma-identifiers-validation/src/server_signing_key_version.rs new file mode 100644 index 00000000..a5b7d026 --- /dev/null +++ b/crates/ruma-identifiers-validation/src/server_signing_key_version.rs @@ -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(()) +} diff --git a/crates/ruma-macros/src/lib.rs b/crates/ruma-macros/src/lib.rs index 74278dc4..355488a5 100644 --- a/crates/ruma-macros/src/lib.rs +++ b/crates/ruma-macros/src/lib.rs @@ -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() diff --git a/crates/ruma-signatures/src/functions.rs b/crates/ruma-signatures/src/functions.rs index 605cdf74..a2be550f 100644 --- a/crates/ruma-signatures/src/functions.rs +++ b/crates/ruma-signatures/src/functions.rs @@ -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); diff --git a/crates/ruma-signatures/tests/tests.rs b/crates/ruma-signatures/tests/tests.rs index 8386a073..00afd206 100644 --- a/crates/ruma-signatures/tests/tests.rs +++ b/crates/ruma-signatures/tests/tests.rs @@ -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); } diff --git a/crates/ruma/CHANGELOG.md b/crates/ruma/CHANGELOG.md index 59a9c6c2..c51dab08 100644 --- a/crates/ruma/CHANGELOG.md +++ b/crates/ruma/CHANGELOG.md @@ -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. diff --git a/crates/ruma/Cargo.toml b/crates/ruma/Cargo.toml index 3f2c6ec0..ce196656 100644 --- a/crates/ruma/Cargo.toml +++ b/crates/ruma/Cargo.toml @@ -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.