crypto: Split out the Account into a read only portion and one with effects.
parent
e1c220e2f7
commit
84066d4a76
|
@ -34,7 +34,7 @@ use serde_json::{json, Value};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::{Account, OlmMachine};
|
use crate::{OlmMachine, ReadOnlyAccount};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
error::{EventError, OlmError, OlmResult, SignatureError},
|
error::{EventError, OlmError, OlmResult, SignatureError},
|
||||||
|
@ -419,7 +419,7 @@ impl ReadOnlyDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub async fn from_account(account: &Account) -> ReadOnlyDevice {
|
pub async fn from_account(account: &ReadOnlyAccount) -> ReadOnlyDevice {
|
||||||
let device_keys = account.device_keys().await;
|
let device_keys = account.device_keys().await;
|
||||||
ReadOnlyDevice::try_from(&device_keys).unwrap()
|
ReadOnlyDevice::try_from(&device_keys).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
@ -666,7 +666,7 @@ pub(crate) mod test {
|
||||||
manager::test::{other_key_query, own_key_query},
|
manager::test::{other_key_query, own_key_query},
|
||||||
Device, ReadOnlyDevice,
|
Device, ReadOnlyDevice,
|
||||||
},
|
},
|
||||||
olm::Account,
|
olm::ReadOnlyAccount,
|
||||||
store::{MemoryStore, Store},
|
store::{MemoryStore, Store},
|
||||||
verification::VerificationMachine,
|
verification::VerificationMachine,
|
||||||
};
|
};
|
||||||
|
@ -735,7 +735,7 @@ pub(crate) mod test {
|
||||||
assert!(identity.is_device_signed(&second).is_ok());
|
assert!(identity.is_device_signed(&second).is_ok());
|
||||||
|
|
||||||
let verification_machine = VerificationMachine::new(
|
let verification_machine = VerificationMachine::new(
|
||||||
Account::new(second.user_id(), second.device_id()),
|
ReadOnlyAccount::new(second.user_id(), second.device_id()),
|
||||||
Store::new(
|
Store::new(
|
||||||
Arc::new(second.user_id().clone()),
|
Arc::new(second.user_id().clone()),
|
||||||
Box::new(MemoryStore::new()),
|
Box::new(MemoryStore::new()),
|
||||||
|
|
|
@ -599,7 +599,7 @@ mod test {
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{LocalTrust, ReadOnlyDevice},
|
identities::{LocalTrust, ReadOnlyDevice},
|
||||||
olm::Account,
|
olm::ReadOnlyAccount,
|
||||||
store::{MemoryStore, Store},
|
store::{MemoryStore, Store},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -625,12 +625,12 @@ mod test {
|
||||||
room_id!("!test:example.org")
|
room_id!("!test:example.org")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn account() -> Account {
|
fn account() -> ReadOnlyAccount {
|
||||||
Account::new(&alice_id(), &alice_device_id())
|
ReadOnlyAccount::new(&alice_id(), &alice_device_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bob_account() -> Account {
|
fn bob_account() -> ReadOnlyAccount {
|
||||||
Account::new(&bob_id(), &bob_device_id())
|
ReadOnlyAccount::new(&bob_id(), &bob_device_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bob_machine() -> KeyRequestMachine {
|
fn bob_machine() -> KeyRequestMachine {
|
||||||
|
|
|
@ -46,8 +46,8 @@ pub use identities::{
|
||||||
Device, LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserDevices, UserIdentities, UserIdentity,
|
Device, LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserDevices, UserIdentities, UserIdentity,
|
||||||
};
|
};
|
||||||
pub use machine::OlmMachine;
|
pub use machine::OlmMachine;
|
||||||
pub(crate) use olm::Account;
|
|
||||||
pub use olm::EncryptionSettings;
|
pub use olm::EncryptionSettings;
|
||||||
|
pub(crate) use olm::ReadOnlyAccount;
|
||||||
pub use requests::{
|
pub use requests::{
|
||||||
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
|
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,7 +17,6 @@ use std::path::Path;
|
||||||
use std::{collections::BTreeMap, convert::TryInto, mem, sync::Arc, time::Duration};
|
use std::{collections::BTreeMap, convert::TryInto, mem, sync::Arc, time::Duration};
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use serde_json::Value;
|
|
||||||
use tracing::{debug, error, info, instrument, trace, warn};
|
use tracing::{debug, error, info, instrument, trace, warn};
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -52,7 +51,7 @@ use super::{
|
||||||
key_request::KeyRequestMachine,
|
key_request::KeyRequestMachine,
|
||||||
olm::{
|
olm::{
|
||||||
Account, EncryptionSettings, ExportedRoomKey, GroupSessionKey, IdentityKeys,
|
Account, EncryptionSettings, ExportedRoomKey, GroupSessionKey, IdentityKeys,
|
||||||
InboundGroupSession, OlmMessage, OutboundGroupSession,
|
InboundGroupSession, OlmMessage, OutboundGroupSession, ReadOnlyAccount,
|
||||||
},
|
},
|
||||||
requests::{IncomingResponse, OutgoingRequest, ToDeviceRequest},
|
requests::{IncomingResponse, OutgoingRequest, ToDeviceRequest},
|
||||||
store::{CryptoStore, MemoryStore, Result as StoreResult, Store},
|
store::{CryptoStore, MemoryStore, Result as StoreResult, Store},
|
||||||
|
@ -113,7 +112,7 @@ impl OlmMachine {
|
||||||
pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
|
pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
|
||||||
let store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
let store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
|
||||||
let device_id: DeviceIdBox = device_id.into();
|
let device_id: DeviceIdBox = device_id.into();
|
||||||
let account = Account::new(&user_id, &device_id);
|
let account = ReadOnlyAccount::new(&user_id, &device_id);
|
||||||
|
|
||||||
OlmMachine::new_helper(user_id, device_id, store, account)
|
OlmMachine::new_helper(user_id, device_id, store, account)
|
||||||
}
|
}
|
||||||
|
@ -122,7 +121,7 @@ impl OlmMachine {
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
device_id: DeviceIdBox,
|
device_id: DeviceIdBox,
|
||||||
store: Box<dyn CryptoStore>,
|
store: Box<dyn CryptoStore>,
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let user_id = Arc::new(user_id.clone());
|
let user_id = Arc::new(user_id.clone());
|
||||||
|
|
||||||
|
@ -142,7 +141,10 @@ impl OlmMachine {
|
||||||
OlmMachine {
|
OlmMachine {
|
||||||
user_id,
|
user_id,
|
||||||
device_id,
|
device_id,
|
||||||
account,
|
account: Account {
|
||||||
|
inner: account,
|
||||||
|
store: store.clone(),
|
||||||
|
},
|
||||||
store,
|
store,
|
||||||
outbound_group_sessions,
|
outbound_group_sessions,
|
||||||
verification_machine,
|
verification_machine,
|
||||||
|
@ -182,7 +184,7 @@ impl OlmMachine {
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
debug!("Creating a new account");
|
debug!("Creating a new account");
|
||||||
Account::new(&user_id, &device_id)
|
ReadOnlyAccount::new(&user_id, &device_id)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -326,7 +328,7 @@ impl OlmMachine {
|
||||||
|
|
||||||
/// Get the underlying Olm account of the machine.
|
/// Get the underlying Olm account of the machine.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn account(&self) -> &Account {
|
pub(crate) fn account(&self) -> &ReadOnlyAccount {
|
||||||
&self.account
|
&self.account
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,26 +343,7 @@ impl OlmMachine {
|
||||||
&self,
|
&self,
|
||||||
response: &upload_keys::Response,
|
response: &upload_keys::Response,
|
||||||
) -> OlmResult<()> {
|
) -> OlmResult<()> {
|
||||||
if !self.account.shared() {
|
self.account.receive_keys_upload_response(response).await
|
||||||
debug!("Marking account as shared");
|
|
||||||
}
|
|
||||||
self.account.mark_as_shared();
|
|
||||||
|
|
||||||
let one_time_key_count = response
|
|
||||||
.one_time_key_counts
|
|
||||||
.get(&DeviceKeyAlgorithm::SignedCurve25519);
|
|
||||||
|
|
||||||
let count: u64 = one_time_key_count.map_or(0, |c| (*c).into());
|
|
||||||
debug!(
|
|
||||||
"Updated uploaded one-time key count {} -> {}, marking keys as published",
|
|
||||||
self.account.uploaded_key_count(),
|
|
||||||
count
|
|
||||||
);
|
|
||||||
self.account.update_uploaded_key_count(count);
|
|
||||||
self.account.mark_keys_as_published().await;
|
|
||||||
self.store.save_account(self.account.clone()).await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the a key claiming request for the user/device pairs that we are
|
/// Get the a key claiming request for the user/device pairs that we are
|
||||||
|
@ -518,197 +501,6 @@ impl OlmMachine {
|
||||||
Some(assign!(upload_keys::Request::new(), { device_keys, one_time_keys }))
|
Some(assign!(upload_keys::Request::new(), { device_keys, one_time_keys }))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to decrypt an Olm message.
|
|
||||||
///
|
|
||||||
/// This try to decrypt an Olm message using all the sessions we share
|
|
||||||
/// have with the given sender.
|
|
||||||
async fn try_decrypt_olm_message(
|
|
||||||
&self,
|
|
||||||
sender: &UserId,
|
|
||||||
sender_key: &str,
|
|
||||||
message: &OlmMessage,
|
|
||||||
) -> OlmResult<Option<String>> {
|
|
||||||
let s = self.store.get_sessions(sender_key).await?;
|
|
||||||
|
|
||||||
// We don't have any existing sessions, return early.
|
|
||||||
let sessions = if let Some(s) = s {
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut session_to_save = None;
|
|
||||||
let mut plaintext = None;
|
|
||||||
|
|
||||||
for session in &mut *sessions.lock().await {
|
|
||||||
let mut matches = false;
|
|
||||||
|
|
||||||
// If this is a pre-key message check if it was encrypted for our
|
|
||||||
// session, if it wasn't decryption will fail so no need to try.
|
|
||||||
if let OlmMessage::PreKey(m) = &message {
|
|
||||||
matches = session.matches(sender_key, m.clone()).await?;
|
|
||||||
|
|
||||||
if !matches {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let ret = session.decrypt(message.clone()).await;
|
|
||||||
|
|
||||||
if let Ok(p) = ret {
|
|
||||||
plaintext = Some(p);
|
|
||||||
session_to_save = Some(session.clone());
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
// Decryption failed with a matching session, the session is
|
|
||||||
// likely wedged and needs to be rotated.
|
|
||||||
if matches {
|
|
||||||
warn!(
|
|
||||||
"Found a matching Olm session yet decryption failed
|
|
||||||
for sender {} and sender_key {}",
|
|
||||||
sender, sender_key
|
|
||||||
);
|
|
||||||
return Err(OlmError::SessionWedged);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(session) = session_to_save {
|
|
||||||
// Decryption was successful, save the new ratchet state of the
|
|
||||||
// session that was used to decrypt the message.
|
|
||||||
trace!("Saved the new session state for {}", sender);
|
|
||||||
self.store.save_sessions(&[session]).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(plaintext)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decrypt an Olm message, creating a new Olm session if possible.
|
|
||||||
async fn decrypt_olm_message(
|
|
||||||
&self,
|
|
||||||
sender: &UserId,
|
|
||||||
sender_key: &str,
|
|
||||||
message: OlmMessage,
|
|
||||||
) -> OlmResult<(Raw<AnyToDeviceEvent>, String)> {
|
|
||||||
// First try to decrypt using an existing session.
|
|
||||||
let plaintext = if let Some(p) = self
|
|
||||||
.try_decrypt_olm_message(sender, sender_key, &message)
|
|
||||||
.await?
|
|
||||||
{
|
|
||||||
// Decryption succeeded, de-structure the plaintext out of the
|
|
||||||
// Option.
|
|
||||||
p
|
|
||||||
} else {
|
|
||||||
// Decryption failed with every known session, let's try to create a
|
|
||||||
// new session.
|
|
||||||
let mut session = match &message {
|
|
||||||
// A new session can only be created using a pre-key message,
|
|
||||||
// return with an error if it isn't one.
|
|
||||||
OlmMessage::Message(_) => {
|
|
||||||
warn!(
|
|
||||||
"Failed to decrypt a non-pre-key message with all
|
|
||||||
available sessions {} {}",
|
|
||||||
sender, sender_key
|
|
||||||
);
|
|
||||||
return Err(OlmError::SessionWedged);
|
|
||||||
}
|
|
||||||
|
|
||||||
OlmMessage::PreKey(m) => {
|
|
||||||
// Create the new session.
|
|
||||||
let session = match self
|
|
||||||
.account
|
|
||||||
.create_inbound_session(sender_key, m.clone())
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(s) => s,
|
|
||||||
Err(e) => {
|
|
||||||
warn!(
|
|
||||||
"Failed to create a new Olm session for {} {}
|
|
||||||
from a prekey message: {}",
|
|
||||||
sender, sender_key, e
|
|
||||||
);
|
|
||||||
return Err(OlmError::SessionWedged);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Save the account since we remove the one-time key that
|
|
||||||
// was used to create this session.
|
|
||||||
self.store.save_account(self.account.clone()).await?;
|
|
||||||
session
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Decrypt our message, this shouldn't fail since we're using a
|
|
||||||
// newly created Session.
|
|
||||||
let plaintext = session.decrypt(message).await?;
|
|
||||||
|
|
||||||
// Save the new ratcheted state of the session.
|
|
||||||
self.store.save_sessions(&[session]).await?;
|
|
||||||
plaintext
|
|
||||||
};
|
|
||||||
|
|
||||||
trace!("Successfully decrypted a Olm message: {}", plaintext);
|
|
||||||
|
|
||||||
self.parse_decrypted_to_device_event(sender, &plaintext)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a decrypted Olm message, check that the plaintext and encrypted
|
|
||||||
/// senders match and that the message was meant for us.
|
|
||||||
fn parse_decrypted_to_device_event(
|
|
||||||
&self,
|
|
||||||
sender: &UserId,
|
|
||||||
plaintext: &str,
|
|
||||||
) -> OlmResult<(Raw<AnyToDeviceEvent>, String)> {
|
|
||||||
// TODO make the errors a bit more specific.
|
|
||||||
let decrypted_json: Value = serde_json::from_str(&plaintext)?;
|
|
||||||
|
|
||||||
let encrytped_sender = decrypted_json
|
|
||||||
.get("sender")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| EventError::MissingField("sender".to_string()))?;
|
|
||||||
let encrytped_sender: UserId = serde_json::from_value(encrytped_sender)?;
|
|
||||||
let recipient = decrypted_json
|
|
||||||
.get("recipient")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| EventError::MissingField("recipient".to_string()))?;
|
|
||||||
let recipient: UserId = serde_json::from_value(recipient)?;
|
|
||||||
|
|
||||||
let recipient_keys: BTreeMap<DeviceKeyAlgorithm, String> = serde_json::from_value(
|
|
||||||
decrypted_json
|
|
||||||
.get("recipient_keys")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| EventError::MissingField("recipient_keys".to_string()))?,
|
|
||||||
)?;
|
|
||||||
let keys: BTreeMap<DeviceKeyAlgorithm, String> = serde_json::from_value(
|
|
||||||
decrypted_json
|
|
||||||
.get("keys")
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| EventError::MissingField("keys".to_string()))?,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if &recipient != self.user_id() || sender != &encrytped_sender {
|
|
||||||
return Err(EventError::MissmatchedSender.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.account.identity_keys().ed25519()
|
|
||||||
!= recipient_keys
|
|
||||||
.get(&DeviceKeyAlgorithm::Ed25519)
|
|
||||||
.ok_or(EventError::MissingSigningKey)?
|
|
||||||
{
|
|
||||||
return Err(EventError::MissmatchedKeys.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
let signing_key = keys
|
|
||||||
.get(&DeviceKeyAlgorithm::Ed25519)
|
|
||||||
.ok_or(EventError::MissingSigningKey)?;
|
|
||||||
|
|
||||||
Ok((
|
|
||||||
Raw::from(serde_json::from_value::<AnyToDeviceEvent>(decrypted_json)?),
|
|
||||||
signing_key.to_owned(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decrypt a to-device event.
|
/// Decrypt a to-device event.
|
||||||
///
|
///
|
||||||
/// Returns a decrypted `ToDeviceEvent` if the decryption was successful,
|
/// Returns a decrypted `ToDeviceEvent` if the decryption was successful,
|
||||||
|
@ -748,6 +540,7 @@ impl OlmMachine {
|
||||||
|
|
||||||
// Decrypt the OlmMessage and get a Ruma event out of it.
|
// Decrypt the OlmMessage and get a Ruma event out of it.
|
||||||
let (decrypted_event, signing_key) = self
|
let (decrypted_event, signing_key) = self
|
||||||
|
.account
|
||||||
.decrypt_olm_message(&event.sender, &content.sender_key, message)
|
.decrypt_olm_message(&event.sender, &content.sender_key, message)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -1070,11 +863,7 @@ impl OlmMachine {
|
||||||
&self,
|
&self,
|
||||||
key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>,
|
key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>,
|
||||||
) -> StoreResult<()> {
|
) -> StoreResult<()> {
|
||||||
let one_time_key_count = key_count.get(&DeviceKeyAlgorithm::SignedCurve25519);
|
self.account.update_uploaded_key_count(key_count).await
|
||||||
|
|
||||||
let count: u64 = one_time_key_count.map_or(0, |c| (*c).into());
|
|
||||||
self.account.update_uploaded_key_count(count);
|
|
||||||
self.store.save_account(self.account.clone()).await
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle a sync response and update the internal state of the Olm machine.
|
/// Handle a sync response and update the internal state of the Olm machine.
|
||||||
|
@ -1496,7 +1285,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
pub(crate) async fn get_prepared_machine() -> (OlmMachine, OneTimeKeys) {
|
pub(crate) async fn get_prepared_machine() -> (OlmMachine, OneTimeKeys) {
|
||||||
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
||||||
machine.account.update_uploaded_key_count(0);
|
machine.account.inner.update_uploaded_key_count(0);
|
||||||
let request = machine
|
let request = machine
|
||||||
.keys_for_upload()
|
.keys_for_upload()
|
||||||
.await
|
.await
|
||||||
|
@ -1699,7 +1488,7 @@ pub(crate) mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_one_time_key_signing() {
|
async fn test_one_time_key_signing() {
|
||||||
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
||||||
machine.account.update_uploaded_key_count(49);
|
machine.account.inner.update_uploaded_key_count(49);
|
||||||
|
|
||||||
let mut one_time_keys = machine.account.signed_one_time_keys().await.unwrap();
|
let mut one_time_keys = machine.account.signed_one_time_keys().await.unwrap();
|
||||||
let identity_keys = machine.account.identity_keys();
|
let identity_keys = machine.account.identity_keys();
|
||||||
|
@ -1720,7 +1509,7 @@ pub(crate) mod test {
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_keys_for_upload() {
|
async fn test_keys_for_upload() {
|
||||||
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
let machine = OlmMachine::new(&user_id(), &alice_device_id());
|
||||||
machine.account.update_uploaded_key_count(0);
|
machine.account.inner.update_uploaded_key_count(0);
|
||||||
|
|
||||||
let identity_keys = machine.account.identity_keys();
|
let identity_keys = machine.account.identity_keys();
|
||||||
let ed25519_key = identity_keys.ed25519();
|
let ed25519_key = identity_keys.ed25519();
|
||||||
|
|
|
@ -12,51 +12,301 @@
|
||||||
// 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.
|
||||||
|
|
||||||
#[cfg(test)]
|
use serde::{Deserialize, Serialize};
|
||||||
use matrix_sdk_common::events::{room::encrypted::EncryptedEventContent, EventType};
|
use serde_json::{json, Value};
|
||||||
use std::{
|
use std::{
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
convert::{TryFrom, TryInto},
|
convert::{TryFrom, TryInto},
|
||||||
fmt,
|
fmt,
|
||||||
|
ops::Deref,
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicBool, AtomicI64, Ordering},
|
atomic::{AtomicBool, AtomicI64, Ordering},
|
||||||
Arc,
|
Arc,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use tracing::{debug, trace, warn};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use matrix_sdk_common::events::{room::encrypted::EncryptedEventContent, EventType};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::{OneTimeKey, SignedKey},
|
api::r0::keys::{upload_keys, OneTimeKey, SignedKey},
|
||||||
encryption::DeviceKeys,
|
encryption::DeviceKeys,
|
||||||
|
events::AnyToDeviceEvent,
|
||||||
identifiers::{
|
identifiers::{
|
||||||
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId,
|
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId,
|
||||||
UserId,
|
UserId,
|
||||||
},
|
},
|
||||||
instant::Instant,
|
instant::Instant,
|
||||||
|
js_int::UInt,
|
||||||
locks::Mutex,
|
locks::Mutex,
|
||||||
|
Raw,
|
||||||
};
|
};
|
||||||
use olm_rs::{
|
use olm_rs::{
|
||||||
account::{OlmAccount, OneTimeKeys},
|
account::{IdentityKeys, OlmAccount, OneTimeKeys},
|
||||||
errors::{OlmAccountError, OlmSessionError},
|
errors::{OlmAccountError, OlmSessionError},
|
||||||
|
session::{OlmMessage, PreKeyMessage},
|
||||||
PicklingMode,
|
PicklingMode,
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use serde_json::{json, Value};
|
|
||||||
|
|
||||||
pub use olm_rs::{
|
use crate::{
|
||||||
account::IdentityKeys,
|
error::{EventError, OlmResult, SessionCreationError},
|
||||||
session::{OlmMessage, PreKeyMessage},
|
identities::ReadOnlyDevice,
|
||||||
utility::OlmUtility,
|
store::{Result as StoreResult, Store},
|
||||||
|
OlmError,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{EncryptionSettings, InboundGroupSession, OutboundGroupSession, Session};
|
use super::{EncryptionSettings, InboundGroupSession, OutboundGroupSession, Session};
|
||||||
use crate::{error::SessionCreationError, identities::ReadOnlyDevice};
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Account {
|
||||||
|
pub(crate) inner: ReadOnlyAccount,
|
||||||
|
pub(crate) store: Store,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for Account {
|
||||||
|
type Target = ReadOnlyAccount;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.inner
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Account {
|
||||||
|
pub async fn update_uploaded_key_count(
|
||||||
|
&self,
|
||||||
|
key_count: &BTreeMap<DeviceKeyAlgorithm, UInt>,
|
||||||
|
) -> StoreResult<()> {
|
||||||
|
let one_time_key_count = key_count.get(&DeviceKeyAlgorithm::SignedCurve25519);
|
||||||
|
|
||||||
|
let count: u64 = one_time_key_count.map_or(0, |c| (*c).into());
|
||||||
|
self.inner.update_uploaded_key_count(count);
|
||||||
|
self.store.save_account(self.inner.clone()).await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn receive_keys_upload_response(
|
||||||
|
&self,
|
||||||
|
response: &upload_keys::Response,
|
||||||
|
) -> OlmResult<()> {
|
||||||
|
if !self.inner.shared() {
|
||||||
|
debug!("Marking account as shared");
|
||||||
|
}
|
||||||
|
self.inner.mark_as_shared();
|
||||||
|
|
||||||
|
let one_time_key_count = response
|
||||||
|
.one_time_key_counts
|
||||||
|
.get(&DeviceKeyAlgorithm::SignedCurve25519);
|
||||||
|
|
||||||
|
let count: u64 = one_time_key_count.map_or(0, |c| (*c).into());
|
||||||
|
debug!(
|
||||||
|
"Updated uploaded one-time key count {} -> {}, marking keys as published",
|
||||||
|
self.inner.uploaded_key_count(),
|
||||||
|
count
|
||||||
|
);
|
||||||
|
self.inner.update_uploaded_key_count(count);
|
||||||
|
self.inner.mark_keys_as_published().await;
|
||||||
|
self.store.save_account(self.inner.clone()).await?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to decrypt an Olm message.
|
||||||
|
///
|
||||||
|
/// This try to decrypt an Olm message using all the sessions we share
|
||||||
|
/// have with the given sender.
|
||||||
|
async fn try_decrypt_olm_message(
|
||||||
|
&self,
|
||||||
|
sender: &UserId,
|
||||||
|
sender_key: &str,
|
||||||
|
message: &OlmMessage,
|
||||||
|
) -> OlmResult<Option<String>> {
|
||||||
|
let s = self.store.get_sessions(sender_key).await?;
|
||||||
|
|
||||||
|
// We don't have any existing sessions, return early.
|
||||||
|
let sessions = if let Some(s) = s {
|
||||||
|
s
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut session_to_save = None;
|
||||||
|
let mut plaintext = None;
|
||||||
|
|
||||||
|
for session in &mut *sessions.lock().await {
|
||||||
|
let mut matches = false;
|
||||||
|
|
||||||
|
// If this is a pre-key message check if it was encrypted for our
|
||||||
|
// session, if it wasn't decryption will fail so no need to try.
|
||||||
|
if let OlmMessage::PreKey(m) = &message {
|
||||||
|
matches = session.matches(sender_key, m.clone()).await?;
|
||||||
|
|
||||||
|
if !matches {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ret = session.decrypt(message.clone()).await;
|
||||||
|
|
||||||
|
if let Ok(p) = ret {
|
||||||
|
plaintext = Some(p);
|
||||||
|
session_to_save = Some(session.clone());
|
||||||
|
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
// Decryption failed with a matching session, the session is
|
||||||
|
// likely wedged and needs to be rotated.
|
||||||
|
if matches {
|
||||||
|
warn!(
|
||||||
|
"Found a matching Olm session yet decryption failed
|
||||||
|
for sender {} and sender_key {}",
|
||||||
|
sender, sender_key
|
||||||
|
);
|
||||||
|
return Err(OlmError::SessionWedged);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(session) = session_to_save {
|
||||||
|
// Decryption was successful, save the new ratchet state of the
|
||||||
|
// session that was used to decrypt the message.
|
||||||
|
trace!("Saved the new session state for {}", sender);
|
||||||
|
self.store.save_sessions(&[session]).await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Decrypt an Olm message, creating a new Olm session if possible.
|
||||||
|
pub async fn decrypt_olm_message(
|
||||||
|
&self,
|
||||||
|
sender: &UserId,
|
||||||
|
sender_key: &str,
|
||||||
|
message: OlmMessage,
|
||||||
|
) -> OlmResult<(Raw<AnyToDeviceEvent>, String)> {
|
||||||
|
// First try to decrypt using an existing session.
|
||||||
|
let plaintext = if let Some(p) = self
|
||||||
|
.try_decrypt_olm_message(sender, sender_key, &message)
|
||||||
|
.await?
|
||||||
|
{
|
||||||
|
// Decryption succeeded, de-structure the plaintext out of the
|
||||||
|
// Option.
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
// Decryption failed with every known session, let's try to create a
|
||||||
|
// new session.
|
||||||
|
let mut session = match &message {
|
||||||
|
// A new session can only be created using a pre-key message,
|
||||||
|
// return with an error if it isn't one.
|
||||||
|
OlmMessage::Message(_) => {
|
||||||
|
warn!(
|
||||||
|
"Failed to decrypt a non-pre-key message with all
|
||||||
|
available sessions {} {}",
|
||||||
|
sender, sender_key
|
||||||
|
);
|
||||||
|
return Err(OlmError::SessionWedged);
|
||||||
|
}
|
||||||
|
|
||||||
|
OlmMessage::PreKey(m) => {
|
||||||
|
// Create the new session.
|
||||||
|
let session = match self
|
||||||
|
.inner
|
||||||
|
.create_inbound_session(sender_key, m.clone())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(e) => {
|
||||||
|
warn!(
|
||||||
|
"Failed to create a new Olm session for {} {}
|
||||||
|
from a prekey message: {}",
|
||||||
|
sender, sender_key, e
|
||||||
|
);
|
||||||
|
return Err(OlmError::SessionWedged);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Save the account since we remove the one-time key that
|
||||||
|
// was used to create this session.
|
||||||
|
self.store.save_account(self.inner.clone()).await?;
|
||||||
|
session
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decrypt our message, this shouldn't fail since we're using a
|
||||||
|
// newly created Session.
|
||||||
|
let plaintext = session.decrypt(message).await?;
|
||||||
|
|
||||||
|
// Save the new ratcheted state of the session.
|
||||||
|
self.store.save_sessions(&[session]).await?;
|
||||||
|
plaintext
|
||||||
|
};
|
||||||
|
|
||||||
|
trace!("Successfully decrypted a Olm message: {}", plaintext);
|
||||||
|
|
||||||
|
self.parse_decrypted_to_device_event(sender, &plaintext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a decrypted Olm message, check that the plaintext and encrypted
|
||||||
|
/// senders match and that the message was meant for us.
|
||||||
|
fn parse_decrypted_to_device_event(
|
||||||
|
&self,
|
||||||
|
sender: &UserId,
|
||||||
|
plaintext: &str,
|
||||||
|
) -> OlmResult<(Raw<AnyToDeviceEvent>, String)> {
|
||||||
|
// TODO make the errors a bit more specific.
|
||||||
|
let decrypted_json: Value = serde_json::from_str(&plaintext)?;
|
||||||
|
|
||||||
|
let encrytped_sender = decrypted_json
|
||||||
|
.get("sender")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| EventError::MissingField("sender".to_string()))?;
|
||||||
|
let encrytped_sender: UserId = serde_json::from_value(encrytped_sender)?;
|
||||||
|
let recipient = decrypted_json
|
||||||
|
.get("recipient")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| EventError::MissingField("recipient".to_string()))?;
|
||||||
|
let recipient: UserId = serde_json::from_value(recipient)?;
|
||||||
|
|
||||||
|
let recipient_keys: BTreeMap<DeviceKeyAlgorithm, String> = serde_json::from_value(
|
||||||
|
decrypted_json
|
||||||
|
.get("recipient_keys")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| EventError::MissingField("recipient_keys".to_string()))?,
|
||||||
|
)?;
|
||||||
|
let keys: BTreeMap<DeviceKeyAlgorithm, String> = serde_json::from_value(
|
||||||
|
decrypted_json
|
||||||
|
.get("keys")
|
||||||
|
.cloned()
|
||||||
|
.ok_or_else(|| EventError::MissingField("keys".to_string()))?,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if &recipient != self.user_id() || sender != &encrytped_sender {
|
||||||
|
return Err(EventError::MissmatchedSender.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.inner.identity_keys().ed25519()
|
||||||
|
!= recipient_keys
|
||||||
|
.get(&DeviceKeyAlgorithm::Ed25519)
|
||||||
|
.ok_or(EventError::MissingSigningKey)?
|
||||||
|
{
|
||||||
|
return Err(EventError::MissmatchedKeys.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
let signing_key = keys
|
||||||
|
.get(&DeviceKeyAlgorithm::Ed25519)
|
||||||
|
.ok_or(EventError::MissingSigningKey)?;
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
Raw::from(serde_json::from_value::<AnyToDeviceEvent>(decrypted_json)?),
|
||||||
|
signing_key.to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Account holding identity keys for which sessions can be created.
|
/// Account holding identity keys for which sessions can be created.
|
||||||
///
|
///
|
||||||
/// An account is the central identity for encrypted communication between two
|
/// An account is the central identity for encrypted communication between two
|
||||||
/// devices.
|
/// devices.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Account {
|
pub struct ReadOnlyAccount {
|
||||||
pub(crate) user_id: Arc<UserId>,
|
pub(crate) user_id: Arc<UserId>,
|
||||||
pub(crate) device_id: Arc<Box<DeviceId>>,
|
pub(crate) device_id: Arc<Box<DeviceId>>,
|
||||||
inner: Arc<Mutex<OlmAccount>>,
|
inner: Arc<Mutex<OlmAccount>>,
|
||||||
|
@ -106,7 +356,7 @@ pub struct PickledAccount {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
impl fmt::Debug for Account {
|
impl fmt::Debug for ReadOnlyAccount {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
f.debug_struct("Account")
|
f.debug_struct("Account")
|
||||||
.field("identity_keys", self.identity_keys())
|
.field("identity_keys", self.identity_keys())
|
||||||
|
@ -115,7 +365,7 @@ impl fmt::Debug for Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Account {
|
impl ReadOnlyAccount {
|
||||||
const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
|
const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
|
||||||
&EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
|
&EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
|
||||||
&EventEncryptionAlgorithm::MegolmV1AesSha2,
|
&EventEncryptionAlgorithm::MegolmV1AesSha2,
|
||||||
|
@ -127,7 +377,7 @@ impl Account {
|
||||||
let account = OlmAccount::new();
|
let account = OlmAccount::new();
|
||||||
let identity_keys = account.parsed_identity_keys();
|
let identity_keys = account.parsed_identity_keys();
|
||||||
|
|
||||||
Account {
|
Self {
|
||||||
user_id: Arc::new(user_id.to_owned()),
|
user_id: Arc::new(user_id.to_owned()),
|
||||||
device_id: Arc::new(device_id.into()),
|
device_id: Arc::new(device_id.into()),
|
||||||
inner: Arc::new(Mutex::new(account)),
|
inner: Arc::new(Mutex::new(account)),
|
||||||
|
@ -307,7 +557,7 @@ impl Account {
|
||||||
let account = OlmAccount::unpickle(pickle.pickle.0, pickle_mode)?;
|
let account = OlmAccount::unpickle(pickle.pickle.0, pickle_mode)?;
|
||||||
let identity_keys = account.parsed_identity_keys();
|
let identity_keys = account.parsed_identity_keys();
|
||||||
|
|
||||||
Ok(Account {
|
Ok(Self {
|
||||||
user_id: Arc::new(pickle.user_id),
|
user_id: Arc::new(pickle.user_id),
|
||||||
device_id: Arc::new(pickle.device_id),
|
device_id: Arc::new(pickle.device_id),
|
||||||
inner: Arc::new(Mutex::new(account)),
|
inner: Arc::new(Mutex::new(account)),
|
||||||
|
@ -336,7 +586,7 @@ impl Account {
|
||||||
let device_keys = json!({
|
let device_keys = json!({
|
||||||
"user_id": (*self.user_id).clone(),
|
"user_id": (*self.user_id).clone(),
|
||||||
"device_id": (*self.device_id).clone(),
|
"device_id": (*self.device_id).clone(),
|
||||||
"algorithms": Account::ALGORITHMS,
|
"algorithms": Self::ALGORITHMS,
|
||||||
"keys": keys,
|
"keys": keys,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -621,7 +871,7 @@ impl Account {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) async fn create_session_for(&self, other: &Account) -> (Session, Session) {
|
pub(crate) async fn create_session_for(&self, other: &ReadOnlyAccount) -> (Session, Session) {
|
||||||
other.generate_one_time_keys_helper(1).await;
|
other.generate_one_time_keys_helper(1).await;
|
||||||
let one_time = other.signed_one_time_keys().await.unwrap();
|
let one_time = other.signed_one_time_keys().await.unwrap();
|
||||||
|
|
||||||
|
@ -676,7 +926,7 @@ impl Account {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Account {
|
impl PartialEq for ReadOnlyAccount {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
|
self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,7 +135,7 @@ mod test {
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::EncryptionSettings;
|
use super::EncryptionSettings;
|
||||||
use crate::Account;
|
use crate::ReadOnlyAccount;
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
@ -145,7 +145,7 @@ mod test {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
let account = Account::new(&user_id!("@alice:example.org"), "DEVICEID".into());
|
let account = ReadOnlyAccount::new(&user_id!("@alice:example.org"), "DEVICEID".into());
|
||||||
let (session, _) = account
|
let (session, _) = account
|
||||||
.create_group_session_pair(&room_id!("!test_room:example.org"), settings, [].iter())
|
.create_group_session_pair(&room_id!("!test_room:example.org"), settings, [].iter())
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -22,20 +22,21 @@ mod group_sessions;
|
||||||
mod session;
|
mod session;
|
||||||
mod utility;
|
mod utility;
|
||||||
|
|
||||||
pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount};
|
pub(crate) use account::Account;
|
||||||
|
pub use account::{AccountPickle, PickledAccount, ReadOnlyAccount};
|
||||||
pub use group_sessions::{
|
pub use group_sessions::{
|
||||||
EncryptionSettings, ExportedRoomKey, InboundGroupSession, InboundGroupSessionPickle,
|
EncryptionSettings, ExportedRoomKey, InboundGroupSession, InboundGroupSessionPickle,
|
||||||
PickledInboundGroupSession,
|
PickledInboundGroupSession,
|
||||||
};
|
};
|
||||||
pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession};
|
pub(crate) use group_sessions::{GroupSessionKey, OutboundGroupSession};
|
||||||
pub use olm_rs::PicklingMode;
|
pub use olm_rs::{account::IdentityKeys, PicklingMode};
|
||||||
pub(crate) use session::OlmMessage;
|
pub(crate) use session::OlmMessage;
|
||||||
pub use session::{PickledSession, Session, SessionPickle};
|
pub use session::{PickledSession, Session, SessionPickle};
|
||||||
pub(crate) use utility::Utility;
|
pub(crate) use utility::Utility;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) mod test {
|
pub(crate) mod test {
|
||||||
use crate::olm::{Account, InboundGroupSession, Session};
|
use crate::olm::{InboundGroupSession, ReadOnlyAccount, Session};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::SignedKey,
|
api::r0::keys::SignedKey,
|
||||||
events::forwarded_room_key::ForwardedRoomKeyEventContent,
|
events::forwarded_room_key::ForwardedRoomKeyEventContent,
|
||||||
|
@ -60,9 +61,9 @@ pub(crate) mod test {
|
||||||
"BOBDEVICE".into()
|
"BOBDEVICE".into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) async fn get_account_and_session() -> (Account, Session) {
|
pub(crate) async fn get_account_and_session() -> (ReadOnlyAccount, Session) {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
|
|
||||||
bob.generate_one_time_keys_helper(1).await;
|
bob.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_key = bob
|
let one_time_key = bob
|
||||||
|
@ -89,7 +90,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn account_creation() {
|
fn account_creation() {
|
||||||
let account = Account::new(&alice_id(), &alice_device_id());
|
let account = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let identyty_keys = account.identity_keys();
|
let identyty_keys = account.identity_keys();
|
||||||
|
|
||||||
assert!(!account.shared());
|
assert!(!account.shared());
|
||||||
|
@ -110,7 +111,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn one_time_keys_creation() {
|
async fn one_time_keys_creation() {
|
||||||
let account = Account::new(&alice_id(), &alice_device_id());
|
let account = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let one_time_keys = account.one_time_keys().await;
|
let one_time_keys = account.one_time_keys().await;
|
||||||
|
|
||||||
assert!(one_time_keys.curve25519().is_empty());
|
assert!(one_time_keys.curve25519().is_empty());
|
||||||
|
@ -137,8 +138,8 @@ pub(crate) mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn session_creation() {
|
async fn session_creation() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
let alice_keys = alice.identity_keys();
|
let alice_keys = alice.identity_keys();
|
||||||
alice.generate_one_time_keys_helper(1).await;
|
alice.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_keys = alice.one_time_keys().await;
|
let one_time_keys = alice.one_time_keys().await;
|
||||||
|
@ -190,7 +191,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn group_session_creation() {
|
async fn group_session_creation() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let room_id = room_id!("!test:localhost");
|
let room_id = room_id!("!test:localhost");
|
||||||
|
|
||||||
let (outbound, _) = alice
|
let (outbound, _) = alice
|
||||||
|
@ -226,7 +227,7 @@ pub(crate) mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn group_session_export() {
|
async fn group_session_export() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let room_id = room_id!("!test:localhost");
|
let room_id = room_id!("!test:localhost");
|
||||||
|
|
||||||
let (_, inbound) = alice
|
let (_, inbound) = alice
|
||||||
|
|
|
@ -23,7 +23,7 @@ use matrix_sdk_common_macros::async_trait;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
caches::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
caches::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
|
||||||
Account, CryptoStore, InboundGroupSession, Result, Session,
|
CryptoStore, InboundGroupSession, ReadOnlyAccount, Result, Session,
|
||||||
};
|
};
|
||||||
use crate::identities::{ReadOnlyDevice, UserIdentities};
|
use crate::identities::{ReadOnlyDevice, UserIdentities};
|
||||||
|
|
||||||
|
@ -62,11 +62,11 @@ impl MemoryStore {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CryptoStore for MemoryStore {
|
impl CryptoStore for MemoryStore {
|
||||||
async fn load_account(&self) -> Result<Option<Account>> {
|
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>> {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_account(&self, _: Account) -> Result<()> {
|
async fn save_account(&self, _: ReadOnlyAccount) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ use matrix_sdk_common_macros::send_sync;
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities},
|
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities},
|
||||||
olm::{Account, InboundGroupSession, Session},
|
olm::{InboundGroupSession, ReadOnlyAccount, Session},
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::SessionUnpicklingError;
|
use crate::error::SessionUnpicklingError;
|
||||||
|
@ -216,14 +216,14 @@ pub enum CryptoStoreError {
|
||||||
#[cfg_attr(not(target_arch = "wasm32"), send_sync)]
|
#[cfg_attr(not(target_arch = "wasm32"), send_sync)]
|
||||||
pub trait CryptoStore: Debug {
|
pub trait CryptoStore: Debug {
|
||||||
/// Load an account that was previously stored.
|
/// Load an account that was previously stored.
|
||||||
async fn load_account(&self) -> Result<Option<Account>>;
|
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>>;
|
||||||
|
|
||||||
/// Save the given account in the store.
|
/// Save the given account in the store.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `account` - The account that should be stored.
|
/// * `account` - The account that should be stored.
|
||||||
async fn save_account(&self, account: Account) -> Result<()>;
|
async fn save_account(&self, account: ReadOnlyAccount) -> Result<()>;
|
||||||
|
|
||||||
/// Save the given sessions in the store.
|
/// Save the given sessions in the store.
|
||||||
///
|
///
|
||||||
|
|
|
@ -41,9 +41,9 @@ use super::{
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserIdentities, UserIdentity},
|
identities::{LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserIdentities, UserIdentity},
|
||||||
olm::{
|
olm::{
|
||||||
Account, AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
|
AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
|
||||||
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, Session,
|
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, ReadOnlyAccount,
|
||||||
SessionPickle,
|
Session, SessionPickle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1167,7 +1167,7 @@ impl SqliteStore {
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl CryptoStore for SqliteStore {
|
impl CryptoStore for SqliteStore {
|
||||||
async fn load_account(&self) -> Result<Option<Account>> {
|
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>> {
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
let row: Option<(i64, String, bool, i64)> = query_as(
|
let row: Option<(i64, String, bool, i64)> = query_as(
|
||||||
|
@ -1188,7 +1188,7 @@ impl CryptoStore for SqliteStore {
|
||||||
uploaded_signed_key_count: uploaded_key_count,
|
uploaded_signed_key_count: uploaded_key_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
let account = Account::from_pickle(pickle, self.get_pickle_mode())?;
|
let account = ReadOnlyAccount::from_pickle(pickle, self.get_pickle_mode())?;
|
||||||
|
|
||||||
*self.account_info.lock().unwrap() = Some(AccountInfo {
|
*self.account_info.lock().unwrap() = Some(AccountInfo {
|
||||||
account_id: id,
|
account_id: id,
|
||||||
|
@ -1209,7 +1209,7 @@ impl CryptoStore for SqliteStore {
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_account(&self, account: Account) -> Result<()> {
|
async fn save_account(&self, account: ReadOnlyAccount) -> Result<()> {
|
||||||
let pickle = account.pickle(self.get_pickle_mode()).await;
|
let pickle = account.pickle(self.get_pickle_mode()).await;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
@ -1456,7 +1456,7 @@ mod test {
|
||||||
device::test::get_device,
|
device::test::get_device,
|
||||||
user::test::{get_other_identity, get_own_identity},
|
user::test::{get_other_identity, get_own_identity},
|
||||||
},
|
},
|
||||||
olm::{Account, GroupSessionKey, InboundGroupSession, Session},
|
olm::{GroupSessionKey, InboundGroupSession, ReadOnlyAccount, Session},
|
||||||
};
|
};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::SignedKey,
|
api::r0::keys::SignedKey,
|
||||||
|
@ -1506,7 +1506,7 @@ mod test {
|
||||||
(store, tmpdir)
|
(store, tmpdir)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_loaded_store() -> (Account, SqliteStore, tempfile::TempDir) {
|
async fn get_loaded_store() -> (ReadOnlyAccount, SqliteStore, tempfile::TempDir) {
|
||||||
let (store, dir) = get_store(None).await;
|
let (store, dir) = get_store(None).await;
|
||||||
let account = get_account();
|
let account = get_account();
|
||||||
store
|
store
|
||||||
|
@ -1517,13 +1517,13 @@ mod test {
|
||||||
(account, store, dir)
|
(account, store, dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_account() -> Account {
|
fn get_account() -> ReadOnlyAccount {
|
||||||
Account::new(&alice_id(), &alice_device_id())
|
ReadOnlyAccount::new(&alice_id(), &alice_device_id())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_account_and_session() -> (Account, Session) {
|
async fn get_account_and_session() -> (ReadOnlyAccount, Session) {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
|
|
||||||
bob.generate_one_time_keys_helper(1).await;
|
bob.generate_one_time_keys_helper(1).await;
|
||||||
let one_time_key = bob
|
let one_time_key = bob
|
||||||
|
@ -1870,7 +1870,7 @@ mod test {
|
||||||
.await
|
.await
|
||||||
.expect("Can't create store");
|
.expect("Can't create store");
|
||||||
|
|
||||||
let account = Account::new(&user_id, &device_id);
|
let account = ReadOnlyAccount::new(&user_id, &device_id);
|
||||||
|
|
||||||
store
|
store
|
||||||
.save_account(account.clone())
|
.save_account(account.clone())
|
||||||
|
|
|
@ -28,19 +28,19 @@ use super::sas::{content_to_request, Sas};
|
||||||
use crate::{
|
use crate::{
|
||||||
requests::{OutgoingRequest, ToDeviceRequest},
|
requests::{OutgoingRequest, ToDeviceRequest},
|
||||||
store::{CryptoStoreError, Store},
|
store::{CryptoStoreError, Store},
|
||||||
Account, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct VerificationMachine {
|
pub struct VerificationMachine {
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
pub(crate) store: Store,
|
pub(crate) store: Store,
|
||||||
verifications: Arc<DashMap<String, Sas>>,
|
verifications: Arc<DashMap<String, Sas>>,
|
||||||
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VerificationMachine {
|
impl VerificationMachine {
|
||||||
pub(crate) fn new(account: Account, store: Store) -> Self {
|
pub(crate) fn new(account: ReadOnlyAccount, store: Store) -> Self {
|
||||||
Self {
|
Self {
|
||||||
account,
|
account,
|
||||||
store,
|
store,
|
||||||
|
@ -235,7 +235,7 @@ mod test {
|
||||||
requests::OutgoingRequests,
|
requests::OutgoingRequests,
|
||||||
store::{CryptoStore, MemoryStore, Store},
|
store::{CryptoStore, MemoryStore, Store},
|
||||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
||||||
Account, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn alice_id() -> UserId {
|
fn alice_id() -> UserId {
|
||||||
|
@ -255,8 +255,8 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn setup_verification_machine() -> (VerificationMachine, Sas) {
|
async fn setup_verification_machine() -> (VerificationMachine, Sas) {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let bob = Account::new(&bob_id(), &bob_device_id());
|
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
|
||||||
let store = MemoryStore::new();
|
let store = MemoryStore::new();
|
||||||
let bob_store = Store::new(Arc::new(bob_id()), Box::new(MemoryStore::new()));
|
let bob_store = Store::new(Arc::new(bob_id()), Box::new(MemoryStore::new()));
|
||||||
|
|
||||||
|
@ -285,7 +285,7 @@ mod test {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create() {
|
fn create() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let user_id = Arc::new(alice_id());
|
let user_id = Arc::new(alice_id());
|
||||||
let store = MemoryStore::new();
|
let store = MemoryStore::new();
|
||||||
let _ = VerificationMachine::new(alice, Store::new(user_id, Box::new(store)));
|
let _ = VerificationMachine::new(alice, Store::new(user_id, Box::new(store)));
|
||||||
|
|
|
@ -30,12 +30,12 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
Account, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SasIds {
|
pub struct SasIds {
|
||||||
pub account: Account,
|
pub account: ReadOnlyAccount,
|
||||||
pub other_device: ReadOnlyDevice,
|
pub other_device: ReadOnlyDevice,
|
||||||
pub other_identity: Option<UserIdentities>,
|
pub other_identity: Option<UserIdentities>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ use matrix_sdk_common::{
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
|
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
|
||||||
store::{CryptoStoreError, Store},
|
store::{CryptoStoreError, Store},
|
||||||
Account, ToDeviceRequest,
|
ReadOnlyAccount, ToDeviceRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use helpers::content_to_request;
|
pub use helpers::content_to_request;
|
||||||
|
@ -48,7 +48,7 @@ use sas_state::{
|
||||||
pub struct Sas {
|
pub struct Sas {
|
||||||
inner: Arc<Mutex<InnerSas>>,
|
inner: Arc<Mutex<InnerSas>>,
|
||||||
store: Store,
|
store: Store,
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
flow_id: Arc<String>,
|
flow_id: Arc<String>,
|
||||||
|
@ -102,7 +102,7 @@ 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.
|
||||||
pub(crate) fn start(
|
pub(crate) fn start(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
store: Store,
|
store: Store,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
@ -137,7 +137,7 @@ impl Sas {
|
||||||
/// * `event` - The m.key.verification.start event that was sent to us by
|
/// * `event` - The m.key.verification.start event that was sent to us by
|
||||||
/// the other side.
|
/// the other side.
|
||||||
pub(crate) fn from_start_event(
|
pub(crate) fn from_start_event(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
store: Store,
|
store: Store,
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
|
@ -426,7 +426,7 @@ enum InnerSas {
|
||||||
|
|
||||||
impl InnerSas {
|
impl InnerSas {
|
||||||
fn start(
|
fn start(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> (InnerSas, StartEventContent) {
|
) -> (InnerSas, StartEventContent) {
|
||||||
|
@ -436,7 +436,7 @@ impl InnerSas {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn from_start_event(
|
fn from_start_event(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
@ -656,7 +656,7 @@ mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
store::{MemoryStore, Store},
|
store::{MemoryStore, Store},
|
||||||
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
verification::test::{get_content_from_request, wrap_any_to_device_content},
|
||||||
Account, ReadOnlyDevice,
|
ReadOnlyAccount, ReadOnlyDevice,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Accepted, Created, Sas, SasState, Started};
|
use super::{Accepted, Created, Sas, SasState, Started};
|
||||||
|
@ -685,10 +685,10 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_sas_pair() -> (SasState<Created>, SasState<Started>) {
|
async fn get_sas_pair() -> (SasState<Created>, SasState<Started>) {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
||||||
|
|
||||||
let bob = Account::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);
|
||||||
|
@ -770,10 +770,10 @@ mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn sas_wrapper_full() {
|
async fn sas_wrapper_full() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
||||||
|
|
||||||
let bob = Account::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_store = Store::new(Arc::new(alice_id()), Box::new(MemoryStore::new()));
|
let alice_store = Store::new(Arc::new(alice_id()), Box::new(MemoryStore::new()));
|
||||||
|
|
|
@ -45,7 +45,7 @@ use super::helpers::{get_decimal, get_emoji, get_mac_content, receive_mac_event,
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{ReadOnlyDevice, UserIdentities},
|
identities::{ReadOnlyDevice, UserIdentities},
|
||||||
Account,
|
ReadOnlyAccount,
|
||||||
};
|
};
|
||||||
|
|
||||||
const KEY_AGREEMENT_PROTOCOLS: &[KeyAgreementProtocol] =
|
const KEY_AGREEMENT_PROTOCOLS: &[KeyAgreementProtocol] =
|
||||||
|
@ -290,7 +290,7 @@ impl SasState<Created> {
|
||||||
///
|
///
|
||||||
/// * `other_device` - The other device which we are going to verify.
|
/// * `other_device` - The other device which we are going to verify.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
) -> SasState<Created> {
|
) -> SasState<Created> {
|
||||||
|
@ -387,7 +387,7 @@ impl SasState<Started> {
|
||||||
/// * `event` - The m.key.verification.start event that was sent to us by
|
/// * `event` - The m.key.verification.start event that was sent to us by
|
||||||
/// the other side.
|
/// the other side.
|
||||||
pub fn from_start_event(
|
pub fn from_start_event(
|
||||||
account: Account,
|
account: ReadOnlyAccount,
|
||||||
other_device: ReadOnlyDevice,
|
other_device: ReadOnlyDevice,
|
||||||
event: &ToDeviceEvent<StartEventContent>,
|
event: &ToDeviceEvent<StartEventContent>,
|
||||||
other_identity: Option<UserIdentities>,
|
other_identity: Option<UserIdentities>,
|
||||||
|
@ -843,7 +843,7 @@ impl SasState<Canceled> {
|
||||||
mod test {
|
mod test {
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
|
||||||
use crate::{Account, ReadOnlyDevice};
|
use crate::{ReadOnlyAccount, ReadOnlyDevice};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
events::{
|
events::{
|
||||||
key::verification::{
|
key::verification::{
|
||||||
|
@ -881,10 +881,10 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_sas_pair() -> (SasState<Created>, SasState<Started>) {
|
async fn get_sas_pair() -> (SasState<Created>, SasState<Started>) {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
||||||
|
|
||||||
let bob = Account::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);
|
||||||
|
@ -1038,10 +1038,10 @@ mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn sas_from_start_unknown_method() {
|
async fn sas_from_start_unknown_method() {
|
||||||
let alice = Account::new(&alice_id(), &alice_device_id());
|
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
|
||||||
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
let alice_device = ReadOnlyDevice::from_account(&alice).await;
|
||||||
|
|
||||||
let bob = Account::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);
|
||||||
|
|
Loading…
Reference in New Issue