crypto: Store a copy of the user_id/device_id and identity keys in sessions.
parent
3f1439fe28
commit
e50cf39a17
|
@ -37,7 +37,7 @@ pub use device::{Device, TrustState};
|
||||||
pub use error::{MegolmError, OlmError};
|
pub use error::{MegolmError, OlmError};
|
||||||
pub use machine::{OlmMachine, OneTimeKeys};
|
pub use machine::{OlmMachine, OneTimeKeys};
|
||||||
pub use memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
|
pub use memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
|
||||||
pub use olm::{Account, InboundGroupSession, OutboundGroupSession, Session};
|
pub use olm::{Account, IdentityKeys, InboundGroupSession, OutboundGroupSession, Session};
|
||||||
#[cfg(feature = "sqlite-cryptostore")]
|
#[cfg(feature = "sqlite-cryptostore")]
|
||||||
pub use store::sqlite::SqliteStore;
|
pub use store::sqlite::SqliteStore;
|
||||||
pub use store::{CryptoStore, CryptoStoreError};
|
pub use store::{CryptoStore, CryptoStoreError};
|
||||||
|
|
|
@ -52,7 +52,7 @@ pub struct Account {
|
||||||
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>>,
|
||||||
identity_keys: Arc<IdentityKeys>,
|
pub(crate) identity_keys: Arc<IdentityKeys>,
|
||||||
shared: Arc<AtomicBool>,
|
shared: Arc<AtomicBool>,
|
||||||
/// The number of signed one-time keys we have uploaded to the server. If
|
/// The number of signed one-time keys we have uploaded to the server. If
|
||||||
/// this is None, no action will be taken. After a sync request the client
|
/// this is None, no action will be taken. After a sync request the client
|
||||||
|
@ -395,6 +395,9 @@ impl Account {
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
|
|
||||||
Ok(Session {
|
Ok(Session {
|
||||||
|
user_id: self.user_id.clone(),
|
||||||
|
device_id: self.device_id.clone(),
|
||||||
|
our_identity_keys: self.identity_keys.clone(),
|
||||||
inner: Arc::new(Mutex::new(session)),
|
inner: Arc::new(Mutex::new(session)),
|
||||||
session_id: Arc::new(session_id),
|
session_id: Arc::new(session_id),
|
||||||
sender_key: Arc::new(their_identity_key.to_owned()),
|
sender_key: Arc::new(their_identity_key.to_owned()),
|
||||||
|
@ -495,6 +498,9 @@ impl Account {
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
|
|
||||||
Ok(Session {
|
Ok(Session {
|
||||||
|
user_id: self.user_id.clone(),
|
||||||
|
device_id: self.device_id.clone(),
|
||||||
|
our_identity_keys: self.identity_keys.clone(),
|
||||||
inner: Arc::new(Mutex::new(session)),
|
inner: Arc::new(Mutex::new(session)),
|
||||||
session_id: Arc::new(session_id),
|
session_id: Arc::new(session_id),
|
||||||
sender_key: Arc::new(their_identity_key.to_owned()),
|
sender_key: Arc::new(their_identity_key.to_owned()),
|
||||||
|
|
|
@ -27,7 +27,7 @@ pub use olm_rs::{
|
||||||
utility::OlmUtility,
|
utility::OlmUtility,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::Account;
|
use super::{Account, IdentityKeys};
|
||||||
use crate::error::{EventError, OlmResult};
|
use crate::error::{EventError, OlmResult};
|
||||||
use crate::Device;
|
use crate::Device;
|
||||||
|
|
||||||
|
@ -37,6 +37,7 @@ use matrix_sdk_common::{
|
||||||
room::encrypted::{CiphertextInfo, EncryptedEventContent, OlmV1Curve25519AesSha2Content},
|
room::encrypted::{CiphertextInfo, EncryptedEventContent, OlmV1Curve25519AesSha2Content},
|
||||||
EventType,
|
EventType,
|
||||||
},
|
},
|
||||||
|
identifiers::{DeviceId, UserId},
|
||||||
instant::Instant,
|
instant::Instant,
|
||||||
locks::Mutex,
|
locks::Mutex,
|
||||||
};
|
};
|
||||||
|
@ -45,6 +46,9 @@ use matrix_sdk_common::{
|
||||||
/// `Account`s
|
/// `Account`s
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Session {
|
pub struct Session {
|
||||||
|
pub(crate) user_id: Arc<UserId>,
|
||||||
|
pub(crate) device_id: Arc<Box<DeviceId>>,
|
||||||
|
pub(crate) our_identity_keys: Arc<IdentityKeys>,
|
||||||
pub(crate) inner: Arc<Mutex<OlmSession>>,
|
pub(crate) inner: Arc<Mutex<OlmSession>>,
|
||||||
pub(crate) session_id: Arc<String>,
|
pub(crate) session_id: Arc<String>,
|
||||||
pub(crate) sender_key: Arc<String>,
|
pub(crate) sender_key: Arc<String>,
|
||||||
|
@ -197,6 +201,9 @@ impl Session {
|
||||||
/// * `last_use_time` - The timestamp that marks when the session was
|
/// * `last_use_time` - The timestamp that marks when the session was
|
||||||
/// last used to encrypt or decrypt an Olm message.
|
/// last used to encrypt or decrypt an Olm message.
|
||||||
pub fn from_pickle(
|
pub fn from_pickle(
|
||||||
|
user_id: Arc<UserId>,
|
||||||
|
device_id: Arc<Box<DeviceId>>,
|
||||||
|
our_identity_keys: Arc<IdentityKeys>,
|
||||||
pickle: String,
|
pickle: String,
|
||||||
pickle_mode: PicklingMode,
|
pickle_mode: PicklingMode,
|
||||||
sender_key: String,
|
sender_key: String,
|
||||||
|
@ -207,6 +214,9 @@ impl Session {
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
|
|
||||||
Ok(Session {
|
Ok(Session {
|
||||||
|
user_id,
|
||||||
|
device_id,
|
||||||
|
our_identity_keys,
|
||||||
inner: Arc::new(Mutex::new(session)),
|
inner: Arc::new(Mutex::new(session)),
|
||||||
session_id: Arc::new(session_id),
|
session_id: Arc::new(session_id),
|
||||||
sender_key: Arc::new(sender_key),
|
sender_key: Arc::new(sender_key),
|
||||||
|
|
|
@ -26,9 +26,10 @@ use olm_rs::PicklingMode;
|
||||||
use sqlx::{query, query_as, sqlite::SqliteQueryAs, Connect, Executor, SqliteConnection};
|
use sqlx::{query, query_as, sqlite::SqliteQueryAs, Connect, Executor, SqliteConnection};
|
||||||
use zeroize::Zeroizing;
|
use zeroize::Zeroizing;
|
||||||
|
|
||||||
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
|
use super::{CryptoStore, CryptoStoreError, Result};
|
||||||
use crate::device::{Device, TrustState};
|
use crate::device::{Device, TrustState};
|
||||||
use crate::memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
|
use crate::memory_stores::{DeviceStore, GroupSessionStore, SessionStore, UserDevices};
|
||||||
|
use crate::{Account, IdentityKeys, InboundGroupSession, Session};
|
||||||
use matrix_sdk_common::api::r0::keys::{AlgorithmAndDeviceId, KeyAlgorithm};
|
use matrix_sdk_common::api::r0::keys::{AlgorithmAndDeviceId, KeyAlgorithm};
|
||||||
use matrix_sdk_common::events::Algorithm;
|
use matrix_sdk_common::events::Algorithm;
|
||||||
use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId};
|
use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId};
|
||||||
|
@ -36,8 +37,8 @@ use matrix_sdk_common::identifiers::{DeviceId, RoomId, UserId};
|
||||||
/// SQLite based implementation of a `CryptoStore`.
|
/// SQLite based implementation of a `CryptoStore`.
|
||||||
pub struct SqliteStore {
|
pub struct SqliteStore {
|
||||||
user_id: Arc<UserId>,
|
user_id: Arc<UserId>,
|
||||||
device_id: Arc<String>,
|
device_id: Arc<Box<DeviceId>>,
|
||||||
account_id: Option<i64>,
|
account_info: Option<AccountInfo>,
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
|
||||||
sessions: SessionStore,
|
sessions: SessionStore,
|
||||||
|
@ -50,6 +51,11 @@ pub struct SqliteStore {
|
||||||
pickle_passphrase: Option<Zeroizing<String>>,
|
pickle_passphrase: Option<Zeroizing<String>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AccountInfo {
|
||||||
|
account_id: i64,
|
||||||
|
identity_keys: Arc<IdentityKeys>,
|
||||||
|
}
|
||||||
|
|
||||||
static DATABASE_NAME: &str = "matrix-sdk-crypto.db";
|
static DATABASE_NAME: &str = "matrix-sdk-crypto.db";
|
||||||
|
|
||||||
impl SqliteStore {
|
impl SqliteStore {
|
||||||
|
@ -118,8 +124,8 @@ impl SqliteStore {
|
||||||
let connection = SqliteConnection::connect(url.as_ref()).await?;
|
let connection = SqliteConnection::connect(url.as_ref()).await?;
|
||||||
let store = SqliteStore {
|
let store = SqliteStore {
|
||||||
user_id: Arc::new(user_id.to_owned()),
|
user_id: Arc::new(user_id.to_owned()),
|
||||||
device_id: Arc::new(device_id.to_owned()),
|
device_id: Arc::new(device_id.into()),
|
||||||
account_id: None,
|
account_info: None,
|
||||||
sessions: SessionStore::new(),
|
sessions: SessionStore::new(),
|
||||||
inbound_group_sessions: GroupSessionStore::new(),
|
inbound_group_sessions: GroupSessionStore::new(),
|
||||||
devices: DeviceStore::new(),
|
devices: DeviceStore::new(),
|
||||||
|
@ -133,6 +139,10 @@ impl SqliteStore {
|
||||||
Ok(store)
|
Ok(store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn account_id(&self) -> Option<i64> {
|
||||||
|
self.account_info.as_ref().map(|i| i.account_id)
|
||||||
|
}
|
||||||
|
|
||||||
async fn create_tables(&self) -> Result<()> {
|
async fn create_tables(&self) -> Result<()> {
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
connection
|
connection
|
||||||
|
@ -288,14 +298,17 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_sessions_for(&mut self, sender_key: &str) -> Result<Vec<Session>> {
|
async fn load_sessions_for(&mut self, sender_key: &str) -> Result<Vec<Session>> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_info = self
|
||||||
|
.account_info
|
||||||
|
.as_ref()
|
||||||
|
.ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
let rows: Vec<(String, String, String, String)> = query_as(
|
let rows: Vec<(String, String, String, String)> = query_as(
|
||||||
"SELECT pickle, sender_key, creation_time, last_use_time
|
"SELECT pickle, sender_key, creation_time, last_use_time
|
||||||
FROM sessions WHERE account_id = ? and sender_key = ?",
|
FROM sessions WHERE account_id = ? and sender_key = ?",
|
||||||
)
|
)
|
||||||
.bind(account_id)
|
.bind(account_info.account_id)
|
||||||
.bind(sender_key)
|
.bind(sender_key)
|
||||||
.fetch_all(&mut *connection)
|
.fetch_all(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -315,6 +328,9 @@ impl SqliteStore {
|
||||||
.ok_or(CryptoStoreError::SessionTimestampError)?;
|
.ok_or(CryptoStoreError::SessionTimestampError)?;
|
||||||
|
|
||||||
Ok(Session::from_pickle(
|
Ok(Session::from_pickle(
|
||||||
|
self.user_id.clone(),
|
||||||
|
self.device_id.clone(),
|
||||||
|
account_info.identity_keys.clone(),
|
||||||
pickle.to_string(),
|
pickle.to_string(),
|
||||||
self.get_pickle_mode(),
|
self.get_pickle_mode(),
|
||||||
sender_key.to_string(),
|
sender_key.to_string(),
|
||||||
|
@ -326,7 +342,7 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_inbound_group_sessions(&self) -> Result<Vec<InboundGroupSession>> {
|
async fn load_inbound_group_sessions(&self) -> Result<Vec<InboundGroupSession>> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
let rows: Vec<(String, String, String, String)> = query_as(
|
let rows: Vec<(String, String, String, String)> = query_as(
|
||||||
|
@ -357,7 +373,7 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_tracked_user(&self, user: &UserId, dirty: bool) -> Result<()> {
|
async fn save_tracked_user(&self, user: &UserId, dirty: bool) -> Result<()> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
query(
|
query(
|
||||||
|
@ -378,7 +394,7 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_tracked_users(&self) -> Result<(HashSet<UserId>, HashSet<UserId>)> {
|
async fn load_tracked_users(&self) -> Result<(HashSet<UserId>, HashSet<UserId>)> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
let rows: Vec<(String, bool)> = query_as(
|
let rows: Vec<(String, bool)> = query_as(
|
||||||
|
@ -410,7 +426,7 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_devices(&self) -> Result<DeviceStore> {
|
async fn load_devices(&self) -> Result<DeviceStore> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
let rows: Vec<(i64, String, String, Option<String>, i64)> = query_as(
|
let rows: Vec<(i64, String, String, Option<String>, i64)> = query_as(
|
||||||
|
@ -490,7 +506,7 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_device_helper(&self, device: Device) -> Result<()> {
|
async fn save_device_helper(&self, device: Device) -> Result<()> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
@ -573,20 +589,26 @@ impl CryptoStore for SqliteStore {
|
||||||
WHERE user_id = ? and device_id = ?",
|
WHERE user_id = ? and device_id = ?",
|
||||||
)
|
)
|
||||||
.bind(self.user_id.as_str())
|
.bind(self.user_id.as_str())
|
||||||
.bind(&*self.device_id)
|
.bind((&*self.device_id).as_ref())
|
||||||
.fetch_optional(&mut *connection)
|
.fetch_optional(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let result = if let Some((id, pickle, shared, uploaded_key_count)) = row {
|
let result = if let Some((id, pickle, shared, uploaded_key_count)) = row {
|
||||||
self.account_id = Some(id);
|
let account = Account::from_pickle(
|
||||||
Some(Account::from_pickle(
|
|
||||||
pickle,
|
pickle,
|
||||||
self.get_pickle_mode(),
|
self.get_pickle_mode(),
|
||||||
shared,
|
shared,
|
||||||
uploaded_key_count,
|
uploaded_key_count,
|
||||||
&self.user_id,
|
&self.user_id,
|
||||||
&self.device_id,
|
&self.device_id,
|
||||||
)?)
|
)?;
|
||||||
|
|
||||||
|
self.account_info = Some(AccountInfo {
|
||||||
|
account_id: id,
|
||||||
|
identity_keys: account.identity_keys.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
Some(account)
|
||||||
} else {
|
} else {
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
@ -640,19 +662,22 @@ impl CryptoStore for SqliteStore {
|
||||||
.fetch_one(&mut *connection)
|
.fetch_one(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
self.account_id = Some(account_id.0);
|
self.account_info = Some(AccountInfo {
|
||||||
|
account_id: account_id.0,
|
||||||
|
identity_keys: account.identity_keys.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_sessions(&mut self, sessions: &[Session]) -> Result<()> {
|
async fn save_sessions(&mut self, sessions: &[Session]) -> Result<()> {
|
||||||
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
|
||||||
// TODO turn this into a transaction
|
// TODO turn this into a transaction
|
||||||
for session in sessions {
|
for session in sessions {
|
||||||
self.lazy_load_sessions(&session.sender_key).await?;
|
self.lazy_load_sessions(&session.sender_key).await?;
|
||||||
self.sessions.add(session.clone()).await;
|
self.sessions.add(session.clone()).await;
|
||||||
|
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
|
||||||
|
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
let creation_time = serde_json::to_string(&session.creation_time.elapsed())?;
|
let creation_time = serde_json::to_string(&session.creation_time.elapsed())?;
|
||||||
let last_use_time = serde_json::to_string(&session.last_use_time.elapsed())?;
|
let last_use_time = serde_json::to_string(&session.last_use_time.elapsed())?;
|
||||||
|
@ -683,7 +708,7 @@ impl CryptoStore for SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_inbound_group_session(&mut self, session: InboundGroupSession) -> Result<bool> {
|
async fn save_inbound_group_session(&mut self, session: InboundGroupSession) -> Result<bool> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let pickle = session.pickle(self.get_pickle_mode()).await;
|
let pickle = session.pickle(self.get_pickle_mode()).await;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
let session_id = session.session_id();
|
let session_id = session.session_id();
|
||||||
|
@ -753,7 +778,7 @@ impl CryptoStore for SqliteStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delete_device(&self, device: Device) -> Result<()> {
|
async fn delete_device(&self, device: Device) -> Result<()> {
|
||||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
query(
|
query(
|
||||||
|
|
Loading…
Reference in New Issue