use std::{cell::RefCell, rc::Rc}; use matrix_sdk::{ encryption::verification::{SasVerification, VerificationRequest}, ruma::{ events::{ key::verification::VerificationMethod, room::message::MessageType, AnySyncMessageLikeEvent, }, UserId, }, }; use crate::{ connection::Connection, render::{Render, StartVerificationContext, VerificationContext}, }; use super::{buffer::RoomBuffer, members::Members}; #[derive(Clone)] pub struct Verification { own_user_id: Rc, connection: Rc>>, members: Members, buffer: RoomBuffer, inner: Rc>>, } #[derive(Clone, Debug)] enum ActiveVerification { Request(VerificationRequest), Sas(SasVerification), } impl From for ActiveVerification { fn from(v: VerificationRequest) -> Self { Self::Request(v) } } impl From for ActiveVerification { fn from(v: SasVerification) -> Self { Self::Sas(v) } } impl Verification { pub fn new( own_user_id: Rc, connection: Rc>>, members: Members, buffer: RoomBuffer, ) -> Self { Self { own_user_id, connection, members, buffer, inner: Rc::new(RefCell::new(None)), } } pub async fn confirm(&self) { let connection = self.connection.borrow().clone(); if let Some(c) = connection { if let Some(ActiveVerification::Sas(verification)) = self.inner.borrow().clone() { let ret = c.spawn(async move { verification.confirm().await }).await; } } } pub async fn accept(&self) { let connection = self.connection.borrow().clone(); let verification = self.inner.borrow().clone(); if let Some(c) = connection { if let Some(ActiveVerification::Request(verification)) = verification { let verification_clone = verification.clone(); let ret = c .spawn(async move { verification .accept_with_methods(vec![ VerificationMethod::SasV1, ]) .await }) .await; // We automatically start SAS verification here since it's the // only method we support. if let Some(sas) = c .spawn(async move { verification_clone.start_sas().await }) .await .unwrap() { *self.inner.borrow_mut() = Some(sas.into()); } } } } pub async fn handle_room_verification( &self, event: &AnySyncMessageLikeEvent, ) { // TODO remove this expect. let sender = self.members.get(event.sender()).await.expect( "Rendering a message but the sender isn't in the nicklist", ); let own_member = self .members .get(&self.own_user_id) .await .expect("Own member missing from the store"); let send_time = event.origin_server_ts(); let connection = self.connection.borrow().clone(); match event { AnySyncMessageLikeEvent::KeyVerificationReady(_) => {} AnySyncMessageLikeEvent::KeyVerificationStart(e) => { if let Some(connection) = connection { let Some(e) = e.as_original() else { // Unhandled redacted event return; }; let flow_id = &e.content.relates_to.event_id; if let Some(sas) = connection .client() .encryption() .get_verification(&e.sender, flow_id.as_str()) .await .map(|s| s.sas()) .flatten() { let context = StartVerificationContext::Room( e.sender.to_owned(), sas.clone().into(), ); let rendered = e.content.render_with_prefix( send_time, event.event_id(), &sender, &context, ); self.buffer .replace_verification_event(flow_id, rendered); *self.inner.borrow_mut() = Some(sas.clone().into()); // We accept here automatically since the only method // we're supporting is SAS verification let ret = connection .spawn(async move { sas.accept().await }) .await; } } } AnySyncMessageLikeEvent::KeyVerificationCancel(_) => { self.inner.borrow_mut().take(); } AnySyncMessageLikeEvent::KeyVerificationAccept(_) => {} AnySyncMessageLikeEvent::KeyVerificationKey(e) => { let Some(e) = e.as_original() else { // Unhandled redacted event return; }; let flow_id = &e.content.relates_to.event_id; if let Some(ActiveVerification::Sas(sas)) = self.inner.borrow().clone() { if sas.can_be_presented() { let rendered = e.content.render_with_prefix( send_time, event.event_id(), &sender, &sas, ); self.buffer .replace_verification_event(flow_id, rendered); } } } AnySyncMessageLikeEvent::KeyVerificationMac(_) => {} AnySyncMessageLikeEvent::KeyVerificationDone(_) => {} AnySyncMessageLikeEvent::RoomMessage(e) => { let Some(e) = e.as_original() else { // Unhandled redacted event return; }; if let MessageType::VerificationRequest(content) = &e.content.msgtype { let rendered = content.render_with_prefix( send_time, &e.event_id, &sender.clone(), &VerificationContext::Room(sender, own_member), ); self.buffer.print_rendered_event(rendered); if let Some(connection) = connection { if let Some(verification) = connection .client() .encryption() .get_verification_request(&e.sender, &e.event_id) .await { *self.inner.borrow_mut() = Some(verification.into()); } } } } _ => {} } } }