Skip to content

Commit c79e62d

Browse files
committed
Merge branch 'fix-verification-double-start'
2 parents f4249c5 + a1cf8b6 commit c79e62d

File tree

3 files changed

+125
-40
lines changed

3 files changed

+125
-40
lines changed

crates/matrix-sdk-crypto/src/verification/requests.rs

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use super::{
4444
event_enums::{
4545
CancelContent, DoneContent, OutgoingContent, ReadyContent, RequestContent, StartContent,
4646
},
47-
CancelInfo, Cancelled, FlowId, VerificationStore,
47+
CancelInfo, Cancelled, FlowId, Verification, VerificationStore,
4848
};
4949
#[cfg(feature = "qrcode")]
5050
use super::{
@@ -1126,11 +1126,10 @@ impl RequestState<Ready> {
11261126
};
11271127

11281128
let identity = self.store.get_user_identity(sender).await?;
1129-
let own_identity = self
1130-
.store
1131-
.get_user_identity(self.store.account.user_id())
1132-
.await?
1133-
.and_then(|i| i.into_own());
1129+
let own_user_id = self.store.account.user_id();
1130+
let own_device_id = self.store.account.device_id();
1131+
let own_identity =
1132+
self.store.get_user_identity(own_user_id).await?.and_then(|i| i.into_own());
11341133

11351134
match content.method() {
11361135
StartMethod::SasV1(_) => {
@@ -1142,13 +1141,27 @@ impl RequestState<Ready> {
11421141
we_started,
11431142
request_handle,
11441143
) {
1145-
// TODO check if there is already a SAS verification, i.e. we
1146-
// already started one before the other side tried to do the
1147-
// same; ignore it if we did and we're the lexicographically
1148-
// smaller user ID, otherwise auto-accept the newly started one.
11491144
Ok(s) => {
1150-
info!("Started a new SAS verification.");
1151-
self.verification_cache.insert_sas(s);
1145+
let start_new = if let Some(Verification::SasV1(_sas)) =
1146+
self.verification_cache.get(sender, self.flow_id.as_str())
1147+
{
1148+
// If there is already a SAS verification, i.e. we already started one
1149+
// before the other side tried to do the same; ignore it if we did and
1150+
// we're the lexicographically smaller user ID (or device ID if equal).
1151+
use std::cmp::Ordering;
1152+
match (sender.cmp(own_user_id), device.device_id().cmp(own_device_id)) {
1153+
(Ordering::Greater, _) | (Ordering::Equal, Ordering::Greater) => {
1154+
false
1155+
}
1156+
_ => true,
1157+
}
1158+
} else {
1159+
true
1160+
};
1161+
if start_new {
1162+
info!("Started a new SAS verification.");
1163+
self.verification_cache.insert_sas(s);
1164+
}
11521165
}
11531166
Err(c) => {
11541167
warn!(

crates/matrix-sdk-crypto/src/verification/sas/inner_sas.rs

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ impl InnerSas {
181181
methods: Vec<ShortAuthenticationString>,
182182
) -> Option<(InnerSas, OwnedAcceptContent)> {
183183
if let InnerSas::Started(s) = self {
184-
let sas = s.into_accepted(methods);
184+
let sas = s.into_we_accepted(methods);
185185
let content = sas.as_content();
186186
Some((InnerSas::WeAccepted(sas), content))
187187
} else {
@@ -258,22 +258,29 @@ impl InnerSas {
258258
content: &AnyVerificationContent,
259259
) -> (Self, Option<OutgoingContent>) {
260260
match content {
261-
AnyVerificationContent::Accept(c) => {
262-
if let InnerSas::Created(s) = self {
263-
match s.into_accepted(sender, c) {
264-
Ok(s) => {
265-
let content = s.as_content();
266-
(InnerSas::Accepted(s), Some(content))
267-
}
268-
Err(s) => {
269-
let content = s.as_content();
270-
(InnerSas::Cancelled(s), Some(content))
271-
}
261+
AnyVerificationContent::Accept(c) => match self {
262+
InnerSas::Created(s) => match s.into_accepted(sender, c) {
263+
Ok(s) => {
264+
let content = s.as_content();
265+
(InnerSas::Accepted(s), Some(content))
272266
}
273-
} else {
274-
(self, None)
275-
}
276-
}
267+
Err(s) => {
268+
let content = s.as_content();
269+
(InnerSas::Cancelled(s), Some(content))
270+
}
271+
},
272+
InnerSas::Started(s) => match s.into_accepted(sender, c) {
273+
Ok(s) => {
274+
let content = s.as_content();
275+
(InnerSas::Accepted(s), Some(content))
276+
}
277+
Err(s) => {
278+
let content = s.as_content();
279+
(InnerSas::Cancelled(s), Some(content))
280+
}
281+
},
282+
_ => (self, None),
283+
},
277284
AnyVerificationContent::Cancel(c) => {
278285
let (sas, _) = self.cancel(false, c.cancel_code().to_owned());
279286
(sas, None)

crates/matrix-sdk-crypto/src/verification/sas/sas_state.rs

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,17 @@ const MACS: &[MessageAuthenticationCode] = &[MessageAuthenticationCode::HkdfHmac
7070
const STRINGS: &[ShortAuthenticationString] =
7171
&[ShortAuthenticationString::Decimal, ShortAuthenticationString::Emoji];
7272

73+
fn the_protocol_definitions() -> SasV1Content {
74+
SasV1ContentInit {
75+
short_authentication_string: STRINGS.to_vec(),
76+
key_agreement_protocols: KEY_AGREEMENT_PROTOCOLS.to_vec(),
77+
message_authentication_codes: MACS.to_vec(),
78+
hashes: HASHES.to_vec(),
79+
}
80+
.try_into()
81+
.expect("Invalid protocol definition.")
82+
}
83+
7384
// The max time a SAS flow can take from start to done.
7485
const MAX_AGE: Duration = Duration::from_secs(60 * 5);
7586

@@ -420,16 +431,7 @@ impl SasState<Created> {
420431
last_event_time: Arc::new(Instant::now()),
421432
started_from_request,
422433

423-
state: Arc::new(Created {
424-
protocol_definitions: SasV1ContentInit {
425-
short_authentication_string: STRINGS.to_vec(),
426-
key_agreement_protocols: KEY_AGREEMENT_PROTOCOLS.to_vec(),
427-
message_authentication_codes: MACS.to_vec(),
428-
hashes: HASHES.to_vec(),
429-
}
430-
.try_into()
431-
.expect("Invalid protocol definition."),
432-
}),
434+
state: Arc::new(Created { protocol_definitions: the_protocol_definitions() }),
433435
}
434436
}
435437

@@ -571,7 +573,7 @@ impl SasState<Started> {
571573
}
572574
}
573575

574-
pub fn into_accepted(self, methods: Vec<ShortAuthenticationString>) -> SasState<WeAccepted> {
576+
pub fn into_we_accepted(self, methods: Vec<ShortAuthenticationString>) -> SasState<WeAccepted> {
575577
let mut accepted_protocols = self.state.accepted_protocols.as_ref().to_owned();
576578
accepted_protocols.short_auth_string = methods;
577579

@@ -594,6 +596,69 @@ impl SasState<Started> {
594596
}),
595597
}
596598
}
599+
600+
fn as_content(&self) -> OwnedStartContent {
601+
match self.verification_flow_id.as_ref() {
602+
FlowId::ToDevice(s) => {
603+
OwnedStartContent::ToDevice(ToDeviceKeyVerificationStartEventContent::new(
604+
self.device_id().into(),
605+
s.to_string(),
606+
StartMethod::SasV1(the_protocol_definitions()),
607+
))
608+
}
609+
FlowId::InRoom(r, e) => OwnedStartContent::Room(
610+
r.clone(),
611+
KeyVerificationStartEventContent::new(
612+
self.device_id().into(),
613+
StartMethod::SasV1(the_protocol_definitions()),
614+
Relation::new(e.clone()),
615+
),
616+
),
617+
}
618+
}
619+
620+
/// Receive a m.key.verification.accept event, changing the state into
621+
/// an Accepted one.
622+
///
623+
/// Note: Even though the other side has started the (or rather "a") sas
624+
/// verification, it can still accept one, if we have sent one
625+
/// simultaneously. In this case we just go on with the verification
626+
/// that *we* started.
627+
///
628+
/// # Arguments
629+
///
630+
/// * `event` - The m.key.verification.accept event that was sent to us by
631+
/// the other side.
632+
pub fn into_accepted(
633+
self,
634+
sender: &UserId,
635+
content: &AcceptContent,
636+
) -> Result<SasState<Accepted>, SasState<Cancelled>> {
637+
self.check_event(sender, content.flow_id()).map_err(|c| self.clone().cancel(true, c))?;
638+
639+
if let AcceptMethod::SasV1(content) = content.method() {
640+
let accepted_protocols = AcceptedProtocols::try_from(content.clone())
641+
.map_err(|c| self.clone().cancel(true, c))?;
642+
643+
let start_content = self.as_content().into();
644+
645+
Ok(SasState {
646+
inner: self.inner,
647+
ids: self.ids,
648+
verification_flow_id: self.verification_flow_id,
649+
creation_time: self.creation_time,
650+
last_event_time: Instant::now().into(),
651+
started_from_request: self.started_from_request,
652+
state: Arc::new(Accepted {
653+
start_content,
654+
commitment: content.commitment.clone(),
655+
accepted_protocols: accepted_protocols.into(),
656+
}),
657+
})
658+
} else {
659+
Err(self.cancel(true, CancelCode::UnknownMethod))
660+
}
661+
}
597662
}
598663

599664
impl SasState<WeAccepted> {
@@ -1191,7 +1256,7 @@ mod test {
11911256
&start_content.as_start_content(),
11921257
false,
11931258
);
1194-
let bob_sas = bob_sas.unwrap().into_accepted(vec![ShortAuthenticationString::Emoji]);
1259+
let bob_sas = bob_sas.unwrap().into_we_accepted(vec![ShortAuthenticationString::Emoji]);
11951260

11961261
(alice_sas, bob_sas)
11971262
}

0 commit comments

Comments
 (0)