Convert m.room.encrypted to the new API.

This commit is contained in:
Jimmy Cuadra 2019-06-22 00:50:40 -07:00
parent 0f49c5e7f6
commit 21351aaff0
2 changed files with 254 additions and 61 deletions

View File

@ -11,7 +11,7 @@ pub mod aliases;
pub mod avatar;
pub mod canonical_alias;
pub mod create;
// pub mod encrypted;
pub mod encrypted;
pub mod encryption;
pub mod guest_access;
pub mod history_visibility;

View File

@ -1,21 +1,41 @@
//! Types for the *m.room.encrypted* event.
use std::{convert::TryFrom, str::FromStr};
use js_int::UInt;
use ruma_identifiers::DeviceId;
use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
use ruma_identifiers::{DeviceId, EventId, RoomId, UserId};
use serde::{de::Error, ser::SerializeStruct, Deserialize, Deserializer, Serialize, Serializer};
use serde_json::{from_value, Value};
use crate::Algorithm;
use crate::{Algorithm, Event, EventType, InvalidEvent, RoomEvent, StateEvent};
room_event! {
/// This event type is used when sending encrypted events.
///
/// This type is to be used within a room. For a to-device event, use `EncryptedEventContent`
/// directly.
pub struct EncryptedEvent(EncryptedEventContent) {}
/// This event type is used when sending encrypted events.
///
/// This type is to be used within a room. For a to-device event, use `EncryptedEventContent`
/// directly.
#[derive(Clone, Debug, PartialEq)]
pub struct EncryptedEvent {
/// The event's content.
pub content: EncryptedEventContent,
/// The unique identifier for the event.
pub event_id: EventId,
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
/// event was sent.
pub origin_server_ts: UInt,
/// The unique identifier for the room associated with this event.
pub room_id: Option<RoomId>,
/// The unique identifier for the user who sent this event.
pub sender: UserId,
/// Additional key-value pairs not signed by the homeserver.
pub unsigned: Option<Value>,
}
/// The payload of an *m.room.encrypted* event.
/// The payload for `EncryptedEvent`.
#[derive(Clone, Debug, PartialEq)]
pub enum EncryptedEventContent {
/// An event encrypted with *m.olm.v1.curve25519-aes-sha2*.
@ -30,7 +50,224 @@ pub enum EncryptedEventContent {
__Nonexhaustive,
}
/// The payload of an *m.room.encrypted* event using the *m.olm.v1.curve25519-aes-sha2* algorithm.
impl FromStr for EncryptedEvent {
type Err = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn from_str(json: &str) -> Result<Self, Self::Err> {
let raw = serde_json::from_str::<raw::EncryptedEvent>(json)?;
let content = match raw.content {
raw::EncryptedEventContent::OlmV1Curve25519AesSha2(content) => {
EncryptedEventContent::OlmV1Curve25519AesSha2(content)
}
raw::EncryptedEventContent::MegolmV1AesSha2(content) => {
EncryptedEventContent::MegolmV1AesSha2(content)
}
raw::EncryptedEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.");
}
};
Ok(Self {
content: content,
event_id: raw.event_id,
origin_server_ts: raw.origin_server_ts,
room_id: raw.room_id,
sender: raw.sender,
unsigned: raw.unsigned,
})
}
}
impl<'a> TryFrom<&'a str> for EncryptedEvent {
type Error = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn try_from(json: &'a str) -> Result<Self, Self::Error> {
FromStr::from_str(json)
}
}
impl Serialize for EncryptedEvent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut len = 6;
if self.room_id.is_some() {
len += 1;
}
if self.unsigned.is_some() {
len += 1;
}
let mut state = serializer.serialize_struct("EncryptedEvent", len)?;
state.serialize_field("content", &self.content)?;
state.serialize_field("event_id", &self.event_id)?;
state.serialize_field("origin_server_ts", &self.origin_server_ts)?;
if self.room_id.is_some() {
state.serialize_field("room_id", &self.room_id)?;
}
if self.unsigned.is_some() {
state.serialize_field("unsigned", &self.unsigned)?;
}
state.serialize_field("sender", &self.sender)?;
state.serialize_field("type", &self.event_type())?;
state.end()
}
}
impl_room_event!(
EncryptedEvent,
EncryptedEventContent,
EventType::RoomEncrypted
);
impl FromStr for EncryptedEventContent {
type Err = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn from_str(json: &str) -> Result<Self, Self::Err> {
let raw = serde_json::from_str::<raw::EncryptedEventContent>(json)?;
match raw {
raw::EncryptedEventContent::OlmV1Curve25519AesSha2(content) => {
Ok(EncryptedEventContent::OlmV1Curve25519AesSha2(content))
}
raw::EncryptedEventContent::MegolmV1AesSha2(content) => {
Ok(EncryptedEventContent::MegolmV1AesSha2(content))
}
raw::EncryptedEventContent::__Nonexhaustive => {
panic!("__Nonexhaustive enum variant is not intended for use.");
}
}
}
}
impl<'a> TryFrom<&'a str> for EncryptedEventContent {
type Error = InvalidEvent;
/// Attempt to create `Self` from parsing a string of JSON data.
fn try_from(json: &'a str) -> Result<Self, Self::Error> {
FromStr::from_str(json)
}
}
mod raw {
use super::*;
/// This event type is used when sending encrypted events.
///
/// This type is to be used within a room. For a to-device event, use `EncryptedEventContent`
/// directly.
#[derive(Clone, Debug, Deserialize, PartialEq)]
pub struct EncryptedEvent {
/// The event's content.
pub content: EncryptedEventContent,
/// The unique identifier for the event.
pub event_id: EventId,
/// Timestamp (milliseconds since the UNIX epoch) on originating homeserver when this
/// event was sent.
pub origin_server_ts: UInt,
/// The unique identifier for the room associated with this event.
pub room_id: Option<RoomId>,
/// The unique identifier for the user who sent this event.
pub sender: UserId,
/// Additional key-value pairs not signed by the homeserver.
pub unsigned: Option<Value>,
}
/// The payload for `EncryptedEvent`.
#[derive(Clone, Debug, PartialEq)]
pub enum EncryptedEventContent {
/// An event encrypted with *m.olm.v1.curve25519-aes-sha2*.
OlmV1Curve25519AesSha2(OlmV1Curve25519AesSha2Content),
/// An event encrypted with *m.megolm.v1.aes-sha2*.
MegolmV1AesSha2(MegolmV1AesSha2Content),
/// Additional variants may be added in the future and will not be considered breaking
/// changes to ruma-events.
#[doc(hidden)]
__Nonexhaustive,
}
impl Serialize for EncryptedEventContent {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
EncryptedEventContent::OlmV1Curve25519AesSha2(ref content) => {
content.serialize(serializer)
}
EncryptedEventContent::MegolmV1AesSha2(ref content) => {
content.serialize(serializer)
}
_ => panic!("Attempted to serialize __Nonexhaustive variant."),
}
}
}
impl<'de> Deserialize<'de> for EncryptedEventContent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: Value = Deserialize::deserialize(deserializer)?;
let method_value = match value.get("algorithm") {
Some(value) => value.clone(),
None => return Err(D::Error::missing_field("algorithm")),
};
let method = match from_value::<Algorithm>(method_value.clone()) {
Ok(method) => method,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
match method {
Algorithm::OlmV1Curve25519AesSha2 => {
let content = match from_value::<OlmV1Curve25519AesSha2Content>(value) {
Ok(content) => content,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
Ok(EncryptedEventContent::OlmV1Curve25519AesSha2(content))
}
Algorithm::MegolmV1AesSha2 => {
let content = match from_value::<MegolmV1AesSha2Content>(value) {
Ok(content) => content,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
Ok(EncryptedEventContent::MegolmV1AesSha2(content))
}
Algorithm::Custom(_) => Err(D::Error::custom(
"Custom algorithms are not supported by `EncryptedEventContent`.",
)),
Algorithm::__Nonexhaustive => Err(D::Error::custom(
"Attempted to deserialize __Nonexhaustive variant.",
)),
}
}
}
}
/// The payload for `EncryptedEvent` using the *m.olm.v1.curve25519-aes-sha2* algorithm.
#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)]
pub struct OlmV1Curve25519AesSha2Content {
/// The encryption algorithm used to encrypt this event.
@ -56,7 +293,7 @@ pub struct CiphertextInfo {
pub message_type: UInt,
}
/// The payload of an *m.room.encrypted* event using the *m.megolm.v1.aes-sha2* algorithm.
/// The payload for `EncryptedEvent` using the *m.megolm.v1.aes-sha2* algorithm.
#[derive(Clone, Debug, Serialize, PartialEq, Deserialize)]
pub struct MegolmV1AesSha2Content {
/// The encryption algorithm used to encrypt this event.
@ -90,52 +327,9 @@ impl Serialize for EncryptedEventContent {
}
}
impl<'de> Deserialize<'de> for EncryptedEventContent {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value: Value = Deserialize::deserialize(deserializer)?;
let method_value = match value.get("algorithm") {
Some(value) => value.clone(),
None => return Err(D::Error::missing_field("algorithm")),
};
let method = match from_value::<Algorithm>(method_value.clone()) {
Ok(method) => method,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
match method {
Algorithm::OlmV1Curve25519AesSha2 => {
let content = match from_value::<OlmV1Curve25519AesSha2Content>(value) {
Ok(content) => content,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
Ok(EncryptedEventContent::OlmV1Curve25519AesSha2(content))
}
Algorithm::MegolmV1AesSha2 => {
let content = match from_value::<MegolmV1AesSha2Content>(value) {
Ok(content) => content,
Err(error) => return Err(D::Error::custom(error.to_string())),
};
Ok(EncryptedEventContent::MegolmV1AesSha2(content))
}
Algorithm::Custom(_) => Err(D::Error::custom(
"Custom algorithms are not supported by `EncryptedEventContent`.",
)),
Algorithm::__Nonexhaustive => Err(D::Error::custom(
"Attempted to deserialize __Nonexhaustive variant.",
)),
}
}
}
#[cfg(test)]
mod tests {
use serde_json::{from_str, to_string};
use serde_json::to_string;
use super::{Algorithm, EncryptedEventContent, MegolmV1AesSha2Content};
@ -168,9 +362,8 @@ mod tests {
});
assert_eq!(
from_str::<EncryptedEventContent>(
r#"{"algorithm":"m.megolm.v1.aes-sha2","ciphertext":"ciphertext","sender_key":"sender_key","device_id":"device_id","session_id":"session_id"}"#
)
r#"{"algorithm":"m.megolm.v1.aes-sha2","ciphertext":"ciphertext","sender_key":"sender_key","device_id":"device_id","session_id":"session_id"}"#
.parse::<EncryptedEventContent>()
.unwrap(),
key_verification_start_content
);
@ -179,7 +372,7 @@ mod tests {
#[test]
fn deserialization_failure() {
assert!(
from_str::<EncryptedEventContent>(r#"{"algorithm":"m.megolm.v1.aes-sha2"}"#).is_err()
r#"{"algorithm":"m.megolm.v1.aes-sha2"}"#.parse::<EncryptedEventContent>().is_err()
);
}
}