7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 1 | // Copyright 2025 The Matrix.org Foundation C.I.C. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 2 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 4 | // you may not use this file except in compliance with the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 5 | // You may obtain a copy of the License at |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 6 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 8 | // |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 9 | // Unless required by applicable law or agreed to in writing, software |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 12 | // See the License for the specific language governing permissions and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 13 | // limitations under the License. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 14 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 15 | use std::{fmt::Debug, sync::Arc, time::Duration}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 16 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 17 | use matrix_sdk_base::crypto::types::events::UtdCause; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 18 | use matrix_sdk_common::{SendOutsideWasm, SyncOutsideWasm}; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 19 | use matrix_sdk_ui::unable_to_decrypt_hook::{ |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 20 | UnableToDecryptHook, UnableToDecryptInfo as SdkUnableToDecryptInfo, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 21 | }; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 22 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 23 | #[matrix_sdk_ffi_macros::export(callback_interface)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 24 | pub trait UnableToDecryptDelegate: SyncOutsideWasm + SendOutsideWasm { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 25 | fn on_utd(&self, info: UnableToDecryptInfo); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 26 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 27 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 28 | pub struct UtdHook { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 29 | pub delegate: Arc<dyn UnableToDecryptDelegate>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 30 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 31 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 32 | impl std::fmt::Debug for UtdHook { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 33 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 34 | f.debug_struct("UtdHook").finish_non_exhaustive() |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 35 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 36 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 37 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 38 | impl UnableToDecryptHook for UtdHook { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 39 | fn on_utd(&self, info: SdkUnableToDecryptInfo) { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 40 | const IGNORE_UTD_PERIOD: Duration = Duration::from_secs(4); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 41 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 42 | // UTDs that have been decrypted in the `IGNORE_UTD_PERIOD` are just ignored and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 43 | // not considered UTDs. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 44 | if let Some(duration) = &info.time_to_decrypt |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 45 | && *duration < IGNORE_UTD_PERIOD |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 46 | { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 47 | return; |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 48 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 49 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 50 | // Report the UTD to the client. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 51 | self.delegate.on_utd(info.into()); |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 52 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 53 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 54 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 55 | #[derive(uniffi::Record)] |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 56 | pub struct UnableToDecryptInfo { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 57 | /// The identifier of the event that couldn't get decrypted. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 58 | event_id: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 59 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 60 | /// If the event could be decrypted late (that is, the event was encrypted |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 61 | /// at first, but could be decrypted later on), then this indicates the |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 62 | /// time it took to decrypt the event. If it is not set, this is |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 63 | /// considered a definite UTD. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 64 | /// |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 65 | /// If set, this is in milliseconds. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 66 | pub time_to_decrypt_ms: Option<u64>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 67 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 68 | /// What we know about what caused this UTD. E.g. was this event sent when |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 69 | /// we were not a member of this room? |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 70 | pub cause: UtdCause, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 71 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 72 | /// The difference between the event creation time (`origin_server_ts`) and |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 73 | /// the time our device was created. If negative, this event was sent |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 74 | /// *before* our device was created. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 75 | pub event_local_age_millis: i64, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 76 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 77 | /// Whether the user had verified their own identity at the point they |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 78 | /// received the UTD event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 79 | pub user_trusts_own_identity: bool, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 80 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 81 | /// The homeserver of the user that sent the undecryptable event. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 82 | pub sender_homeserver: String, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 83 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 84 | /// Our local user's own homeserver, or `None` if the client is not logged |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 85 | /// in. |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 86 | pub own_homeserver: Option<String>, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 87 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 88 | |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 89 | impl From<SdkUnableToDecryptInfo> for UnableToDecryptInfo { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 90 | fn from(value: SdkUnableToDecryptInfo) -> Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 91 | Self { |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 92 | event_id: value.event_id.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 93 | time_to_decrypt_ms: value.time_to_decrypt.map(|ttd| ttd.as_millis() as u64), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 94 | cause: value.cause, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 95 | event_local_age_millis: value.event_local_age_millis, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 96 | user_trusts_own_identity: value.user_trusts_own_identity, |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 97 | sender_homeserver: value.sender_homeserver.to_string(), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 98 | own_homeserver: value.own_homeserver.map(String::from), |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 99 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 100 | } |
7ff8adafe9e4 | atagen | 2026-10-22 12:30 UTC | 101 | } |