crypto: Initial support for the longer to-device verification flow
parent
ec55258be9
commit
09a7858702
|
@ -103,14 +103,11 @@ use matrix_sdk_common::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::api::r0::{
|
||||||
api::r0::{
|
|
||||||
keys::{get_keys, upload_keys, upload_signing_keys::Request as UploadSigningKeysRequest},
|
keys::{get_keys, upload_keys, upload_signing_keys::Request as UploadSigningKeysRequest},
|
||||||
to_device::send_event_to_device::{
|
to_device::send_event_to_device::{
|
||||||
Request as RumaToDeviceRequest, Response as ToDeviceResponse,
|
Request as RumaToDeviceRequest, Response as ToDeviceResponse,
|
||||||
},
|
},
|
||||||
},
|
|
||||||
identifiers::EventId,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use matrix_sdk_common::locks::Mutex;
|
use matrix_sdk_common::locks::Mutex;
|
||||||
|
@ -2131,12 +2128,16 @@ impl Client {
|
||||||
/// Get a `VerificationRequest` object with the given flow id.
|
/// Get a `VerificationRequest` object with the given flow id.
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
pub async fn get_verification_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
pub async fn get_verification_request(
|
||||||
|
&self,
|
||||||
|
flow_id: impl AsRef<str>,
|
||||||
|
) -> Option<VerificationRequest> {
|
||||||
let olm = self.base_client.olm_machine().await?;
|
let olm = self.base_client.olm_machine().await?;
|
||||||
|
|
||||||
olm.get_verification_request(flow_id).and_then(|r| {
|
olm.get_verification_request(flow_id)
|
||||||
self.get_joined_room(r.room_id())
|
.map(|r| VerificationRequest {
|
||||||
.map(|room| VerificationRequest { inner: r, room })
|
inner: r,
|
||||||
|
client: self.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -110,6 +110,9 @@ pub use room_member::RoomMember;
|
||||||
#[cfg(feature = "encryption")]
|
#[cfg(feature = "encryption")]
|
||||||
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
pub use sas::Sas;
|
pub use sas::Sas;
|
||||||
|
#[cfg(feature = "encryption")]
|
||||||
|
#[cfg_attr(feature = "docs", doc(cfg(encryption)))]
|
||||||
|
pub use verification_request::VerificationRequest;
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
|
@ -12,27 +12,38 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use matrix_sdk_base::{
|
use matrix_sdk_base::crypto::{
|
||||||
crypto::VerificationRequest as BaseVerificationRequest, events::AnyMessageEventContent,
|
OutgoingVerificationRequest, VerificationRequest as BaseVerificationRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{room::Joined, Result};
|
use crate::{Client, Result};
|
||||||
|
|
||||||
/// An object controling the interactive verification flow.
|
/// An object controling the interactive verification flow.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
pub(crate) inner: BaseVerificationRequest,
|
pub(crate) inner: BaseVerificationRequest,
|
||||||
pub(crate) room: Joined,
|
pub(crate) client: Client,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationRequest {
|
impl VerificationRequest {
|
||||||
/// Accept the interactive verification flow.
|
/// Accept the verification request
|
||||||
pub async fn accept(&self) -> Result<()> {
|
pub async fn accept(&self) -> Result<()> {
|
||||||
if let Some(content) = self.inner.accept() {
|
if let Some(request) = self.inner.accept() {
|
||||||
let content = AnyMessageEventContent::KeyVerificationReady(content);
|
match request {
|
||||||
self.room.send(content, None).await?;
|
OutgoingVerificationRequest::ToDevice(r) => {
|
||||||
|
self.client.send_to_device(&r).await?;
|
||||||
|
}
|
||||||
|
OutgoingVerificationRequest::InRoom(r) => {
|
||||||
|
self.client.room_send_helper(&r).await?;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Cancel the verification request
|
||||||
|
pub async fn cancel(&self) -> Result<()> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,8 +37,7 @@ use matrix_sdk_common::{
|
||||||
AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
AnyMessageEventContent, AnyToDeviceEvent, SyncMessageEvent, ToDeviceEvent,
|
||||||
},
|
},
|
||||||
identifiers::{
|
identifiers::{
|
||||||
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, EventId, RoomId,
|
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, EventEncryptionAlgorithm, RoomId, UserId,
|
||||||
UserId,
|
|
||||||
},
|
},
|
||||||
locks::Mutex,
|
locks::Mutex,
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
|
@ -317,8 +316,7 @@ impl OlmMachine {
|
||||||
requests.push(request);
|
requests.push(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
requests.append(&mut self.outgoing_to_device_requests());
|
requests.append(&mut self.verification_machine.outgoing_messages());
|
||||||
requests.append(&mut self.verification_machine.outgoing_room_message_requests());
|
|
||||||
requests.append(
|
requests.append(
|
||||||
&mut self
|
&mut self
|
||||||
.key_request_machine
|
.key_request_machine
|
||||||
|
@ -747,11 +745,6 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the to-device requests that need to be sent out.
|
|
||||||
fn outgoing_to_device_requests(&self) -> Vec<OutgoingRequest> {
|
|
||||||
self.verification_machine.outgoing_to_device_requests()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark an outgoing to-device requests as sent.
|
/// Mark an outgoing to-device requests as sent.
|
||||||
async fn mark_to_device_request_as_sent(&self, request_id: &Uuid) -> StoreResult<()> {
|
async fn mark_to_device_request_as_sent(&self, request_id: &Uuid) -> StoreResult<()> {
|
||||||
self.verification_machine.mark_request_as_sent(request_id);
|
self.verification_machine.mark_request_as_sent(request_id);
|
||||||
|
@ -773,7 +766,10 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a verification request object with the given flow id.
|
/// Get a verification request object with the given flow id.
|
||||||
pub fn get_verification_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
pub fn get_verification_request(
|
||||||
|
&self,
|
||||||
|
flow_id: impl AsRef<str>,
|
||||||
|
) -> Option<VerificationRequest> {
|
||||||
self.verification_machine.get_request(flow_id)
|
self.verification_machine.get_request(flow_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1967,14 +1963,16 @@ pub(crate) mod test {
|
||||||
alice.handle_verification_event(&event).await;
|
alice.handle_verification_event(&event).await;
|
||||||
|
|
||||||
let event = alice
|
let event = alice
|
||||||
.outgoing_to_device_requests()
|
.verification_machine
|
||||||
|
.outgoing_messages()
|
||||||
.first()
|
.first()
|
||||||
.map(|r| outgoing_request_to_event(alice.user_id(), r))
|
.map(|r| outgoing_request_to_event(alice.user_id(), r))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
bob.handle_verification_event(&event).await;
|
bob.handle_verification_event(&event).await;
|
||||||
|
|
||||||
let event = bob
|
let event = bob
|
||||||
.outgoing_to_device_requests()
|
.verification_machine
|
||||||
|
.outgoing_messages()
|
||||||
.first()
|
.first()
|
||||||
.map(|r| outgoing_request_to_event(bob.user_id(), r))
|
.map(|r| outgoing_request_to_event(bob.user_id(), r))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
|
@ -47,9 +47,8 @@ pub struct VerificationMachine {
|
||||||
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
pub(crate) store: Arc<Box<dyn CryptoStore>>,
|
||||||
verifications: Arc<DashMap<String, Sas>>,
|
verifications: Arc<DashMap<String, Sas>>,
|
||||||
room_verifications: Arc<DashMap<EventId, Sas>>,
|
room_verifications: Arc<DashMap<EventId, Sas>>,
|
||||||
requests: Arc<DashMap<EventId, VerificationRequest>>,
|
requests: Arc<DashMap<String, VerificationRequest>>,
|
||||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
outgoing_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||||
outgoing_room_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationMachine {
|
impl VerificationMachine {
|
||||||
|
@ -64,9 +63,8 @@ impl VerificationMachine {
|
||||||
store,
|
store,
|
||||||
verifications: DashMap::new().into(),
|
verifications: DashMap::new().into(),
|
||||||
requests: DashMap::new().into(),
|
requests: DashMap::new().into(),
|
||||||
outgoing_to_device_messages: DashMap::new().into(),
|
|
||||||
room_verifications: DashMap::new().into(),
|
room_verifications: DashMap::new().into(),
|
||||||
outgoing_room_messages: DashMap::new().into(),
|
outgoing_messages: DashMap::new().into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +81,7 @@ impl VerificationMachine {
|
||||||
device.clone(),
|
device.clone(),
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
identity,
|
identity,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = match content.into() {
|
let request = match content.into() {
|
||||||
|
@ -93,7 +92,8 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
OutgoingContent::ToDevice(c) => {
|
OutgoingContent::ToDevice(c) => {
|
||||||
let request = content_to_request(device.user_id(), device.device_id(), c);
|
let request =
|
||||||
|
content_to_request(device.user_id(), device.device_id().to_owned(), c);
|
||||||
|
|
||||||
self.verifications
|
self.verifications
|
||||||
.insert(sas.flow_id().as_str().to_owned(), sas.clone());
|
.insert(sas.flow_id().as_str().to_owned(), sas.clone());
|
||||||
|
@ -105,9 +105,8 @@ impl VerificationMachine {
|
||||||
Ok((sas, request))
|
Ok((sas, request))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_request(&self, flow_id: &EventId) -> Option<VerificationRequest> {
|
pub fn get_request(&self, flow_id: impl AsRef<str>) -> Option<VerificationRequest> {
|
||||||
#[allow(clippy::map_clone)]
|
self.requests.get(flow_id.as_ref()).map(|s| s.clone())
|
||||||
self.requests.get(flow_id).map(|s| s.clone())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
pub fn get_sas(&self, transaction_id: &str) -> Option<Sas> {
|
||||||
|
@ -134,7 +133,7 @@ impl VerificationMachine {
|
||||||
) {
|
) {
|
||||||
match content {
|
match content {
|
||||||
OutgoingContent::ToDevice(c) => {
|
OutgoingContent::ToDevice(c) => {
|
||||||
let request = content_to_request(recipient, recipient_device, c);
|
let request = content_to_request(recipient, recipient_device.to_owned(), c);
|
||||||
let request_id = request.txn_id;
|
let request_id = request.txn_id;
|
||||||
|
|
||||||
let request = OutgoingRequest {
|
let request = OutgoingRequest {
|
||||||
|
@ -142,7 +141,7 @@ impl VerificationMachine {
|
||||||
request: Arc::new(request.into()),
|
request: Arc::new(request.into()),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.outgoing_to_device_messages.insert(request_id, request);
|
self.outgoing_messages.insert(request_id, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
OutgoingContent::Room(r, c) => {
|
OutgoingContent::Room(r, c) => {
|
||||||
|
@ -160,12 +159,11 @@ impl VerificationMachine {
|
||||||
request_id,
|
request_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.outgoing_room_messages.insert(request_id, request);
|
self.outgoing_messages.insert(request_id, request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
fn receive_room_event_helper(&self, sas: &Sas, event: &AnyMessageEvent) {
|
fn receive_room_event_helper(&self, sas: &Sas, event: &AnyMessageEvent) {
|
||||||
if let Some(c) = sas.receive_room_event(event) {
|
if let Some(c) = sas.receive_room_event(event) {
|
||||||
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
self.queue_up_content(sas.other_user_id(), sas.other_device_id(), c);
|
||||||
|
@ -179,20 +177,11 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
|
pub fn mark_request_as_sent(&self, uuid: &Uuid) {
|
||||||
self.outgoing_room_messages.remove(uuid);
|
self.outgoing_messages.remove(uuid);
|
||||||
self.outgoing_to_device_messages.remove(uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn outgoing_room_message_requests(&self) -> Vec<OutgoingRequest> {
|
pub fn outgoing_messages(&self) -> Vec<OutgoingRequest> {
|
||||||
self.outgoing_room_messages
|
self.outgoing_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
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|r| (*r).clone())
|
.map(|r| (*r).clone())
|
||||||
.collect()
|
.collect()
|
||||||
|
@ -204,7 +193,7 @@ impl VerificationMachine {
|
||||||
|
|
||||||
for sas in self.verifications.iter() {
|
for sas in self.verifications.iter() {
|
||||||
if let Some(r) = sas.cancel_if_timed_out() {
|
if let Some(r) = sas.cancel_if_timed_out() {
|
||||||
self.outgoing_to_device_messages.insert(
|
self.outgoing_messages.insert(
|
||||||
r.request_id(),
|
r.request_id(),
|
||||||
OutgoingRequest {
|
OutgoingRequest {
|
||||||
request_id: r.request_id(),
|
request_id: r.request_id(),
|
||||||
|
@ -240,22 +229,23 @@ impl VerificationMachine {
|
||||||
m.sender, r.from_device
|
m.sender, r.from_device
|
||||||
);
|
);
|
||||||
|
|
||||||
let request = VerificationRequest::from_request_event(
|
let request = VerificationRequest::from_room_request(
|
||||||
self.account.clone(),
|
self.account.clone(),
|
||||||
self.private_identity.lock().await.clone(),
|
self.private_identity.lock().await.clone(),
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
room_id,
|
|
||||||
&m.sender,
|
&m.sender,
|
||||||
&m.event_id,
|
&m.event_id,
|
||||||
|
room_id,
|
||||||
r,
|
r,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.requests.insert(m.event_id.clone(), request);
|
self.requests
|
||||||
|
.insert(request.flow_id().as_str().to_owned(), request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnySyncMessageEvent::KeyVerificationReady(e) => {
|
AnySyncMessageEvent::KeyVerificationReady(e) => {
|
||||||
if let Some(request) = self.requests.get(&e.content.relation.event_id) {
|
if let Some(request) = self.requests.get(e.content.relation.event_id.as_str()) {
|
||||||
if &e.sender == request.other_user() {
|
if &e.sender == request.other_user() {
|
||||||
// TODO remove this unwrap.
|
// TODO remove this unwrap.
|
||||||
request.receive_ready(&e.sender, &e.content).unwrap();
|
request.receive_ready(&e.sender, &e.content).unwrap();
|
||||||
|
@ -268,7 +258,9 @@ impl VerificationMachine {
|
||||||
e.sender, e.content.from_device
|
e.sender, e.content.from_device
|
||||||
);
|
);
|
||||||
|
|
||||||
if let Some((_, request)) = self.requests.remove(&e.content.relation.event_id) {
|
if let Some((_, request)) =
|
||||||
|
self.requests.remove(e.content.relation.event_id.as_str())
|
||||||
|
{
|
||||||
if let Some(d) = self
|
if let Some(d) = self
|
||||||
.store
|
.store
|
||||||
.get_device(&e.sender, &e.content.from_device)
|
.get_device(&e.sender, &e.content.from_device)
|
||||||
|
@ -282,7 +274,7 @@ impl VerificationMachine {
|
||||||
Ok(s) => {
|
Ok(s) => {
|
||||||
info!(
|
info!(
|
||||||
"Started a new SAS verification, \
|
"Started a new SAS verification, \
|
||||||
automatically accepting because of in-room"
|
automatically accepting because we accepted from a request"
|
||||||
);
|
);
|
||||||
|
|
||||||
// TODO remove this unwrap
|
// TODO remove this unwrap
|
||||||
|
@ -291,7 +283,7 @@ impl VerificationMachine {
|
||||||
self.room_verifications
|
self.room_verifications
|
||||||
.insert(e.content.relation.event_id.clone(), s);
|
.insert(e.content.relation.event_id.clone(), s);
|
||||||
|
|
||||||
self.outgoing_room_messages
|
self.outgoing_messages
|
||||||
.insert(accept_request.request_id(), accept_request.into());
|
.insert(accept_request.request_id(), accept_request.into());
|
||||||
}
|
}
|
||||||
Err(c) => {
|
Err(c) => {
|
||||||
|
@ -299,7 +291,7 @@ impl VerificationMachine {
|
||||||
"Can't start key verification with {} {}, canceling: {:?}",
|
"Can't start key verification with {} {}, canceling: {:?}",
|
||||||
e.sender, e.content.from_device, c
|
e.sender, e.content.from_device, c
|
||||||
);
|
);
|
||||||
// self.queue_up_content(&e.sender, &e.content.from_device, c)
|
self.queue_up_content(&e.sender, &e.content.from_device, c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,14 +331,12 @@ impl VerificationMachine {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VerificationResult::Cancel(r) => {
|
VerificationResult::Cancel(r) => {
|
||||||
self.outgoing_to_device_messages
|
self.outgoing_messages.insert(r.request_id(), r.into());
|
||||||
.insert(r.request_id(), r.into());
|
|
||||||
}
|
}
|
||||||
VerificationResult::SignatureUpload(r) => {
|
VerificationResult::SignatureUpload(r) => {
|
||||||
let request: OutgoingRequest = r.into();
|
let request: OutgoingRequest = r.into();
|
||||||
|
|
||||||
self.outgoing_to_device_messages
|
self.outgoing_messages.insert(request.request_id, request);
|
||||||
.insert(request.request_id, request);
|
|
||||||
|
|
||||||
if let Some(c) = content {
|
if let Some(c) = content {
|
||||||
self.queue_up_content(
|
self.queue_up_content(
|
||||||
|
@ -371,6 +361,26 @@ impl VerificationMachine {
|
||||||
trace!("Received a key verification event {:?}", event);
|
trace!("Received a key verification event {:?}", event);
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
|
AnyToDeviceEvent::KeyVerificationRequest(e) => {
|
||||||
|
let request = VerificationRequest::from_request(
|
||||||
|
self.account.clone(),
|
||||||
|
self.private_identity.lock().await.clone(),
|
||||||
|
self.store.clone(),
|
||||||
|
&e.sender,
|
||||||
|
&e.content,
|
||||||
|
);
|
||||||
|
|
||||||
|
self.requests
|
||||||
|
.insert(request.flow_id().as_str().to_string(), request);
|
||||||
|
}
|
||||||
|
AnyToDeviceEvent::KeyVerificationReady(e) => {
|
||||||
|
if let Some(request) = self.requests.get(&e.content.transaction_id) {
|
||||||
|
if &e.sender == request.other_user() {
|
||||||
|
// TODO remove this unwrap.
|
||||||
|
request.receive_ready(&e.sender, &e.content).unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
AnyToDeviceEvent::KeyVerificationStart(e) => {
|
||||||
trace!(
|
trace!(
|
||||||
"Received a m.key.verification start event from {} {}",
|
"Received a m.key.verification start event from {} {}",
|
||||||
|
@ -432,7 +442,7 @@ impl VerificationMachine {
|
||||||
match s.mark_as_done().await? {
|
match s.mark_as_done().await? {
|
||||||
VerificationResult::Ok => (),
|
VerificationResult::Ok => (),
|
||||||
VerificationResult::Cancel(r) => {
|
VerificationResult::Cancel(r) => {
|
||||||
self.outgoing_to_device_messages.insert(
|
self.outgoing_messages.insert(
|
||||||
r.request_id(),
|
r.request_id(),
|
||||||
OutgoingRequest {
|
OutgoingRequest {
|
||||||
request_id: r.request_id(),
|
request_id: r.request_id(),
|
||||||
|
@ -443,7 +453,7 @@ impl VerificationMachine {
|
||||||
VerificationResult::SignatureUpload(r) => {
|
VerificationResult::SignatureUpload(r) => {
|
||||||
let request_id = Uuid::new_v4();
|
let request_id = Uuid::new_v4();
|
||||||
|
|
||||||
self.outgoing_to_device_messages.insert(
|
self.outgoing_messages.insert(
|
||||||
request_id,
|
request_id,
|
||||||
OutgoingRequest {
|
OutgoingRequest {
|
||||||
request_id,
|
request_id,
|
||||||
|
@ -521,6 +531,7 @@ mod test {
|
||||||
alice_device,
|
alice_device,
|
||||||
bob_store,
|
bob_store,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
machine
|
machine
|
||||||
|
@ -558,15 +569,11 @@ mod test {
|
||||||
.map(|c| wrap_any_to_device_content(bob.user_id(), c))
|
.map(|c| wrap_any_to_device_content(bob.user_id(), c))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert!(alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(alice_machine.outgoing_messages.is_empty());
|
||||||
alice_machine.receive_event(&event).await.unwrap();
|
alice_machine.receive_event(&event).await.unwrap();
|
||||||
assert!(!alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(!alice_machine.outgoing_messages.is_empty());
|
||||||
|
|
||||||
let request = alice_machine
|
let request = alice_machine.outgoing_messages.iter().next().unwrap();
|
||||||
.outgoing_to_device_messages
|
|
||||||
.iter()
|
|
||||||
.next()
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let txn_id = *request.request_id();
|
let txn_id = *request.request_id();
|
||||||
|
|
||||||
|
@ -611,14 +618,14 @@ mod test {
|
||||||
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
let alice = alice_machine.get_sas(bob.flow_id().as_str()).unwrap();
|
||||||
|
|
||||||
assert!(!alice.timed_out());
|
assert!(!alice.timed_out());
|
||||||
assert!(alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(alice_machine.outgoing_messages.is_empty());
|
||||||
|
|
||||||
// This line panics on macOS, so we're disabled for now.
|
// This line panics on macOS, so we're disabled for now.
|
||||||
alice.set_creation_time(Instant::now() - Duration::from_secs(60 * 15));
|
alice.set_creation_time(Instant::now() - Duration::from_secs(60 * 15));
|
||||||
assert!(alice.timed_out());
|
assert!(alice.timed_out());
|
||||||
assert!(alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(alice_machine.outgoing_messages.is_empty());
|
||||||
alice_machine.garbage_collect();
|
alice_machine.garbage_collect();
|
||||||
assert!(!alice_machine.outgoing_to_device_messages.is_empty());
|
assert!(!alice_machine.outgoing_messages.is_empty());
|
||||||
alice_machine.garbage_collect();
|
alice_machine.garbage_collect();
|
||||||
assert!(alice_machine.verifications.is_empty());
|
assert!(alice_machine.verifications.is_empty());
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,43 @@ pub use machine::VerificationMachine;
|
||||||
pub use requests::VerificationRequest;
|
pub use requests::VerificationRequest;
|
||||||
pub use sas::{AcceptSettings, Sas, VerificationResult};
|
pub use sas::{AcceptSettings, Sas, VerificationResult};
|
||||||
|
|
||||||
|
use matrix_sdk_common::identifiers::{EventId, RoomId};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Hash, PartialEq, PartialOrd)]
|
||||||
|
pub enum FlowId {
|
||||||
|
ToDevice(String),
|
||||||
|
InRoom(RoomId, EventId),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FlowId {
|
||||||
|
pub fn room_id(&self) -> Option<&RoomId> {
|
||||||
|
if let FlowId::InRoom(r, _) = &self {
|
||||||
|
Some(r)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
match self {
|
||||||
|
FlowId::InRoom(_, r) => r.as_str(),
|
||||||
|
FlowId::ToDevice(t) => t.as_str(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for FlowId {
|
||||||
|
fn from(transaciton_id: String) -> Self {
|
||||||
|
FlowId::ToDevice(transaciton_id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(RoomId, EventId)> for FlowId {
|
||||||
|
fn from(ids: (RoomId, EventId)) -> Self {
|
||||||
|
FlowId::InRoom(ids.0, ids.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test {
|
pub(crate) mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
|
@ -14,30 +14,130 @@
|
||||||
|
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
use std::sync::{Arc, Mutex};
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
api::r0::to_device::DeviceIdOrAllDevices,
|
||||||
events::{
|
events::{
|
||||||
key::verification::{
|
key::verification::{
|
||||||
ready::ReadyEventContent, start::StartEventContent, Relation, VerificationMethod,
|
ready::{ReadyEventContent, ReadyToDeviceEventContent},
|
||||||
|
request::RequestToDeviceEventContent,
|
||||||
|
start::StartEventContent,
|
||||||
|
Relation, VerificationMethod,
|
||||||
},
|
},
|
||||||
room::message::KeyVerificationRequestEventContent,
|
room::message::KeyVerificationRequestEventContent,
|
||||||
MessageEvent, SyncMessageEvent,
|
AnyMessageEventContent, AnyToDeviceEventContent, MessageEvent, SyncMessageEvent,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
|
identifiers::{DeviceId, DeviceIdBox, EventId, RoomId, UserId},
|
||||||
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||||
store::CryptoStore,
|
store::CryptoStore,
|
||||||
ReadOnlyDevice, Sas, UserIdentities,
|
OutgoingVerificationRequest, ReadOnlyDevice, RoomMessageRequest, Sas, ToDeviceRequest,
|
||||||
|
UserIdentities,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::sas::{OutgoingContent, StartContent};
|
use super::{
|
||||||
|
sas::{content_to_request, OutgoingContent, StartContent},
|
||||||
|
FlowId,
|
||||||
|
};
|
||||||
|
|
||||||
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
const SUPPORTED_METHODS: &[VerificationMethod] = &[VerificationMethod::MSasV1];
|
||||||
|
|
||||||
|
pub enum RequestContent<'a> {
|
||||||
|
ToDevice(&'a RequestToDeviceEventContent),
|
||||||
|
Room(&'a KeyVerificationRequestEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RequestContent<'_> {
|
||||||
|
fn from_device(&self) -> &DeviceId {
|
||||||
|
match self {
|
||||||
|
RequestContent::ToDevice(t) => &t.from_device,
|
||||||
|
RequestContent::Room(r) => &r.from_device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn methods(&self) -> &[VerificationMethod] {
|
||||||
|
match self {
|
||||||
|
RequestContent::ToDevice(t) => &t.methods,
|
||||||
|
RequestContent::Room(r) => &r.methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a KeyVerificationRequestEventContent> for RequestContent<'a> {
|
||||||
|
fn from(c: &'a KeyVerificationRequestEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a RequestToDeviceEventContent> for RequestContent<'a> {
|
||||||
|
fn from(c: &'a RequestToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ReadyContent<'a> {
|
||||||
|
ToDevice(&'a ReadyToDeviceEventContent),
|
||||||
|
Room(&'a ReadyEventContent),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReadyContent<'_> {
|
||||||
|
fn from_device(&self) -> &DeviceId {
|
||||||
|
match self {
|
||||||
|
ReadyContent::ToDevice(t) => &t.from_device,
|
||||||
|
ReadyContent::Room(r) => &r.from_device,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn methods(&self) -> &[VerificationMethod] {
|
||||||
|
match self {
|
||||||
|
ReadyContent::ToDevice(t) => &t.methods,
|
||||||
|
ReadyContent::Room(r) => &r.methods,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ReadyEventContent> for ReadyContent<'a> {
|
||||||
|
fn from(c: &'a ReadyEventContent) -> Self {
|
||||||
|
Self::Room(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a ReadyToDeviceEventContent> for ReadyContent<'a> {
|
||||||
|
fn from(c: &'a ReadyToDeviceEventContent) -> Self {
|
||||||
|
Self::ToDevice(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> TryFrom<&'a OutgoingContent> for ReadyContent<'a> {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &'a OutgoingContent) -> Result<Self, Self::Error> {
|
||||||
|
match value {
|
||||||
|
OutgoingContent::Room(_, c) => {
|
||||||
|
if let AnyMessageEventContent::KeyVerificationReady(c) = c {
|
||||||
|
Ok(ReadyContent::Room(c))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OutgoingContent::ToDevice(c) => {
|
||||||
|
if let AnyToDeviceEventContent::KeyVerificationReady(c) = c {
|
||||||
|
Ok(ReadyContent::ToDevice(c))
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
/// TODO
|
/// TODO
|
||||||
pub struct VerificationRequest {
|
pub struct VerificationRequest {
|
||||||
|
@ -46,7 +146,7 @@ pub struct VerificationRequest {
|
||||||
other_user_id: Arc<UserId>,
|
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>,
|
flow_id: Arc<FlowId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationRequest {
|
impl VerificationRequest {
|
||||||
|
@ -55,30 +155,46 @@ impl VerificationRequest {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
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: &RoomId,
|
||||||
|
event_id: &EventId,
|
||||||
other_user: &UserId,
|
other_user: &UserId,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
let flow_id = (room_id.to_owned(), event_id.to_owned()).into();
|
||||||
|
|
||||||
let inner = Mutex::new(InnerRequest::Created(RequestState::new(
|
let inner = Mutex::new(InnerRequest::Created(RequestState::new(
|
||||||
account.user_id(),
|
account.user_id(),
|
||||||
account.device_id(),
|
account.device_id(),
|
||||||
other_user,
|
other_user,
|
||||||
|
&flow_id,
|
||||||
)))
|
)))
|
||||||
.into();
|
.into();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
inner,
|
inner,
|
||||||
account,
|
account,
|
||||||
private_cross_signing_identity,
|
private_cross_signing_identity,
|
||||||
store,
|
store,
|
||||||
other_user_id: other_user.clone().into(),
|
other_user_id: other_user.clone().into(),
|
||||||
room_id,
|
flow_id: flow_id.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
pub fn request(&self) -> Option<KeyVerificationRequestEventContent> {
|
pub fn request(
|
||||||
match &*self.inner.lock().unwrap() {
|
own_user_id: &UserId,
|
||||||
InnerRequest::Created(c) => Some(c.as_content()),
|
own_device_id: &DeviceId,
|
||||||
_ => None,
|
other_user_id: &UserId,
|
||||||
|
) -> KeyVerificationRequestEventContent {
|
||||||
|
KeyVerificationRequestEventContent {
|
||||||
|
body: format!(
|
||||||
|
"{} is requesting to verify your key, but your client does not \
|
||||||
|
support in-chat key verification. You will need to use legacy \
|
||||||
|
key verification to verify keys.",
|
||||||
|
own_user_id
|
||||||
|
),
|
||||||
|
methods: SUPPORTED_METHODS.to_vec(),
|
||||||
|
from_device: own_device_id.into(),
|
||||||
|
to: other_user_id.to_owned(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,23 +204,56 @@ impl VerificationRequest {
|
||||||
&self.other_user_id
|
&self.other_user_id
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mark the request as sent.
|
/// Get the unique ID of this verification request
|
||||||
pub fn mark_as_sent(&self, response: &RoomMessageResponse) {
|
pub fn flow_id(&self) -> &FlowId {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
&self.flow_id
|
||||||
|
|
||||||
if let InnerRequest::Created(c) = &*inner {
|
|
||||||
*inner = InnerRequest::Sent(c.clone().into_sent(response));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_request_event(
|
pub(crate) fn from_room_request(
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
room_id: &RoomId,
|
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
event_id: &EventId,
|
event_id: &EventId,
|
||||||
|
room_id: &RoomId,
|
||||||
content: &KeyVerificationRequestEventContent,
|
content: &KeyVerificationRequestEventContent,
|
||||||
|
) -> Self {
|
||||||
|
let flow_id = FlowId::from((room_id.to_owned(), event_id.to_owned()));
|
||||||
|
Self::from_helper(
|
||||||
|
account,
|
||||||
|
private_cross_signing_identity,
|
||||||
|
store,
|
||||||
|
sender,
|
||||||
|
flow_id,
|
||||||
|
content.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn from_request(
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
|
sender: &UserId,
|
||||||
|
content: &RequestToDeviceEventContent,
|
||||||
|
) -> Self {
|
||||||
|
let flow_id = FlowId::from(content.transaction_id.to_owned());
|
||||||
|
Self::from_helper(
|
||||||
|
account,
|
||||||
|
private_cross_signing_identity,
|
||||||
|
store,
|
||||||
|
sender,
|
||||||
|
flow_id,
|
||||||
|
content.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_helper(
|
||||||
|
account: ReadOnlyAccount,
|
||||||
|
private_cross_signing_identity: PrivateCrossSigningIdentity,
|
||||||
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
|
sender: &UserId,
|
||||||
|
flow_id: FlowId,
|
||||||
|
content: RequestContent,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
inner: Arc::new(Mutex::new(InnerRequest::Requested(
|
inner: Arc::new(Mutex::new(InnerRequest::Requested(
|
||||||
|
@ -112,7 +261,7 @@ impl VerificationRequest {
|
||||||
account.user_id(),
|
account.user_id(),
|
||||||
account.device_id(),
|
account.device_id(),
|
||||||
sender,
|
sender,
|
||||||
event_id,
|
&flow_id,
|
||||||
content,
|
content,
|
||||||
),
|
),
|
||||||
))),
|
))),
|
||||||
|
@ -120,29 +269,37 @@ impl VerificationRequest {
|
||||||
other_user_id: sender.clone().into(),
|
other_user_id: sender.clone().into(),
|
||||||
private_cross_signing_identity,
|
private_cross_signing_identity,
|
||||||
store,
|
store,
|
||||||
room_id: room_id.clone().into(),
|
flow_id: flow_id.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The room id where the verification is happening.
|
|
||||||
pub fn room_id(&self) -> &RoomId {
|
|
||||||
&self.room_id
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Accept the verification request.
|
/// Accept the verification request.
|
||||||
pub fn accept(&self) -> Option<ReadyEventContent> {
|
pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
|
||||||
self.inner.lock().unwrap().accept()
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
|
||||||
|
inner.accept().map(|c| match c {
|
||||||
|
OutgoingContent::ToDevice(content) => self
|
||||||
|
.content_to_request(inner.other_device_id(), content)
|
||||||
|
.into(),
|
||||||
|
OutgoingContent::Room(room_id, content) => RoomMessageRequest {
|
||||||
|
room_id,
|
||||||
|
txn_id: Uuid::new_v4(),
|
||||||
|
content,
|
||||||
|
}
|
||||||
|
.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_wraps)]
|
#[allow(clippy::unnecessary_wraps)]
|
||||||
pub(crate) fn receive_ready(
|
pub(crate) fn receive_ready<'a>(
|
||||||
&self,
|
&self,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
content: &ReadyEventContent,
|
content: impl Into<ReadyContent<'a>>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
let mut inner = self.inner.lock().unwrap();
|
let mut inner = self.inner.lock().unwrap();
|
||||||
|
let content = content.into();
|
||||||
|
|
||||||
if let InnerRequest::Sent(s) = &*inner {
|
if let InnerRequest::Created(s) = &*inner {
|
||||||
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
*inner = InnerRequest::Ready(s.clone().into_ready(sender, content));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,14 +318,17 @@ impl VerificationRequest {
|
||||||
user_identity: Option<UserIdentities>,
|
user_identity: Option<UserIdentities>,
|
||||||
) -> Result<Sas, OutgoingContent> {
|
) -> Result<Sas, OutgoingContent> {
|
||||||
match &*self.inner.lock().unwrap() {
|
match &*self.inner.lock().unwrap() {
|
||||||
InnerRequest::Ready(s) => s.clone().into_started_sas(
|
InnerRequest::Ready(s) => match &s.state.flow_id {
|
||||||
&event.clone().into_full_event(self.room_id().clone()),
|
FlowId::ToDevice(_) => todo!(),
|
||||||
|
FlowId::InRoom(r, _) => s.clone().into_started_sas(
|
||||||
|
&event.clone().into_full_event(r.to_owned()),
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
self.account.clone(),
|
self.account.clone(),
|
||||||
self.private_cross_signing_identity.clone(),
|
self.private_cross_signing_identity.clone(),
|
||||||
device,
|
device,
|
||||||
user_identity,
|
user_identity,
|
||||||
),
|
),
|
||||||
|
},
|
||||||
// TODO cancel here since we got a missmatched message or do
|
// TODO cancel here since we got a missmatched message or do
|
||||||
// nothing?
|
// nothing?
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
|
@ -181,30 +341,50 @@ impl VerificationRequest {
|
||||||
user_identity: Option<UserIdentities>,
|
user_identity: Option<UserIdentities>,
|
||||||
) -> Option<(Sas, StartContent)> {
|
) -> Option<(Sas, StartContent)> {
|
||||||
match &*self.inner.lock().unwrap() {
|
match &*self.inner.lock().unwrap() {
|
||||||
InnerRequest::Ready(s) => Some(s.clone().start_sas(
|
InnerRequest::Ready(s) => match &s.state.flow_id {
|
||||||
self.room_id(),
|
FlowId::ToDevice(_) => todo!(),
|
||||||
|
FlowId::InRoom(_, _) => Some(s.clone().start_sas(
|
||||||
self.store.clone(),
|
self.store.clone(),
|
||||||
self.account.clone(),
|
self.account.clone(),
|
||||||
self.private_cross_signing_identity.clone(),
|
self.private_cross_signing_identity.clone(),
|
||||||
device,
|
device,
|
||||||
user_identity,
|
user_identity,
|
||||||
)),
|
)),
|
||||||
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn content_to_request(
|
||||||
|
&self,
|
||||||
|
other_device_id: DeviceIdOrAllDevices,
|
||||||
|
content: AnyToDeviceEventContent,
|
||||||
|
) -> ToDeviceRequest {
|
||||||
|
content_to_request(&self.other_user_id, other_device_id, content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum InnerRequest {
|
enum InnerRequest {
|
||||||
Created(RequestState<Created>),
|
Created(RequestState<Created>),
|
||||||
Sent(RequestState<Sent>),
|
|
||||||
Requested(RequestState<Requested>),
|
Requested(RequestState<Requested>),
|
||||||
Ready(RequestState<Ready>),
|
Ready(RequestState<Ready>),
|
||||||
Passive(RequestState<Passive>),
|
Passive(RequestState<Passive>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InnerRequest {
|
impl InnerRequest {
|
||||||
fn accept(&mut self) -> Option<ReadyEventContent> {
|
fn other_device_id(&self) -> DeviceIdOrAllDevices {
|
||||||
|
match self {
|
||||||
|
InnerRequest::Created(_) => DeviceIdOrAllDevices::AllDevices,
|
||||||
|
InnerRequest::Requested(_) => DeviceIdOrAllDevices::AllDevices,
|
||||||
|
InnerRequest::Ready(r) => {
|
||||||
|
DeviceIdOrAllDevices::DeviceId(r.state.other_device_id.to_owned())
|
||||||
|
}
|
||||||
|
InnerRequest::Passive(_) => DeviceIdOrAllDevices::AllDevices,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accept(&mut self) -> Option<OutgoingContent> {
|
||||||
if let InnerRequest::Requested(s) = self {
|
if let InnerRequest::Requested(s) = self {
|
||||||
let (state, content) = s.clone().accept();
|
let (state, content) = s.clone().accept();
|
||||||
*self = InnerRequest::Ready(state);
|
*self = InnerRequest::Ready(state);
|
||||||
|
@ -254,72 +434,49 @@ struct RequestState<S: Clone> {
|
||||||
state: S,
|
state: S,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
struct Created {}
|
|
||||||
|
|
||||||
impl RequestState<Created> {
|
impl RequestState<Created> {
|
||||||
fn new(own_user_id: &UserId, own_device_id: &DeviceId, other_user: &UserId) -> Self {
|
fn new(
|
||||||
|
own_user_id: &UserId,
|
||||||
|
own_device_id: &DeviceId,
|
||||||
|
other_user_id: &UserId,
|
||||||
|
flow_id: &FlowId,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
own_user_id: own_user_id.clone(),
|
own_user_id: own_user_id.to_owned(),
|
||||||
own_device_id: own_device_id.into(),
|
own_device_id: own_device_id.to_owned(),
|
||||||
other_user_id: other_user.clone(),
|
other_user_id: other_user_id.to_owned(),
|
||||||
state: Created {},
|
state: Created {
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_content(&self) -> KeyVerificationRequestEventContent {
|
|
||||||
KeyVerificationRequestEventContent {
|
|
||||||
body: format!(
|
|
||||||
"{} is requesting to verify your key, but your client does not \
|
|
||||||
support in-chat key verification. You will need to use legacy \
|
|
||||||
key verification to verify keys.",
|
|
||||||
self.own_user_id
|
|
||||||
),
|
|
||||||
methods: SUPPORTED_METHODS.to_vec(),
|
methods: SUPPORTED_METHODS.to_vec(),
|
||||||
from_device: self.own_device_id.clone(),
|
flow_id: flow_id.to_owned(),
|
||||||
to: self.other_user_id.clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_sent(self, response: &RoomMessageResponse) -> RequestState<Sent> {
|
|
||||||
RequestState {
|
|
||||||
own_user_id: self.own_user_id,
|
|
||||||
own_device_id: self.own_device_id,
|
|
||||||
other_user_id: self.other_user_id,
|
|
||||||
state: Sent {
|
|
||||||
methods: SUPPORTED_METHODS.to_vec(),
|
|
||||||
flow_id: response.event_id.clone(),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
fn into_ready(self, _sender: &UserId, content: ReadyContent) -> RequestState<Ready> {
|
||||||
struct Sent {
|
|
||||||
/// The verification methods supported by the sender.
|
|
||||||
pub methods: Vec<VerificationMethod>,
|
|
||||||
|
|
||||||
/// The event id of our `m.key.verification.request` event which acts as an
|
|
||||||
/// unique id identifying this verification flow.
|
|
||||||
pub flow_id: EventId,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RequestState<Sent> {
|
|
||||||
fn into_ready(self, _sender: &UserId, content: &ReadyEventContent) -> RequestState<Ready> {
|
|
||||||
// TODO check the flow id, and that the methods match what we suggested.
|
// TODO check the flow id, and that the methods match what we suggested.
|
||||||
RequestState {
|
RequestState {
|
||||||
own_user_id: self.own_user_id,
|
own_user_id: self.own_user_id,
|
||||||
own_device_id: self.own_device_id,
|
own_device_id: self.own_device_id,
|
||||||
other_user_id: self.other_user_id,
|
other_user_id: self.other_user_id,
|
||||||
state: Ready {
|
state: Ready {
|
||||||
methods: content.methods.to_owned(),
|
methods: content.methods().to_owned(),
|
||||||
other_device_id: content.from_device.clone(),
|
other_device_id: content.from_device().into(),
|
||||||
flow_id: self.state.flow_id,
|
flow_id: self.state.flow_id,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
struct Created {
|
||||||
|
/// The verification methods supported by the sender.
|
||||||
|
pub methods: Vec<VerificationMethod>,
|
||||||
|
|
||||||
|
/// The event id of our `m.key.verification.request` event which acts as an
|
||||||
|
/// unique id identifying this verification flow.
|
||||||
|
pub flow_id: FlowId,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct Requested {
|
struct Requested {
|
||||||
/// The verification methods supported by the sender.
|
/// The verification methods supported by the sender.
|
||||||
|
@ -327,7 +484,7 @@ struct Requested {
|
||||||
|
|
||||||
/// The event id of the `m.key.verification.request` event which acts as an
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
/// unique id identifying this verification flow.
|
/// unique id identifying this verification flow.
|
||||||
pub flow_id: EventId,
|
pub flow_id: FlowId,
|
||||||
|
|
||||||
/// The device id of the device that responded to the verification request.
|
/// The device id of the device that responded to the verification request.
|
||||||
pub other_device_id: DeviceIdBox,
|
pub other_device_id: DeviceIdBox,
|
||||||
|
@ -338,8 +495,8 @@ impl RequestState<Requested> {
|
||||||
own_user_id: &UserId,
|
own_user_id: &UserId,
|
||||||
own_device_id: &DeviceId,
|
own_device_id: &DeviceId,
|
||||||
sender: &UserId,
|
sender: &UserId,
|
||||||
event_id: &EventId,
|
flow_id: &FlowId,
|
||||||
content: &KeyVerificationRequestEventContent,
|
content: RequestContent,
|
||||||
) -> RequestState<Requested> {
|
) -> RequestState<Requested> {
|
||||||
// TODO only create this if we suport the methods
|
// TODO only create this if we suport the methods
|
||||||
RequestState {
|
RequestState {
|
||||||
|
@ -347,14 +504,14 @@ impl RequestState<Requested> {
|
||||||
own_device_id: own_device_id.into(),
|
own_device_id: own_device_id.into(),
|
||||||
other_user_id: sender.clone(),
|
other_user_id: sender.clone(),
|
||||||
state: Requested {
|
state: Requested {
|
||||||
methods: content.methods.clone(),
|
methods: content.methods().to_owned(),
|
||||||
flow_id: event_id.clone(),
|
flow_id: flow_id.clone(),
|
||||||
other_device_id: content.from_device.clone(),
|
other_device_id: content.from_device().into(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept(self) -> (RequestState<Ready>, ReadyEventContent) {
|
fn accept(self) -> (RequestState<Ready>, OutgoingContent) {
|
||||||
let state = RequestState {
|
let state = RequestState {
|
||||||
own_user_id: self.own_user_id,
|
own_user_id: self.own_user_id,
|
||||||
own_device_id: self.own_device_id.clone(),
|
own_device_id: self.own_device_id.clone(),
|
||||||
|
@ -366,12 +523,24 @@ impl RequestState<Requested> {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = ReadyEventContent {
|
let content = match self.state.flow_id {
|
||||||
|
FlowId::ToDevice(i) => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationReady(ReadyToDeviceEventContent {
|
||||||
from_device: self.own_device_id,
|
from_device: self.own_device_id,
|
||||||
methods: self.state.methods,
|
methods: self.state.methods,
|
||||||
relation: Relation {
|
transaction_id: i,
|
||||||
event_id: self.state.flow_id,
|
})
|
||||||
},
|
.into()
|
||||||
|
}
|
||||||
|
FlowId::InRoom(r, e) => (
|
||||||
|
r,
|
||||||
|
AnyMessageEventContent::KeyVerificationReady(ReadyEventContent {
|
||||||
|
from_device: self.own_device_id,
|
||||||
|
methods: self.state.methods,
|
||||||
|
relation: Relation { event_id: e },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
};
|
};
|
||||||
|
|
||||||
(state, content)
|
(state, content)
|
||||||
|
@ -388,7 +557,7 @@ struct Ready {
|
||||||
|
|
||||||
/// The event id of the `m.key.verification.request` event which acts as an
|
/// The event id of the `m.key.verification.request` event which acts as an
|
||||||
/// unique id identifying this verification flow.
|
/// unique id identifying this verification flow.
|
||||||
pub flow_id: EventId,
|
pub flow_id: FlowId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RequestState<Ready> {
|
impl RequestState<Ready> {
|
||||||
|
@ -413,22 +582,31 @@ impl RequestState<Ready> {
|
||||||
|
|
||||||
fn start_sas(
|
fn start_sas(
|
||||||
self,
|
self,
|
||||||
room_id: &RoomId,
|
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
private_identity: PrivateCrossSigningIdentity,
|
private_identity: PrivateCrossSigningIdentity,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (Sas, StartContent) {
|
) -> (Sas, StartContent) {
|
||||||
Sas::start_in_room(
|
match self.state.flow_id {
|
||||||
self.state.flow_id,
|
FlowId::ToDevice(t) => Sas::start(
|
||||||
room_id.clone(),
|
|
||||||
account,
|
account,
|
||||||
private_identity,
|
private_identity,
|
||||||
other_device,
|
other_device,
|
||||||
store,
|
store,
|
||||||
other_identity,
|
other_identity,
|
||||||
)
|
Some(t),
|
||||||
|
),
|
||||||
|
FlowId::InRoom(r, e) => Sas::start_in_room(
|
||||||
|
e,
|
||||||
|
r,
|
||||||
|
account,
|
||||||
|
private_identity,
|
||||||
|
other_device,
|
||||||
|
store,
|
||||||
|
other_identity,
|
||||||
|
),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +625,6 @@ mod test {
|
||||||
use std::{convert::TryFrom, time::SystemTime};
|
use std::{convert::TryFrom, time::SystemTime};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::message::send_message_event::Response as RoomMessageResponse,
|
|
||||||
events::{SyncMessageEvent, Unsigned},
|
events::{SyncMessageEvent, Unsigned},
|
||||||
identifiers::{event_id, room_id, DeviceIdBox, UserId},
|
identifiers::{event_id, room_id, DeviceIdBox, UserId},
|
||||||
};
|
};
|
||||||
|
@ -456,7 +633,10 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
olm::{PrivateCrossSigningIdentity, ReadOnlyAccount},
|
||||||
store::{CryptoStore, MemoryStore},
|
store::{CryptoStore, MemoryStore},
|
||||||
verification::sas::StartContent,
|
verification::{
|
||||||
|
requests::ReadyContent,
|
||||||
|
sas::{OutgoingContent, StartContent},
|
||||||
|
},
|
||||||
ReadOnlyDevice,
|
ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -491,32 +671,31 @@ mod test {
|
||||||
let bob_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
let bob_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
||||||
let bob_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
let bob_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
||||||
|
|
||||||
|
let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id());
|
||||||
|
|
||||||
let bob_request = VerificationRequest::new(
|
let bob_request = VerificationRequest::new(
|
||||||
bob,
|
bob,
|
||||||
bob_identity,
|
bob_identity,
|
||||||
bob_store.into(),
|
bob_store.into(),
|
||||||
room_id.clone().into(),
|
&room_id,
|
||||||
|
&event_id,
|
||||||
&alice_id(),
|
&alice_id(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = bob_request.request().unwrap();
|
let alice_request = VerificationRequest::from_room_request(
|
||||||
|
|
||||||
let alice_request = VerificationRequest::from_request_event(
|
|
||||||
alice,
|
alice,
|
||||||
alice_identity,
|
alice_identity,
|
||||||
alice_store.into(),
|
alice_store.into(),
|
||||||
&room_id,
|
|
||||||
&bob_id(),
|
&bob_id(),
|
||||||
&event_id,
|
&event_id,
|
||||||
|
&room_id,
|
||||||
&content,
|
&content,
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = alice_request.accept().unwrap();
|
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||||
|
let content = ReadyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let response = RoomMessageResponse::new(event_id);
|
bob_request.receive_ready(&alice_id(), content).unwrap();
|
||||||
bob_request.mark_as_sent(&response);
|
|
||||||
|
|
||||||
bob_request.receive_ready(&alice_id(), &content).unwrap();
|
|
||||||
|
|
||||||
assert!(bob_request.is_ready());
|
assert!(bob_request.is_ready());
|
||||||
assert!(alice_request.is_ready());
|
assert!(alice_request.is_ready());
|
||||||
|
@ -538,32 +717,31 @@ mod test {
|
||||||
let bob_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
let bob_store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
||||||
let bob_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
let bob_identity = PrivateCrossSigningIdentity::empty(alice_id());
|
||||||
|
|
||||||
|
let content = VerificationRequest::request(bob.user_id(), bob.device_id(), &alice_id());
|
||||||
|
|
||||||
let bob_request = VerificationRequest::new(
|
let bob_request = VerificationRequest::new(
|
||||||
bob,
|
bob,
|
||||||
bob_identity,
|
bob_identity,
|
||||||
bob_store.into(),
|
bob_store.into(),
|
||||||
room_id.clone().into(),
|
&room_id,
|
||||||
|
&event_id,
|
||||||
&alice_id(),
|
&alice_id(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = bob_request.request().unwrap();
|
let alice_request = VerificationRequest::from_room_request(
|
||||||
|
|
||||||
let alice_request = VerificationRequest::from_request_event(
|
|
||||||
alice,
|
alice,
|
||||||
alice_identity,
|
alice_identity,
|
||||||
alice_store.into(),
|
alice_store.into(),
|
||||||
&room_id,
|
|
||||||
&bob_id(),
|
&bob_id(),
|
||||||
&event_id,
|
&event_id,
|
||||||
|
&room_id,
|
||||||
&content,
|
&content,
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = alice_request.accept().unwrap();
|
let content: OutgoingContent = alice_request.accept().unwrap().into();
|
||||||
|
let content = ReadyContent::try_from(&content).unwrap();
|
||||||
|
|
||||||
let response = RoomMessageResponse::new(event_id.clone());
|
bob_request.receive_ready(&alice_id(), content).unwrap();
|
||||||
bob_request.mark_as_sent(&response);
|
|
||||||
|
|
||||||
bob_request.receive_ready(&alice_id(), &content).unwrap();
|
|
||||||
|
|
||||||
assert!(bob_request.is_ready());
|
assert!(bob_request.is_ready());
|
||||||
assert!(alice_request.is_ready());
|
assert!(alice_request.is_ready());
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use std::{collections::BTreeMap, convert::TryInto};
|
use std::{collections::BTreeMap, convert::TryInto};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -276,3 +274,71 @@ impl From<(RoomId, AnyMessageEventContent)> for OutgoingContent {
|
||||||
OutgoingContent::Room(content.0, content.1)
|
OutgoingContent::Room(content.0, content.1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use crate::OutgoingVerificationRequest;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
impl From<OutgoingVerificationRequest> for OutgoingContent {
|
||||||
|
fn from(request: OutgoingVerificationRequest) -> Self {
|
||||||
|
use matrix_sdk_common::events::EventType;
|
||||||
|
use serde_json::Value;
|
||||||
|
|
||||||
|
match request {
|
||||||
|
OutgoingVerificationRequest::ToDevice(r) => {
|
||||||
|
let json: Value = serde_json::from_str(
|
||||||
|
r.messages
|
||||||
|
.values()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.values()
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.get(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
match r.event_type {
|
||||||
|
EventType::KeyVerificationRequest => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationRequest(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
EventType::KeyVerificationReady => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationReady(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
EventType::KeyVerificationDone => AnyToDeviceEventContent::KeyVerificationDone(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
),
|
||||||
|
EventType::KeyVerificationStart => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationStart(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
EventType::KeyVerificationKey => AnyToDeviceEventContent::KeyVerificationKey(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
),
|
||||||
|
EventType::KeyVerificationAccept => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationAccept(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
EventType::KeyVerificationMac => AnyToDeviceEventContent::KeyVerificationMac(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
),
|
||||||
|
EventType::KeyVerificationCancel => {
|
||||||
|
AnyToDeviceEventContent::KeyVerificationCancel(
|
||||||
|
serde_json::from_value(json).unwrap(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
OutgoingVerificationRequest::InRoom(r) => (r.room_id, r.content).into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ use matrix_sdk_common::{
|
||||||
},
|
},
|
||||||
AnyToDeviceEventContent, EventType,
|
AnyToDeviceEventContent, EventType,
|
||||||
},
|
},
|
||||||
identifiers::{DeviceId, DeviceKeyAlgorithm, DeviceKeyId, UserId},
|
identifiers::{DeviceKeyAlgorithm, DeviceKeyId, UserId},
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ use crate::{
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
event_enums::{MacContent, StartContent},
|
event_enums::{MacContent, StartContent},
|
||||||
sas_state::FlowId,
|
FlowId,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -562,14 +562,14 @@ fn bytes_to_decimal(bytes: Vec<u8>) -> (u16, u16, u16) {
|
||||||
|
|
||||||
pub fn content_to_request(
|
pub fn content_to_request(
|
||||||
recipient: &UserId,
|
recipient: &UserId,
|
||||||
recipient_device: &DeviceId,
|
recipient_device: impl Into<DeviceIdOrAllDevices>,
|
||||||
content: AnyToDeviceEventContent,
|
content: AnyToDeviceEventContent,
|
||||||
) -> ToDeviceRequest {
|
) -> ToDeviceRequest {
|
||||||
let mut messages = BTreeMap::new();
|
let mut messages = BTreeMap::new();
|
||||||
let mut user_messages = BTreeMap::new();
|
let mut user_messages = BTreeMap::new();
|
||||||
|
|
||||||
user_messages.insert(
|
user_messages.insert(
|
||||||
DeviceIdOrAllDevices::DeviceId(recipient_device.into()),
|
recipient_device.into(),
|
||||||
serde_json::value::to_raw_value(&content).expect("Can't serialize to-device content"),
|
serde_json::value::to_raw_value(&content).expect("Can't serialize to-device content"),
|
||||||
);
|
);
|
||||||
messages.insert(recipient.clone(), user_messages);
|
messages.insert(recipient.clone(), user_messages);
|
||||||
|
@ -580,6 +580,8 @@ pub fn content_to_request(
|
||||||
AnyToDeviceEventContent::KeyVerificationKey(_) => EventType::KeyVerificationKey,
|
AnyToDeviceEventContent::KeyVerificationKey(_) => EventType::KeyVerificationKey,
|
||||||
AnyToDeviceEventContent::KeyVerificationMac(_) => EventType::KeyVerificationMac,
|
AnyToDeviceEventContent::KeyVerificationMac(_) => EventType::KeyVerificationMac,
|
||||||
AnyToDeviceEventContent::KeyVerificationCancel(_) => EventType::KeyVerificationCancel,
|
AnyToDeviceEventContent::KeyVerificationCancel(_) => EventType::KeyVerificationCancel,
|
||||||
|
AnyToDeviceEventContent::KeyVerificationReady(_) => EventType::KeyVerificationReady,
|
||||||
|
AnyToDeviceEventContent::KeyVerificationDone(_) => EventType::KeyVerificationDone,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -33,10 +33,10 @@ use crate::{
|
||||||
use super::{
|
use super::{
|
||||||
event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
|
event_enums::{AcceptContent, CancelContent, MacContent, OutgoingContent},
|
||||||
sas_state::{
|
sas_state::{
|
||||||
Accepted, Canceled, Confirmed, Created, Done, FlowId, KeyReceived, MacReceived, SasState,
|
Accepted, Canceled, Confirmed, Created, Done, KeyReceived, MacReceived, SasState, Started,
|
||||||
Started, WaitingForDone,
|
WaitingForDone,
|
||||||
},
|
},
|
||||||
StartContent,
|
FlowId, StartContent,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -58,8 +58,9 @@ impl InnerSas {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
transaction_id: Option<String>,
|
||||||
) -> (InnerSas, StartContent) {
|
) -> (InnerSas, StartContent) {
|
||||||
let sas = SasState::<Created>::new(account, other_device, other_identity);
|
let sas = SasState::<Created>::new(account, other_device, other_identity, transaction_id);
|
||||||
let content = sas.as_content();
|
let content = sas.as_content();
|
||||||
(InnerSas::Created(sas), content)
|
(InnerSas::Created(sas), content)
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,13 +47,11 @@ use crate::{
|
||||||
ReadOnlyAccount, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::FlowId;
|
||||||
|
|
||||||
|
pub use event_enums::{CancelContent, OutgoingContent, StartContent};
|
||||||
pub use helpers::content_to_request;
|
pub use helpers::content_to_request;
|
||||||
use inner_sas::InnerSas;
|
use inner_sas::InnerSas;
|
||||||
pub use sas_state::FlowId;
|
|
||||||
|
|
||||||
pub use event_enums::{OutgoingContent, StartContent};
|
|
||||||
|
|
||||||
use self::event_enums::CancelContent;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
/// A result of a verification flow.
|
/// A result of a verification flow.
|
||||||
|
@ -159,11 +157,13 @@ impl Sas {
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
store: Arc<Box<dyn CryptoStore>>,
|
store: Arc<Box<dyn CryptoStore>>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
transaction_id: Option<String>,
|
||||||
) -> (Sas, StartContent) {
|
) -> (Sas, StartContent) {
|
||||||
let (inner, content) = InnerSas::start(
|
let (inner, content) = InnerSas::start(
|
||||||
account.clone(),
|
account.clone(),
|
||||||
other_device.clone(),
|
other_device.clone(),
|
||||||
other_identity.clone(),
|
other_identity.clone(),
|
||||||
|
transaction_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
(
|
(
|
||||||
|
@ -189,7 +189,6 @@ impl Sas {
|
||||||
///
|
///
|
||||||
/// Returns the new `Sas` object and a `StartEventContent` that needs to be
|
/// Returns the new `Sas` object and a `StartEventContent` that needs to be
|
||||||
/// sent out through the server to the other device.
|
/// sent out through the server to the other device.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn start_in_room(
|
pub(crate) fn start_in_room(
|
||||||
flow_id: EventId,
|
flow_id: EventId,
|
||||||
room_id: RoomId,
|
room_id: RoomId,
|
||||||
|
@ -685,7 +684,11 @@ impl Sas {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn content_to_request(&self, content: AnyToDeviceEventContent) -> ToDeviceRequest {
|
pub(crate) fn content_to_request(&self, content: AnyToDeviceEventContent) -> ToDeviceRequest {
|
||||||
content_to_request(self.other_user_id(), self.other_device_id(), content)
|
content_to_request(
|
||||||
|
self.other_user_id(),
|
||||||
|
self.other_device_id().to_owned(),
|
||||||
|
content,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,6 +796,7 @@ mod test {
|
||||||
bob_device,
|
bob_device,
|
||||||
alice_store,
|
alice_store,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
let bob = Sas::from_start_event(
|
let bob = Sas::from_start_event(
|
||||||
|
|
|
@ -54,6 +54,7 @@ use super::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
|
verification::FlowId,
|
||||||
ReadOnlyAccount,
|
ReadOnlyAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -72,29 +73,6 @@ const MAX_AGE: Duration = Duration::from_secs(60 * 5);
|
||||||
// The max time a SAS object will wait for a new event to arrive.
|
// The max time a SAS object will wait for a new event to arrive.
|
||||||
const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
const MAX_EVENT_TIMEOUT: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub enum FlowId {
|
|
||||||
ToDevice(String),
|
|
||||||
InRoom(RoomId, EventId),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FlowId {
|
|
||||||
pub fn room_id(&self) -> Option<&RoomId> {
|
|
||||||
if let FlowId::InRoom(r, _) = &self {
|
|
||||||
Some(r)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
|
||||||
match self {
|
|
||||||
FlowId::InRoom(_, r) => r.as_str(),
|
|
||||||
FlowId::ToDevice(t) => t.as_str(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Struct containing the protocols that were agreed to be used for the SAS
|
/// Struct containing the protocols that were agreed to be used for the SAS
|
||||||
/// flow.
|
/// flow.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -386,8 +364,10 @@ impl SasState<Created> {
|
||||||
account: ReadOnlyAccount,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
transaction_id: Option<String>,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
let flow_id = FlowId::ToDevice(Uuid::new_v4().to_string());
|
let flow_id =
|
||||||
|
FlowId::ToDevice(transaction_id.unwrap_or_else(|| Uuid::new_v4().to_string()));
|
||||||
Self::new_helper(flow_id, account, other_device, other_identity)
|
Self::new_helper(flow_id, account, other_device, other_identity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1259,7 +1239,7 @@ mod test {
|
||||||
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
||||||
|
|
||||||
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None);
|
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
||||||
|
|
||||||
let start_content = alice_sas.as_content();
|
let start_content = alice_sas.as_content();
|
||||||
|
|
||||||
|
@ -1430,7 +1410,7 @@ mod test {
|
||||||
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
let bob_device = ReadOnlyDevice::from_account(&bob).await;
|
||||||
|
|
||||||
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None);
|
let alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None, None);
|
||||||
|
|
||||||
let mut start_content = alice_sas.as_content();
|
let mut start_content = alice_sas.as_content();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue