crypto: Store a copy of the user_id/device_id and identity keys in sessions.
This commit is contained in:
parent
3f1439fe28
commit
e50cf39a17
4 changed files with 65 additions and 24 deletions
|
@ -37,7 +37,7 @@ pub use device::{Device, TrustState};
|
|||
pub use error::{MegolmError, OlmError};
|
||||
pub use machine::{OlmMachine, OneTimeKeys};
|
||||
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")]
|
||||
pub use store::sqlite::SqliteStore;
|
||||
pub use store::{CryptoStore, CryptoStoreError};
|
||||
|
|
|
@ -52,7 +52,7 @@ pub struct Account {
|
|||
pub(crate) user_id: Arc<UserId>,
|
||||
pub(crate) device_id: Arc<Box<DeviceId>>,
|
||||
inner: Arc<Mutex<OlmAccount>>,
|
||||
identity_keys: Arc<IdentityKeys>,
|
||||
pub(crate) identity_keys: Arc<IdentityKeys>,
|
||||
shared: Arc<AtomicBool>,
|
||||
/// 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
|
||||
|
@ -395,6 +395,9 @@ impl Account {
|
|||
let session_id = session.session_id();
|
||||
|
||||
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)),
|
||||
session_id: Arc::new(session_id),
|
||||
sender_key: Arc::new(their_identity_key.to_owned()),
|
||||
|
@ -495,6 +498,9 @@ impl Account {
|
|||
let session_id = session.session_id();
|
||||
|
||||
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)),
|
||||
session_id: Arc::new(session_id),
|
||||
sender_key: Arc::new(their_identity_key.to_owned()),
|
||||
|
|
|
@ -27,7 +27,7 @@ pub use olm_rs::{
|
|||
utility::OlmUtility,
|
||||
};
|
||||
|
||||
use super::Account;
|
||||
use super::{Account, IdentityKeys};
|
||||
use crate::error::{EventError, OlmResult};
|
||||
use crate::Device;
|
||||
|
||||
|
@ -37,6 +37,7 @@ use matrix_sdk_common::{
|
|||
room::encrypted::{CiphertextInfo, EncryptedEventContent, OlmV1Curve25519AesSha2Content},
|
||||
EventType,
|
||||
},
|
||||
identifiers::{DeviceId, UserId},
|
||||
instant::Instant,
|
||||
locks::Mutex,
|
||||
};
|
||||
|
@ -45,6 +46,9 @@ use matrix_sdk_common::{
|
|||
/// `Account`s
|
||||
#[derive(Clone)]
|
||||
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) session_id: 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 used to encrypt or decrypt an Olm message.
|
||||
pub fn from_pickle(
|
||||
user_id: Arc<UserId>,
|
||||
device_id: Arc<Box<DeviceId>>,
|
||||
our_identity_keys: Arc<IdentityKeys>,
|
||||
pickle: String,
|
||||
pickle_mode: PicklingMode,
|
||||
sender_key: String,
|
||||
|
@ -207,6 +214,9 @@ impl Session {
|
|||
let session_id = session.session_id();
|
||||
|
||||
Ok(Session {
|
||||
user_id,
|
||||
device_id,
|
||||
our_identity_keys,
|
||||
inner: Arc::new(Mutex::new(session)),
|
||||
session_id: Arc::new(session_id),
|
||||
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 zeroize::Zeroizing;
|
||||
|
||||
use super::{Account, CryptoStore, CryptoStoreError, InboundGroupSession, Result, Session};
|
||||
use super::{CryptoStore, CryptoStoreError, Result};
|
||||
use crate::device::{Device, TrustState};
|
||||
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::events::Algorithm;
|
||||
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`.
|
||||
pub struct SqliteStore {
|
||||
user_id: Arc<UserId>,
|
||||
device_id: Arc<String>,
|
||||
account_id: Option<i64>,
|
||||
device_id: Arc<Box<DeviceId>>,
|
||||
account_info: Option<AccountInfo>,
|
||||
path: PathBuf,
|
||||
|
||||
sessions: SessionStore,
|
||||
|
@ -50,6 +51,11 @@ pub struct SqliteStore {
|
|||
pickle_passphrase: Option<Zeroizing<String>>,
|
||||
}
|
||||
|
||||
struct AccountInfo {
|
||||
account_id: i64,
|
||||
identity_keys: Arc<IdentityKeys>,
|
||||
}
|
||||
|
||||
static DATABASE_NAME: &str = "matrix-sdk-crypto.db";
|
||||
|
||||
impl SqliteStore {
|
||||
|
@ -118,8 +124,8 @@ impl SqliteStore {
|
|||
let connection = SqliteConnection::connect(url.as_ref()).await?;
|
||||
let store = SqliteStore {
|
||||
user_id: Arc::new(user_id.to_owned()),
|
||||
device_id: Arc::new(device_id.to_owned()),
|
||||
account_id: None,
|
||||
device_id: Arc::new(device_id.into()),
|
||||
account_info: None,
|
||||
sessions: SessionStore::new(),
|
||||
inbound_group_sessions: GroupSessionStore::new(),
|
||||
devices: DeviceStore::new(),
|
||||
|
@ -133,6 +139,10 @@ impl SqliteStore {
|
|||
Ok(store)
|
||||
}
|
||||
|
||||
fn account_id(&self) -> Option<i64> {
|
||||
self.account_info.as_ref().map(|i| i.account_id)
|
||||
}
|
||||
|
||||
async fn create_tables(&self) -> Result<()> {
|
||||
let mut connection = self.connection.lock().await;
|
||||
connection
|
||||
|
@ -288,14 +298,17 @@ impl SqliteStore {
|
|||
}
|
||||
|
||||
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 rows: Vec<(String, String, String, String)> = query_as(
|
||||
"SELECT pickle, sender_key, creation_time, last_use_time
|
||||
FROM sessions WHERE account_id = ? and sender_key = ?",
|
||||
)
|
||||
.bind(account_id)
|
||||
.bind(account_info.account_id)
|
||||
.bind(sender_key)
|
||||
.fetch_all(&mut *connection)
|
||||
.await?;
|
||||
|
@ -315,6 +328,9 @@ impl SqliteStore {
|
|||
.ok_or(CryptoStoreError::SessionTimestampError)?;
|
||||
|
||||
Ok(Session::from_pickle(
|
||||
self.user_id.clone(),
|
||||
self.device_id.clone(),
|
||||
account_info.identity_keys.clone(),
|
||||
pickle.to_string(),
|
||||
self.get_pickle_mode(),
|
||||
sender_key.to_string(),
|
||||
|
@ -326,7 +342,7 @@ impl SqliteStore {
|
|||
}
|
||||
|
||||
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 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<()> {
|
||||
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;
|
||||
|
||||
query(
|
||||
|
@ -378,7 +394,7 @@ impl SqliteStore {
|
|||
}
|
||||
|
||||
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 rows: Vec<(String, bool)> = query_as(
|
||||
|
@ -410,7 +426,7 @@ impl SqliteStore {
|
|||
}
|
||||
|
||||
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 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<()> {
|
||||
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;
|
||||
|
||||
|
@ -573,20 +589,26 @@ impl CryptoStore for SqliteStore {
|
|||
WHERE user_id = ? and device_id = ?",
|
||||
)
|
||||
.bind(self.user_id.as_str())
|
||||
.bind(&*self.device_id)
|
||||
.bind((&*self.device_id).as_ref())
|
||||
.fetch_optional(&mut *connection)
|
||||
.await?;
|
||||
|
||||
let result = if let Some((id, pickle, shared, uploaded_key_count)) = row {
|
||||
self.account_id = Some(id);
|
||||
Some(Account::from_pickle(
|
||||
let account = Account::from_pickle(
|
||||
pickle,
|
||||
self.get_pickle_mode(),
|
||||
shared,
|
||||
uploaded_key_count,
|
||||
&self.user_id,
|
||||
&self.device_id,
|
||||
)?)
|
||||
)?;
|
||||
|
||||
self.account_info = Some(AccountInfo {
|
||||
account_id: id,
|
||||
identity_keys: account.identity_keys.clone(),
|
||||
});
|
||||
|
||||
Some(account)
|
||||
} else {
|
||||
return Ok(None);
|
||||
};
|
||||
|
@ -640,19 +662,22 @@ impl CryptoStore for SqliteStore {
|
|||
.fetch_one(&mut *connection)
|
||||
.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(())
|
||||
}
|
||||
|
||||
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
|
||||
for session in sessions {
|
||||
self.lazy_load_sessions(&session.sender_key).await?;
|
||||
self.sessions.add(session.clone()).await;
|
||||
|
||||
let account_id = self.account_id.ok_or(CryptoStoreError::AccountUnset)?;
|
||||
|
||||
let session_id = session.session_id();
|
||||
let creation_time = serde_json::to_string(&session.creation_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> {
|
||||
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 mut connection = self.connection.lock().await;
|
||||
let session_id = session.session_id();
|
||||
|
@ -753,7 +778,7 @@ impl CryptoStore for SqliteStore {
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
query(
|
||||
|
|
Loading…
Reference in a new issue