identifiers: Differentiate one-time and fallback keys from device keys

Move the `DeviceKeyAlgorithm::SignedCurve25519` into the new
`OneTimeKeyAlgorithm` type.
Add `(Owned)OneTimeKeyId` and `(Owned)OneTimeKeyName` instead of using
`(Owned)DeviceKeyId`.
This commit is contained in:
Kévin Commaille 2024-10-10 10:27:31 +02:00 committed by strawberry
parent 263ddb6545
commit 09ff0b2819
17 changed files with 130 additions and 51 deletions

View File

@ -1,5 +1,11 @@
# [unreleased]
Breaking changes:
- Use `OwnedOneTimeKeyId` and `OneTimeKeyAlgorithm` instead of
`OwnedDeviceKeyId` and `DeviceKeyAlgorithm` respectively to identify one-time
and fallback keys and their algorithm.
# 0.10.0
Breaking changes:

View File

@ -30,7 +30,7 @@ pub mod v1 {
presence::PresenceState, serde::from_raw_json_value, OwnedEventId, OwnedRoomId,
};
#[cfg(feature = "unstable-msc3202")]
use ruma_common::{DeviceKeyAlgorithm, OwnedDeviceId};
use ruma_common::{OneTimeKeyAlgorithm, OwnedDeviceId};
use ruma_events::AnyTimelineEvent;
#[cfg(feature = "unstable-msc2409")]
use ruma_events::{receipt::Receipt, AnyToDeviceEvent};
@ -80,7 +80,7 @@ pub mod v1 {
rename = "org.matrix.msc3202.device_one_time_keys_count"
)]
pub device_one_time_keys_count:
BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, BTreeMap<DeviceKeyAlgorithm, UInt>>>,
BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, BTreeMap<OneTimeKeyAlgorithm, UInt>>>,
/// A list of key algorithms for which the server has an unused fallback key for the
/// device.
@ -91,7 +91,7 @@ pub mod v1 {
rename = "org.matrix.msc3202.device_unused_fallback_key_types"
)]
pub device_unused_fallback_key_types:
BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<DeviceKeyAlgorithm>>>,
BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<OneTimeKeyAlgorithm>>>,
/// A list of EDUs.
#[cfg(feature = "unstable-msc2409")]

View File

@ -16,6 +16,11 @@ Breaking changes:
- Remove `RuleScope`, due to a clarification in the Matrix 1.12 where the `global`
scope is now hardcoded.
- The `push` endpoints don't take a scope anymore.
- Make `Content-Type` and `Content-Disposition` mandatory when creating media
responses, according to MSC2701 / MSC2702 / Matrix 1.12.
- Use `OwnedOneTimeKeyId` and `OneTimeKeyAlgorithm` instead of
`OwnedDeviceKeyId` and `DeviceKeyAlgorithm` respectively to identify one-time
and fallback keys and their algorithm.
Improvements:

View File

@ -14,7 +14,7 @@ pub mod unstable {
encryption::{DeviceKeys, OneTimeKey},
metadata,
serde::Raw,
OwnedDeviceId, OwnedDeviceKeyId,
OwnedDeviceId, OwnedOneTimeKeyId,
};
use crate::dehydrated_device::DehydratedDeviceData;
@ -46,11 +46,11 @@ pub mod unstable {
/// One-time public keys for "pre-key" messages.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub one_time_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
pub one_time_keys: BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>,
/// Fallback public keys for "pre-key" messages.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub fallback_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
pub fallback_keys: BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>,
}
/// Response type for the `upload_keys` endpoint.

View File

