crypto: Add a test for verification request flows.
parent
ec863a928d
commit
55436c6514
|
@ -2172,8 +2172,8 @@ impl Client {
|
||||||
|
|
||||||
let encrypt = move || -> Result<()> {
|
let encrypt = move || -> Result<()> {
|
||||||
let export: String = encrypt_key_export(&keys, &passphrase, 500_000)?;
|
let export: String = encrypt_key_export(&keys, &passphrase, 500_000)?;
|
||||||
let mut file = std::fs::File::create(path).unwrap();
|
let mut file = std::fs::File::create(path)?;
|
||||||
file.write_all(&export.into_bytes()).unwrap();
|
file.write_all(&export.into_bytes())?;
|
||||||
Ok(())
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2237,6 +2237,7 @@ impl Client {
|
||||||
};
|
};
|
||||||
|
|
||||||
let task = tokio::task::spawn_blocking(decrypt);
|
let task = tokio::task::spawn_blocking(decrypt);
|
||||||
|
// TODO remove this unwrap.
|
||||||
let import = task.await.expect("Task join error").unwrap();
|
let import = task.await.expect("Task join error").unwrap();
|
||||||
|
|
||||||
Ok(olm.import_keys(import).await?)
|
Ok(olm.import_keys(import).await?)
|
||||||
|
|
|
@ -224,6 +224,10 @@ impl VerificationMachine {
|
||||||
// Since these are room events we will get events that we send out on
|
// Since these are room events we will get events that we send out on
|
||||||
// our own as well.
|
// our own as well.
|
||||||
if m.sender() == self.account.user_id() {
|
if m.sender() == self.account.user_id() {
|
||||||
|
if let AnySyncMessageEvent::KeyVerificationReady(_e) = m {
|
||||||
|
// TODO if there is a verification request, go into passive
|
||||||
|
// mode since another device is handling this request.
|
||||||
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -250,6 +254,14 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AnySyncMessageEvent::KeyVerificationReady(e) => {
|
||||||
|
if let Some(request) = self.requests.get(&e.content.relation.event_id) {
|
||||||
|
if &e.sender == request.other_user() {
|
||||||
|
// TODO remove this unwrap.
|
||||||
|
request.receive_ready(&e.sender, &e.content).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
AnySyncMessageEvent::KeyVerificationStart(e) => {
|
AnySyncMessageEvent::KeyVerificationStart(e) => {
|
||||||
info!(
|
info!(
|
||||||
"Received a new verification start event from {} {}",
|
"Received a new verification start event from {} {}",
|
||||||
|
|
|
@ -43,12 +43,63 @@ const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
inner: Arc<Mutex<InnerRequest>>,
|
inner: Arc<Mutex<InnerRequest>>,
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
|
other_user_id: Arc<UserId>,
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
room_id: Arc<RoomId>,
|
room_id: Arc<RoomId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationRequest {
|
impl VerificationRequest {
|
||||||
|
/// TODO
|
||||||
|
pub fn new(
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
|
room_id: Arc<RoomId>,
|
||||||
|
other_user: &UserId,
|
||||||
|
) -> Self {
|
||||||
|
let inner = Mutex::new(InnerRequest::Created(RequestState::new(
|
||||||
|
account.user_id(),
|
||||||
|
account.device_id(),
|
||||||
|
other_user,
|
||||||
|
)))
|
||||||
|
.into();
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
account,
|
||||||
|
private_cross_signing_identity,
|
||||||
|
store,
|
||||||
|
other_user_id: other_user.clone().into(),
|
||||||
|
room_id,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
pub fn request(&self) -> Option<KeyVerificationRequestEventContent> {
|
||||||
|
match &*self.inner.lock().unwrap() {
|
||||||
|
InnerRequest::Created(c) => Some(c.as_content()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The id of the other user that is participating in this verification
|
||||||
|
/// request.
|
||||||
|
pub fn other_user(&self) -> &UserId {
|
||||||
|
&self.other_user_id
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Mark the request as sent.
|
||||||
|
pub fn mark_as_sent(&self, response: &RoomMessageResponse) {
|
||||||
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
match &*inner {
|
||||||
|
InnerRequest::Created(c) => {
|
||||||
|
*inner = InnerRequest::Sent(c.clone().into_sent(response));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn from_request_event(
|
pub(crate) fn from_request_event(
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
|
@ -69,6 +120,7 @@ impl VerificationRequest {
|
||||||
),
|
),
|
||||||
))),
|
))),
|
||||||
account,
|
account,
|
||||||
|
other_user_id: sender.clone().into(),
|
||||||
private_cross_signing_identity,
|
private_cross_signing_identity,
|
||||||
store,
|
store,
|
||||||
room_id: room_id.clone().into(),
|
room_id: room_id.clone().into(),
|
||||||
|
@ -85,6 +137,28 @@ impl VerificationRequest {
|
||||||
self.inner.lock().unwrap().accept()
|
self.inner.lock().unwrap().accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn receive_ready(
|
||||||
|
&self,
|
||||||
|
sender: &UserId,
|
||||||
|
content: &ReadyEventContent,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
match &*inner {
|
||||||
|
InnerRequest::Sent(s) => {
|
||||||
|
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Is the verification request ready to start a verification flow.
|
||||||
|
pub fn is_ready(&self) -> bool {
|
||||||
|
matches!(&*self.inner.lock().unwrap(), InnerRequest::Ready(_))
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn into_started_sas(
|
pub(crate) fn into_started_sas(
|
||||||
self,
|
self,
|
||||||
event: &SyncMessageEvent<StartEventContent>,
|
event: &SyncMessageEvent<StartEventContent>,
|
||||||
|
@ -171,6 +245,15 @@ struct RequestState<S: Clone> {
|
||||||
struct Created {}
|
struct Created {}
|
||||||
|
|
||||||
impl RequestState<Created> {
|
impl RequestState<Created> {
|
||||||
|
fn new(own_user_id: &UserId, own_device_id: &DeviceId, other_user: &UserId) -> Self {
|
||||||
|
Self {
|
||||||
|
own_user_id: own_user_id.clone(),
|
||||||
|
own_device_id: own_device_id.into(),
|
||||||
|
other_user_id: other_user.clone(),
|
||||||
|
state: Created {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn as_content(&self) -> KeyVerificationRequestEventContent {
|
fn as_content(&self) -> KeyVerificationRequestEventContent {
|
||||||
KeyVerificationRequestEventContent {
|
KeyVerificationRequestEventContent {
|
||||||
body: format!(
|
body: format!(
|
||||||
|
@ -343,3 +426,81 @@ struct Passive {
|
||||||
/// unique id identifying this verification flow.
|
/// unique id identifying this verification flow.
|
||||||
pub flow_id: EventId,
|
pub flow_id: EventId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
|
use matrix_sdk_common::{
|
||||||
|
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
||||||
|
identifiers::{event_id, room_id, DeviceIdBox, UserId},
|
||||||
|
};
|
||||||
|
use matrix_sdk_test::async_test;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||||
|
store::{CryptoStore, MemoryStore},
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::VerificationRequest;
|
||||||
|
|
||||||
|
fn alice_id() -> UserId {
|
||||||
|
UserId::try_from("@alice:example.org").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn alice_device_id() -> DeviceIdBox {
|
||||||
|
"JLAFKJWSCS".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bob_id() -> UserId {
|
||||||
|
UserId::try_from("@bob:example.org").unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bob_device_id() -> DeviceIdBox {
|
||||||
|
"BOBDEVCIE".into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_test]
|
||||||
|
async fn test_request_accepting() {
|
||||||
|
let event_id = event_id!("$1234localhost");
|
||||||
|
let room_id = room_id!("!test:localhost");
|
||||||
|
|
||||||
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
|
let alice_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
||||||
|
let alice_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
||||||
|
|
||||||
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
|
let bob_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
||||||
|
let bob_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
||||||
|
|
||||||
|
let bob_request = VerificationRequest::new(
|
||||||
|
bob,
|
||||||
|
bob_identity,
|
||||||
|
bob_store.into(),
|
||||||
|
room_id.clone().into(),
|
||||||
|
&alice_id(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let content = bob_request.request().unwrap();
|
||||||
|
|
||||||
|
let alice_request = VerificationRequest::from_request_event(
|
||||||
|
alice,
|
||||||
|
alice_identity,
|
||||||
|
alice_store.into(),
|
||||||
|
&room_id,
|
||||||
|
&bob_id(),
|
||||||
|
&event_id,
|
||||||
|
&content,
|
||||||
|
);
|
||||||
|
|
||||||
|
let content = alice_request.accept().unwrap();
|
||||||
|
|
||||||
|
let response = RoomMessageResponse::new(event_id);
|
||||||
|
bob_request.mark_as_sent(&response);
|
||||||
|
|
||||||
|
bob_request.receive_ready(&alice_id(), &content).unwrap();
|
||||||
|
|
||||||
|
assert!(bob_request.is_ready());
|
||||||
|
assert!(alice_request.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue