ruma-events: Add the majority of in-room verification events

This patch adds equivalent in-room versions of the m.key.verfication.*
events we have for to-device events.

The MSC that adds this is found over here:
https://github.com/matrix-org/matrix-doc/pull/2241
This commit is contained in:
Damir Jelić 2020-12-03 15:36:22 +01:00 committed by Jonas Platte
parent 7ec2b0b555
commit 4afafa8b37
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
7 changed files with 363 additions and 6 deletions

View File

@ -37,6 +37,16 @@ event_enum! {
"m.call.hangup",
"m.call.candidates",
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.start",
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.cancel",
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.accept",
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.key",
#[cfg(feature = "unstable-pre-spec")]
"m.key.verification.mac",
#[cfg(feature = "unstable-pre-spec")]
"m.reaction",
"m.room.encrypted",
"m.room.message",

View File

@ -1,9 +1,22 @@
//! Modules for events in the *m.key.verification* namespace.
//!
//! This module also contains types shared by events in its child namespaces.
//!
//! The MSC for the in-room variants of the `m.key.verification.*` events can be found
//! [here](https://github.com/matrix-org/matrix-doc/pull/2241).
#[cfg(feature = "unstable-pre-spec")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "unstable-pre-spec")]
use std::convert::TryFrom;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::EventId;
use ruma_serde::StringEnum;
#[cfg(feature = "unstable-pre-spec")]
use crate::room::relationships::{Reference, RelatesToJsonRepr, RelationJsonRepr};
pub mod accept;
pub mod cancel;
pub mod key;
@ -64,6 +77,37 @@ pub enum ShortAuthenticationString {
_Custom(String),
}
/// The relation that contains info which event the reaction is applying to.
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(try_from = "RelatesToJsonRepr", into = "RelatesToJsonRepr")]
#[cfg(feature = "unstable-pre-spec")]
pub struct Relation {
/// The event that is being referenced.
pub event_id: EventId,
}
#[cfg(feature = "unstable-pre-spec")]
impl From<Relation> for RelatesToJsonRepr {
fn from(relation: Relation) -> Self {
RelatesToJsonRepr::Relation(RelationJsonRepr::Reference(Reference {
event_id: relation.event_id,
}))
}
}
#[cfg(feature = "unstable-pre-spec")]
impl TryFrom<RelatesToJsonRepr> for Relation {
type Error = &'static str;
fn try_from(value: RelatesToJsonRepr) -> Result<Self, Self::Error> {
if let RelatesToJsonRepr::Relation(RelationJsonRepr::Reference(r)) = value {
Ok(Relation { event_id: r.event_id })
} else {
Err("Expected a relation with a rel_type of `reference`")
}
}
}
/// A Short Authentication String (SAS) verification method.
#[derive(Clone, Debug, PartialEq, Eq, StringEnum)]
pub enum VerificationMethod {

View File

@ -3,6 +3,8 @@
use std::collections::BTreeMap;
use ruma_events_macros::BasicEventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events_macros::MessageEventContent;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
@ -10,7 +12,17 @@ use super::{
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, ShortAuthenticationString,
};
/// The payload for `AcceptEvent`.
#[cfg(feature = "unstable-pre-spec")]
use super::Relation;
#[cfg(feature = "unstable-pre-spec")]
use crate::MessageEvent;
/// Accepts a previously sent *m.key.verification.start* message.
#[cfg(feature = "unstable-pre-spec")]
pub type AcceptEvent = MessageEvent<AcceptEventContent>;
/// The payload for a to-device `AcceptEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.key.verification.accept")]
pub struct AcceptToDeviceEventContent {
@ -25,6 +37,20 @@ pub struct AcceptToDeviceEventContent {
pub method: AcceptMethod,
}
/// The payload for a in-room `AcceptEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
#[ruma_event(type = "m.key.verification.accept")]
#[cfg(feature = "unstable-pre-spec")]
pub struct AcceptEventContent {
/// The method specific content.
#[serde(flatten)]
pub method: AcceptMethod,
/// Information about the related event.
#[serde(rename = "m.relates_to")]
pub relation: Relation,
}
/// An enum representing the different method specific
/// *m.key.verification.accept* content.
#[derive(Clone, Debug, Deserialize, Serialize)]
@ -124,12 +150,16 @@ mod tests {
use std::collections::BTreeMap;
use matches::assert_matches;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::event_id;
use ruma_identifiers::user_id;
use ruma_serde::Raw;
use serde_json::{
from_value as from_json_value, json, to_value as to_json_value, Value as JsonValue,
};
#[cfg(feature = "unstable-pre-spec")]
use super::{AcceptEventContent, Relation};
use super::{
AcceptMethod, AcceptToDeviceEventContent, CustomContent, HashAlgorithm,
KeyAgreementProtocol, MSasV1Content, MessageAuthenticationCode, ShortAuthenticationString,
@ -198,6 +228,38 @@ mod tests {
assert_eq!(to_json_value(&key_verification_accept).unwrap(), json_data);
}
#[test]
#[cfg(feature = "unstable-pre-spec")]
fn in_room_serialization() {
let event_id = event_id!("$1598361704261elfgc:localhost");
let key_verification_accept_content = AcceptEventContent {
relation: Relation { event_id: event_id.clone() },
method: AcceptMethod::MSasV1(MSasV1Content {
hash: HashAlgorithm::Sha256,
key_agreement_protocol: KeyAgreementProtocol::Curve25519,
message_authentication_code: MessageAuthenticationCode::HkdfHmacSha256,
short_authentication_string: vec![ShortAuthenticationString::Decimal],
commitment: "test_commitment".into(),
}),
};
let json_data = json!({
"method": "m.sas.v1",
"commitment": "test_commitment",
"key_agreement_protocol": "curve25519",
"hash": "sha256",
"message_authentication_code": "hkdf-hmac-sha256",
"short_authentication_string": ["decimal"],
"m.relates_to": {
"rel_type": "m.reference",
"event_id": event_id,
}
});
assert_eq!(to_json_value(&key_verification_accept_content).unwrap(), json_data);
}
#[test]
fn deserialization() {
let json = json!({
@ -308,4 +370,48 @@ mod tests {
&& fields.get("test").unwrap() == &JsonValue::from("field")
);
}
#[test]
#[cfg(feature = "unstable-pre-spec")]
fn in_room_deserialization() {
let id = event_id!("$1598361704261elfgc:localhost");
let json = json!({
"commitment": "test_commitment",
"method": "m.sas.v1",
"hash": "sha256",
"key_agreement_protocol": "curve25519",
"message_authentication_code": "hkdf-hmac-sha256",
"short_authentication_string": ["decimal"],
"m.relates_to": {
"rel_type": "m.reference",
"event_id": id,
}
});
// Deserialize the content struct separately to verify `TryFromRaw` is implemented for it.
assert_matches!(
from_json_value::<Raw<AcceptEventContent>>(json)
.unwrap()
.deserialize()
.unwrap(),
AcceptEventContent {
relation: Relation {
event_id
},
method: AcceptMethod::MSasV1(MSasV1Content {
commitment,
hash,
key_agreement_protocol,
message_authentication_code,
short_authentication_string,
})
} if commitment == "test_commitment"
&& event_id == id
&& hash == HashAlgorithm::Sha256
&& key_agreement_protocol == KeyAgreementProtocol::Curve25519
&& message_authentication_code == MessageAuthenticationCode::HkdfHmacSha256
&& short_authentication_string == vec![ShortAuthenticationString::Decimal]
);
}
}

View File

@ -1,10 +1,22 @@
//! Types for the *m.key.verification.cancel* event.
use ruma_events_macros::BasicEventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events_macros::MessageEventContent;
use ruma_serde::StringEnum;
use serde::{Deserialize, Serialize};
/// The payload for `CancelEvent`.
#[cfg(feature = "unstable-pre-spec")]
use crate::MessageEvent;
#[cfg(feature = "unstable-pre-spec")]
use super::Relation;
/// Cancels a key verification process/request.
#[cfg(feature = "unstable-pre-spec")]
pub type CancelEvent = MessageEvent<CancelEventContent>;
/// The payload for a to-device `CancelEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.key.verification.cancel")]
pub struct CancelToDeviceEventContent {
@ -20,6 +32,24 @@ pub struct CancelToDeviceEventContent {
pub code: CancelCode,
}
/// The payload for an in-room `CancelEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
#[ruma_event(type = "m.key.verification.cancel")]
#[cfg(feature = "unstable-pre-spec")]
pub struct CancelEventContent {
/// A human readable description of the `code`.
///
/// The client should only rely on this string if it does not understand the `code`.
pub reason: String,
/// The error code for why the process/request was cancelled by the user.
pub code: CancelCode,
/// Information about the related event.
#[serde(rename = "m.relates_to")]
pub relation: Relation,
}
/// An error code for why the process/request was cancelled by the user.
///
/// Custom error codes should use the Java package naming convention.

View File

@ -1,9 +1,21 @@
//! Types for the *m.key.verification.key* event.
use ruma_events_macros::BasicEventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events_macros::MessageEventContent;
use serde::{Deserialize, Serialize};
/// The payload for `KeyEvent`.
#[cfg(feature = "unstable-pre-spec")]
use super::Relation;
#[cfg(feature = "unstable-pre-spec")]
use crate::MessageEvent;
/// Sends the ephemeral public key for a device to the partner device.
#[cfg(feature = "unstable-pre-spec")]
pub type KeyEvent = MessageEvent<KeyEventContent>;
/// The payload for a to-device `KeyEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.key.verification.key")]
pub struct KeyToDeviceEventContent {
@ -15,3 +27,16 @@ pub struct KeyToDeviceEventContent {
/// The device's ephemeral public key, encoded as unpadded Base64.
pub key: String,
}
/// The payload for in-room `KeyEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
#[ruma_event(type = "m.key.verification.key")]
#[cfg(feature = "unstable-pre-spec")]
pub struct KeyEventContent {
/// The device's ephemeral public key, encoded as unpadded Base64.
pub key: String,
/// Information about the related event.
#[serde(rename = "m.relates_to")]
pub relation: Relation,
}

View File

@ -3,9 +3,21 @@
use std::collections::BTreeMap;
use ruma_events_macros::BasicEventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events_macros::MessageEventContent;
use serde::{Deserialize, Serialize};
/// The payload for `MacEvent`.
#[cfg(feature = "unstable-pre-spec")]
use super::Relation;
#[cfg(feature = "unstable-pre-spec")]
use crate::MessageEvent;
/// Sends the MAC of a device's key to the partner device.
#[cfg(feature = "unstable-pre-spec")]
pub type MacEvent = MessageEvent<MacEventContent>;
/// The payload for a to-device `MacEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.key.verification.mac")]
pub struct MacToDeviceEventContent {
@ -23,3 +35,22 @@ pub struct MacToDeviceEventContent {
/// encoded as unpadded Base64.
pub keys: String,
}
/// The payload for an in-room `MacEvent`.
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
#[ruma_event(type = "m.key.verification.mac")]
#[cfg(feature = "unstable-pre-spec")]
pub struct MacEventContent {
/// A map of the key ID to the MAC of the key, using the algorithm in the verification process.
///
/// The MAC is encoded as unpadded Base64.
pub mac: BTreeMap<String, String>,
/// The MAC of the comma-separated, sorted, list of key IDs given in the `mac` property,
/// encoded as unpadded Base64.
pub keys: String,
/// Information about the related event.
#[serde(rename = "m.relates_to")]
pub relation: Relation,
}

View File

@ -3,16 +3,27 @@
use std::{collections::BTreeMap, convert::TryFrom};
use ruma_events_macros::BasicEventContent;
#[cfg(feature = "unstable-pre-spec")]
use ruma_events_macros::MessageEventContent;
use ruma_identifiers::DeviceIdBox;
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;
#[cfg(feature = "unstable-pre-spec")]
use super::Relation;
use super::{
HashAlgorithm, KeyAgreementProtocol, MessageAuthenticationCode, ShortAuthenticationString,
};
use crate::InvalidInput;
/// The payload of an *m.key.verification.start* event.
use crate::InvalidInput;
#[cfg(feature = "unstable-pre-spec")]
use crate::MessageEvent;
/// Begins an SAS key verification process.
#[cfg(feature = "unstable-pre-spec")]
pub type StartEvent = MessageEvent<StartEventContent>;
/// The payload of a to-device *m.key.verification.start* event.
#[derive(Clone, Debug, Deserialize, Serialize, BasicEventContent)]
#[ruma_event(type = "m.key.verification.start")]
pub struct StartToDeviceEventContent {
@ -31,6 +42,23 @@ pub struct StartToDeviceEventContent {
pub method: StartMethod,
}
/// The payload of an in-room *m.key.verification.start* event.
#[derive(Clone, Debug, Deserialize, Serialize, MessageEventContent)]
#[ruma_event(type = "m.key.verification.start")]
#[cfg(feature = "unstable-pre-spec")]
pub struct StartEventContent {
/// The device ID which is initiating the process.
pub from_device: DeviceIdBox,
/// Method specific content.
#[serde(flatten)]
pub method: StartMethod,
/// Information about the related event.
#[serde(rename = "m.relates_to")]
pub relation: Relation,
}
/// An enum representing the different method specific
/// *m.key.verification.start* content.
#[derive(Clone, Debug, Deserialize, Serialize)]
@ -174,6 +202,8 @@ mod tests {
use std::collections::BTreeMap;
use matches::assert_matches;
#[cfg(feature = "unstable-pre-spec")]
use ruma_identifiers::event_id;
use ruma_identifiers::user_id;
use ruma_serde::Raw;
use serde_json::{
@ -185,6 +215,8 @@ mod tests {
MessageAuthenticationCode, ShortAuthenticationString, StartMethod,
StartToDeviceEventContent,
};
#[cfg(feature = "unstable-pre-spec")]
use super::{Relation, StartEventContent};
use crate::ToDeviceEvent;
#[test]
@ -310,6 +342,41 @@ mod tests {
assert_eq!(to_json_value(&key_verification_start).unwrap(), json_data);
}
#[test]
#[cfg(feature = "unstable-pre-spec")]
fn in_room_serialization() {
let event_id = event_id!("$1598361704261elfgc:localhost");
let key_verification_start_content = StartEventContent {
from_device: "123".into(),
relation: Relation { event_id: event_id.clone() },
method: StartMethod::MSasV1(
MSasV1Content::new(MSasV1ContentInit {
hashes: vec![HashAlgorithm::Sha256],
key_agreement_protocols: vec![KeyAgreementProtocol::Curve25519],
message_authentication_codes: vec![MessageAuthenticationCode::HkdfHmacSha256],
short_authentication_string: vec![ShortAuthenticationString::Decimal],
})
.unwrap(),
),
};
let json_data = json!({
"from_device": "123",
"method": "m.sas.v1",
"key_agreement_protocols": ["curve25519"],
"hashes": ["sha256"],
"message_authentication_codes": ["hkdf-hmac-sha256"],
"short_authentication_string": ["decimal"],
"m.relates_to": {
"rel_type": "m.reference",
"event_id": event_id,
}
});
assert_eq!(to_json_value(&key_verification_start_content).unwrap(), json_data);
}
#[test]
fn deserialization() {
let json = json!({
@ -423,6 +490,50 @@ mod tests {
);
}
#[test]
#[cfg(feature = "unstable-pre-spec")]
fn in_room_deserialization() {
let id = event_id!("$1598361704261elfgc:localhost");
let json = json!({
"from_device": "123",
"method": "m.sas.v1",
"hashes": ["sha256"],
"key_agreement_protocols": ["curve25519"],
"message_authentication_codes": ["hkdf-hmac-sha256"],
"short_authentication_string": ["decimal"],
"m.relates_to": {
"rel_type": "m.reference",
"event_id": id,
}
});
// Deserialize the content struct separately to verify `TryFromRaw` is implemented for it.
assert_matches!(
from_json_value::<Raw<StartEventContent>>(json)
.unwrap()
.deserialize()
.unwrap(),
StartEventContent {
from_device,
relation: Relation {
event_id,
},
method: StartMethod::MSasV1(MSasV1Content {
hashes,
key_agreement_protocols,
message_authentication_codes,
short_authentication_string,
})
} if from_device == "123"
&& event_id == id
&& hashes == vec![HashAlgorithm::Sha256]
&& key_agreement_protocols == vec![KeyAgreementProtocol::Curve25519]
&& message_authentication_codes == vec![MessageAuthenticationCode::HkdfHmacSha256]
&& short_authentication_string == vec![ShortAuthenticationString::Decimal]
);
}
#[test]
fn deserialization_failure() {
// Ensure that invalid JSON creates a `serde_json::Error` and not `InvalidEvent`