@ -9,7 +9,7 @@ use ruma_common::{
encryption::OneTimeKey,
metadata,
serde::Raw,
DeviceKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId, OwnedUserId,
OneTimeKeyAlgorithm, OwnedDeviceId, OwnedOneTimeKeyId, OwnedUserId,
};
use serde_json::Value as JsonValue;
@ -36,7 +36,7 @@ pub struct Request {
pub timeout: Option<Duration>,
/// The keys to be claimed.
pub one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>>,
pub one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
}
/// Response type for the `claim_keys` endpoint.
@ -55,7 +55,7 @@ pub struct Response {
impl Request {
/// Creates a new `Request` with the given key claims and the recommended 10 second timeout.
pub fn new(
one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>>,
one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>,
) -> Self {
Self { timeout: Some(Duration::from_secs(10)), one_time_keys }
}
@ -69,4 +69,4 @@ impl Response {
}
/// The one-time keys for a given device.
pub type OneTimeKeys = BTreeMap<OwnedDeviceId, BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>>;
pub type OneTimeKeys = BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>;

View File

@ -9,7 +9,7 @@ use ruma_common::{
encryption::OneTimeKey,
metadata,
serde::Raw,
DeviceKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId, OwnedUserId,
OneTimeKeyAlgorithm, OwnedDeviceId, OwnedOneTimeKeyId, OwnedUserId,
};
use serde_json::Value as JsonValue;
@ -35,7 +35,7 @@ pub struct Request {
pub timeout: Option<Duration>,
/// The keys to be claimed.
pub one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<DeviceKeyAlgorithm>>>,
pub one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<OneTimeKeyAlgorithm>>>,
}
/// Response type for the `claim_keys` endpoint.
@ -54,7 +54,7 @@ pub struct Response {
impl Request {
/// Creates a new `Request` with the given key claims and the recommended 10 second timeout.
pub fn new(
one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<DeviceKeyAlgorithm>>>,
one_time_keys: BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, Vec<OneTimeKeyAlgorithm>>>,
) -> Self {
Self { timeout: Some(Duration::from_secs(10)), one_time_keys }
}
@ -68,4 +68,4 @@ impl Response {
}
/// The one-time keys for a given device.
pub type OneTimeKeys = BTreeMap<OwnedDeviceId, BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>>;
pub type OneTimeKeys = BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>;

View File

@ -15,7 +15,7 @@ pub mod v3 {
encryption::{DeviceKeys, OneTimeKey},
metadata,
serde::Raw,
DeviceKeyAlgorithm, OwnedDeviceKeyId,
OneTimeKeyAlgorithm, OwnedOneTimeKeyId,
};
const METADATA: Metadata = metadata! {
@ -40,11 +40,11 @@ pub mod v3 {
/// One-time public keys for "pre-key" messages.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub one_time_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
pub one_time_keys: BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>,
/// Fallback public keys for "pre-key" messages.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub fallback_keys: BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>,
pub fallback_keys: BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>,
}
/// Response type for the `upload_keys` endpoint.
@ -52,7 +52,7 @@ pub mod v3 {
pub struct Response {
/// For each key algorithm, the number of unclaimed one-time keys of that
/// type currently held on the server for this device.
pub one_time_key_counts: BTreeMap<DeviceKeyAlgorithm, UInt>,
pub one_time_key_counts: BTreeMap<OneTimeKeyAlgorithm, UInt>,
}
impl Request {
@ -64,7 +64,7 @@ pub mod v3 {
impl Response {
/// Creates a new `Response` with the given one time key counts.
pub fn new(one_time_key_counts: BTreeMap<DeviceKeyAlgorithm, UInt>) -> Self {
pub fn new(one_time_key_counts: BTreeMap<OneTimeKeyAlgorithm, UInt>) -> Self {
Self { one_time_key_counts }
}
}

View File

@ -10,7 +10,7 @@ use ruma_common::{
metadata,
presence::PresenceState,
serde::Raw,
DeviceKeyAlgorithm, OwnedEventId, OwnedRoomId, OwnedUserId,
OneTimeKeyAlgorithm, OwnedEventId, OwnedRoomId, OwnedUserId,
};
use ruma_events::{
presence::PresenceEvent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
@ -102,14 +102,13 @@ pub struct Response {
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub device_one_time_keys_count: BTreeMap<DeviceKeyAlgorithm, UInt>,
pub device_one_time_keys_count: BTreeMap<OneTimeKeyAlgorithm, UInt>,
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
/// The unused fallback key algorithms.
///
/// The presence of this field indicates that the server supports
/// fallback keys.
pub device_unused_fallback_key_types: Option<Vec<DeviceKeyAlgorithm>>,
pub device_unused_fallback_key_types: Option<Vec<OneTimeKeyAlgorithm>>,
}
impl Request {

View File

@ -14,7 +14,7 @@ use ruma_common::{
metadata,
room::RoomType,
serde::{deserialize_cow_str, duration::opt_ms, Raw},
DeviceKeyAlgorithm, MilliSecondsSinceUnixEpoch, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId,
MilliSecondsSinceUnixEpoch, OneTimeKeyAlgorithm, OwnedMxcUri, OwnedRoomId, OwnedUserId, RoomId,
};
use ruma_events::{
receipt::SyncReceiptEvent, typing::SyncTypingEvent, AnyGlobalAccountDataEvent,
@ -700,15 +700,14 @@ pub struct E2EE {
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub device_one_time_keys_count: BTreeMap<DeviceKeyAlgorithm, UInt>,
pub device_one_time_keys_count: BTreeMap<OneTimeKeyAlgorithm, UInt>,
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
/// The unused fallback key algorithms.
///
/// The presence of this field indicates that the server supports
/// fallback keys.
#[serde(skip_serializing_if = "Option::is_none")]
pub device_unused_fallback_key_types: Option<Vec<DeviceKeyAlgorithm>>,
pub device_unused_fallback_key_types: Option<Vec<OneTimeKeyAlgorithm>>,
}
impl E2EE {

View File

@ -454,7 +454,7 @@ impl Response {
/// HTTP types related to a [`Response`].
pub mod response {
use ruma_common::DeviceKeyAlgorithm;
use ruma_common::OneTimeKeyAlgorithm;
use ruma_events::{
receipt::SyncReceiptEvent, typing::SyncTypingEvent, AnyGlobalAccountDataEvent,
AnyRoomAccountDataEvent, AnyToDeviceEvent,
@ -645,15 +645,14 @@ pub mod response {
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub device_one_time_keys_count: BTreeMap<DeviceKeyAlgorithm, UInt>,
pub device_one_time_keys_count: BTreeMap<OneTimeKeyAlgorithm, UInt>,
/// For each key algorithm, the number of unclaimed one-time keys
/// currently held on the server for a device.
/// The unused fallback key algorithms.
///
/// The presence of this field indicates that the server supports
/// fallback keys.
#[serde(skip_serializing_if = "Option::is_none")]
pub device_unused_fallback_key_types: Option<Vec<DeviceKeyAlgorithm>>,
pub device_unused_fallback_key_types: Option<Vec<OneTimeKeyAlgorithm>>,
}
impl E2EE {

View File

@ -27,6 +27,8 @@ Breaking changes:
`SigningKeyAlgorithm` and the `server_signing_key_version` macro.
- Rename `Signatures::insert` to `Signatures::insert_signature`.
`Signatures::insert` is now dereferenced to `BTreeMap::insert`.
- Move the `DeviceKeyAlgorithm::SignedCurve25519` into the new
`OneTimeKeyAlgorithm` type.
Improvements:
@ -45,6 +47,8 @@ Improvements:
- Improve the API of `Signatures`, by implementing `Deref` and `DerefMut`, as
well as `From`, `Extend` and `FromIterator` from a list of
`(entity, key_identifier, value)` tuples.
- Add `(Owned)OneTimeKeyId` and `(Owned)OneTimeKeyName` to identify one-time and
fallback keys instead of using `(Owned)DeviceKeyId`.
# 0.13.0

View File

@ -18,17 +18,20 @@ use serde::de::{self, Deserializer, Unexpected};
pub use self::{
client_secret::{ClientSecret, OwnedClientSecret},
crypto_algorithms::{
DeviceKeyAlgorithm, EventEncryptionAlgorithm, KeyDerivationAlgorithm, SigningKeyAlgorithm,
DeviceKeyAlgorithm, EventEncryptionAlgorithm, KeyDerivationAlgorithm, OneTimeKeyAlgorithm,
SigningKeyAlgorithm,
},
device_id::{DeviceId, OwnedDeviceId},
device_key_id::{DeviceKeyId, OwnedDeviceKeyId},
event_id::{EventId, OwnedEventId},
key_id::{
DeviceSigningKeyId, KeyAlgorithm, KeyId, OwnedDeviceSigningKeyId, OwnedKeyId,
OwnedServerSigningKeyId, OwnedSigningKeyId, ServerSigningKeyId, SigningKeyId,
DeviceSigningKeyId, KeyAlgorithm, KeyId, OneTimeKeyId, OwnedDeviceSigningKeyId, OwnedKeyId,
OwnedOneTimeKeyId, OwnedServerSigningKeyId, OwnedSigningKeyId, ServerSigningKeyId,
SigningKeyId,
},
matrix_uri::{MatrixToUri, MatrixUri},
mxc_uri::{Mxc, MxcUri, OwnedMxcUri},
one_time_key_name::{OneTimeKeyName, OwnedOneTimeKeyName},
room_alias_id::{OwnedRoomAliasId, RoomAliasId},
room_id::{OwnedRoomId, RoomId},
room_or_alias_id::{OwnedRoomOrAliasId, RoomOrAliasId},
@ -53,6 +56,7 @@ mod device_key_id;
mod event_id;
mod key_id;
mod mxc_uri;
mod one_time_key_name;
mod room_alias_id;
mod room_id;
mod room_or_alias_id;

View File

@ -4,7 +4,9 @@ use ruma_macros::StringEnum;
use crate::PrivOwnedStr;
/// The basic key algorithms in the specification.
/// The algorithms for the [device keys] defined in the Matrix spec.
///
/// [device keys]: https://spec.matrix.org/latest/client-server-api/#device-keys
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
#[non_exhaustive]
@ -16,9 +18,6 @@ pub enum DeviceKeyAlgorithm {
/// The Curve25519 ECDH algorithm.
Curve25519,
/// The Curve25519 ECDH algorithm, but the key also contains signatures
SignedCurve25519,
#[doc(hidden)]
_Custom(PrivOwnedStr),
}
@ -66,18 +65,29 @@ pub enum KeyDerivationAlgorithm {
_Custom(PrivOwnedStr),
}
/// The algorithms for [one-time and fallback keys] defined in the Matrix spec.
///
/// [one-time and fallback keys]: https://spec.matrix.org/latest/client-server-api/#one-time-and-fallback-keys
#[doc = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/src/doc/string_enum.md"))]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, StringEnum)]
#[non_exhaustive]
#[ruma_enum(rename_all = "snake_case")]
pub enum OneTimeKeyAlgorithm {
/// The Curve25519 ECDH algorithm, but the key also contains signatures.
SignedCurve25519,
#[doc(hidden)]
_Custom(PrivOwnedStr),
}
#[cfg(test)]
mod tests {
use super::{DeviceKeyAlgorithm, SigningKeyAlgorithm};
use super::{DeviceKeyAlgorithm, OneTimeKeyAlgorithm, SigningKeyAlgorithm};
#[test]
fn parse_device_key_algorithm() {
assert_eq!(DeviceKeyAlgorithm::from("ed25519"), DeviceKeyAlgorithm::Ed25519);
assert_eq!(DeviceKeyAlgorithm::from("curve25519"), DeviceKeyAlgorithm::Curve25519);
assert_eq!(
DeviceKeyAlgorithm::from("signed_curve25519"),
DeviceKeyAlgorithm::SignedCurve25519
);
}
#[test]
@ -109,4 +119,12 @@ mod tests {
serde_json_eq(KeyDerivationAlgorithm::Pbkfd2, json!("m.pbkdf2"));
}
#[test]
fn parse_one_time_key_algorithm() {
assert_eq!(
OneTimeKeyAlgorithm::from("signed_curve25519"),
OneTimeKeyAlgorithm::SignedCurve25519
);
}
}

View File

@ -6,7 +6,10 @@ use std::{
use ruma_macros::IdZst;
use super::{crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName, ServerSigningKeyVersion};
use super::{
crypto_algorithms::SigningKeyAlgorithm, DeviceId, KeyName, OneTimeKeyAlgorithm, OneTimeKeyName,
ServerSigningKeyVersion,
};
/// A key algorithm and key name delimited by a colon.
#[repr(transparent)]
@ -66,6 +69,16 @@ pub type DeviceSigningKeyId = SigningKeyId<DeviceId>;
/// Algorithm + key name for device keys.
pub type OwnedDeviceSigningKeyId = OwnedSigningKeyId<DeviceId>;
/// Algorithm + key name for [one-time and fallback keys].
///
/// [one-time and fallback keys]: https://spec.matrix.org/latest/client-server-api/#one-time-and-fallback-keys
pub type OneTimeKeyId = KeyId<OneTimeKeyAlgorithm, OneTimeKeyName>;
/// Algorithm + key name for [one-time and fallback keys].
///
/// [one-time and fallback keys]: https://spec.matrix.org/latest/client-server-api/#one-time-and-fallback-keys
pub type OwnedOneTimeKeyId = OwnedKeyId<OneTimeKeyAlgorithm, OneTimeKeyName>;
// The following impls are usually derived using the std macros.
// They are implemented manually here to avoid unnecessary bounds.
impl<A: KeyAlgorithm, K: KeyName + ?Sized> PartialEq for KeyId<A, K> {
@ -98,3 +111,5 @@ impl<A: KeyAlgorithm, K: KeyName + ?Sized> Hash for KeyId<A, K> {
pub trait KeyAlgorithm: for<'a> From<&'a str> + AsRef<str> {}
impl KeyAlgorithm for SigningKeyAlgorithm {}
impl KeyAlgorithm for OneTimeKeyAlgorithm {}

View File

@ -0,0 +1,25 @@
use ruma_macros::IdZst;
use super::{IdParseError, KeyName};
/// The name of a [one-time or fallback key].
///
/// One-time and fallback key names in Matrix are completely opaque character sequences. This
/// type is provided simply for its semantic value.
///
/// [one-time or fallback key]: https://spec.matrix.org/latest/client-server-api/#one-time-and-fallback-keys
#[repr(transparent)]
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, IdZst)]
pub struct OneTimeKeyName(str);
impl KeyName for OneTimeKeyName {
fn validate(_s: &str) -> Result<(), IdParseError> {
Ok(())
}
}
impl KeyName for OwnedOneTimeKeyName {
fn validate(_s: &str) -> Result<(), IdParseError> {
Ok(())
}
}

View File

@ -4,6 +4,9 @@ Breaking changes:
- Remove the unused `KeyObject` struct. It is actually supposed to be the same type
as `ruma_common::encryption::SignedKey`.
- Use `OwnedOneTimeKeyId` and `OneTimeKeyAlgorithm` instead of
`OwnedDeviceKeyId` and `DeviceKeyAlgorithm` respectively to identify one-time
and fallback keys and their algorithm.
Bug fixes:

View File

@ -14,7 +14,7 @@ pub mod v1 {
encryption::OneTimeKey,
metadata,
serde::Raw,
DeviceKeyAlgorithm, OwnedDeviceId, OwnedDeviceKeyId, OwnedUserId,
OneTimeKeyAlgorithm, OwnedDeviceId, OwnedOneTimeKeyId, OwnedUserId,
};
const METADATA: Metadata = metadata! {
@ -55,9 +55,11 @@ pub mod v1 {
}
/// A claim for one time keys
pub type OneTimeKeyClaims = BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, DeviceKeyAlgorithm>>;
pub type OneTimeKeyClaims = BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, OneTimeKeyAlgorithm>>;
/// One time keys for use in pre-key messages
pub type OneTimeKeys =
BTreeMap<OwnedUserId, BTreeMap<OwnedDeviceId, BTreeMap<OwnedDeviceKeyId, Raw<OneTimeKey>>>>;
pub type OneTimeKeys = BTreeMap<
OwnedUserId,
BTreeMap<OwnedDeviceId, BTreeMap<OwnedOneTimeKeyId, Raw<OneTimeKey>>>,
>;
}