1use std::sync::Arc;
16
17use as_variant::as_variant;
18#[cfg(test)]
19use ruma::time::Instant;
20use ruma::{
21 events::key::verification::{cancel::CancelCode, ShortAuthenticationString},
22 TransactionId, UserId,
23};
24use tracing::trace;
25
26use super::{
27 sas_state::{
28 Accepted, Confirmed, Created, Done, KeyReceived, KeySent, KeysExchanged, MacReceived,
29 SasState, Started, WaitingForDone, WeAccepted,
30 },
31 FlowId,
32};
33use crate::{
34 identities::{DeviceData, UserIdentityData},
35 olm::StaticAccountData,
36 verification::{
37 cache::RequestInfo,
38 event_enums::{AnyVerificationContent, OutgoingContent, OwnedAcceptContent, StartContent},
39 Cancelled, Emoji,
40 },
41 OwnUserIdentityData,
42};
43
44#[derive(Clone, Debug)]
45pub enum InnerSas {
46 Created(SasState<Created>),
47 Started(SasState<Started>),
48 Accepted(SasState<Accepted>),
49 WeAccepted(SasState<WeAccepted>),
50 KeyReceived(SasState<KeyReceived>),
51 KeySent(SasState<KeySent>),
52 KeysExchanged(SasState<KeysExchanged>),
53 Confirmed(SasState<Confirmed>),
54 MacReceived(SasState<MacReceived>),
55 WaitingForDone(SasState<WaitingForDone>),
56 Done(SasState<Done>),
57 Cancelled(SasState<Cancelled>),
58}
59
60impl InnerSas {
61 pub fn start(
62 account: StaticAccountData,
63 other_device: DeviceData,
64 own_identity: Option<OwnUserIdentityData>,
65 other_identity: Option<UserIdentityData>,
66 transaction_id: FlowId,
67 started_from_request: bool,
68 short_auth_string: Option<Vec<ShortAuthenticationString>>,
69 ) -> (InnerSas, OutgoingContent) {
70 let sas = SasState::<Created>::new(
71 account,
72 other_device,
73 own_identity,
74 other_identity,
75 transaction_id,
76 started_from_request,
77 short_auth_string,
78 );
79 let content = sas.as_content();
80 (InnerSas::Created(sas), content.into())
81 }
82
83 pub fn started_from_request(&self) -> bool {
84 match self {
85 InnerSas::Created(s) => s.started_from_request,
86 InnerSas::Started(s) => s.started_from_request,
87 InnerSas::WeAccepted(s) => s.started_from_request,
88 InnerSas::Accepted(s) => s.started_from_request,
89 InnerSas::KeyReceived(s) => s.started_from_request,
90 InnerSas::KeySent(s) => s.started_from_request,
91 InnerSas::KeysExchanged(s) => s.started_from_request,
92 InnerSas::Confirmed(s) => s.started_from_request,
93 InnerSas::MacReceived(s) => s.started_from_request,
94 InnerSas::WaitingForDone(s) => s.started_from_request,
95 InnerSas::Done(s) => s.started_from_request,
96 InnerSas::Cancelled(s) => s.started_from_request,
97 }
98 }
99
100 pub fn has_been_accepted(&self) -> bool {
101 match self {
102 InnerSas::Created(_) | InnerSas::Started(_) | InnerSas::Cancelled(_) => false,
103 InnerSas::Accepted(_)
104 | InnerSas::WeAccepted(_)
105 | InnerSas::KeyReceived(_)
106 | InnerSas::KeySent(_)
107 | InnerSas::KeysExchanged(_)
108 | InnerSas::Confirmed(_)
109 | InnerSas::MacReceived(_)
110 | InnerSas::WaitingForDone(_)
111 | InnerSas::Done(_) => true,
112 }
113 }
114
115 pub fn supports_emoji(&self) -> bool {
116 match self {
117 InnerSas::Created(_) => false,
118 InnerSas::Started(s) => s
119 .state
120 .accepted_protocols
121 .short_auth_string
122 .contains(&ShortAuthenticationString::Emoji),
123 InnerSas::WeAccepted(s) => s
124 .state
125 .accepted_protocols
126 .short_auth_string
127 .contains(&ShortAuthenticationString::Emoji),
128 InnerSas::Accepted(s) => s
129 .state
130 .accepted_protocols
131 .short_auth_string
132 .contains(&ShortAuthenticationString::Emoji),
133 InnerSas::KeyReceived(s) => s
134 .state
135 .accepted_protocols
136 .short_auth_string
137 .contains(&ShortAuthenticationString::Emoji),
138 InnerSas::KeySent(s) => s
139 .state
140 .accepted_protocols
141 .short_auth_string
142 .contains(&ShortAuthenticationString::Emoji),
143 InnerSas::KeysExchanged(s) => s
144 .state
145 .accepted_protocols
146 .short_auth_string
147 .contains(&ShortAuthenticationString::Emoji),
148 InnerSas::Confirmed(_) => false,
149 InnerSas::MacReceived(s) => s
150 .state
151 .accepted_protocols
152 .short_auth_string
153 .contains(&ShortAuthenticationString::Emoji),
154 InnerSas::WaitingForDone(_) => false,
155 InnerSas::Done(_) => false,
156 InnerSas::Cancelled(_) => false,
157 }
158 }
159
160 pub fn from_start_event(
161 account: StaticAccountData,
162 other_device: DeviceData,
163 flow_id: FlowId,
164 content: &StartContent<'_>,
165 own_identity: Option<OwnUserIdentityData>,
166 other_identity: Option<UserIdentityData>,
167 started_from_request: bool,
168 ) -> Result<InnerSas, OutgoingContent> {
169 match SasState::<Started>::from_start_event(
170 account,
171 other_device,
172 own_identity,
173 other_identity,
174 flow_id,
175 content,
176 started_from_request,
177 ) {
178 Ok(s) => Ok(InnerSas::Started(s)),
179 Err(s) => Err(s.as_content()),
180 }
181 }
182
183 pub fn accept(
184 self,
185 methods: Vec<ShortAuthenticationString>,
186 ) -> Option<(InnerSas, OwnedAcceptContent)> {
187 let InnerSas::Started(s) = self else { return None };
188 let sas = s.into_we_accepted(methods);
189 let content = sas.as_content();
190
191 trace!(
192 flow_id = sas.verification_flow_id.as_str(),
193 accepted_protocols = ?sas.state.accepted_protocols,
194 "Accepted a SAS verification"
195 );
196
197 Some((InnerSas::WeAccepted(sas), content))
198 }
199
200 #[cfg(test)]
201 #[allow(dead_code)]
202 pub fn set_creation_time(&mut self, time: Instant) {
203 match self {
204 InnerSas::Created(s) => s.set_creation_time(time),
205 InnerSas::Started(s) => s.set_creation_time(time),
206 InnerSas::Cancelled(s) => s.set_creation_time(time),
207 InnerSas::Accepted(s) => s.set_creation_time(time),
208 InnerSas::KeyReceived(s) => s.set_creation_time(time),
209 InnerSas::KeySent(s) => s.set_creation_time(time),
210 InnerSas::KeysExchanged(s) => s.set_creation_time(time),
211 InnerSas::Confirmed(s) => s.set_creation_time(time),
212 InnerSas::MacReceived(s) => s.set_creation_time(time),
213 InnerSas::Done(s) => s.set_creation_time(time),
214 InnerSas::WaitingForDone(s) => s.set_creation_time(time),
215 InnerSas::WeAccepted(s) => s.set_creation_time(time),
216 }
217 }
218
219 pub fn cancel(
220 self,
221 cancelled_by_us: bool,
222 code: CancelCode,
223 ) -> (InnerSas, Option<OutgoingContent>) {
224 let sas = match self {
225 InnerSas::Created(s) => s.cancel(cancelled_by_us, code),
226 InnerSas::Started(s) => s.cancel(cancelled_by_us, code),
227 InnerSas::Accepted(s) => s.cancel(cancelled_by_us, code),
228 InnerSas::WeAccepted(s) => s.cancel(cancelled_by_us, code),
229 InnerSas::KeyReceived(s) => s.cancel(cancelled_by_us, code),
230 InnerSas::KeySent(s) => s.cancel(cancelled_by_us, code),
231 InnerSas::KeysExchanged(s) => s.cancel(cancelled_by_us, code),
232 InnerSas::MacReceived(s) => s.cancel(cancelled_by_us, code),
233 InnerSas::Confirmed(s) => s.cancel(cancelled_by_us, code),
234 InnerSas::WaitingForDone(s) => s.cancel(cancelled_by_us, code),
235 InnerSas::Done(_) | InnerSas::Cancelled(_) => return (self, None),
236 };
237
238 let content = sas.as_content();
239
240 (InnerSas::Cancelled(sas), Some(content))
241 }
242
243 pub fn confirm(self) -> (InnerSas, Vec<OutgoingContent>) {
244 match self {
245 InnerSas::KeysExchanged(s) => {
246 let sas = s.confirm();
247 let content = sas.as_content();
248 (InnerSas::Confirmed(sas), vec![content])
249 }
250 InnerSas::MacReceived(s) => {
251 if s.started_from_request {
252 let sas = s.confirm_and_wait_for_done();
253 let contents = vec![sas.as_content(), sas.done_content()];
254
255 (InnerSas::WaitingForDone(sas), contents)
256 } else {
257 let sas = s.confirm();
258 let content = sas.as_content();
259
260 (InnerSas::Done(sas), vec![content])
261 }
262 }
263 _ => (self, Vec::new()),
264 }
265 }
266
267 pub fn receive_any_event(
268 self,
269 sender: &UserId,
270 content: &AnyVerificationContent<'_>,
271 ) -> (Self, Option<(OutgoingContent, Option<RequestInfo>)>) {
272 match content {
273 AnyVerificationContent::Accept(c) => match self {
274 InnerSas::Created(s) => match s.into_accepted(sender, c) {
275 Ok(s) => {
276 let (content, request_info) = s.as_content();
277 (InnerSas::Accepted(s), Some((content, Some(request_info))))
278 }
279 Err(s) => {
280 let content = s.as_content();
281 (InnerSas::Cancelled(s), Some((content, None)))
282 }
283 },
284 InnerSas::Started(s) => match s.into_accepted(sender, c) {
285 Ok(s) => {
286 let (content, request_info) = s.as_content();
287 (InnerSas::Accepted(s), Some((content, Some(request_info))))
288 }
289 Err(s) => {
290 let content = s.as_content();
291 (InnerSas::Cancelled(s), Some((content, None)))
292 }
293 },
294 _ => (self, None),
295 },
296 AnyVerificationContent::Cancel(c) => {
297 let (sas, _) = self.cancel(false, c.cancel_code().to_owned());
298 (sas, None)
299 }
300 AnyVerificationContent::Key(c) => match self {
301 InnerSas::Accepted(s) => match s.into_key_received(sender, c) {
302 Ok(s) => (InnerSas::KeyReceived(s), None),
303 Err(s) => {
304 let content = s.as_content();
305 (InnerSas::Cancelled(s), Some((content, None)))
306 }
307 },
308 InnerSas::KeySent(s) => match s.into_keys_exchanged(sender, c) {
309 Ok(s) => (InnerSas::KeysExchanged(s), None),
310 Err(s) => {
311 let content = s.as_content();
312 (InnerSas::Cancelled(s), Some((content, None)))
313 }
314 },
315 InnerSas::WeAccepted(s) => match s.into_key_received(sender, c) {
316 Ok(s) => {
317 let (content, request_info) = s.as_content();
318 (InnerSas::KeyReceived(s), Some((content, Some(request_info))))
319 }
320 Err(s) => {
321 let content = s.as_content();
322 (InnerSas::Cancelled(s), Some((content, None)))
323 }
324 },
325
326 _ => (self, None),
327 },
328 AnyVerificationContent::Mac(c) => match self {
329 InnerSas::KeysExchanged(s) => match s.into_mac_received(sender, c) {
330 Ok(s) => (InnerSas::MacReceived(s), None),
331 Err(s) => {
332 let content = s.as_content();
333 (InnerSas::Cancelled(s), Some((content, None)))
334 }
335 },
336 InnerSas::Confirmed(s) =>
337 {
340 match if s.started_from_request {
341 s.into_waiting_for_done(sender, c)
342 .map(|s| (Some((s.done_content(), None)), InnerSas::WaitingForDone(s)))
343 } else {
344 s.into_done(sender, c).map(|s| (None, InnerSas::Done(s)))
345 } {
346 Ok((c, s)) => (s, c),
347 Err(s) => {
348 let content = s.as_content();
349 (InnerSas::Cancelled(s), Some((content, None)))
350 }
351 }
352 }
353 _ => (self, None),
354 },
355 AnyVerificationContent::Done(c) => match self {
356 InnerSas::WaitingForDone(s) => match s.into_done(sender, c) {
357 Ok(s) => (InnerSas::Done(s), None),
358 Err(s) => {
359 let content = s.as_content();
360 (InnerSas::Cancelled(s), Some((content, None)))
361 }
362 },
363 _ => (self, None),
364 },
365 AnyVerificationContent::Request(_)
366 | AnyVerificationContent::Ready(_)
367 | AnyVerificationContent::Start(_) => (self, None),
368 }
369 }
370
371 pub fn mark_request_as_sent(self, request_id: &TransactionId) -> Option<Self> {
372 match self {
373 InnerSas::Accepted(s) => s.into_key_sent(request_id).map(InnerSas::KeySent),
374 InnerSas::KeyReceived(s) => {
375 s.into_keys_exchanged(request_id).map(InnerSas::KeysExchanged)
376 }
377 InnerSas::Created(_)
378 | InnerSas::WeAccepted(_)
379 | InnerSas::Started(_)
380 | InnerSas::KeySent(_)
381 | InnerSas::KeysExchanged(_)
382 | InnerSas::Confirmed(_)
383 | InnerSas::MacReceived(_)
384 | InnerSas::WaitingForDone(_)
385 | InnerSas::Done(_)
386 | InnerSas::Cancelled(_) => Some(self),
387 }
388 }
389
390 pub fn can_be_presented(&self) -> bool {
391 matches!(self, InnerSas::KeysExchanged(_) | InnerSas::MacReceived(_))
392 }
393
394 pub fn is_done(&self) -> bool {
395 matches!(self, InnerSas::Done(_))
396 }
397
398 pub fn is_cancelled(&self) -> bool {
399 matches!(self, InnerSas::Cancelled(_))
400 }
401
402 pub fn have_we_confirmed(&self) -> bool {
403 matches!(self, InnerSas::Confirmed(_) | InnerSas::WaitingForDone(_) | InnerSas::Done(_))
404 }
405
406 pub fn timed_out(&self) -> bool {
407 match self {
408 InnerSas::Created(s) => s.timed_out(),
409 InnerSas::Started(s) => s.timed_out(),
410 InnerSas::Cancelled(s) => s.timed_out(),
411 InnerSas::Accepted(s) => s.timed_out(),
412 InnerSas::KeyReceived(s) => s.timed_out(),
413 InnerSas::KeySent(s) => s.timed_out(),
414 InnerSas::KeysExchanged(s) => s.timed_out(),
415 InnerSas::Confirmed(s) => s.timed_out(),
416 InnerSas::MacReceived(s) => s.timed_out(),
417 InnerSas::WaitingForDone(s) => s.timed_out(),
418 InnerSas::Done(s) => s.timed_out(),
419 InnerSas::WeAccepted(s) => s.timed_out(),
420 }
421 }
422
423 pub fn emoji(&self) -> Option<[Emoji; 7]> {
424 match self {
425 InnerSas::KeysExchanged(s) => Some(s.get_emoji()),
426 InnerSas::MacReceived(s) => Some(s.get_emoji()),
427 _ => None,
428 }
429 }
430
431 pub fn emoji_index(&self) -> Option<[u8; 7]> {
432 match self {
433 InnerSas::KeysExchanged(s) => Some(s.get_emoji_index()),
434 InnerSas::MacReceived(s) => Some(s.get_emoji_index()),
435 _ => None,
436 }
437 }
438
439 pub fn decimals(&self) -> Option<(u16, u16, u16)> {
440 match self {
441 InnerSas::KeysExchanged(s) => Some(s.get_decimal()),
442 InnerSas::MacReceived(s) => Some(s.get_decimal()),
443 _ => None,
444 }
445 }
446
447 pub fn verified_devices(&self) -> Option<Arc<[DeviceData]>> {
448 as_variant!(self, InnerSas::Done).map(|s| s.verified_devices())
449 }
450
451 pub fn verified_identities(&self) -> Option<Arc<[UserIdentityData]>> {
452 as_variant!(self, InnerSas::Done).map(|s| s.verified_identities())
453 }
454}