crypto: Finish up the cross signing storing for the sqlite store.
parent
d35cf56dc8
commit
9810a2f630
|
@ -54,7 +54,7 @@ features = ["std", "std-future"]
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
features = ["runtime-tokio", "sqlite"]
|
features = ["runtime-tokio", "sqlite", "macros"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] }
|
tokio = { version = "0.2.22", features = ["rt-threaded", "macros"] }
|
||||||
|
|
|
@ -56,6 +56,54 @@ impl PartialEq for MasterPubkey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl PartialEq for SelfSigningPubkey {
|
||||||
|
fn eq(&self, other: &SelfSigningPubkey) -> bool {
|
||||||
|
self.0.user_id == other.0.user_id && self.0.keys == other.0.keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for UserSigningPubkey {
|
||||||
|
fn eq(&self, other: &UserSigningPubkey) -> bool {
|
||||||
|
self.0.user_id == other.0.user_id && self.0.keys == other.0.keys
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CrossSigningKey> for MasterPubkey {
|
||||||
|
fn from(key: CrossSigningKey) -> Self {
|
||||||
|
Self(Arc::new(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CrossSigningKey> for SelfSigningPubkey {
|
||||||
|
fn from(key: CrossSigningKey) -> Self {
|
||||||
|
Self(Arc::new(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CrossSigningKey> for UserSigningPubkey {
|
||||||
|
fn from(key: CrossSigningKey) -> Self {
|
||||||
|
Self(Arc::new(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<CrossSigningKey> for MasterPubkey {
|
||||||
|
fn as_ref(&self) -> &CrossSigningKey {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<CrossSigningKey> for SelfSigningPubkey {
|
||||||
|
fn as_ref(&self) -> &CrossSigningKey {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<CrossSigningKey> for UserSigningPubkey {
|
||||||
|
fn as_ref(&self) -> &CrossSigningKey {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<&CrossSigningKey> for MasterPubkey {
|
impl From<&CrossSigningKey> for MasterPubkey {
|
||||||
fn from(key: &CrossSigningKey) -> Self {
|
fn from(key: &CrossSigningKey) -> Self {
|
||||||
Self(Arc::new(key.clone()))
|
Self(Arc::new(key.clone()))
|
||||||
|
@ -304,6 +352,12 @@ impl From<OwnUserIdentity> for UserIdentities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<UserIdentity> for UserIdentities {
|
||||||
|
fn from(identity: UserIdentity) -> Self {
|
||||||
|
UserIdentities::Other(identity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl UserIdentities {
|
impl UserIdentities {
|
||||||
/// The unique user id of this identity.
|
/// The unique user id of this identity.
|
||||||
pub fn user_id(&self) -> &UserId {
|
pub fn user_id(&self) -> &UserId {
|
||||||
|
@ -321,6 +375,23 @@ impl UserIdentities {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the self-signing key of the identity.
|
||||||
|
pub fn self_signing_key(&self) -> &SelfSigningPubkey {
|
||||||
|
match self {
|
||||||
|
UserIdentities::Own(i) => &i.self_signing_key,
|
||||||
|
UserIdentities::Other(i) => &i.self_signing_key,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the user-signing key of the identity, this is only present for our
|
||||||
|
/// own user identity..
|
||||||
|
pub fn user_signing_key(&self) -> Option<&UserSigningPubkey> {
|
||||||
|
match self {
|
||||||
|
UserIdentities::Own(i) => Some(&i.user_signing_key),
|
||||||
|
UserIdentities::Other(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Destructure the enum into an `OwnUserIdentity` if it's of the correct
|
/// Destructure the enum into an `OwnUserIdentity` if it's of the correct
|
||||||
/// type.
|
/// type.
|
||||||
pub fn own(&self) -> Option<&OwnUserIdentity> {
|
pub fn own(&self) -> Option<&OwnUserIdentity> {
|
||||||
|
@ -383,6 +454,11 @@ impl UserIdentity {
|
||||||
&self.master_key
|
&self.master_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the public self-signing key of the identity.
|
||||||
|
pub fn self_signing_key(&self) -> &SelfSigningPubkey {
|
||||||
|
&self.self_signing_key
|
||||||
|
}
|
||||||
|
|
||||||
/// Update the identity with a new master key and self signing key.
|
/// Update the identity with a new master key and self signing key.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -483,6 +559,16 @@ impl OwnUserIdentity {
|
||||||
&self.master_key
|
&self.master_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the public self-signing key of the identity.
|
||||||
|
pub fn self_signing_key(&self) -> &SelfSigningPubkey {
|
||||||
|
&self.self_signing_key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the public user-signing key of the identity.
|
||||||
|
pub fn user_signing_key(&self) -> &UserSigningPubkey {
|
||||||
|
&self.user_signing_key
|
||||||
|
}
|
||||||
|
|
||||||
/// Check if the given identity has been signed by this identity.
|
/// Check if the given identity has been signed by this identity.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
|
@ -760,6 +846,16 @@ pub(crate) mod test {
|
||||||
own_identity(&own_key_query())
|
own_identity(&own_key_query())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_other_identity() -> UserIdentity {
|
||||||
|
let user_id = user_id!("@example2:localhost");
|
||||||
|
let response = other_key_query();
|
||||||
|
|
||||||
|
let master_key = response.master_keys.get(&user_id).unwrap();
|
||||||
|
let self_signing = response.self_signing_keys.get(&user_id).unwrap();
|
||||||
|
|
||||||
|
UserIdentity::new(master_key.into(), self_signing.into()).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn own_identity_create() {
|
fn own_identity_create() {
|
||||||
let user_id = user_id!("@example:localhost");
|
let user_id = user_id!("@example:localhost");
|
||||||
|
|
|
@ -21,7 +21,7 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use dashmap::{DashMap, DashSet};
|
use dashmap::DashSet;
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::keys::{CrossSigningKey, KeyUsage},
|
api::r0::keys::{CrossSigningKey, KeyUsage},
|
||||||
identifiers::{
|
identifiers::{
|
||||||
|
@ -39,7 +39,7 @@ use super::{
|
||||||
CryptoStore, CryptoStoreError, Result,
|
CryptoStore, CryptoStoreError, Result,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{LocalTrust, ReadOnlyDevice, UserIdentities},
|
identities::{LocalTrust, OwnUserIdentity, ReadOnlyDevice, UserIdentities, UserIdentity},
|
||||||
olm::{
|
olm::{
|
||||||
Account, AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
|
Account, AccountPickle, IdentityKeys, InboundGroupSession, InboundGroupSessionPickle,
|
||||||
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, Session,
|
PickledAccount, PickledInboundGroupSession, PickledSession, PicklingMode, Session,
|
||||||
|
@ -72,6 +72,24 @@ struct AccountInfo {
|
||||||
identity_keys: Arc<IdentityKeys>,
|
identity_keys: Arc<IdentityKeys>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Copy, Clone, sqlx::Type)]
|
||||||
|
#[repr(i32)]
|
||||||
|
enum CrosssigningKeyType {
|
||||||
|
Master = 0,
|
||||||
|
SelfSigning = 1,
|
||||||
|
UserSigning = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<KeyUsage> for CrosssigningKeyType {
|
||||||
|
fn into(self) -> KeyUsage {
|
||||||
|
match self {
|
||||||
|
CrosssigningKeyType::Master => KeyUsage::Master,
|
||||||
|
CrosssigningKeyType::SelfSigning => KeyUsage::SelfSigning,
|
||||||
|
CrosssigningKeyType::UserSigning => KeyUsage::UserSigning,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static DATABASE_NAME: &str = "matrix-sdk-crypto.db";
|
static DATABASE_NAME: &str = "matrix-sdk-crypto.db";
|
||||||
|
|
||||||
impl SqliteStore {
|
impl SqliteStore {
|
||||||
|
@ -329,6 +347,23 @@ impl SqliteStore {
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
connection
|
||||||
|
.execute(
|
||||||
|
r#"
|
||||||
|
CREATE TABLE IF NOT EXISTS cross_signing_keys (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
"key_type" INTEGER NOT NULL,
|
||||||
|
"usage" STRING NOT NULL,
|
||||||
|
"user_id" INTEGER NOT NULL,
|
||||||
|
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
|
||||||
|
UNIQUE(user_id, key_type)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE INDEX IF NOT EXISTS "cross_signing_keys_users" ON "users" ("user_id");
|
||||||
|
"#,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
connection
|
connection
|
||||||
.execute(
|
.execute(
|
||||||
r#"
|
r#"
|
||||||
|
@ -336,14 +371,12 @@ impl SqliteStore {
|
||||||
"id" INTEGER NOT NULL PRIMARY KEY,
|
"id" INTEGER NOT NULL PRIMARY KEY,
|
||||||
"key" TEXT NOT NULL,
|
"key" TEXT NOT NULL,
|
||||||
"key_id" TEXT NOT NULL,
|
"key_id" TEXT NOT NULL,
|
||||||
"key_type" TEXT NOT NULL,
|
"cross_signing_key" INTEGER NOT NULL,
|
||||||
"usage" TEXT NOT NULL,
|
FOREIGN KEY ("cross_signing_key") REFERENCES "cross_signing_keys" ("id") ON DELETE CASCADE
|
||||||
"user_id" INTEGER NOT NULL,
|
UNIQUE(cross_signing_key, key_id)
|
||||||
FOREIGN KEY ("user_id") REFERENCES "users" ("id") ON DELETE CASCADE
|
|
||||||
UNIQUE(user_id, key_id, key_type)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS "user_keys_user_id" ON "users" ("user_id");
|
CREATE INDEX IF NOT EXISTS "cross_signing_keys_keys" ON "cross_signing_keys" ("cross_signing_key");
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -356,13 +389,13 @@ impl SqliteStore {
|
||||||
"user_id" TEXT NOT NULL,
|
"user_id" TEXT NOT NULL,
|
||||||
"key_id" INTEGER NOT NULL,
|
"key_id" INTEGER NOT NULL,
|
||||||
"signature" TEXT NOT NULL,
|
"signature" TEXT NOT NULL,
|
||||||
"user_key" INTEGER NOT NULL,
|
"cross_signing_key" INTEGER NOT NULL,
|
||||||
FOREIGN KEY ("user_key") REFERENCES "user_keys" ("id")
|
FOREIGN KEY ("cross_signing_key") REFERENCES "cross_signing_keys" ("id")
|
||||||
ON DELETE CASCADE
|
ON DELETE CASCADE
|
||||||
UNIQUE(user_id, key_id, user_key)
|
UNIQUE(user_id, key_id, cross_signing_key)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE INDEX IF NOT EXISTS "user_keys_device_id" ON "device_keys" ("device_id");
|
CREATE INDEX IF NOT EXISTS "cross_signing_keys_signatures" ON "cross_signing_keys" ("cross_signing_key");
|
||||||
"#,
|
"#,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -728,49 +761,42 @@ impl SqliteStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_user(&self, user_id: &UserId) -> Result<Option<UserIdentities>> {
|
async fn load_cross_signing_key(
|
||||||
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
connection: &mut SqliteConnection,
|
||||||
let mut connection = self.connection.lock().await;
|
user_id: &UserId,
|
||||||
|
user_row_id: i64,
|
||||||
let row: Option<(i64,)> =
|
key_type: CrosssigningKeyType,
|
||||||
query_as("SELECT id FROM users WHERE account_id = ? and user_id = ?")
|
) -> Result<CrossSigningKey> {
|
||||||
.bind(account_id)
|
let row: (i64, String) =
|
||||||
.bind(user_id.as_str())
|
query_as("SELECT id, usage FROM cross_signing_keys WHERE user_id =? and key_type =?")
|
||||||
.fetch_optional(&mut *connection)
|
.bind(user_row_id)
|
||||||
|
.bind(key_type)
|
||||||
|
.fetch_one(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let user_row_id = if let Some(row) = row {
|
let key_row_id = row.0;
|
||||||
row.0
|
let usage: Vec<KeyUsage> = serde_json::from_str(&row.1)?;
|
||||||
} else {
|
|
||||||
return Ok(None);
|
|
||||||
};
|
|
||||||
|
|
||||||
let key_rows: Vec<(i64, String, String, String)> = query_as(
|
let key_rows: Vec<(String, String)> =
|
||||||
"SELECT id, key_id, key, usage FROM user_keys WHERE user_id = ? and key_type = ?",
|
query_as("SELECT key_id, key FROM user_keys WHERE cross_signing_key = ?")
|
||||||
)
|
.bind(key_row_id)
|
||||||
.bind(user_row_id)
|
|
||||||
.bind("master_key")
|
|
||||||
.fetch_all(&mut *connection)
|
.fetch_all(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let mut keys = BTreeMap::new();
|
let mut keys = BTreeMap::new();
|
||||||
let mut signatures = BTreeMap::new();
|
let mut signatures = BTreeMap::new();
|
||||||
let mut key_usage = HashSet::new();
|
|
||||||
|
|
||||||
for row in key_rows {
|
for row in key_rows {
|
||||||
let key_row_id = row.0;
|
let key_id = row.0;
|
||||||
let key_id = row.1;
|
let key = row.1;
|
||||||
let key = row.2;
|
|
||||||
let usage: Vec<String> = serde_json::from_str(&row.3)?;
|
|
||||||
|
|
||||||
keys.insert(key_id, key);
|
keys.insert(key_id, key);
|
||||||
key_usage.extend(usage);
|
}
|
||||||
|
|
||||||
let mut signature_rows: Vec<(String, String, String)> = query_as(
|
let mut signature_rows: Vec<(String, String, String)> = query_as(
|
||||||
"SELECT user_id, key_id, signature, FROM user_key_signatures WHERE user_key = ?",
|
"SELECT user_id, key_id, signature FROM user_key_signatures WHERE cross_signing_key = ?",
|
||||||
)
|
)
|
||||||
.bind(user_row_id)
|
.bind(key_row_id)
|
||||||
.bind("master_key")
|
|
||||||
.fetch_all(&mut *connection)
|
.fetch_all(&mut *connection)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
@ -789,21 +815,130 @@ impl SqliteStore {
|
||||||
.or_insert_with(BTreeMap::new)
|
.or_insert_with(BTreeMap::new)
|
||||||
.insert(key_id, signature);
|
.insert(key_id, signature);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
let usage: Vec<KeyUsage> = key_usage
|
Ok(CrossSigningKey {
|
||||||
.iter()
|
|
||||||
.filter_map(|u| serde_json::from_str(u).ok())
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let key = CrossSigningKey {
|
|
||||||
user_id: user_id.to_owned(),
|
user_id: user_id.to_owned(),
|
||||||
usage,
|
usage,
|
||||||
keys,
|
keys,
|
||||||
signatures,
|
signatures,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn load_user(&self, user_id: &UserId) -> Result<Option<UserIdentities>> {
|
||||||
|
let account_id = self.account_id().ok_or(CryptoStoreError::AccountUnset)?;
|
||||||
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
|
let row: Option<(i64,)> =
|
||||||
|
query_as("SELECT id FROM users WHERE account_id = ? and user_id = ?")
|
||||||
|
.bind(account_id)
|
||||||
|
.bind(user_id.as_str())
|
||||||
|
.fetch_optional(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let user_row_id = if let Some(row) = row {
|
||||||
|
row.0
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(None)
|
let master = SqliteStore::load_cross_signing_key(
|
||||||
|
&mut connection,
|
||||||
|
user_id,
|
||||||
|
user_row_id,
|
||||||
|
CrosssigningKeyType::Master,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let self_singing = SqliteStore::load_cross_signing_key(
|
||||||
|
&mut connection,
|
||||||
|
user_id,
|
||||||
|
user_row_id,
|
||||||
|
CrosssigningKeyType::SelfSigning,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
if user_id == &*self.user_id {
|
||||||
|
let user_signing = SqliteStore::load_cross_signing_key(
|
||||||
|
&mut connection,
|
||||||
|
user_id,
|
||||||
|
user_row_id,
|
||||||
|
CrosssigningKeyType::UserSigning,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(Some(UserIdentities::Own(
|
||||||
|
OwnUserIdentity::new(master.into(), self_singing.into(), user_signing.into())
|
||||||
|
.unwrap(),
|
||||||
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(Some(UserIdentities::Other(
|
||||||
|
UserIdentity::new(master.into(), self_singing.into()).unwrap(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn save_cross_signing_key(
|
||||||
|
connection: &mut SqliteConnection,
|
||||||
|
user_row_id: i64,
|
||||||
|
key_type: CrosssigningKeyType,
|
||||||
|
cross_signing_key: impl AsRef<CrossSigningKey>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let cross_signing_key: &CrossSigningKey = cross_signing_key.as_ref();
|
||||||
|
|
||||||
|
query(
|
||||||
|
"REPLACE INTO cross_signing_keys (
|
||||||
|
user_id, key_type, usage
|
||||||
|
) VALUES (?1, ?2, ?3)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(user_row_id)
|
||||||
|
.bind(key_type)
|
||||||
|
.bind(serde_json::to_string(&cross_signing_key.usage)?)
|
||||||
|
.execute(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let row: (i64,) = query_as(
|
||||||
|
"SELECT id FROM cross_signing_keys
|
||||||
|
WHERE user_id = ? and key_type = ?",
|
||||||
|
)
|
||||||
|
.bind(user_row_id)
|
||||||
|
.bind(key_type)
|
||||||
|
.fetch_one(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let key_row_id = row.0;
|
||||||
|
|
||||||
|
for (key_id, key) in &cross_signing_key.keys {
|
||||||
|
query(
|
||||||
|
"REPLACE INTO user_keys (
|
||||||
|
cross_signing_key, key_id, key
|
||||||
|
) VALUES (?1, ?2, ?3)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(key_row_id)
|
||||||
|
.bind(key_id.as_str())
|
||||||
|
.bind(key)
|
||||||
|
.execute(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (user_id, signature_map) in &cross_signing_key.signatures {
|
||||||
|
for (key_id, signature) in signature_map {
|
||||||
|
query(
|
||||||
|
"REPLACE INTO user_key_signatures (
|
||||||
|
cross_signing_key, user_id, key_id, signature
|
||||||
|
) VALUES (?1, ?2, ?3, ?4)
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.bind(key_row_id)
|
||||||
|
.bind(user_id.as_str())
|
||||||
|
.bind(key_id.as_str())
|
||||||
|
.bind(signature)
|
||||||
|
.execute(&mut *connection)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn save_user_helper(&self, user: &UserIdentities) -> Result<()> {
|
async fn save_user_helper(&self, user: &UserIdentities) -> Result<()> {
|
||||||
|
@ -811,12 +946,7 @@ impl SqliteStore {
|
||||||
|
|
||||||
let mut connection = self.connection.lock().await;
|
let mut connection = self.connection.lock().await;
|
||||||
|
|
||||||
query(
|
query("REPLACE INTO users (account_id, user_id) VALUES (?1, ?2)")
|
||||||
"INSERT OR IGNORE INTO users (
|
|
||||||
account_id, user_id
|
|
||||||
) VALUES (?1, ?2)
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.bind(account_id)
|
.bind(account_id)
|
||||||
.bind(user.user_id().as_str())
|
.bind(user.user_id().as_str())
|
||||||
.execute(&mut *connection)
|
.execute(&mut *connection)
|
||||||
|
@ -833,49 +963,29 @@ impl SqliteStore {
|
||||||
|
|
||||||
let user_row_id = row.0;
|
let user_row_id = row.0;
|
||||||
|
|
||||||
for (key_id, key) in user.master_key() {
|
SqliteStore::save_cross_signing_key(
|
||||||
query(
|
&mut connection,
|
||||||
"INSERT OR IGNORE INTO user_keys (
|
user_row_id,
|
||||||
user_id, key_type, key_id, key, usage
|
CrosssigningKeyType::Master,
|
||||||
) VALUES (?1, ?2, ?3, ?4, ?5)
|
user.master_key(),
|
||||||
",
|
)
|
||||||
|
.await?;
|
||||||
|
SqliteStore::save_cross_signing_key(
|
||||||
|
&mut connection,
|
||||||
|
user_row_id,
|
||||||
|
CrosssigningKeyType::SelfSigning,
|
||||||
|
user.self_signing_key(),
|
||||||
)
|
)
|
||||||
.bind(user_row_id)
|
|
||||||
.bind("master_key")
|
|
||||||
.bind(key_id.as_str())
|
|
||||||
.bind(key)
|
|
||||||
.bind(serde_json::to_string(user.master_key().usage())?)
|
|
||||||
.execute(&mut *connection)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let row: (i64,) = query_as(
|
if let Some(user_signing_key) = user.user_signing_key() {
|
||||||
"SELECT id FROM user_keys
|
SqliteStore::save_cross_signing_key(
|
||||||
WHERE user_id = ? and key_id = ? and key_type = ?",
|
&mut connection,
|
||||||
|
user_row_id,
|
||||||
|
CrosssigningKeyType::UserSigning,
|
||||||
|
user_signing_key,
|
||||||
)
|
)
|
||||||
.bind(user_row_id)
|
|
||||||
.bind(key_id.as_str())
|
|
||||||
.bind("master_key")
|
|
||||||
.fetch_one(&mut *connection)
|
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let key_row_id = row.0;
|
|
||||||
|
|
||||||
for (user_id, signature_map) in user.master_key().signatures() {
|
|
||||||
for (key_id, signature) in signature_map {
|
|
||||||
query(
|
|
||||||
"INSERT OR IGNORE INTO user_key_signatures (
|
|
||||||
user_key, user_id, key_id, signature
|
|
||||||
) VALUES (?1, ?2, ?3, ?4)
|
|
||||||
",
|
|
||||||
)
|
|
||||||
.bind(key_row_id)
|
|
||||||
.bind(user_id.as_str())
|
|
||||||
.bind(key_id.as_str())
|
|
||||||
.bind(signature)
|
|
||||||
.execute(&mut *connection)
|
|
||||||
.await?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1136,7 +1246,10 @@ impl std::fmt::Debug for SqliteStore {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::{
|
use crate::{
|
||||||
identities::{device::test::get_device, user::test::get_own_identity},
|
identities::{
|
||||||
|
device::test::get_device,
|
||||||
|
user::test::{get_other_identity, get_own_identity},
|
||||||
|
},
|
||||||
olm::{Account, GroupSessionKey, InboundGroupSession, Session},
|
olm::{Account, GroupSessionKey, InboundGroupSession, Session},
|
||||||
};
|
};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -1528,38 +1641,69 @@ mod test {
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn user_saving() {
|
async fn user_saving() {
|
||||||
let (_account, store, dir) = get_loaded_store().await;
|
let dir = tempdir().unwrap();
|
||||||
|
let tmpdir_path = dir.path().to_str().unwrap();
|
||||||
|
|
||||||
|
let user_id = user_id!("@example:localhost");
|
||||||
|
let device_id: &DeviceId = "WSKKLTJZCL".into();
|
||||||
|
|
||||||
|
let store = SqliteStore::open(&user_id, &device_id, tmpdir_path)
|
||||||
|
.await
|
||||||
|
.expect("Can't create store");
|
||||||
|
|
||||||
|
let account = Account::new(&user_id, &device_id);
|
||||||
|
|
||||||
|
store
|
||||||
|
.save_account(account.clone())
|
||||||
|
.await
|
||||||
|
.expect("Can't save account");
|
||||||
|
|
||||||
let own_identity = get_own_identity();
|
let own_identity = get_own_identity();
|
||||||
|
|
||||||
store
|
store
|
||||||
.save_user_identities(&[own_identity.into()])
|
.save_user_identities(&[own_identity.clone().into()])
|
||||||
.await
|
.await
|
||||||
.expect("Can't save identity");
|
.expect("Can't save identity");
|
||||||
|
|
||||||
drop(store);
|
drop(store);
|
||||||
|
|
||||||
// let store = SqliteStore::open(&alice_id(), &alice_device_id(), dir.path())
|
let store = SqliteStore::open(&user_id, &device_id, dir.path())
|
||||||
// .await
|
.await
|
||||||
// .expect("Can't create store");
|
.expect("Can't create store");
|
||||||
|
|
||||||
// store.load_account().await.unwrap();
|
store.load_account().await.unwrap();
|
||||||
|
|
||||||
// let loaded_device = store
|
let loaded_user = store
|
||||||
// .get_device(device.user_id(), device.device_id())
|
.get_user_identity(own_identity.user_id())
|
||||||
// .await
|
.await
|
||||||
// .unwrap()
|
.unwrap()
|
||||||
// .unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// assert_eq!(device, loaded_device);
|
assert_eq!(loaded_user.master_key(), own_identity.master_key());
|
||||||
|
assert_eq!(
|
||||||
|
loaded_user.self_signing_key(),
|
||||||
|
own_identity.self_signing_key()
|
||||||
|
);
|
||||||
|
assert_eq!(loaded_user, own_identity.into());
|
||||||
|
|
||||||
// for algorithm in loaded_device.algorithms() {
|
let other_identity = get_other_identity();
|
||||||
// assert!(device.algorithms().contains(algorithm));
|
|
||||||
// }
|
|
||||||
// assert_eq!(device.algorithms().len(), loaded_device.algorithms().len());
|
|
||||||
// assert_eq!(device.keys(), loaded_device.keys());
|
|
||||||
|
|
||||||
// let user_devices = store.get_user_devices(device.user_id()).await.unwrap();
|
store
|
||||||
// assert_eq!(user_devices.keys().next().unwrap(), device.device_id());
|
.save_user_identities(&[other_identity.clone().into()])
|
||||||
// assert_eq!(user_devices.devices().next().unwrap(), &device);
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let loaded_user = store
|
||||||
|
.load_user(other_identity.user_id())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(loaded_user.master_key(), other_identity.master_key());
|
||||||
|
assert_eq!(
|
||||||
|
loaded_user.self_signing_key(),
|
||||||
|
other_identity.self_signing_key()
|
||||||
|
);
|
||||||
|
assert_eq!(loaded_user, other_identity.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue