crypto: WIP more work on in-room verifications now up to accepting them.

master
Damir Jelić 2020-12-15 16:35:54 +01:00
parent 5105629c08
commit b6e28e2280
13 changed files with 320 additions and 117 deletions

View File

@ -45,7 +45,7 @@ use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
#[cfg(feature = "encryption")]
use matrix_sdk_base::crypto::{
decrypt_key_export, encrypt_key_export, olm::InboundGroupSession, store::CryptoStoreError,
AttachmentEncryptor, OutgoingRequests, ToDeviceRequest,
AttachmentEncryptor, OutgoingRequests, RoomMessageRequest, ToDeviceRequest,
};
/// Enum controlling if a loop running callbacks should continue or abort.
@ -1160,6 +1160,17 @@ impl Client {
Ok(())
}
async fn room_send_helper(
&self,
request: &RoomMessageRequest,
) -> Result<send_message_event::Response> {
let content = request.content.clone();
let txn_id = request.txn_id.into();
let room_id = &request.room_id;
self.room_send(&room_id, content, Some(txn_id)).await
}
/// Send a room message to the homeserver.
///
/// Returns the parsed response from the server.
@ -1458,7 +1469,10 @@ impl Client {
}
#[cfg(feature = "encryption")]
async fn send_to_device(&self, request: &ToDeviceRequest) -> Result<ToDeviceResponse> {
pub(crate) async fn send_to_device(
&self,
request: &ToDeviceRequest,
) -> Result<ToDeviceResponse> {
let txn_id_string = request.txn_id_string();
let request = RumaToDeviceRequest::new(
request.event_type.clone(),
@ -1737,6 +1751,14 @@ impl Client {
.unwrap();
}
}
OutgoingRequests::RoomMessage(request) => {
if let Ok(resp) = self.room_send_helper(request).await {
self.base_client
.mark_request_as_sent(&r.request_id(), &resp)
.await
.unwrap();
}
}
}
}
}
@ -1891,7 +1913,7 @@ impl Client {
.await
.map(|sas| Sas {
inner: sas,
http_client: self.http_client.clone(),
client: self.clone(),
})
}
@ -1953,7 +1975,7 @@ impl Client {
Ok(device.map(|d| Device {
inner: d,
http_client: self.http_client.clone(),
client: self.clone(),
}))
}
@ -2070,7 +2092,7 @@ impl Client {
Ok(UserDevices {
inner: devices,
http_client: self.http_client.clone(),
client: self.clone(),
})
}

View File

