crypto: Split out the Account into a read only portion and one with effects.

This commit is contained in:
Damir Jelić 2020-09-29 12:03:41 +02:00
parent e1c220e2f7
commit 84066d4a76
15 changed files with 357 additions and 317 deletions

View file

@ -34,7 +34,7 @@ use serde_json::{json, Value};
use tracing::warn;
#[cfg(test)]
use crate::{Account, OlmMachine};
use crate::{OlmMachine, ReadOnlyAccount};
use crate::{
error::{EventError, OlmError, OlmResult, SignatureError},
@ -419,7 +419,7 @@ impl ReadOnlyDevice {
}
#[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;
ReadOnlyDevice::try_from(&device_keys).unwrap()
}

View file

@ -666,7 +666,7 @@ pub(crate) mod test {
manager::test::{other_key_query, own_key_query},
Device, ReadOnlyDevice,
},
olm::Account,
olm::ReadOnlyAccount,
store::{MemoryStore, Store},
verification::VerificationMachine,
};
@ -735,7 +735,7 @@ pub(crate) mod test {
assert!(identity.is_device_signed(&second).is_ok());
let verification_machine = VerificationMachine::new(
Account::new(second.user_id(), second.device_id()),
ReadOnlyAccount::new(second.user_id(), second.device_id()),
Store::new(
Arc::new(second.user_id().clone()),
Box::new(MemoryStore::new()),

View file

@ -599,7 +599,7 @@ mod test {
use crate::{
identities::{LocalTrust, ReadOnlyDevice},
olm::Account,
olm::ReadOnlyAccount,
store::{MemoryStore, Store},
};
@ -625,12 +625,12 @@ mod test {
room_id!("!test:example.org")
}
fn account() -> Account {
Account::new(&alice_id(), &alice_device_id())
fn account() -> ReadOnlyAccount {
ReadOnlyAccount::new(&alice_id(), &alice_device_id())
}
fn bob_account() -> Account {
Account::new(&bob_id(), &bob_device_id())
fn bob_account() -> ReadOnlyAccount {
ReadOnlyAccount::new(&bob_id(), &bob_device_id())
}
fn bob_machine() -> KeyRequestMachine {

View file

@ -46,8 +46,8 @@ pub use identities::{
Device, LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserDevices, UserIdentities, UserIdentity,
};
pub use machine::OlmMachine;
pub(crate) use olm::Account;
pub use olm::EncryptionSettings;
pub(crate) use olm::ReadOnlyAccount;
pub use requests::{
IncomingResponse, KeysQueryRequest, OutgoingRequest, OutgoingRequests, ToDeviceRequest,
};

View file

@ -17,7 +17,6 @@ use std::path::Path;
use std::{collections::BTreeMap, convert::TryInto, mem, sync::Arc, time::Duration};
use dashmap::DashMap;
use serde_json::Value;
use tracing::{debug, error, info, instrument, trace, warn};
use matrix_sdk_common::{
@ -52,7 +51,7 @@ use super::{
key_request::KeyRequestMachine,
olm::{
Account, EncryptionSettings, ExportedRoomKey, GroupSessionKey, IdentityKeys,
InboundGroupSession, OlmMessage, OutboundGroupSession,
InboundGroupSession, OlmMessage, OutboundGroupSession, ReadOnlyAccount,
},
requests::{IncomingResponse, OutgoingRequest, ToDeviceRequest},
store::{CryptoStore, MemoryStore, Result as StoreResult, Store},
@ -113,7 +112,7 @@ impl OlmMachine {
pub fn new(user_id: &UserId, device_id: &DeviceId) -> Self {
let store: Box<dyn CryptoStore> = Box::new(MemoryStore::new());
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)
}
@ -122,7 +121,7 @@ impl OlmMachine {
user_id: &UserId,
device_id: DeviceIdBox,
store: Box<dyn CryptoStore>,
account: Account,
account: ReadOnlyAccount,
) -> Self {
let user_id = Arc::new(user_id.clone());
@ -142,7 +141,10 @@ impl OlmMachine {
OlmMachine {
user_id,
device_id,
account,
account: Account {
inner: account,
store: store.clone(),
},
store,
outbound_group_sessions,
verification_machine,
@ -182,7 +184,7 @@ impl OlmMachine {
}
None => {
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.
#[cfg(test)]
pub(crate) fn account(&self) -> &Account {
pub(crate) fn account(&self) -> &ReadOnlyAccount {
&self.account
}
@ -341,26 +343,7 @@ impl OlmMachine {
&self,
response: &upload_keys::Response,
) -> OlmResult<()> {
if !self.account.shared() {
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(())
self.account.receive_keys_upload_response(response).await
}
/// 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 }))
}
/// 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.
///
/// 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.
let (decrypted_event, signing_key) = self
.account
.decrypt_olm_message(&event.sender, &content.sender_key, message)
.await?;
@ -1070,11 +863,7 @@ impl OlmMachine {
&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.account.update_uploaded_key_count(count);
self.store.save_account(self.account.clone()).await
self.account.update_uploaded_key_count(key_count).await
}
/// 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) {
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
.keys_for_upload()
.await
@ -1699,7 +1488,7 @@ pub(crate) mod test {
#[tokio::test]
async fn test_one_time_key_signing() {
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 identity_keys = machine.account.identity_keys();
@ -1720,7 +1509,7 @@ pub(crate) mod test {
#[tokio::test]
async fn test_keys_for_upload() {
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 ed25519_key = identity_keys.ed25519();

View file

@ -12,51 +12,301 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#[cfg(test)]
use matrix_sdk_common::events::{room::encrypted::EncryptedEventContent, EventType};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::{
collections::BTreeMap,
convert::{TryFrom, TryInto},
fmt,
ops::Deref,
sync::{
atomic::{AtomicBool, AtomicI64, Ordering},
Arc,
},
};
use tracing::{debug, trace, warn};
#[cfg(test)]
use matrix_sdk_common::events::{room::encrypted::EncryptedEventContent, EventType};
use matrix_sdk_common::{
api::r0::keys::{OneTimeKey, SignedKey},
api::r0::keys::{upload_keys, OneTimeKey, SignedKey},
encryption::DeviceKeys,
events::AnyToDeviceEvent,
identifiers::{
DeviceId, DeviceIdBox, DeviceKeyAlgorithm, DeviceKeyId, EventEncryptionAlgorithm, RoomId,
UserId,
},
instant::Instant,
js_int::UInt,
locks::Mutex,
Raw,
};
use olm_rs::{
account::{OlmAccount, OneTimeKeys},
account::{IdentityKeys, OlmAccount, OneTimeKeys},
errors::{OlmAccountError, OlmSessionError},
session::{OlmMessage, PreKeyMessage},
PicklingMode,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
pub use olm_rs::{
account::IdentityKeys,
session::{OlmMessage, PreKeyMessage},
utility::OlmUtility,
use crate::{
error::{EventError, OlmResult, SessionCreationError},
identities::ReadOnlyDevice,
store::{Result as StoreResult, Store},
OlmError,
};
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.
///
/// An account is the central identity for encrypted communication between two
/// devices.
#[derive(Clone)]
pub struct Account {
pub struct ReadOnlyAccount {
pub(crate) user_id: Arc<UserId>,
pub(crate) device_id: Arc<Box<DeviceId>>,
inner: Arc<Mutex<OlmAccount>>,
@ -106,7 +356,7 @@ pub struct PickledAccount {
}
#[cfg(not(tarpaulin_include))]
impl fmt::Debug for Account {
impl fmt::Debug for ReadOnlyAccount {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Account")
.field("identity_keys", self.identity_keys())
@ -115,7 +365,7 @@ impl fmt::Debug for Account {
}
}
impl Account {
impl ReadOnlyAccount {
const ALGORITHMS: &'static [&'static EventEncryptionAlgorithm] = &[
&EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
&EventEncryptionAlgorithm::MegolmV1AesSha2,
@ -127,7 +377,7 @@ impl Account {
let account = OlmAccount::new();
let identity_keys = account.parsed_identity_keys();
Account {
Self {
user_id: Arc::new(user_id.to_owned()),
device_id: Arc::new(device_id.into()),
inner: Arc::new(Mutex::new(account)),
@ -307,7 +557,7 @@ impl Account {
let account = OlmAccount::unpickle(pickle.pickle.0, pickle_mode)?;
let identity_keys = account.parsed_identity_keys();
Ok(Account {
Ok(Self {
user_id: Arc::new(pickle.user_id),
device_id: Arc::new(pickle.device_id),
inner: Arc::new(Mutex::new(account)),
@ -336,7 +586,7 @@ impl Account {
let device_keys = json!({
"user_id": (*self.user_id).clone(),
"device_id": (*self.device_id).clone(),
"algorithms": Account::ALGORITHMS,
"algorithms": Self::ALGORITHMS,
"keys": keys,
});
@ -621,7 +871,7 @@ impl Account {
}
#[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;
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 {
self.identity_keys() == other.identity_keys() && self.shared() == other.shared()
}

View file

@ -135,7 +135,7 @@ mod test {
};
use super::EncryptionSettings;
use crate::Account;
use crate::ReadOnlyAccount;
#[tokio::test]
#[cfg(not(target_os = "macos"))]
@ -145,7 +145,7 @@ mod test {
..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
.create_group_session_pair(&room_id!("!test_room:example.org"), settings, [].iter())
.await

View file

@ -22,20 +22,21 @@ mod group_sessions;
mod session;
mod utility;
pub use account::{Account, AccountPickle, IdentityKeys, PickledAccount};
pub(crate) use account::Account;
pub use account::{AccountPickle, PickledAccount, ReadOnlyAccount};
pub use group_sessions::{
EncryptionSettings, ExportedRoomKey, InboundGroupSession, InboundGroupSessionPickle,
PickledInboundGroupSession,
};
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 use session::{PickledSession, Session, SessionPickle};
pub(crate) use utility::Utility;
#[cfg(test)]
pub(crate) mod test {
use crate::olm::{Account, InboundGroupSession, Session};
use crate::olm::{InboundGroupSession, ReadOnlyAccount, Session};
use matrix_sdk_common::{
api::r0::keys::SignedKey,
events::forwarded_room_key::ForwardedRoomKeyEventContent,
@ -60,9 +61,9 @@ pub(crate) mod test {
"BOBDEVICE".into()
}
pub(crate) async fn get_account_and_session() -> (Account, Session) {
let alice = Account::new(&alice_id(), &alice_device_id());
let bob = Account::new(&bob_id(), &bob_device_id());
pub(crate) async fn get_account_and_session() -> (ReadOnlyAccount, Session) {
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
bob.generate_one_time_keys_helper(1).await;
let one_time_key = bob
@ -89,7 +90,7 @@ pub(crate) mod test {
#[test]
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();
assert!(!account.shared());
@ -110,7 +111,7 @@ pub(crate) mod test {
#[tokio::test]
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;
assert!(one_time_keys.curve25519().is_empty());
@ -137,8 +138,8 @@ pub(crate) mod test {
#[tokio::test]
async fn session_creation() {
let alice = Account::new(&alice_id(), &alice_device_id());
let bob = Account::new(&bob_id(), &bob_device_id());
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
let alice_keys = alice.identity_keys();
alice.generate_one_time_keys_helper(1).await;
let one_time_keys = alice.one_time_keys().await;
@ -190,7 +191,7 @@ pub(crate) mod test {
#[tokio::test]
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 (outbound, _) = alice
@ -226,7 +227,7 @@ pub(crate) mod test {
#[tokio::test]
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 (_, inbound) = alice

View file

@ -23,7 +23,7 @@ use matrix_sdk_common_macros::async_trait;
use super::{
caches::{DeviceStore, GroupSessionStore, ReadOnlyUserDevices, SessionStore},
Account, CryptoStore, InboundGroupSession, Result, Session,
CryptoStore, InboundGroupSession, ReadOnlyAccount, Result, Session,
};
use crate::identities::{ReadOnlyDevice, UserIdentities};
@ -62,11 +62,11 @@ impl MemoryStore {
#[async_trait]
impl CryptoStore for MemoryStore {
async fn load_account(&self) -> Result<Option<Account>> {
async fn load_account(&self) -> Result<Option<ReadOnlyAccount>> {
Ok(None)
}
async fn save_account(&self, _: Account) -> Result<()> {
async fn save_account(&self, _: ReadOnlyAccount) -> Result<()> {
Ok(())
}

View file

@ -72,7 +72,7 @@ use matrix_sdk_common_macros::send_sync;
use super::{
identities::{OwnUserIdentity, ReadOnlyDevice, UserIdentities},
olm::{Account, InboundGroupSession, Session},
olm::{InboundGroupSession, ReadOnlyAccount, Session},
};
use crate::error::SessionUnpicklingError;
@ -216,14 +216,14 @@ pub enum CryptoStoreError {
#[cfg_attr(not(target_arch = "wasm32"), send_sync)]
pub trait CryptoStore: Debug {
/// 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.
///
/// # Arguments
///
/// * `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.
///

View file

@ -41,9 +41,9 @@ use super::{
use crate::{
identities::{LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserIdentities, UserIdentity},
olm::{
Account, AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, Session,
SessionPickle,
AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, ReadOnlyAccount,
Session, SessionPickle,
},
};
@ -1167,7 +1167,7 @@ impl SqliteStore {
#[async_trait]
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 row: Option<(i64, String, bool, i64)> = query_as(
@ -1188,7 +1188,7 @@ impl CryptoStore for SqliteStore {
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 {
account_id: id,
@ -1209,7 +1209,7 @@ impl CryptoStore for SqliteStore {
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 mut connection = self.connection.lock().await;
@ -1456,7 +1456,7 @@ mod test {
device::test::get_device,
user::test::{get_other_identity, get_own_identity},
},
olm::{Account, GroupSessionKey, InboundGroupSession, Session},
olm::{GroupSessionKey, InboundGroupSession, ReadOnlyAccount, Session},
};
use matrix_sdk_common::{
api::r0::keys::SignedKey,
@ -1506,7 +1506,7 @@ mod test {
(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 account = get_account();
store
@ -1517,13 +1517,13 @@ mod test {
(account, store, dir)
}
fn get_account() -> Account {
Account::new(&alice_id(), &alice_device_id())
fn get_account() -> ReadOnlyAccount {
ReadOnlyAccount::new(&alice_id(), &alice_device_id())
}
async fn get_account_and_session() -> (Account, Session) {
let alice = Account::new(&alice_id(), &alice_device_id());
let bob = Account::new(&bob_id(), &bob_device_id());
async fn get_account_and_session() -> (ReadOnlyAccount, Session) {
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
bob.generate_one_time_keys_helper(1).await;
let one_time_key = bob
@ -1870,7 +1870,7 @@ mod test {
.await
.expect("Can't create store");
let account = Account::new(&user_id, &device_id);
let account = ReadOnlyAccount::new(&user_id, &device_id);
store
.save_account(account.clone())

View file

@ -28,19 +28,19 @@ use super::sas::{content_to_request, Sas};
use crate::{
requests::{OutgoingRequest, ToDeviceRequest},
store::{CryptoStoreError, Store},
Account, ReadOnlyDevice,
ReadOnlyAccount, ReadOnlyDevice,
};
#[derive(Clone, Debug)]
pub struct VerificationMachine {
account: Account,
account: ReadOnlyAccount,
pub(crate) store: Store,
verifications: Arc<DashMap<String, Sas>>,
outgoing_to_device_messages: Arc<DashMap<Uuid, OutgoingRequest>>,
}
impl VerificationMachine {
pub(crate) fn new(account: Account, store: Store) -> Self {
pub(crate) fn new(account: ReadOnlyAccount, store: Store) -> Self {
Self {
account,
store,
@ -235,7 +235,7 @@ mod test {
requests::OutgoingRequests,
store::{CryptoStore, MemoryStore, Store},
verification::test::{get_content_from_request, wrap_any_to_device_content},
Account, ReadOnlyDevice,
ReadOnlyAccount, ReadOnlyDevice,
};
fn alice_id() -> UserId {
@ -255,8 +255,8 @@ mod test {
}
async fn setup_verification_machine() -> (VerificationMachine, Sas) {
let alice = Account::new(&alice_id(), &alice_device_id());
let bob = Account::new(&bob_id(), &bob_device_id());
let alice = ReadOnlyAccount::new(&alice_id(), &alice_device_id());
let bob = ReadOnlyAccount::new(&bob_id(), &bob_device_id());
let store = MemoryStore::new();
let bob_store = Store::new(Arc::new(bob_id()), Box::new(MemoryStore::new()));
@ -285,7 +285,7 @@ mod test {
#[test]
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 store = MemoryStore::new();
let _ = VerificationMachine::new(alice, Store::new(user_id, Box::new(store)));

View file

@ -30,12 +30,12 @@ use matrix_sdk_common::{
use crate::{
identities::{ReadOnlyDevice, UserIdentities},
Account, ToDeviceRequest,
ReadOnlyAccount, ToDeviceRequest,
};
#[derive(Clone, Debug)]
pub struct SasIds {
pub account: Account,
pub account: ReadOnlyAccount,
pub other_device: ReadOnlyDevice,
pub other_identity: Option<UserIdentities>,
}

View file

@ -35,7 +35,7 @@ use matrix_sdk_common::{
use crate::{
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
store::{CryptoStoreError, Store},
Account, ToDeviceRequest,
ReadOnlyAccount, ToDeviceRequest,
};
pub use helpers::content_to_request;
@ -48,7 +48,7 @@ use sas_state::{
pub struct Sas {
inner: Arc<Mutex<InnerSas>>,
store: Store,
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
flow_id: Arc<String>,
@ -102,7 +102,7 @@ impl Sas {
/// Returns the new `Sas` object and a `StartEventContent` that needs to be
/// sent out through the server to the other device.
pub(crate) fn start(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
store: Store,
other_identity: Option<UserIdentities>,
@ -137,7 +137,7 @@ impl Sas {
/// * `event` - The m.key.verification.start event that was sent to us by
/// the other side.
pub(crate) fn from_start_event(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
store: Store,
event: &ToDeviceEvent<StartEventContent>,
@ -426,7 +426,7 @@ enum InnerSas {
impl InnerSas {
fn start(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> (InnerSas, StartEventContent) {
@ -436,7 +436,7 @@ impl InnerSas {
}
fn from_start_event(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartEventContent>,
other_identity: Option<UserIdentities>,
@ -656,7 +656,7 @@ mod test {
use crate::{
store::{MemoryStore, Store},
verification::test::{get_content_from_request, wrap_any_to_device_content},
Account, ReadOnlyDevice,
ReadOnlyAccount, ReadOnlyDevice,
};
use super::{Accepted, Created, Sas, SasState, Started};
@ -685,10 +685,10 @@ mod test {
}
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 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 alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None);
@ -770,10 +770,10 @@ mod test {
#[tokio::test]
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 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 alice_store = Store::new(Arc::new(alice_id()), Box::new(MemoryStore::new()));

View file

@ -45,7 +45,7 @@ use super::helpers::{get_decimal, get_emoji, get_mac_content, receive_mac_event,
use crate::{
identities::{ReadOnlyDevice, UserIdentities},
Account,
ReadOnlyAccount,
};
const KEY_AGREEMENT_PROTOCOLS: &[KeyAgreementProtocol] =
@ -290,7 +290,7 @@ impl SasState<Created> {
///
/// * `other_device` - The other device which we are going to verify.
pub fn new(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
other_identity: Option<UserIdentities>,
) -> SasState<Created> {
@ -387,7 +387,7 @@ impl SasState<Started> {
/// * `event` - The m.key.verification.start event that was sent to us by
/// the other side.
pub fn from_start_event(
account: Account,
account: ReadOnlyAccount,
other_device: ReadOnlyDevice,
event: &ToDeviceEvent<StartEventContent>,
other_identity: Option<UserIdentities>,
@ -843,7 +843,7 @@ impl SasState<Canceled> {
mod test {
use std::convert::TryFrom;
use crate::{Account, ReadOnlyDevice};
use crate::{ReadOnlyAccount, ReadOnlyDevice};
use matrix_sdk_common::{
events::{
key::verification::{
@ -881,10 +881,10 @@ mod test {
}
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 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 alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None);
@ -1038,10 +1038,10 @@ mod test {
#[tokio::test]
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 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 alice_sas = SasState::<Created>::new(alice.clone(), bob_device, None);