@ -18,18 +18,15 @@ use matrix_sdk_base::crypto::{
store::CryptoStoreError, Device as BaseDevice, LocalTrust, ReadOnlyDevice,
UserDevices as BaseUserDevices,
};
use matrix_sdk_common::{
api::r0::to_device::send_event_to_device::Request as ToDeviceRequest,
identifiers::{DeviceId, DeviceIdBox},
};
use matrix_sdk_common::identifiers::{DeviceId, DeviceIdBox};
use crate::{error::Result, http_client::HttpClient, Sas};
use crate::{error::Result, Client, Sas};
#[derive(Clone, Debug)]
/// A device represents a E2EE capable client of an user.
pub struct Device {
pub(crate) inner: BaseDevice,
pub(crate) http_client: HttpClient,
pub(crate) client: Client,
}
impl Deref for Device {
@ -66,14 +63,11 @@ impl Device {
/// ```
pub async fn start_verification(&self) -> Result<Sas> {
let (sas, request) = self.inner.start_verification().await?;
let txn_id_string = request.txn_id_string();
let request = ToDeviceRequest::new(request.event_type, &txn_id_string, request.messages);
self.http_client.send(request).await?;
self.client.send_to_device(&request).await?;
Ok(Sas {
inner: sas,
http_client: self.http_client.clone(),
client: self.client.clone(),
})
}
@ -102,7 +96,7 @@ impl Device {
#[derive(Debug)]
pub struct UserDevices {
pub(crate) inner: BaseUserDevices,
pub(crate) http_client: HttpClient,
pub(crate) client: Client,
}
impl UserDevices {
@ -110,7 +104,7 @@ impl UserDevices {
pub fn get(&self, device_id: &DeviceId) -> Option<Device> {
self.inner.get(device_id).map(|d| Device {
inner: d,
http_client: self.http_client.clone(),
client: self.client.clone(),
})
}
@ -121,11 +115,11 @@ impl UserDevices {
/// Iterator over all the devices of the user devices.
pub fn devices(&self) -> impl Iterator<Item = Device> + '_ {
let client = self.http_client.clone();
let client = self.client.clone();
self.inner.devices().map(move |d| Device {
inner: d,
http_client: client.clone(),
client: client.clone(),
})
}
}

View File

@ -12,26 +12,27 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use matrix_sdk_base::crypto::{ReadOnlyDevice, Sas as BaseSas};
use matrix_sdk_common::api::r0::to_device::send_event_to_device::Request as ToDeviceRequest;
use matrix_sdk_base::crypto::{OutgoingVerificationRequest, ReadOnlyDevice, Sas as BaseSas};
use crate::{error::Result, http_client::HttpClient};
use crate::{error::Result, Client};
/// An object controling the interactive verification flow.
#[derive(Debug, Clone)]
pub struct Sas {
pub(crate) inner: BaseSas,
pub(crate) http_client: HttpClient,
pub(crate) client: Client,
}
impl Sas {
/// Accept the interactive verification flow.
pub async fn accept(&self) -> Result<()> {
if let Some(req) = self.inner.accept() {
let txn_id_string = req.txn_id_string();
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
self.http_client.send(request).await?;
match req {
OutgoingVerificationRequest::ToDevice(r) => {
self.client.send_to_device(&r).await?;
}
OutgoingVerificationRequest::InRoom(_) => todo!(),
}
}
Ok(())
}
@ -40,15 +41,12 @@ impl Sas {
pub async fn confirm(&self) -> Result<()> {
let (to_device, signature) = self.inner.confirm().await?;
if let Some(req) = to_device {
let txn_id_string = req.txn_id_string();
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
self.http_client.send(request).await?;
if let Some(request) = to_device {
self.client.send_to_device(&request).await?;
}
if let Some(s) = signature {
self.http_client.send(s).await?;
self.client.send(s).await?;
}
Ok(())
@ -56,12 +54,10 @@ impl Sas {
/// Cancel the interactive verification flow.
pub async fn cancel(&self) -> Result<()> {
if let Some(req) = self.inner.cancel() {
let txn_id_string = req.txn_id_string();
let request = ToDeviceRequest::new(req.event_type, &txn_id_string, req.messages);
self.http_client.send(request).await?;
if let Some(request) = self.inner.cancel() {
self.client.send_to_device(&request).await?;
}
Ok(())
}

View File

@ -42,7 +42,7 @@ use tracing::warn;
use crate::{
olm::{InboundGroupSession, PrivateCrossSigningIdentity, Session},
store::{Changes, DeviceChanges},
OutgoingRequest, OutgoingRequests,
OutgoingRequest, OutgoingRequests, OutgoingVerificationRequest,
};
#[cfg(test)]
use crate::{OlmMachine, ReadOnlyAccount};
@ -97,7 +97,7 @@ impl Device {
.start_sas(self.inner.clone())
.await?;
if let OutgoingRequests::ToDeviceRequest(r) = request {
if let OutgoingVerificationRequest::ToDevice(r) = request {
Ok((sas, r))
} else {
panic!("Invalid verification request type");

View File

@ -51,6 +51,7 @@ pub use machine::OlmMachine;
pub use olm::EncryptionSettings;
pub(crate) use olm::ReadOnlyAccount;
pub use requests::{
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests,
OutgoingVerificationRequest, RoomMessageRequest, ToDeviceRequest,
};
pub use verification::{Sas, VerificationRequest};

View File

@ -322,6 +322,7 @@ impl OlmMachine {
}
requests.append(&mut self.outgoing_to_device_requests());
requests.append(&mut self.verification_machine.outgoing_room_message_requests());
requests.append(&mut self.key_request_machine.outgoing_to_device_requests());
requests
@ -360,6 +361,9 @@ impl OlmMachine {
IncomingResponse::SignatureUpload(_) => {
self.verification_machine.mark_request_as_sent(request_id);
}
IncomingResponse::RoomMessage(_) => {
self.verification_machine.mark_request_as_sent(request_id);
}
};
Ok(())

View File

@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#![allow(missing_docs)]
use std::{collections::BTreeMap, sync::Arc, time::Duration};
use matrix_sdk_common::{
@ -26,10 +28,11 @@ use matrix_sdk_common::{
upload_signing_keys::Response as SigningKeysUploadResponse,
CrossSigningKey,
},
message::send_message_event::Response as RoomMessageResponse,
to_device::{send_event_to_device::Response as ToDeviceResponse, DeviceIdOrAllDevices},
},
events::EventType,
identifiers::{DeviceIdBox, UserId},
events::{AnyMessageEventContent, EventType},
identifiers::{DeviceIdBox, RoomId, UserId},
uuid::Uuid,
};
@ -120,6 +123,7 @@ pub enum OutgoingRequests {
/// Signature upload request, this request is used after a successful device
/// or user verification is done.
SignatureUpload(SignatureUploadRequest),
RoomMessage(RoomMessageRequest),
}
#[cfg(test)]
@ -150,6 +154,12 @@ impl From<ToDeviceRequest> for OutgoingRequests {
}
}
impl From<RoomMessageRequest> for OutgoingRequests {
fn from(request: RoomMessageRequest) -> Self {
OutgoingRequests::RoomMessage(request)
}
}
impl From<SignatureUploadRequest> for OutgoingRequests {
fn from(request: SignatureUploadRequest) -> Self {
OutgoingRequests::SignatureUpload(request)
@ -176,6 +186,7 @@ pub enum IncomingResponse<'a> {
/// The cross signing keys upload response, marking our private cross
/// signing identity as shared.
SignatureUpload(&'a SignatureUploadResponse),
RoomMessage(&'a RoomMessageResponse),
}
impl<'a> From<&'a KeysUploadResponse> for IncomingResponse<'a> {
@ -196,6 +207,12 @@ impl<'a> From<&'a ToDeviceResponse> for IncomingResponse<'a> {
}
}
impl<'a> From<&'a RoomMessageResponse> for IncomingResponse<'a> {
fn from(response: &'a RoomMessageResponse) -> Self {
IncomingResponse::RoomMessage(response)
}
}
impl<'a> From<&'a KeysClaimResponse> for IncomingResponse<'a> {
fn from(response: &'a KeysClaimResponse) -> Self {
IncomingResponse::KeysClaim(response)
@ -230,3 +247,55 @@ impl OutgoingRequest {
&self.request
}
}
#[derive(Clone, Debug)]
pub struct RoomMessageRequest {
/// The room to send the event to.
pub room_id: RoomId,
/// The transaction ID for this event.
///
/// Clients should generate an ID unique across requests with the
/// same access token; it will be used by the server to ensure
/// idempotency of requests.
pub txn_id: Uuid,
/// The event content to send.
pub content: AnyMessageEventContent,
}
#[derive(Clone, Debug)]
pub enum OutgoingVerificationRequest {
ToDevice(ToDeviceRequest),
InRoom(RoomMessageRequest),
}
impl OutgoingVerificationRequest {
pub fn request_id(&self) -> Uuid {
match self {
OutgoingVerificationRequest::ToDevice(t) => t.txn_id,
OutgoingVerificationRequest::InRoom(r) => r.txn_id,
}
}
}
impl From<ToDeviceRequest> for OutgoingVerificationRequest {
fn from(r: ToDeviceRequest) -> Self {
OutgoingVerificationRequest::ToDevice(r)
}
}
impl From<RoomMessageRequest> for OutgoingVerificationRequest {
fn from(r: RoomMessageRequest) -> Self {
OutgoingVerificationRequest::InRoom(r)
}
}
impl From<OutgoingVerificationRequest> for OutgoingRequests {
fn from(request: OutgoingVerificationRequest) -> Self {
match request {
OutgoingVerificationRequest::ToDevice(r) => OutgoingRequests::ToDeviceRequest(r),
OutgoingVerificationRequest::InRoom(r) => OutgoingRequests::RoomMessage(r),
}
}
}

View File

@ -37,7 +37,8 @@ use crate::{
olm::PrivateCrossSigningIdentity,
requests::{OutgoingRequest, ToDeviceRequest},
store::{CryptoStore, CryptoStoreError},
OutgoingRequests, ReadOnlyAccount, ReadOnlyDevice,
OutgoingRequests, OutgoingVerificationRequest, ReadOnlyAccount, ReadOnlyDevice,
RoomMessageRequest,
};
#[derive(Clone, Debug)]
@ -49,6 +50,7 @@ pub struct VerificationMachine {
room_verifications: Arc<DashMap<EventId, Sas>>,
requests: Arc<DashMap<EventId, VerificationRequest>>,
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
outgoing_room_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
}
impl VerificationMachine {
@ -65,13 +67,14 @@ impl VerificationMachine {
requests: DashMap::new().into(),
outgoing_to_device_messages: DashMap::new().into(),
room_verifications: DashMap::new().into(),
outgoing_room_messages: DashMap::new().into(),
}
}
pub async fn start_sas(
&self,
device: ReadOnlyDevice,
) -> Result<(Sas, OutgoingRequests), CryptoStoreError> {
) -> Result<(Sas, OutgoingVerificationRequest), CryptoStoreError> {
let identity = self.store.get_user_identity(device.user_id()).await?;
let private_identity = self.private_identity.lock().await.clone();
@ -83,8 +86,13 @@ impl VerificationMachine {
identity,
);
let request: OutgoingRequests = match content {
OutgoingContent::Room(c) => todo!(),
let request = match content {
OutgoingContent::Room(r, c) => RoomMessageRequest {
room_id: r,
txn_id: Uuid::new_v4(),
content: c,
}
.into(),
OutgoingContent::ToDevice(c) => {
let request = content_to_request(device.user_id(), device.device_id(), c);
@ -127,7 +135,23 @@ impl VerificationMachine {
self.outgoing_to_device_messages.insert(request_id, request);
}
OutgoingContent::Room(c) => todo!(),
OutgoingContent::Room(r, c) => {
let request_id = Uuid::new_v4();
let request = OutgoingRequest {
request: Arc::new(
RoomMessageRequest {
room_id: r,
txn_id: request_id.clone(),
content: c,
}
.into(),
),
request_id,
};
self.outgoing_room_messages.insert(request_id, request);
}
}
}
@ -138,9 +162,17 @@ impl VerificationMachine {
}
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
self.outgoing_room_messages.remove(uuid);
self.outgoing_to_device_messages.remove(uuid);
}
pub fn outgoing_room_message_requests(&self) -> Vec<OutgoingRequest> {
self.outgoing_room_messages
.iter()
.map(|r| (*r).clone())
.collect()
}
pub fn outgoing_to_device_requests(&self) -> Vec<OutgoingRequest> {
#[allow(clippy::map_clone)]
self.outgoing_to_device_messages
@ -215,9 +247,23 @@ impl VerificationMachine {
Ok(s) => {
// TODO we need to queue up the accept event
// here.
let accept_event = s.accept();
info!(
"Started a new SAS verification, \
automatically accepting because of in-room"
);
let accept_request = s.accept().unwrap();
self.room_verifications
.insert(e.content.relation.event_id.clone(), s);
self.outgoing_room_messages.insert(
accept_request.request_id(),
OutgoingRequest {
request_id: accept_request.request_id(),
request: Arc::new(accept_request.into()),
},
);
}
Err(c) => {
warn!(

View File

@ -93,13 +93,15 @@ impl VerificationRequest {
) -> Result<Sas, OutgoingContent> {
match &*self.inner.lock().unwrap() {
InnerRequest::Ready(s) => s.into_started_sas(
event,
&event.clone().into_full_event(self.room_id().clone()),
self.store.clone(),
self.account.clone(),
self.private_cross_signing_identity.clone(),
device,
user_identity,
),
// TODO cancel here since we got a missmatched message or do
// nothing?
_ => todo!(),
}
}
@ -128,7 +130,7 @@ impl InnerRequest {
fn into_started_sas(
&mut self,
event: &SyncMessageEvent<StartEventContent>,
event: &MessageEvent<StartEventContent>,
store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity,
@ -299,7 +301,7 @@ struct Ready {
impl RequestState<Ready> {
fn into_started_sas(
&self,
event: &SyncMessageEvent<StartEventContent>,
event: &MessageEvent<StartEventContent>,
store: Arc<Box<dyn CryptoStore>>,
account: ReadOnlyAccount,
private_identity: PrivateCrossSigningIdentity,
@ -312,7 +314,7 @@ impl RequestState<Ready> {
other_device,
store,
&event.sender,
event.content.clone(),
(event.room_id.clone(), event.content.clone()),
other_identity,
)
}
@ -325,13 +327,14 @@ impl RequestState<Ready> {
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> (Sas, OutgoingContent) {
Sas::start(
account,
private_identity,
other_device,
store,
other_identity,
)
todo!()
// Sas::start_in_room(
// account,
// private_identity,
// other_device,
// store,
// other_identity,
// )
}
}

View File

@ -19,11 +19,13 @@ use std::convert::TryInto;
use matrix_sdk_common::{
events::{
key::verification::{
accept::{AcceptEventContent, AcceptToDeviceEventContent},
start::{StartEventContent, StartMethod, StartToDeviceEventContent},
KeyAgreementProtocol,
},
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
},
identifiers::RoomId,
CanonicalJsonValue,
};
@ -32,28 +34,28 @@ use super::FlowId;
#[derive(Clone, Debug)]
pub enum StartContent {
ToDevice(StartToDeviceEventContent),
Room(StartEventContent),
Room(RoomId, StartEventContent),
}
impl StartContent {
pub fn method(&self) -> &StartMethod {
match self {
StartContent::ToDevice(c) => &c.method,
StartContent::Room(c) => &c.method,
StartContent::Room(_, c) => &c.method,
}
}
pub fn flow_id(&self) -> FlowId {
match self {
StartContent::ToDevice(c) => FlowId::ToDevice(c.transaction_id.clone()),
StartContent::Room(c) => FlowId::InRoom(c.relation.event_id.clone()),
StartContent::Room(r, c) => FlowId::InRoom(r.clone(), c.relation.event_id.clone()),
}
}
pub fn to_canonical_json(self) -> CanonicalJsonValue {
let content = match self {
StartContent::Room(c) => serde_json::to_value(c),
StartContent::ToDevice(c) => serde_json::to_value(c),
StartContent::Room(_, c) => serde_json::to_value(c),
};
content
@ -63,9 +65,9 @@ impl StartContent {
}
}
impl From<StartEventContent> for StartContent {
fn from(content: StartEventContent) -> Self {
StartContent::Room(content)
impl From<(RoomId, StartEventContent)> for StartContent {
fn from(tuple: (RoomId, StartEventContent)) -> Self {
StartContent::Room(tuple.0, tuple.1)
}
}
@ -75,16 +77,34 @@ impl From<StartToDeviceEventContent> for StartContent {
}
}
#[derive(Clone, Debug)]
pub enum AcceptContent {
ToDevice(AcceptToDeviceEventContent),
Room(RoomId, AcceptEventContent),
}
impl From<AcceptToDeviceEventContent> for AcceptContent {
fn from(content: AcceptToDeviceEventContent) -> Self {
AcceptContent::ToDevice(content)
}
}
impl From<(RoomId, AcceptEventContent)> for AcceptContent {
fn from(content: (RoomId, AcceptEventContent)) -> Self {
AcceptContent::Room(content.0, content.1)
}
}
#[derive(Clone, Debug)]
pub enum OutgoingContent {
Room(AnyMessageEventContent),
Room(RoomId, AnyMessageEventContent),
ToDevice(AnyToDeviceEventContent),
}
impl From<StartContent> for OutgoingContent {
fn from(content: StartContent) -> Self {
match content {
StartContent::Room(c) => AnyMessageEventContent::KeyVerificationStart(c).into(),
StartContent::Room(r, c) => (r, AnyMessageEventContent::KeyVerificationStart(c)).into(),
StartContent::ToDevice(c) => AnyToDeviceEventContent::KeyVerificationStart(c).into(),
}
}
@ -96,8 +116,8 @@ impl From<AnyToDeviceEventContent> for OutgoingContent {
}
}
impl From<AnyMessageEventContent> for OutgoingContent {
fn from(content: AnyMessageEventContent) -> Self {
OutgoingContent::Room(content)
impl From<(RoomId, AnyMessageEventContent)> for OutgoingContent {
fn from(content: (RoomId, AnyMessageEventContent)) -> Self {
OutgoingContent::Room(content.0, content.1)
}
}

View File

@ -27,7 +27,7 @@ use matrix_sdk_common::{
},
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
},
identifiers::{EventId, UserId},
identifiers::{EventId, RoomId, UserId},
};
use crate::{
@ -36,7 +36,7 @@ use crate::{
};
use super::{
event_enums::OutgoingContent,
event_enums::{AcceptContent, OutgoingContent},
sas_state::{
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
Started,
@ -69,11 +69,18 @@ impl InnerSas {
pub fn start_in_room(
event_id: EventId,
room_id: RoomId,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> (InnerSas, OutgoingContent) {
let sas = SasState::<Created>::new_in_room(event_id, account, other_device, other_identity);
let sas = SasState::<Created>::new_in_room(
room_id,
event_id,
account,
other_device,
other_identity,
);
let content = sas.as_content();
(InnerSas::Created(sas), content)
}
@ -97,7 +104,7 @@ impl InnerSas {
}
}
pub fn accept(&self) -> Option<AcceptToDeviceEventContent> {
pub fn accept(&self) -> Option<AcceptContent> {
if let InnerSas::Started(s) = self {
Some(s.as_content())
} else {

View File

@ -20,6 +20,7 @@ mod sas_state;
#[cfg(test)]
use std::time::Instant;
use event_enums::AcceptContent;
use std::sync::{Arc, Mutex};
use tracing::{error, info, trace, warn};
@ -30,15 +31,18 @@ use matrix_sdk_common::{
cancel::CancelCode,
start::{StartEventContent, StartToDeviceEventContent},
},
AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
AnyMessageEventContent, AnyToDeviceEvent, AnyToDeviceEventContent, MessageEvent,
ToDeviceEvent,
},
identifiers::{DeviceId, EventId, RoomId, UserId},
uuid::Uuid,
};
use crate::{
error::SignatureError,
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
olm::PrivateCrossSigningIdentity,
requests::{OutgoingVerificationRequest, RoomMessageRequest},
store::{Changes, CryptoStore, CryptoStoreError, DeviceChanges},
ReadOnlyAccount, ToDeviceRequest,
};
@ -189,6 +193,7 @@ impl Sas {
) -> (Sas, OutgoingContent) {
let (inner, content) = InnerSas::start_in_room(
flow_id,
room_id,
account.clone(),
other_device.clone(),
other_identity.clone(),
@ -249,10 +254,18 @@ impl Sas {
///
/// This does nothing if the verification was already accepted, otherwise it
/// returns an `AcceptEventContent` that needs to be sent out.
pub fn accept(&self) -> Option<ToDeviceRequest> {
self.inner.lock().unwrap().accept().map(|c| {
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
self.content_to_request(content)
pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
self.inner.lock().unwrap().accept().map(|c| match c {
AcceptContent::ToDevice(c) => {
let content = AnyToDeviceEventContent::KeyVerificationAccept(c);
self.content_to_request(content).into()
}
AcceptContent::Room(room_id, content) => RoomMessageRequest {
room_id,
txn_id: Uuid::new_v4(),
content: AnyMessageEventContent::KeyVerificationAccept(content),
}
.into(),
})
}

View File

@ -14,6 +14,7 @@
use std::{
convert::TryFrom,
matches,
sync::{Arc, Mutex},
time::{Duration, Instant},
};
@ -24,8 +25,8 @@ use matrix_sdk_common::{
events::{
key::verification::{
accept::{
AcceptMethod, AcceptToDeviceEventContent, MSasV1Content as AcceptV1Content,
MSasV1ContentInit as AcceptV1ContentInit,
AcceptEventContent, AcceptMethod, AcceptToDeviceEventContent,
MSasV1Content as AcceptV1Content, MSasV1ContentInit as AcceptV1ContentInit,
},
cancel::{CancelCode, CancelToDeviceEventContent},
key::KeyToDeviceEventContent,
@ -39,13 +40,13 @@ use matrix_sdk_common::{
},
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, ToDeviceEvent,
},
identifiers::{DeviceId, EventId, UserId},
identifiers::{DeviceId, EventId, RoomId, UserId},
uuid::Uuid,
};
use tracing::error;
use super::{
event_enums::{OutgoingContent, StartContent},
event_enums::{AcceptContent, OutgoingContent, StartContent},
helpers::{
calculate_commitment, get_decimal, get_emoji, get_mac_content, receive_mac_event, SasIds,
},
@ -74,20 +75,28 @@ const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
#[derive(Clone, Debug)]
pub enum FlowId {
ToDevice(String),
InRoom(EventId),
InRoom(RoomId, EventId),
}
impl FlowId {
pub fn room_id(&self) -> Option<&RoomId> {
if let FlowId::InRoom(r, _) = &self {
Some(r)
} else {
None
}
}
pub fn to_string(&self) -> String {
match self {
FlowId::InRoom(r) => r.to_string(),
FlowId::InRoom(_, r) => r.to_string(),
FlowId::ToDevice(t) => t.to_string(),
}
}
pub fn as_str(&self) -> &str {
match self {
FlowId::InRoom(r) => r.as_str(),
FlowId::InRoom(_, r) => r.as_str(),
FlowId::ToDevice(t) => t.as_str(),
}
}
@ -340,12 +349,13 @@ impl SasState<Created> {
///
/// * `other_identity` - The identity of the other user if one exists.
pub fn new_in_room(
room_id: RoomId,
event_id: EventId,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> SasState<Created> {
let flow_id = FlowId::InRoom(event_id);
let flow_id = FlowId::InRoom(room_id, event_id);
Self::new_helper(flow_id, account, other_device, other_identity)
}
@ -380,7 +390,7 @@ impl SasState<Created> {
pub fn as_start_content(&self) -> StartContent {
match self.verification_flow_id.as_ref() {
FlowId::ToDevice(s) => StartContent::ToDevice(StartToDeviceEventContent {
FlowId::ToDevice(_) => StartContent::ToDevice(StartToDeviceEventContent {
transaction_id: self.verification_flow_id.to_string(),
from_device: self.device_id().into(),
method: StartMethod::MSasV1(
@ -388,16 +398,19 @@ impl SasState<Created> {
.expect("Invalid initial protocol definitions."),
),
}),
FlowId::InRoom(e) => StartContent::Room(StartEventContent {
from_device: self.device_id().into(),
method: StartMethod::MSasV1(
MSasV1Content::new(self.state.protocol_definitions.clone())
.expect("Invalid initial protocol definitions."),
),
relation: Relation {
event_id: e.clone(),
FlowId::InRoom(r, e) => StartContent::Room(
r.clone(),
StartEventContent {
from_device: self.device_id().into(),
method: StartMethod::MSasV1(
MSasV1Content::new(self.state.protocol_definitions.clone())
.expect("Invalid initial protocol definitions."),
),
relation: Relation {
event_id: e.clone(),
},
},
}),
),
}
}
@ -558,25 +571,40 @@ impl SasState<Started> {
/// This should be sent out automatically if the SAS verification flow has
/// been started because of a
/// m.key.verification.request -> m.key.verification.ready flow.
pub fn as_content(&self) -> AcceptToDeviceEventContent {
pub fn as_content(&self) -> AcceptContent {
let accepted_protocols = AcceptedProtocols::default();
AcceptToDeviceEventContent {
transaction_id: self.verification_flow_id.to_string(),
method: AcceptMethod::MSasV1(
AcceptV1ContentInit {
commitment: self.state.commitment.clone(),
hash: accepted_protocols.hash,
key_agreement_protocol: accepted_protocols.key_agreement_protocol,
message_authentication_code: accepted_protocols.message_auth_code,
short_authentication_string: self
.state
.protocol_definitions
.short_authentication_string
.clone(),
}
let method = AcceptMethod::MSasV1(
AcceptV1ContentInit {
commitment: self.state.commitment.clone(),
hash: accepted_protocols.hash,
key_agreement_protocol: accepted_protocols.key_agreement_protocol,
message_authentication_code: accepted_protocols.message_auth_code,
short_authentication_string: self
.state
.protocol_definitions
.short_authentication_string
.clone(),
}
.into(),
);
match self.verification_flow_id.as_ref() {
FlowId::ToDevice(_) => AcceptToDeviceEventContent {
transaction_id: self.verification_flow_id.to_string(),
method,
}
.into(),
FlowId::InRoom(r, e) => (
r.clone(),
AcceptEventContent {
method,
relation: Relation {
event_id: e.clone(),
},
},
)
.into(),
),
}
}
@ -676,7 +704,7 @@ impl SasState<Accepted> {
transaction_id: s.to_string(),
key: self.inner.lock().unwrap().public_key(),
},
FlowId::InRoom(r) => {
FlowId::InRoom(_, r) => {
todo!("In-room verifications aren't implemented")
}
}