From c94e039207b716dc934dffd867ac8da38d736e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 10:09:26 +0200 Subject: [PATCH 01/25] Implement PreKeyStore --- presage-store-sqlite/.cargo/config.toml | 2 ++ ...1696250d675b95c2e64bae9c4ca2593de1ff4.json | 12 +++++++ ...12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json | 12 +++++++ ...9d5942084f6ef038ab3608b4b84fb961371f8.json | 26 ++++++++++++++ presage-store-sqlite/Cargo.toml | 1 + .../20241024072558_Initial_data_model.sql | 28 +++++++++++++++ presage-store-sqlite/presage.sqlite | Bin 0 -> 36864 bytes presage-store-sqlite/src/lib.rs | 13 ++++++- presage-store-sqlite/src/protocol.rs | 34 +++++++++++++++--- 9 files changed, 123 insertions(+), 5 deletions(-) create mode 100644 presage-store-sqlite/.cargo/config.toml create mode 100644 presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json create mode 100644 presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json create mode 100644 presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json create mode 100644 presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql create mode 100644 presage-store-sqlite/presage.sqlite diff --git a/presage-store-sqlite/.cargo/config.toml b/presage-store-sqlite/.cargo/config.toml new file mode 100644 index 000000000..646a331bd --- /dev/null +++ b/presage-store-sqlite/.cargo/config.toml @@ -0,0 +1,2 @@ +[env] +DATABASE_URL = {relative = false, value = "sqlite:/tmp/presage.sqlite"} \ No newline at end of file diff --git a/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json b/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json new file mode 100644 index 000000000..24e331147 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM prekey_records WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4" +} diff --git a/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json b/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json new file mode 100644 index 000000000..f57fbe9a1 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO prekey_records( id, record ) VALUES( ?1, ?2 )", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2" +} diff --git a/presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json b/presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json new file mode 100644 index 000000000..185c03d08 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT id, record FROM prekey_records WHERE id = $1 LIMIT 1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "record", + "ordinal": 1, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false + ] + }, + "hash": "c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8" +} diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index 4f3d6057b..37338183c 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -11,3 +11,4 @@ presage-store-cipher = { path = "../presage-store-cipher", optional = true } sqlx = { version = "0.8.2", features = ["sqlite"] } thiserror = "1.0.65" +tracing = "0.1.40" diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql new file mode 100644 index 000000000..a70b213b4 --- /dev/null +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -0,0 +1,28 @@ +CREATE TABLE session_records ( + address TEXT NOT NULL, + device_id INTEGER NOT NULL, + record BLOB NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', + + PRIMARY KEY(address, device_id, identity) +); + +CREATE TABLE identity_records ( + address TEXT NOT NULL, + record BLOB NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', + + -- TODO: Signal adds a lot more fields here that I don't yet care about. + + PRIMARY KEY(address, identity) +); + +CREATE TABLE prekey_records ( + id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + record BLOB NOT NULL +); + +CREATE TABLE signed_prekey_records ( + id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + record BLOB NOT NULL +); diff --git a/presage-store-sqlite/presage.sqlite b/presage-store-sqlite/presage.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..2131990d9c74b040c3e9c1f5b50c681f0cdc45c3 GIT binary patch literal 36864 zcmeI&!Ee)690zbaZJH*ulX(6V;}S(?E*8PqE_np6&en zdA~TaUs@X~4;X##dL1L6)6xkkk&wP7k|Zf1mb6#~B`H?M2Nm%yA6kFcYC>B0ac6qw zr8JqjC>_5w^V{^oarM~Usb|NgL<0&0AOHafKmY;|fWQa|?46oSWtW%by`KZ)lFfX+ z?J!H<@z`Z{Rri?bdX|4=W4hW@%9=u2xuPm`SSmX=CtvG?IW6$G>kM}A zqt)@q5X3s)KLQrJ!c8Wk8s_*%8KEOhhp|O?zZ##&Zp^)lHwK^=V-3muyc}kDvX85a z0ov6&eA_buf$YcYi3o4J_rUiG^LishmD+i6r8s<*2$R`jzUlFu-Ul4@E#QtH7`830 zTfP3;n$ptBYwK^Pbak`YRO*^O+$21@-!;wN_p8!qs7kp$+%N1k+swS|cRSI`P}s+I znc3|{r3bvj2H_79KxA^_zcM+Fp%>#VW8#NqviD;%Ef#s^wj^FC5P$##AOHafKmY;| zfB*y_009VmXaOdtlEu?$d+gKp{i*v-&EWwT56CPdFvO!Vi`h$yOQk|_v9MI4#pRV! zX{A_vy}j|ue)7+s4}O1g>-PLF_L*lVZ#=#ES^MGh?d)HFoc;3e)y%zb-+Z$C*mGLH zJ}Rvyf4Y+q=Oxd)ki-iG0uX=z1Rwwb2tWV=5P$##AOL}p5=f6F)8TW4-u%D#(?1FX zAOHafKmY;|fB*y_009U<00JW{(3}6q{r?CLFis5u5P$##AOHafKmY;|fB*y_AOtY~ zk2HV)1Rwwb2tWV=5P$##AOHafjJ^Qo|3`m}afT3p00bZa0SG_<0uX=z1Rwwb%>N?? yAOHafKmY;|fB*y_009U<00N^gfcyW^A7h*$1Rwwb2tWV=5P$##AOHafK;U1GeE#nM literal 0 HcmV?d00001 diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index 90e58977b..2cd392e88 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -3,11 +3,12 @@ use std::path::Path; use presage::{ + libsignal_service::protocol::SignalProtocolError, model::identity::OnNewIdentity, store::{StateStore, Store}, }; use protocol::SqliteProtocolStore; -use sqlx::{sqlite::SqliteConnectOptions, SqlitePool}; +use sqlx::{migrate::MigrateDatabase, sqlite::SqliteConnectOptions, Sqlite, SqlitePool}; mod content; mod error; @@ -37,6 +38,16 @@ impl SqliteStore { } } +trait SqlxErrorExt { + fn into_protocol_error(self) -> Result; +} + +impl SqlxErrorExt for Result { + fn into_protocol_error(self) -> Result { + self.map_err(|error| SignalProtocolError::InvalidState("sqlite", error.to_string())) + } +} + impl Store for SqliteStore { type Error = SqliteStoreError; diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 196229f26..08a532944 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -12,8 +12,10 @@ use presage::libsignal_service::{ }, ServiceAddress, }; +use sqlx::{query, Executor}; +use tracing::trace; -use crate::SqliteStore; +use crate::{SqliteStore, SqlxErrorExt}; #[derive(Clone)] pub struct SqliteProtocolStore { @@ -72,7 +74,15 @@ impl SessionStoreExt for SqliteProtocolStore { impl PreKeyStore for SqliteProtocolStore { /// Look up the pre-key corresponding to `prekey_id`. async fn get_pre_key(&self, prekey_id: PreKeyId) -> Result { - todo!() + let id: u32 = prekey_id.into(); + query!( + "SELECT id, record FROM prekey_records WHERE id = $1 LIMIT 1", + id + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .and_then(|record| PreKeyRecord::deserialize(&record.record)) } /// Set the entry for `prekey_id` to the value of `record`. @@ -81,12 +91,28 @@ impl PreKeyStore for SqliteProtocolStore { prekey_id: PreKeyId, record: &PreKeyRecord, ) -> Result<(), ProtocolError> { - todo!() + let id: u32 = prekey_id.into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO prekey_records( id, record ) VALUES( ?1, ?2 )", + id, + record_data + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } /// Remove the entry for `prekey_id`. async fn remove_pre_key(&mut self, prekey_id: PreKeyId) -> Result<(), ProtocolError> { - todo!() + let id: u32 = prekey_id.into(); + let rows_affected = query!("DELETE FROM prekey_records WHERE id = $1", id) + .execute(&self.store.db) + .await + .into_protocol_error()?; + Ok(()) } } From 288bab95b139bdbe30e5b043613cff7786fee628 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 10:11:26 +0200 Subject: [PATCH 02/25] Implement SignedPreKeyStore --- ...e0080ac07a078191474acdb50259a72f4ba3f.json | 26 +++++++++++++++++ ...deeb0244355460093d6be851220670fe23f2b.json | 12 ++++++++ presage-store-sqlite/src/protocol.rs | 29 +++++++++++++++---- 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json create mode 100644 presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json diff --git a/presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json b/presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json new file mode 100644 index 000000000..621af74c9 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT id, record FROM signed_prekey_records WHERE id = $1 LIMIT 1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "record", + "ordinal": 1, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false + ] + }, + "hash": "adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f" +} diff --git a/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json b/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json new file mode 100644 index 000000000..56dacb548 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO signed_prekey_records( id, record ) VALUES( ?1, ?2 )", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b" +} diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 08a532944..46861e814 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -4,9 +4,9 @@ use presage::libsignal_service::{ pre_keys::{KyberPreKeyStoreExt, PreKeysStore}, prelude::{IdentityKeyStore, SessionStoreExt, Uuid}, protocol::{ - Direction, IdentityKey, IdentityKeyPair, KyberPreKeyId, KyberPreKeyRecord, - KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, ProtocolAddress, ProtocolStore, - SenderKeyRecord, SenderKeyStore, SessionRecord, SessionStore, + Direction, GenericSignedPreKey, IdentityKey, IdentityKeyPair, KyberPreKeyId, + KyberPreKeyRecord, KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, ProtocolAddress, + ProtocolStore, SenderKeyRecord, SenderKeyStore, SessionRecord, SessionStore, SignalProtocolError as ProtocolError, SignedPreKeyId, SignedPreKeyRecord, SignedPreKeyStore, }, @@ -151,7 +151,15 @@ impl SignedPreKeyStore for SqliteProtocolStore { &self, signed_prekey_id: SignedPreKeyId, ) -> Result { - todo!() + let id: u32 = signed_prekey_id.into(); + query!( + "SELECT id, record FROM signed_prekey_records WHERE id = $1 LIMIT 1", + id + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .and_then(|record| SignedPreKeyRecord::deserialize(&record.record)) } /// Set the entry for `signed_prekey_id` to the value of `record`. @@ -160,7 +168,18 @@ impl SignedPreKeyStore for SqliteProtocolStore { signed_prekey_id: SignedPreKeyId, record: &SignedPreKeyRecord, ) -> Result<(), ProtocolError> { - todo!() + let id: u32 = signed_prekey_id.into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO signed_prekey_records( id, record ) VALUES( ?1, ?2 )", + id, + record_data + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } } From fdf19cf9ed0568a254f01f12afda151207795079 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 13:25:31 +0200 Subject: [PATCH 03/25] Impl PreKeysStore --- presage-store-sqlite/.cargo/config.toml | 2 - ...66a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json | 20 ++++++ ...1696250d675b95c2e64bae9c4ca2593de1ff4.json | 12 ---- ...c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json | 12 ++++ ...e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json | 20 ++++++ ...12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json | 12 ---- ...64e76f5668266c7b2eb956bb9d7feb18f195.json} | 4 +- ...2c34186cb05df09af183ab87b627cebc6895.json} | 4 +- ...20b59a8fb880969b56537f00fc8a9f396957a.json | 12 ++++ ...deeb0244355460093d6be851220670fe23f2b.json | 12 ---- ...350e536b4cf5bc3ee6abde2529395486680dc.json | 20 ++++++ ...556a38d4d52d5fd4b9e16b6d81f6f42188922.json | 12 ++++ ...8bb01e04b2fc9c824dff5ca4410c33e9fa768.json | 20 ++++++ ...ecd0b63612b882306dce24e4057dd54454af8.json | 20 ++++++ .../20241024072558_Initial_data_model.sql | 23 +++++-- presage-store-sqlite/presage.sqlite | Bin 36864 -> 40960 bytes presage-store-sqlite/src/lib.rs | 2 + presage-store-sqlite/src/protocol.rs | 62 ++++++++++++------ 18 files changed, 200 insertions(+), 69 deletions(-) delete mode 100644 presage-store-sqlite/.cargo/config.toml create mode 100644 presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json delete mode 100644 presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json create mode 100644 presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json create mode 100644 presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json delete mode 100644 presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json rename presage-store-sqlite/.sqlx/{query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json => query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json} (71%) rename presage-store-sqlite/.sqlx/{query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json => query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json} (68%) create mode 100644 presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json delete mode 100644 presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json create mode 100644 presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json create mode 100644 presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json create mode 100644 presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json create mode 100644 presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json diff --git a/presage-store-sqlite/.cargo/config.toml b/presage-store-sqlite/.cargo/config.toml deleted file mode 100644 index 646a331bd..000000000 --- a/presage-store-sqlite/.cargo/config.toml +++ /dev/null @@ -1,2 +0,0 @@ -[env] -DATABASE_URL = {relative = false, value = "sqlite:/tmp/presage.sqlite"} \ No newline at end of file diff --git a/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json b/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json new file mode 100644 index 000000000..e1e47d5db --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT MAX(id) as 'max_id: u32' FROM kyber_prekeys", + "describe": { + "columns": [ + { + "name": "max_id: u32", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + true + ] + }, + "hash": "22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4" +} diff --git a/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json b/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json deleted file mode 100644 index 24e331147..000000000 --- a/presage-store-sqlite/.sqlx/query-48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM prekey_records WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Right": 1 - }, - "nullable": [] - }, - "hash": "48700c9970ec802e942a0c25d231696250d675b95c2e64bae9c4ca2593de1ff4" -} diff --git a/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json b/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json new file mode 100644 index 000000000..a915fd113 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO signed_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2" +} diff --git a/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json b/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json new file mode 100644 index 000000000..ee147c710 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT COUNT(id) FROM kyber_prekeys", + "describe": { + "columns": [ + { + "name": "COUNT(id)", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a" +} diff --git a/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json b/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json deleted file mode 100644 index f57fbe9a1..000000000 --- a/presage-store-sqlite/.sqlx/query-81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO prekey_records( id, record ) VALUES( ?1, ?2 )", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "81e198ecaaef60cebd001f064da12d40cf10cc54afc9ea8d267b2ed1be78f9e2" -} diff --git a/presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json b/presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json similarity index 71% rename from presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json rename to presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json index 185c03d08..35ab2d811 100644 --- a/presage-store-sqlite/.sqlx/query-c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8.json +++ b/presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT id, record FROM prekey_records WHERE id = $1 LIMIT 1", + "query": "SELECT id, record FROM signed_prekeys WHERE id = $1 LIMIT 1", "describe": { "columns": [ { @@ -22,5 +22,5 @@ false ] }, - "hash": "c901819d83824d5feabb1bd920f9d5942084f6ef038ab3608b4b84fb961371f8" + "hash": "9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195" } diff --git a/presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json b/presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json similarity index 68% rename from presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json rename to presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json index 621af74c9..90245c039 100644 --- a/presage-store-sqlite/.sqlx/query-adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f.json +++ b/presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "SELECT id, record FROM signed_prekey_records WHERE id = $1 LIMIT 1", + "query": "SELECT id, record FROM prekeys WHERE id = $1 LIMIT 1", "describe": { "columns": [ { @@ -22,5 +22,5 @@ false ] }, - "hash": "adc27c6741d7c541b5b22d060e9e0080ac07a078191474acdb50259a72f4ba3f" + "hash": "aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895" } diff --git a/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json b/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json new file mode 100644 index 000000000..b40661b49 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM prekeys WHERE id = $1", + "describe": { + "columns": [], + "parameters": { + "Right": 1 + }, + "nullable": [] + }, + "hash": "bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a" +} diff --git a/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json b/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json deleted file mode 100644 index 56dacb548..000000000 --- a/presage-store-sqlite/.sqlx/query-c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO signed_prekey_records( id, record ) VALUES( ?1, ?2 )", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "c40ee19300b7e08f0da4e6cbbbddeeb0244355460093d6be851220670fe23f2b" -} diff --git a/presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json b/presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json new file mode 100644 index 000000000..60834c94d --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT MAX(id) as 'max_id: u32' FROM prekeys", + "describe": { + "columns": [ + { + "name": "max_id: u32", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + true + ] + }, + "hash": "ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc" +} diff --git a/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json b/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json new file mode 100644 index 000000000..6134279da --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922" +} diff --git a/presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json b/presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json new file mode 100644 index 000000000..c6f7f91fa --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT MAX(id) as 'max_id: u32' FROM signed_prekeys", + "describe": { + "columns": [ + { + "name": "max_id: u32", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + true + ] + }, + "hash": "f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768" +} diff --git a/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json b/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json new file mode 100644 index 000000000..cf7d09d59 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT COUNT(id) FROM signed_prekeys", + "describe": { + "columns": [ + { + "name": "COUNT(id)", + "ordinal": 0, + "type_info": "Integer" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false + ] + }, + "hash": "f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8" +} diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index a70b213b4..4ea46b122 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -1,4 +1,4 @@ -CREATE TABLE session_records ( +CREATE TABLE sessions ( address TEXT NOT NULL, device_id INTEGER NOT NULL, record BLOB NOT NULL, @@ -7,22 +7,31 @@ CREATE TABLE session_records ( PRIMARY KEY(address, device_id, identity) ); -CREATE TABLE identity_records ( +CREATE TABLE identities ( address TEXT NOT NULL, record BLOB NOT NULL, - identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL, -- TODO: Signal adds a lot more fields here that I don't yet care about. PRIMARY KEY(address, identity) ); -CREATE TABLE prekey_records ( +CREATE TABLE prekeys ( id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, - record BLOB NOT NULL + record BLOB NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL ); -CREATE TABLE signed_prekey_records ( +CREATE TABLE signed_prekeys ( id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, - record BLOB NOT NULL + record BLOB NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci' +); + +CREATE TABLE kyber_prekeys ( + id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + record BLOB NOT NULL, + is_last_resort BOOLEAN DEFAULT FALSE NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL ); diff --git a/presage-store-sqlite/presage.sqlite b/presage-store-sqlite/presage.sqlite index 2131990d9c74b040c3e9c1f5b50c681f0cdc45c3..043e7a7dee28944139e5c75b4ad01086e3b73ac7 100644 GIT binary patch delta 573 zcmZozz|?SnX@Wd27Xt#YP1Lawet3rsQlaH$cvee|QT%nWC@vIjF@x#y|s|+1bUVr5T%I!3IJ-0HrukjDQG2_1f8RX*Mac zvWqJ!GPdx7^=77|=9OfYWTqA)SZpXJz{Mw*^D0l?#Tzuaf~SE^XR9~!#e45dE b#>&sD##U}d()|6lZtSWD7bz4h3J?GQsgu6p delta 526 zcmZoTz|^pSX@Wd2Cj$boPSmjx;oyp5;Opk!&a21g!@ZK{EjJHW)Mi0}dz{gY`W)=y z=H`rzwIzv3IjO~&>3OLs@dZVx*{PNBMXAa8MJdHt1v#CATpdGP6+#@Hd|VZd_rljVTWR}2P ziq2<4F%V65ax1U$$e}3xzv5pI3|>Dh0IiDw{0}n|Po$&? Self::AciStore { SqliteProtocolStore { store: self.clone(), + identity_type: "aci", } } fn pni_protocol_store(&self) -> Self::PniStore { SqliteProtocolStore { store: self.clone(), + identity_type: "pni", } } } diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 46861e814..a4df04777 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -1,3 +1,5 @@ +use std::fmt::{self, Formatter}; + use async_trait::async_trait; use chrono::{DateTime, Utc}; use presage::libsignal_service::{ @@ -12,7 +14,7 @@ use presage::libsignal_service::{ }, ServiceAddress, }; -use sqlx::{query, Executor}; +use sqlx::{query, query_scalar, Executor}; use tracing::trace; use crate::{SqliteStore, SqlxErrorExt}; @@ -20,6 +22,7 @@ use crate::{SqliteStore, SqlxErrorExt}; #[derive(Clone)] pub struct SqliteProtocolStore { pub(crate) store: SqliteStore, + pub(crate) identity_type: &'static str, } impl ProtocolStore for SqliteProtocolStore {} @@ -75,14 +78,11 @@ impl PreKeyStore for SqliteProtocolStore { /// Look up the pre-key corresponding to `prekey_id`. async fn get_pre_key(&self, prekey_id: PreKeyId) -> Result { let id: u32 = prekey_id.into(); - query!( - "SELECT id, record FROM prekey_records WHERE id = $1 LIMIT 1", - id - ) - .fetch_one(&self.store.db) - .await - .into_protocol_error() - .and_then(|record| PreKeyRecord::deserialize(&record.record)) + query!("SELECT id, record FROM prekeys WHERE id = $1 LIMIT 1", id) + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .and_then(|record| PreKeyRecord::deserialize(&record.record)) } /// Set the entry for `prekey_id` to the value of `record`. @@ -94,9 +94,10 @@ impl PreKeyStore for SqliteProtocolStore { let id: u32 = prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO prekey_records( id, record ) VALUES( ?1, ?2 )", + "INSERT INTO prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", id, - record_data + record_data, + self.identity_type, ) .execute(&self.store.db) .await @@ -108,7 +109,7 @@ impl PreKeyStore for SqliteProtocolStore { /// Remove the entry for `prekey_id`. async fn remove_pre_key(&mut self, prekey_id: PreKeyId) -> Result<(), ProtocolError> { let id: u32 = prekey_id.into(); - let rows_affected = query!("DELETE FROM prekey_records WHERE id = $1", id) + let rows_affected = query!("DELETE FROM prekeys WHERE id = $1", id) .execute(&self.store.db) .await .into_protocol_error()?; @@ -120,27 +121,47 @@ impl PreKeyStore for SqliteProtocolStore { impl PreKeysStore for SqliteProtocolStore { /// ID of the next pre key async fn next_pre_key_id(&self) -> Result { - todo!() + query!("SELECT MAX(id) as 'max_id: u32' FROM prekeys") + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .map(|record| record.max_id.map(|i| i + 1).unwrap_or_default()) } /// ID of the next signed pre key async fn next_signed_pre_key_id(&self) -> Result { - todo!() + query!("SELECT MAX(id) as 'max_id: u32' FROM signed_prekeys") + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .map(|record| record.max_id.map(|i| i + 1).unwrap_or_default()) } /// ID of the next PQ pre key async fn next_pq_pre_key_id(&self) -> Result { - todo!() + query!("SELECT MAX(id) as 'max_id: u32' FROM kyber_prekeys") + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .map(|record| record.max_id.map(|i| i + 1).unwrap_or_default()) } /// number of signed pre-keys we currently have in store async fn signed_pre_keys_count(&self) -> Result { - todo!() + let count = query_scalar!("SELECT COUNT(id) FROM signed_prekeys") + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + Ok(count as usize) } /// number of kyber pre-keys we currently have in store async fn kyber_pre_keys_count(&self, last_resort: bool) -> Result { - todo!() + let count = query_scalar!("SELECT COUNT(id) FROM kyber_prekeys") + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + Ok(count as usize) } } @@ -153,7 +174,7 @@ impl SignedPreKeyStore for SqliteProtocolStore { ) -> Result { let id: u32 = signed_prekey_id.into(); query!( - "SELECT id, record FROM signed_prekey_records WHERE id = $1 LIMIT 1", + "SELECT id, record FROM signed_prekeys WHERE id = $1 LIMIT 1", id ) .fetch_one(&self.store.db) @@ -171,9 +192,10 @@ impl SignedPreKeyStore for SqliteProtocolStore { let id: u32 = signed_prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO signed_prekey_records( id, record ) VALUES( ?1, ?2 )", + "INSERT INTO signed_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", id, - record_data + record_data, + self.identity_type ) .execute(&self.store.db) .await From 3e0b40b15467d21e8bca4f720b2dc344d7521412 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 13:42:54 +0200 Subject: [PATCH 04/25] Impl KyberPreKeysStore --- ...8480806af402afaa06c5556b55d2aa0695c7.json} | 6 +- ...4a7f6a0f387be690a380a276a109daf2a726d.json | 12 ++++ ...6e0292eb9baa57ba51d3ca9798573a2c8697e.json | 12 ++++ ...3eeef7d5c19d2e373a31ed56ea853ed57690e.json | 12 ++++ ...82a82f00197519fd9b4b6aceeb6a0850ccfd.json} | 6 +- ...371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json | 26 +++++++ ...71790fb09f691f52a1d533ef3e3d4bd82a651.json | 38 ++++++++++ presage-store-sqlite/src/protocol.rs | 70 +++++++++++++++---- 8 files changed, 163 insertions(+), 19 deletions(-) rename presage-store-sqlite/.sqlx/{query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json => query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json} (56%) create mode 100644 presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json create mode 100644 presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json create mode 100644 presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json rename presage-store-sqlite/.sqlx/{query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json => query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json} (55%) create mode 100644 presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json create mode 100644 presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json diff --git a/presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json b/presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json similarity index 56% rename from presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json rename to presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json index 60834c94d..35ec23090 100644 --- a/presage-store-sqlite/.sqlx/query-ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc.json +++ b/presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json @@ -1,10 +1,10 @@ { "db_name": "SQLite", - "query": "SELECT MAX(id) as 'max_id: u32' FROM prekeys", + "query": "SELECT MAX(id) FROM prekeys", "describe": { "columns": [ { - "name": "max_id: u32", + "name": "MAX(id)", "ordinal": 0, "type_info": "Integer" } @@ -16,5 +16,5 @@ true ] }, - "hash": "ce8fa6148c79dc6a3e44154a81d350e536b4cf5bc3ee6abde2529395486680dc" + "hash": "02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7" } diff --git a/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json b/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json new file mode 100644 index 000000000..17de1601a --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO kyber_prekeys( id, record, is_last_resort, identity )\n VALUES( $1, $2, true, $4 )", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d" +} diff --git a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json new file mode 100644 index 000000000..d0f40687f --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM kyber_prekeys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e" +} diff --git a/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json b/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json new file mode 100644 index 000000000..cdb551951 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO kyber_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e" +} diff --git a/presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json b/presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json similarity index 55% rename from presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json rename to presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json index c6f7f91fa..ef3bbe38a 100644 --- a/presage-store-sqlite/.sqlx/query-f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768.json +++ b/presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json @@ -1,10 +1,10 @@ { "db_name": "SQLite", - "query": "SELECT MAX(id) as 'max_id: u32' FROM signed_prekeys", + "query": "SELECT MAX(id) FROM signed_prekeys", "describe": { "columns": [ { - "name": "max_id: u32", + "name": "MAX(id)", "ordinal": 0, "type_info": "Integer" } @@ -16,5 +16,5 @@ true ] }, - "hash": "f8879b881f8983393b627bde4308bb01e04b2fc9c824dff5ca4410c33e9fa768" + "hash": "3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd" } diff --git a/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json b/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json new file mode 100644 index 000000000..44e0107a2 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json @@ -0,0 +1,26 @@ +{ + "db_name": "SQLite", + "query": "SELECT id, record FROM kyber_prekeys WHERE id = $1 LIMIT 1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "record", + "ordinal": 1, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false + ] + }, + "hash": "bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a" +} diff --git a/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json b/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json new file mode 100644 index 000000000..7d15757f7 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json @@ -0,0 +1,38 @@ +{ + "db_name": "SQLite", + "query": "SELECT * FROM kyber_prekeys WHERE is_last_resort = true AND identity = $1", + "describe": { + "columns": [ + { + "name": "id", + "ordinal": 0, + "type_info": "Integer" + }, + { + "name": "record", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "is_last_resort", + "ordinal": 2, + "type_info": "Bool" + }, + { + "name": "identity", + "ordinal": 3, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false + ] + }, + "hash": "eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651" +} diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index a4df04777..a0bd04e07 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -121,20 +121,20 @@ impl PreKeyStore for SqliteProtocolStore { impl PreKeysStore for SqliteProtocolStore { /// ID of the next pre key async fn next_pre_key_id(&self) -> Result { - query!("SELECT MAX(id) as 'max_id: u32' FROM prekeys") + query_scalar!("SELECT MAX(id) FROM prekeys") .fetch_one(&self.store.db) .await .into_protocol_error() - .map(|record| record.max_id.map(|i| i + 1).unwrap_or_default()) + .map(|record| record.map(|i| i as u32 + 1).unwrap_or_default()) } /// ID of the next signed pre key async fn next_signed_pre_key_id(&self) -> Result { - query!("SELECT MAX(id) as 'max_id: u32' FROM signed_prekeys") + query_scalar!("SELECT MAX(id) FROM signed_prekeys") .fetch_one(&self.store.db) .await .into_protocol_error() - .map(|record| record.max_id.map(|i| i + 1).unwrap_or_default()) + .map(|record| record.map(|i| i as u32 + 1).unwrap_or_default()) } /// ID of the next PQ pre key @@ -212,7 +212,15 @@ impl KyberPreKeyStore for SqliteProtocolStore { &self, kyber_prekey_id: KyberPreKeyId, ) -> Result { - todo!() + let id: u32 = kyber_prekey_id.into(); + query!( + "SELECT id, record FROM kyber_prekeys WHERE id = $1 LIMIT 1", + id + ) + .fetch_one(&self.store.db) + .await + .into_protocol_error() + .and_then(|record| KyberPreKeyRecord::deserialize(&record.record)) } /// Set the entry for `kyber_prekey_id` to the value of `record`. @@ -221,7 +229,19 @@ impl KyberPreKeyStore for SqliteProtocolStore { kyber_prekey_id: KyberPreKeyId, record: &KyberPreKeyRecord, ) -> Result<(), ProtocolError> { - todo!() + let id: u32 = kyber_prekey_id.into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO kyber_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + id, + record_data, + self.identity_type, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } /// Mark the entry for `kyber_prekey_id` as "used". @@ -241,37 +261,61 @@ impl KyberPreKeyStoreExt for SqliteProtocolStore { kyber_prekey_id: KyberPreKeyId, record: &KyberPreKeyRecord, ) -> Result<(), ProtocolError> { - todo!() + let id: u32 = kyber_prekey_id.into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO kyber_prekeys( id, record, is_last_resort, identity ) + VALUES( $1, $2, true, $4 )", + id, + record_data, + self.identity_type, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } async fn load_last_resort_kyber_pre_keys( &self, ) -> Result, ProtocolError> { - todo!() + let records = query!( + "SELECT * FROM kyber_prekeys WHERE is_last_resort = true AND identity = $1", + self.identity_type, + ) + .fetch_all(&self.store.db) + .await + .into_protocol_error()?; + + let kyber_prekeys: Result, ProtocolError> = records + .into_iter() + .map(|record| KyberPreKeyRecord::deserialize(&record.record)) + .collect(); + + Ok(kyber_prekeys?) } async fn remove_kyber_pre_key( &mut self, kyber_prekey_id: KyberPreKeyId, ) -> Result<(), ProtocolError> { - todo!() + unimplemented!("unexpected in this flow") } - /// Analogous to markAllOneTimeKyberPreKeysStaleIfNecessary async fn mark_all_one_time_kyber_pre_keys_stale_if_necessary( &mut self, stale_time: DateTime, ) -> Result<(), ProtocolError> { - todo!() + unimplemented!("unexpected in this flow") } - /// Analogue of deleteAllStaleOneTimeKyberPreKeys async fn delete_all_stale_one_time_kyber_pre_keys( &mut self, threshold: DateTime, min_count: usize, ) -> Result<(), ProtocolError> { - todo!() + unimplemented!("unexpected in this flow") } } From 5badb56ba5d5b103116ab9d57b235b54b16a6d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 13:57:50 +0200 Subject: [PATCH 05/25] Impl SessionsStore --- ...01338bc61cdcc34a4cc78279c284711ab1028.json | 20 ++++++++++++ ...f98a3f663a822ae69a4ad00114ab31f1596e2.json | 12 +++++++ ...6e0292eb9baa57ba51d3ca9798573a2c8697e.json | 12 ------- presage-store-sqlite/presage.sqlite | Bin 40960 -> 40960 bytes presage-store-sqlite/src/protocol.rs | 30 ++++++++++++++++-- presage.sqlite | Bin 0 -> 36864 bytes 6 files changed, 60 insertions(+), 14 deletions(-) create mode 100644 presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json create mode 100644 presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json delete mode 100644 presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json create mode 100644 presage.sqlite diff --git a/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json b/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json new file mode 100644 index 000000000..1ee8847dd --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT record FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3 LIMIT 1", + "describe": { + "columns": [ + { + "name": "record", + "ordinal": 0, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + false + ] + }, + "hash": "11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028" +} diff --git a/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json b/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json new file mode 100644 index 000000000..361aef933 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO sessions ( address, device_id, identity, record ) VALUES ( $1, $2, $3, $4 )", + "describe": { + "columns": [], + "parameters": { + "Right": 4 + }, + "nullable": [] + }, + "hash": "15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2" +} diff --git a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json deleted file mode 100644 index d0f40687f..000000000 --- a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM kyber_prekeys WHERE id = $1 AND identity = $2", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e" -} diff --git a/presage-store-sqlite/presage.sqlite b/presage-store-sqlite/presage.sqlite index 043e7a7dee28944139e5c75b4ad01086e3b73ac7..467d6e472d94c5dec735e263cfb9fbe77424a4c0 100644 GIT binary patch delta 26 icmZoTz|?SnX~PM5RufArLzBs8 Result, ProtocolError> { - todo!() + let uuid = address.name(); + let device_id: u32 = address.device_id().into(); + query!( + "SELECT record FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3 LIMIT 1", + uuid, + device_id, + self.identity_type + ) + .fetch_optional(&self.store.db) + .await + .into_protocol_error()? + .map(|record| SessionRecord::deserialize(&record.record)) + .transpose() } /// Set the entry for `address` to the value of `record`. @@ -43,7 +55,21 @@ impl SessionStore for SqliteProtocolStore { address: &ProtocolAddress, record: &SessionRecord, ) -> Result<(), ProtocolError> { - todo!(); + let uuid = address.name(); + let device_id: u32 = address.device_id().into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO sessions ( address, device_id, identity, record ) VALUES ( $1, $2, $3, $4 )", + uuid, + device_id, + self.identity_type, + record_data, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } } diff --git a/presage.sqlite b/presage.sqlite new file mode 100644 index 0000000000000000000000000000000000000000..111f50b63baa5f9189e41b6daf50cc5429fda12c GIT binary patch literal 36864 zcmeI&!E4)A90zd8iR0K!nynYJ?y%owI3{rxr!E?Rydy@Rq z=lv`rJ-2r>9y0pe^Sfq9=cIR}R7$!;BuP?AELpLPN?NQ;k1FC_KDPd*)s(byXMcX- z4{0`cT{`_>;k)^j)7q&=b1zTLi3Su1KmY;|fB*y_0D%b-=zlbu$*-@={VzlFhQk8B z=Q7*a_t{N$+whs?`F3z(W46{(6RU?d8eLVd zQL{m{W@A&U*K}&B+nQ2SsnOJ_v8!pz!yTiKr>fShj(c*&{@F|>Uo6UfZy0er)Oc++ z7Gu2c-wEzeNoVqSsddtwNFA=vdKS zwNKRA)x~jJy+Mlw)8d6?D(t(wP%Ms*OPAG6WmnTF>dy@aqEsTidAYekZIK?PLn5Mp zOme)Cx}GoYOE_~xONWW|up{nJ>STLvA*9Luka*(X2V!X-TBi~!hAB+%H>sQ2;;`mh}N@kk{me2PGA8^vQfV)9xI*zz* z4f^X_YFk&fwqH-_+HR|*HgsdWNp$p}XIX>qSGC#HRHZTAFY2{A%(@x$y79|U)W;5( z)f+@*guKf};g1qPWOC}CGC7H1l#?w};)iB-@MAMC7J1>JBwi>GfB*y_009U<00Izz z00bZa0SNrp0!+@N%jdGr)S1rXxyNqZGv-lJY4?9Isfv5d%xa)uk-A;z5J6OE`IoYGxznUf4#f@i|@9- z{kgJvM(O9odC3dEOX7tB0SG_<0uX=z1Rwwb2tWV=5P-l$31p|z+32~#VE$kH=^q6G z5P$##AOHafKmY;|fB*y_0D%b>7|j3U{(pi87^emS2tWV=5P$##AOHafKmY;|5CWM0 zM;br?0uX=z1Rwwb2tWV=5P$##CSL&a|C2w)I70|P00Izz00bZa0SG_<0uX=z=Kqlc y5P$##AOHafKmY;|fB*y_0D;LD!2SQ^k1@^=0uX=z1Rwwb2tWV=5P$##An-R{?f$9& literal 0 HcmV?d00001 From bbaee3a5e3a0430716512704b33eb5de57dfa8af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 24 Oct 2024 14:00:37 +0200 Subject: [PATCH 06/25] Impl SessionStoreExt --- ...541ca9a896f85dabaad6e76d67402cbc82b68.json | 12 +++++++++ ...c76168dcb5054032e3a217cc125c567abc33c.json | 12 +++++++++ presage-store-sqlite/src/protocol.rs | 27 +++++++++++++++++-- 3 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json create mode 100644 presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json diff --git a/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json b/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json new file mode 100644 index 000000000..17b2c6cc3 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM sessions WHERE address = $1 AND identity = $3", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68" +} diff --git a/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json b/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json new file mode 100644 index 000000000..51c86cd60 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c" +} diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index fa6ffb870..bf9ba6c0e 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -87,7 +87,19 @@ impl SessionStoreExt for SqliteProtocolStore { /// Remove a session record for a recipient ID + device ID tuple. async fn delete_session(&self, address: &ProtocolAddress) -> Result<(), ProtocolError> { - todo!() + let uuid = address.name(); + let device_id: u32 = address.device_id().into(); + query!( + "DELETE FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3", + uuid, + device_id, + self.identity_type + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } /// Remove the session records corresponding to all devices of a recipient @@ -95,7 +107,18 @@ impl SessionStoreExt for SqliteProtocolStore { /// /// Returns the number of deleted sessions. async fn delete_all_sessions(&self, address: &ServiceAddress) -> Result { - todo!() + let uuid = address.uuid.to_string(); + let rows = query!( + "DELETE FROM sessions WHERE address = $1 AND identity = $3", + uuid, + self.identity_type + ) + .execute(&self.store.db) + .await + .into_protocol_error()? + .rows_affected(); + + Ok(rows as usize) } } From 09fffe2b30e66d87c04290b868a457bacd1b61c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Fri, 25 Oct 2024 10:09:11 +0200 Subject: [PATCH 07/25] Impl ContactsStore --- presage-store-sled/src/content.rs | 2 +- presage-store-sqlite/.gitignore | 2 + ...04470b6a61278a8edc257b324ecf8e20e8af2.json | 20 ++ ...c07b339ad028dcfad92c928dd381d891e3ad0.json | 12 + ...6151cead304e35b7b0fb01ee0fb65a4102fa4.json | 12 + ...6e0292eb9baa57ba51d3ca9798573a2c8697e.json | 12 + ...181f12233ad20a6af32514c25fcd646b7ff19.json | 20 ++ ...64f0a13c34eb5a4048a3ebbfe5e4069d15719.json | 12 + ...f6f78a45867816ea459e8cb2cc2bacf66812a.json | 12 + ...88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json | 12 + ...d367a4755ec5555e85945bb12fc1fc94772d3.json | 92 +++++++ ...f5b62ec49534742a292116f74ea9672f85c87.json | 12 + presage-store-sqlite/Cargo.toml | 3 +- .../20241024072558_Initial_data_model.sql | 73 +++++- presage-store-sqlite/presage.sqlite | Bin 40960 -> 0 bytes presage-store-sqlite/src/content.rs | 227 ++++++++++++++---- presage-store-sqlite/src/error.rs | 7 +- presage-store-sqlite/src/protocol.rs | 86 ++++++- presage.sqlite | Bin 36864 -> 0 bytes presage/src/manager/registered.rs | 4 +- presage/src/store.rs | 4 +- 21 files changed, 559 insertions(+), 65 deletions(-) create mode 100644 presage-store-sqlite/.gitignore create mode 100644 presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json create mode 100644 presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json create mode 100644 presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json create mode 100644 presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json create mode 100644 presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json create mode 100644 presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json create mode 100644 presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json create mode 100644 presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json create mode 100644 presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json create mode 100644 presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json delete mode 100644 presage-store-sqlite/presage.sqlite delete mode 100644 presage.sqlite diff --git a/presage-store-sled/src/content.rs b/presage-store-sled/src/content.rs index de986e886..b76841d84 100644 --- a/presage-store-sled/src/content.rs +++ b/presage-store-sled/src/content.rs @@ -70,7 +70,7 @@ impl ContentsStore for SledStore { Ok(()) } - async fn save_contact(&mut self, contact: &Contact) -> Result<(), SledStoreError> { + async fn save_contact(&mut self, contact: Contact) -> Result<(), SledStoreError> { self.insert(SLED_TREE_CONTACTS, contact.uuid, contact)?; debug!("saved contact"); Ok(()) diff --git a/presage-store-sqlite/.gitignore b/presage-store-sqlite/.gitignore new file mode 100644 index 000000000..9262b372b --- /dev/null +++ b/presage-store-sqlite/.gitignore @@ -0,0 +1,2 @@ +.sqlx/* +presage.sqlite diff --git a/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json b/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json new file mode 100644 index 000000000..a489e97c4 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT record FROM identities WHERE address = $1 AND identity = $2", + "describe": { + "columns": [ + { + "name": "record", + "ordinal": 0, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + false + ] + }, + "hash": "068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2" +} diff --git a/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json b/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json new file mode 100644 index 000000000..6de08a22a --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO sender_keys (address, device, distribution_id, record, identity) VALUES ($1, $2, $3, $4, $5)", + "describe": { + "columns": [], + "parameters": { + "Right": 5 + }, + "nullable": [] + }, + "hash": "113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0" +} diff --git a/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json b/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json new file mode 100644 index 000000000..19eaf5570 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO contacts_verification_state(destination_aci, identity_key, is_verified)\n VALUES($1, $2, $3)", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4" +} diff --git a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json new file mode 100644 index 000000000..d0f40687f --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM kyber_prekeys WHERE id = $1 AND identity = $2", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e" +} diff --git a/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json b/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json new file mode 100644 index 000000000..d7fe9b2e6 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json @@ -0,0 +1,20 @@ +{ + "db_name": "SQLite", + "query": "SELECT record FROM sender_keys WHERE address = $1 AND device = $2 AND distribution_id = $3 AND identity = $4", + "describe": { + "columns": [ + { + "name": "record", + "ordinal": 0, + "type_info": "Blob" + } + ], + "parameters": { + "Right": 4 + }, + "nullable": [ + false + ] + }, + "hash": "55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19" +} diff --git a/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json b/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json new file mode 100644 index 000000000..c378d3d37 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM contacts", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719" +} diff --git a/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json b/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json new file mode 100644 index 000000000..c5a54ec91 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "DELETE FROM groups", + "describe": { + "columns": [], + "parameters": { + "Right": 0 + }, + "nullable": [] + }, + "hash": "75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a" +} diff --git a/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json b/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json new file mode 100644 index 000000000..d567a956f --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO contacts(uuid, phone_number, name, color, profile_key, expire_timer, expire_timer_version, inbox_position, archived, avatar)\n VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + "describe": { + "columns": [], + "parameters": { + "Right": 10 + }, + "nullable": [] + }, + "hash": "99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e" +} diff --git a/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json b/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json new file mode 100644 index 000000000..a37789268 --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json @@ -0,0 +1,92 @@ +{ + "db_name": "SQLite", + "query": "SELECT *\n FROM contacts c\n LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci \n ORDER BY inbox_position\n ", + "describe": { + "columns": [ + { + "name": "uuid", + "ordinal": 0, + "type_info": "Text" + }, + { + "name": "phone_number", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "name", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "color", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "profile_key", + "ordinal": 4, + "type_info": "Blob" + }, + { + "name": "expire_timer", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "expire_timer_version", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "inbox_position", + "ordinal": 7, + "type_info": "Integer" + }, + { + "name": "archived", + "ordinal": 8, + "type_info": "Bool" + }, + { + "name": "avatar", + "ordinal": 9, + "type_info": "Blob" + }, + { + "name": "destination_aci", + "ordinal": 10, + "type_info": "Text" + }, + { + "name": "identity_key", + "ordinal": 11, + "type_info": "Blob" + }, + { + "name": "is_verified", + "ordinal": 12, + "type_info": "Bool" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + true, + false, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true + ] + }, + "hash": "b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3" +} diff --git a/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json b/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json new file mode 100644 index 000000000..fbd57c55c --- /dev/null +++ b/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json @@ -0,0 +1,12 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO identities ( address, record, identity ) VALUES ( $1, $2, $3 )", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87" +} diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index 37338183c..bc50d9bd3 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -5,10 +5,11 @@ edition = "2021" [dependencies] async-trait = "0.1.83" +bytes = "1.8.0" chrono = "0.4.38" presage = { path = "../presage" } presage-store-cipher = { path = "../presage-store-cipher", optional = true } -sqlx = { version = "0.8.2", features = ["sqlite"] } +sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } thiserror = "1.0.65" tracing = "0.1.40" diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 4ea46b122..79ee1abd5 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -1,5 +1,5 @@ CREATE TABLE sessions ( - address TEXT NOT NULL, + address VARCHAR(36) NOT NULL, device_id INTEGER NOT NULL, record BLOB NOT NULL, identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', @@ -8,13 +8,13 @@ CREATE TABLE sessions ( ); CREATE TABLE identities ( - address TEXT NOT NULL, + address VARCHAR(36) NOT NULL, record BLOB NOT NULL, - identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', -- TODO: Signal adds a lot more fields here that I don't yet care about. - PRIMARY KEY(address, identity) + PRIMARY KEY(address, identity) ON CONFLICT REPLACE ); CREATE TABLE prekeys ( @@ -35,3 +35,68 @@ CREATE TABLE kyber_prekeys ( is_last_resort BOOLEAN DEFAULT FALSE NOT NULL, identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL ); + +CREATE TABLE sender_keys ( + address VARCHAR(36), + device INTEGER NOT NULL, + distribution_id TEXT NOT NULL, + record BLOB NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', + + PRIMARY KEY(address, device, distribution_id), + UNIQUE(address, device, distribution_id) ON CONFLICT REPLACE +); + +-- Groups +CREATE TABLE groups ( + id VARCHAR(64) PRIMARY KEY NOT NULL, + name TEXT NOT NULL, + master_key VARCHAR(64) NOT NULL, + revision INTEGER NOT NULL DEFAULT 0, + invite_link_password BLOB, + access_required_for_attributes INTEGER NOT NULL DEFAULT 0, + access_required_for_members INTEGER NOT NULL DEFAULT 0, + access_required_for_add_from_invite_link INTEGER NOT NULL DEFAULT 0, + avatar TEXT, + description TEXT +); + +CREATE TABLE group_members ( + group_id VARCHAR(64) NOT NULL, + recipient_id INTEGER NOT NULL, + member_since TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + joined_at_revision INTEGER NOT NULL, + role INTEGER NOT NULL, + + FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE, + FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE RESTRICT, + PRIMARY KEY(group_id, recipient_id) +); +CREATE INDEX group_member_recipient_id ON group_members(recipient_id DESC); +CREATE INDEX group_member_id ON group_members(group_id); + +CREATE TABLE contacts( + uuid VARCHAR(36) NOT NULL, + -- E.164 numbers should never be longer than 15 chars (excl. international prefix) + phone_number VARCHAR(20), + name TEXT NOT NULL, + color VARCHAR(32), + profile_key BLOB NOT NULL, + expire_timer INTEGER NOT NULL, + expire_timer_version INTEGER NOT NULL DEFAULT 2, + inbox_position INTEGER NOT NULL, + archived BOOLEAN NOT NULL, + avatar BLOB, + + PRIMARY KEY(uuid) ON CONFLICT REPLACE +); + +CREATE TABLE contacts_verification_state( + destination_aci VARCHAR(36) NOT NULL, + identity_key BLOB NOT NULL, + is_verified BOOLEAN, + + FOREIGN KEY(destination_aci) REFERENCES contacts(uuid) ON UPDATE CASCADE, + PRIMARY KEY(destination_aci) ON CONFLICT REPLACE +); \ No newline at end of file diff --git a/presage-store-sqlite/presage.sqlite b/presage-store-sqlite/presage.sqlite deleted file mode 100644 index 467d6e472d94c5dec735e263cfb9fbe77424a4c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40960 zcmeI(!Ef7C90zbaZQ{ly%fuyzQuKO2sZlbPwih}LNHV8{xk;C}5(R!=lI(hx-7r&xY|ud)66yyq7^ zyKdjnm`};wzS}i@vMF2@5((iALIgob@I~fJlu|si7;W&icrJfgHX&U5@HmrwETq$~ z30FSLexJE><(=innHQEfV>a#i%pVe6eOo8hH`VIx^=VnXLDuu8#qtG`Kkl)-qD&7cD<9uol5&b7o=PEw z$L{s09a+S;(lLy9-80m9%Fw1>Vdy;2swCxBR>aYJVW5-No~)K)p-l?^dojt%Xe}w_ z*4D&_nJ|h;8#C&iX|7^)kIEa-$UGk|RZwa>b(f zFd51jT>Ql7vU{%S2ZFQPiJ0VU?L_nebpw7>9z1R8SuQ&c4scONWO-guK)9cmqUgYHE`H$9=& zAUG?-XI&bde)N4=c|DQJwTqYG&SDs)*^&kRL%S6G*k<@5X1^5p2MGcYfB*y_009U< z00Izz00bZafqz?oic+$)nRXVQ?>u_$QLo-(KI3=1Y|}USy)K(N8`n3silyttjV)3t zZEwB0UE2EQmp|Wc-za=Kynpq{55>{T?|xVK>i3_QYd1c>pLprFZx4R$eDc$Fa%`009U<00Izz00bZa0SG_<0uY#Q0X+Yo@AgG>5P$##AOHafKmY;|fB*y_ z0D(XN@BgD8KmY;|fB*y_009U<00Izz00ib=0Q3L(Z(~FV0SG_<0uX=z1Rwwb2tWV= f5WxH&eE>; + type ContactsIter = Box>>; type GroupsIter = DummyIter>; @@ -31,24 +42,21 @@ impl ContentsStore for SqliteStore { todo!() } - async fn clear_thread( - &mut self, - thread: &presage::store::Thread, - ) -> Result<(), Self::ContentsStoreError> { + async fn clear_thread(&mut self, thread: &Thread) -> Result<(), Self::ContentsStoreError> { todo!() } async fn save_message( &self, - thread: &presage::store::Thread, - message: presage::libsignal_service::prelude::Content, + thread: &Thread, + message: Content, ) -> Result<(), Self::ContentsStoreError> { todo!() } async fn delete_message( &mut self, - thread: &presage::store::Thread, + thread: &Thread, timestamp: u64, ) -> Result { todo!() @@ -56,50 +64,180 @@ impl ContentsStore for SqliteStore { async fn message( &self, - thread: &presage::store::Thread, + thread: &Thread, timestamp: u64, - ) -> Result, Self::ContentsStoreError> - { + ) -> Result, Self::ContentsStoreError> { todo!() } async fn messages( &self, - thread: &presage::store::Thread, + thread: &Thread, range: impl std::ops::RangeBounds, ) -> Result { todo!() } async fn clear_contacts(&mut self) -> Result<(), Self::ContentsStoreError> { - todo!() + query!("DELETE FROM contacts").execute(&self.db).await?; + Ok(()) } - async fn save_contact( - &mut self, - contacts: &presage::model::contacts::Contact, - ) -> Result<(), Self::ContentsStoreError> { - todo!() + async fn save_contact(&mut self, contact: Contact) -> Result<(), Self::ContentsStoreError> { + let profile_key: &[u8] = contact.profile_key.as_ref(); + let avatar_bytes = contact.avatar.map(|a| a.reader.to_vec()); + let phone_number = contact.phone_number.map(|p| p.to_string()); + + let mut tx = self.db.begin().await?; + + query!( + "INSERT INTO contacts(uuid, phone_number, name, color, profile_key, expire_timer, expire_timer_version, inbox_position, archived, avatar) + VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + contact.uuid, + phone_number, + contact.name, + contact.color, + profile_key, + contact.expire_timer, + contact.expire_timer_version, + contact.inbox_position, + contact.archived, + avatar_bytes, + ).execute(&mut *tx).await?; + + let Verified { + destination_aci, + identity_key, + state, + .. + } = contact.verified; + let verified_state = match verified::State::from_i32(state.unwrap_or_default()) { + None | Some(verified::State::Default) => None, + Some(verified::State::Unverified) => Some("unverified"), + Some(verified::State::Verified) => Some("verified"), + }; + + query!( + "INSERT INTO contacts_verification_state(destination_aci, identity_key, is_verified) + VALUES($1, $2, $3)", + destination_aci, + identity_key, + verified_state, + ) + .execute(&mut *tx) + .await?; + + tx.commit().await; + + Ok(()) } async fn contacts(&self) -> Result { - todo!() + let contacts = query!( + "SELECT * + FROM contacts c + LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci + ORDER BY inbox_position + " + ) + .fetch_all(&self.db) + .await? + .into_iter() + .map(|r| { + Ok(Contact { + uuid: r.uuid.parse()?, + phone_number: r + .phone_number + .map(|p| phonenumber::parse(None, &p)) + .transpose()?, + name: r.name, + color: r.color, + verified: Verified { + destination_aci: r.destination_aci, + identity_key: r.identity_key, + state: r.is_verified.map(|v| { + match v { + true => verified::State::Verified, + false => verified::State::Unverified, + } + .into() + }), + null_message: None, + }, + profile_key: r.profile_key, + expire_timer: r.expire_timer as u32, + expire_timer_version: r.expire_timer_version as u32, + inbox_position: r.inbox_position as u32, + archived: r.archived, + avatar: r.avatar.map(|b| Attachment { + content_type: "application/octet-stream".into(), + reader: Bytes::from(b), + }), + }) + }); + + Ok(Box::new(contacts)) } async fn contact_by_id( &self, - id: &presage::libsignal_service::prelude::Uuid, + uuid: &Uuid, ) -> Result, Self::ContentsStoreError> { - todo!() + query!( + "SELECT * + FROM contacts c + LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci + WHERE c.uuid = $1 + ORDER BY inbox_position + LIMIT 1 + ", + uuid + ) + .fetch_optional(&self.db) + .await? + .map(|r| { + Ok(Contact { + uuid: r.uuid.parse()?, + phone_number: r + .phone_number + .map(|p| phonenumber::parse(None, &p)) + .transpose()?, + name: r.name, + color: r.color, + verified: Verified { + destination_aci: Some(r.destination_aci), + identity_key: Some(r.identity_key), + state: r.is_verified.map(|v| { + match v { + true => verified::State::Verified, + false => verified::State::Unverified, + } + .into() + }), + null_message: None, + }, + profile_key: r.profile_key, + expire_timer: r.expire_timer as u32, + expire_timer_version: r.expire_timer_version as u32, + inbox_position: r.inbox_position as u32, + archived: r.archived, + avatar: r.avatar.map(|b| Attachment { + content_type: "application/octet-stream".into(), + reader: Bytes::from(b), + }), + }) + }) + .transpose() } async fn clear_groups(&mut self) -> Result<(), Self::ContentsStoreError> { - todo!() + query!("DELETE FROM groups").execute(&self.db).await?; + Ok(()) } async fn save_group( &self, - master_key: presage::libsignal_service::zkgroup::GroupMasterKeyBytes, + master_key: zkgroup::GroupMasterKeyBytes, group: impl Into, ) -> Result<(), Self::ContentsStoreError> { todo!() @@ -111,14 +249,14 @@ impl ContentsStore for SqliteStore { async fn group( &self, - master_key: presage::libsignal_service::zkgroup::GroupMasterKeyBytes, + master_key: zkgroup::GroupMasterKeyBytes, ) -> Result, Self::ContentsStoreError> { todo!() } async fn save_group_avatar( &self, - master_key: presage::libsignal_service::zkgroup::GroupMasterKeyBytes, + master_key: zkgroup::GroupMasterKeyBytes, avatar: &presage::AvatarBytes, ) -> Result<(), Self::ContentsStoreError> { todo!() @@ -126,48 +264,47 @@ impl ContentsStore for SqliteStore { async fn group_avatar( &self, - master_key: presage::libsignal_service::zkgroup::GroupMasterKeyBytes, + master_key: zkgroup::GroupMasterKeyBytes, ) -> Result, Self::ContentsStoreError> { todo!() } async fn upsert_profile_key( &mut self, - uuid: &presage::libsignal_service::prelude::Uuid, - key: presage::libsignal_service::prelude::ProfileKey, + uuid: &Uuid, + key: ProfileKey, ) -> Result { todo!() } async fn profile_key( &self, - uuid: &presage::libsignal_service::prelude::Uuid, - ) -> Result, Self::ContentsStoreError> - { + uuid: &Uuid, + ) -> Result, Self::ContentsStoreError> { todo!() } async fn save_profile( &mut self, - uuid: presage::libsignal_service::prelude::Uuid, - key: presage::libsignal_service::prelude::ProfileKey, - profile: presage::libsignal_service::Profile, + uuid: Uuid, + key: ProfileKey, + profile: Profile, ) -> Result<(), Self::ContentsStoreError> { todo!() } async fn profile( &self, - uuid: presage::libsignal_service::prelude::Uuid, - key: presage::libsignal_service::prelude::ProfileKey, - ) -> Result, Self::ContentsStoreError> { + uuid: Uuid, + key: ProfileKey, + ) -> Result, Self::ContentsStoreError> { todo!() } async fn save_profile_avatar( &mut self, - uuid: presage::libsignal_service::prelude::Uuid, - key: presage::libsignal_service::prelude::ProfileKey, + uuid: Uuid, + key: ProfileKey, profile: &presage::AvatarBytes, ) -> Result<(), Self::ContentsStoreError> { todo!() @@ -175,15 +312,15 @@ impl ContentsStore for SqliteStore { async fn profile_avatar( &self, - uuid: presage::libsignal_service::prelude::Uuid, - key: presage::libsignal_service::prelude::ProfileKey, + uuid: Uuid, + key: ProfileKey, ) -> Result, Self::ContentsStoreError> { todo!() } async fn add_sticker_pack( &mut self, - pack: &presage::store::StickerPack, + pack: &StickerPack, ) -> Result<(), Self::ContentsStoreError> { todo!() } @@ -191,7 +328,7 @@ impl ContentsStore for SqliteStore { async fn sticker_pack( &self, id: &[u8], - ) -> Result, Self::ContentsStoreError> { + ) -> Result, Self::ContentsStoreError> { todo!() } diff --git a/presage-store-sqlite/src/error.rs b/presage-store-sqlite/src/error.rs index fa7764462..32bc5ee51 100644 --- a/presage-store-sqlite/src/error.rs +++ b/presage-store-sqlite/src/error.rs @@ -1,4 +1,5 @@ -use presage::store::StoreError; +use presage::{libsignal_service::prelude::phonenumber, store::StoreError}; +use sqlx::types::uuid; #[derive(Debug, thiserror::Error)] pub enum SqliteStoreError { @@ -6,6 +7,10 @@ pub enum SqliteStoreError { MigrationConflict, #[error("data store error: {0}")] Db(#[from] sqlx::Error), + #[error("error parsing phonenumber: {0}")] + PhoneNumber(#[from] phonenumber::ParseError), + #[error("error parsing UUID: {0}")] + Uuid(#[from] uuid::Error), } impl StoreError for SqliteStoreError {} diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index bf9ba6c0e..59b5921c0 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -299,7 +299,17 @@ impl KyberPreKeyStore for SqliteProtocolStore { &mut self, kyber_prekey_id: KyberPreKeyId, ) -> Result<(), ProtocolError> { - todo!() + let id: u32 = kyber_prekey_id.into(); + query!( + "DELETE FROM kyber_prekeys WHERE id = $1 AND identity = $2", + id, + self.identity_type, + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } } @@ -395,19 +405,41 @@ impl IdentityKeyStore for SqliteProtocolStore { async fn save_identity( &mut self, address: &ProtocolAddress, - identity: &IdentityKey, + identity_key: &IdentityKey, ) -> Result { - todo!() + let previous = self.get_identity(address).await?; + let ret = previous.as_ref() == Some(identity_key); + + let address = address.name(); + let record_data = identity_key.serialize(); + query!( + "INSERT INTO identities ( address, record, identity ) VALUES ( $1, $2, $3 )", + address, + record_data, + self.identity_type + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(ret) } + // TODO: take this out of the store trait! /// Return whether an identity is trusted for the role specified by `direction`. async fn is_trusted_identity( &self, address: &ProtocolAddress, - identity: &IdentityKey, + identity_key: &IdentityKey, direction: Direction, ) -> Result { - todo!() + if let Some(trusted_key) = self.get_identity(address).await? { + Ok(trusted_key == *identity_key) + } else { + // Trust on first use + // TODO: we should most likely expose this behaviour as a setting + Ok(true) + } } /// Return the public identity for the given `address`, if known. @@ -415,7 +447,17 @@ impl IdentityKeyStore for SqliteProtocolStore { &self, address: &ProtocolAddress, ) -> Result, ProtocolError> { - todo!() + let address_name = address.name(); + query!( + "SELECT record FROM identities WHERE address = $1 AND identity = $2", + address_name, + self.identity_type + ) + .fetch_optional(&self.store.db) + .await + .into_protocol_error()? + .map(|record| IdentityKey::decode(&record.record)) + .transpose() } } @@ -426,10 +468,24 @@ impl SenderKeyStore for SqliteProtocolStore { &mut self, sender: &ProtocolAddress, distribution_id: Uuid, - // TODO: pass this by value! record: &SenderKeyRecord, ) -> Result<(), ProtocolError> { - todo!() + let address = sender.name(); + let device_id: u32 = sender.device_id().into(); + let record_data = record.serialize()?; + query!( + "INSERT INTO sender_keys (address, device, distribution_id, record, identity) VALUES ($1, $2, $3, $4, $5)", + address, + device_id, + distribution_id, + record_data, + self.identity_type + ) + .execute(&self.store.db) + .await + .into_protocol_error()?; + + Ok(()) } /// Look up the entry corresponding to `(sender, distribution_id)`. @@ -438,6 +494,18 @@ impl SenderKeyStore for SqliteProtocolStore { sender: &ProtocolAddress, distribution_id: Uuid, ) -> Result, ProtocolError> { - todo!() + let address = sender.name(); + let device_id: u32 = sender.device_id().into(); + query!( + "SELECT record FROM sender_keys WHERE address = $1 AND device = $2 AND distribution_id = $3 AND identity = $4", + address, + device_id, + distribution_id, + self.identity_type + ) + .fetch_optional(&self.store.db) .await + .into_protocol_error()? + .map(|record| SenderKeyRecord::deserialize(&record.record)) + .transpose() } } diff --git a/presage.sqlite b/presage.sqlite deleted file mode 100644 index 111f50b63baa5f9189e41b6daf50cc5429fda12c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36864 zcmeI&!E4)A90zd8iR0K!nynYJ?y%owI3{rxr!E?Rydy@Rq z=lv`rJ-2r>9y0pe^Sfq9=cIR}R7$!;BuP?AELpLPN?NQ;k1FC_KDPd*)s(byXMcX- z4{0`cT{`_>;k)^j)7q&=b1zTLi3Su1KmY;|fB*y_0D%b-=zlbu$*-@={VzlFhQk8B z=Q7*a_t{N$+whs?`F3z(W46{(6RU?d8eLVd zQL{m{W@A&U*K}&B+nQ2SsnOJ_v8!pz!yTiKr>fShj(c*&{@F|>Uo6UfZy0er)Oc++ z7Gu2c-wEzeNoVqSsddtwNFA=vdKS zwNKRA)x~jJy+Mlw)8d6?D(t(wP%Ms*OPAG6WmnTF>dy@aqEsTidAYekZIK?PLn5Mp zOme)Cx}GoYOE_~xONWW|up{nJ>STLvA*9Luka*(X2V!X-TBi~!hAB+%H>sQ2;;`mh}N@kk{me2PGA8^vQfV)9xI*zz* z4f^X_YFk&fwqH-_+HR|*HgsdWNp$p}XIX>qSGC#HRHZTAFY2{A%(@x$y79|U)W;5( z)f+@*guKf};g1qPWOC}CGC7H1l#?w};)iB-@MAMC7J1>JBwi>GfB*y_009U<00Izz z00bZa0SNrp0!+@N%jdGr)S1rXxyNqZGv-lJY4?9Isfv5d%xa)uk-A;z5J6OE`IoYGxznUf4#f@i|@9- z{kgJvM(O9odC3dEOX7tB0SG_<0uX=z1Rwwb2tWV=5P-l$31p|z+32~#VE$kH=^q6G z5P$##AOHafKmY;|fB*y_0D%b>7|j3U{(pi87^emS2tWV=5P$##AOHafKmY;|5CWM0 zM;br?0uX=z1Rwwb2tWV=5P$##CSL&a|C2w)I70|P00Izz00bZa0SG_<0uX=z=Kqlc y5P$##AOHafKmY;|fB*y_0D;LD!2SQ^k1@^=0uX=z1Rwwb2tWV=5P$##An-R{?f$9& diff --git a/presage/src/manager/registered.rs b/presage/src/manager/registered.rs index 40e846b91..4e6e4f8ef 100644 --- a/presage/src/manager/registered.rs +++ b/presage/src/manager/registered.rs @@ -671,7 +671,7 @@ impl Manager { info!("saving contacts"); for contact in contacts.filter_map(Result::ok) { if let Err(error) = - state.store.save_contact(&contact.into()).await + state.store.save_contact(contact.into()).await { warn!(%error, "failed to save contacts"); break; @@ -1517,7 +1517,7 @@ async fn save_message( }; info!(%sender_uuid, "saved contact on first sight"); - store.save_contact(&contact).await?; + store.save_contact(contact).await?; } store.upsert_profile_key(&sender_uuid, profile_key).await?; diff --git a/presage/src/store.rs b/presage/src/store.rs index 956e95068..629a10a1c 100644 --- a/presage/src/store.rs +++ b/presage/src/store.rs @@ -166,7 +166,7 @@ pub trait ContentsStore: Send + Sync { } contact.expire_timer_version = version; contact.expire_timer = timer; - self.save_contact(&contact).await?; + self.save_contact(contact).await?; } Ok(()) } @@ -190,7 +190,7 @@ pub trait ContentsStore: Send + Sync { /// Save a contact fn save_contact( &mut self, - contacts: &Contact, + contacts: Contact, ) -> impl Future>; /// Get an iterator on all stored (synchronized) contacts From f34774a8d946abc6b9adb3af0018bbe7c673708c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Fri, 25 Oct 2024 12:26:16 +0200 Subject: [PATCH 08/25] Impl ProfileKeyStore --- ...88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json | 12 - .../20241024072558_Initial_data_model.sql | 19 ++ presage-store-sqlite/src/content.rs | 210 ++++++++++++------ 3 files changed, 156 insertions(+), 85 deletions(-) delete mode 100644 presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json diff --git a/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json b/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json deleted file mode 100644 index d567a956f..000000000 --- a/presage-store-sqlite/.sqlx/query-99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO contacts(uuid, phone_number, name, color, profile_key, expire_timer, expire_timer_version, inbox_position, archived, avatar)\n VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", - "describe": { - "columns": [], - "parameters": { - "Right": 10 - }, - "nullable": [] - }, - "hash": "99ecf093a982fa46e594eb2c46c88cd4bc7f22cc9a1318ed6b7ec69d18d7604e" -} diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 79ee1abd5..90c3bc120 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -99,4 +99,23 @@ CREATE TABLE contacts_verification_state( FOREIGN KEY(destination_aci) REFERENCES contacts(uuid) ON UPDATE CASCADE, PRIMARY KEY(destination_aci) ON CONFLICT REPLACE +); + +CREATE TABLE profile_keys( + uuid VARCHAR(36) NOT NULL, + key BLOB NOT NULL, + + PRIMARY KEY(uuid) ON CONFLICT REPLACE +); + +CREATE TABLE profiles( + uuid VARCHAR(36) NOT NULL, + given_name TEXT, + family_name TEXT, + about TEXT, + about_emoji TEXT, + avatar TEXT, + + FOREIGN KEY(uuid) REFERENCES profile_keys(uuid) ON UPDATE CASCADE + PRIMARY KEY(uuid) ON CONFLICT REPLACE ); \ No newline at end of file diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index a97fc7b07..7d8e0ad77 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -8,6 +8,7 @@ use presage::{ phonenumber::{self, PhoneNumber}, Content, ProfileKey, }, + profile_name::ProfileName, zkgroup::{self, GroupMasterKeyBytes}, Profile, }, @@ -15,7 +16,7 @@ use presage::{ proto::{verified, Verified}, store::{ContentsStore, StickerPack, Thread}, }; -use sqlx::{query, types::Uuid}; +use sqlx::{query, query_as, query_scalar, types::Uuid}; use crate::{SqliteStore, SqliteStoreError}; @@ -91,7 +92,7 @@ impl ContentsStore for SqliteStore { let mut tx = self.db.begin().await?; query!( - "INSERT INTO contacts(uuid, phone_number, name, color, profile_key, expire_timer, expire_timer_version, inbox_position, archived, avatar) + "INSERT INTO contacts VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", contact.uuid, phone_number, @@ -103,7 +104,9 @@ impl ContentsStore for SqliteStore { contact.inbox_position, contact.archived, avatar_bytes, - ).execute(&mut *tx).await?; + ) + .execute(&mut *tx) + .await?; let Verified { destination_aci, @@ -133,7 +136,8 @@ impl ContentsStore for SqliteStore { } async fn contacts(&self) -> Result { - let contacts = query!( + let contacts = query_as!( + SqlContact, "SELECT * FROM contacts c LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci @@ -143,38 +147,7 @@ impl ContentsStore for SqliteStore { .fetch_all(&self.db) .await? .into_iter() - .map(|r| { - Ok(Contact { - uuid: r.uuid.parse()?, - phone_number: r - .phone_number - .map(|p| phonenumber::parse(None, &p)) - .transpose()?, - name: r.name, - color: r.color, - verified: Verified { - destination_aci: r.destination_aci, - identity_key: r.identity_key, - state: r.is_verified.map(|v| { - match v { - true => verified::State::Verified, - false => verified::State::Unverified, - } - .into() - }), - null_message: None, - }, - profile_key: r.profile_key, - expire_timer: r.expire_timer as u32, - expire_timer_version: r.expire_timer_version as u32, - inbox_position: r.inbox_position as u32, - archived: r.archived, - avatar: r.avatar.map(|b| Attachment { - content_type: "application/octet-stream".into(), - reader: Bytes::from(b), - }), - }) - }); + .map(TryInto::try_into); Ok(Box::new(contacts)) } @@ -183,7 +156,8 @@ impl ContentsStore for SqliteStore { &self, uuid: &Uuid, ) -> Result, Self::ContentsStoreError> { - query!( + query_as!( + SqlContact, "SELECT * FROM contacts c LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci @@ -195,38 +169,7 @@ impl ContentsStore for SqliteStore { ) .fetch_optional(&self.db) .await? - .map(|r| { - Ok(Contact { - uuid: r.uuid.parse()?, - phone_number: r - .phone_number - .map(|p| phonenumber::parse(None, &p)) - .transpose()?, - name: r.name, - color: r.color, - verified: Verified { - destination_aci: Some(r.destination_aci), - identity_key: Some(r.identity_key), - state: r.is_verified.map(|v| { - match v { - true => verified::State::Verified, - false => verified::State::Unverified, - } - .into() - }), - null_message: None, - }, - profile_key: r.profile_key, - expire_timer: r.expire_timer as u32, - expire_timer_version: r.expire_timer_version as u32, - inbox_position: r.inbox_position as u32, - archived: r.archived, - avatar: r.avatar.map(|b| Attachment { - content_type: "application/octet-stream".into(), - reader: Bytes::from(b), - }), - }) - }) + .map(TryInto::try_into) .transpose() } @@ -274,22 +217,50 @@ impl ContentsStore for SqliteStore { uuid: &Uuid, key: ProfileKey, ) -> Result { - todo!() + let profile_key_bytes = key.get_bytes(); + let profile_key_slice = profile_key_bytes.as_slice(); + let rows_upserted = query!( + "INSERT INTO profile_keys VALUES($1, $2)", + uuid, + profile_key_slice + ) + .execute(&self.db) + .await? + .rows_affected(); + Ok(rows_upserted == 1) } async fn profile_key( &self, uuid: &Uuid, ) -> Result, Self::ContentsStoreError> { - todo!() + let profile_key = + query_scalar!("SELECT key FROM profile_keys WHERE uuid = $1 LIMIT 1", uuid) + .fetch_optional(&self.db) + .await? + .and_then(|key_bytes| key_bytes.try_into().ok().map(ProfileKey::create)); + Ok(profile_key) } async fn save_profile( &mut self, uuid: Uuid, - key: ProfileKey, + _key: ProfileKey, profile: Profile, ) -> Result<(), Self::ContentsStoreError> { + let given_name = profile.name.clone().map(|n| n.given_name); + let family_name = profile.name.map(|n| n.family_name).flatten(); + query!( + "INSERT INTO profiles VALUES($1, $2, $3, $4, $5, $6)", + uuid, + given_name, + family_name, + profile.about, + profile.about_emoji, + profile.avatar + ) + .execute(&self.db) + .await?; todo!() } @@ -298,7 +269,20 @@ impl ContentsStore for SqliteStore { uuid: Uuid, key: ProfileKey, ) -> Result, Self::ContentsStoreError> { - todo!() + let key_bytes = key.get_bytes(); + let key_slice = key_bytes.as_slice(); + query_as!( + SqlProfile, + "SELECT pk.key, p.* FROM profile_keys pk + LEFT JOIN profiles p ON pk.uuid = p.uuid + WHERE pk.uuid = $1 + LIMIT 1", + uuid + ) + .fetch_optional(&self.db) + .await? + .map(TryInto::try_into) + .transpose() } async fn save_profile_avatar( @@ -352,3 +336,83 @@ impl Iterator for DummyIter { todo!() } } + +struct SqlContact { + uuid: String, + phone_number: Option, + name: String, + color: Option, + profile_key: Vec, + expire_timer: i64, + expire_timer_version: i64, + inbox_position: i64, + archived: bool, + avatar: Option>, + + destination_aci: Option, + identity_key: Option>, + is_verified: Option, +} + +impl TryInto for SqlContact { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + Ok(Contact { + uuid: self.uuid.parse()?, + phone_number: self + .phone_number + .map(|p| phonenumber::parse(None, &p)) + .transpose()?, + name: self.name, + color: self.color, + verified: Verified { + destination_aci: self.destination_aci, + identity_key: self.identity_key, + state: self.is_verified.map(|v| { + match v { + true => verified::State::Verified, + false => verified::State::Unverified, + } + .into() + }), + null_message: None, + }, + profile_key: self.profile_key, + expire_timer: self.expire_timer as u32, + expire_timer_version: self.expire_timer_version as u32, + inbox_position: self.inbox_position as u32, + archived: self.archived, + avatar: self.avatar.map(|b| Attachment { + content_type: "application/octet-stream".into(), + reader: Bytes::from(b), + }), + }) + } +} + +struct SqlProfile { + uuid: String, + key: Vec, + given_name: Option, + family_name: Option, + about: Option, + about_emoji: Option, + avatar: Option, +} + +impl TryInto for SqlProfile { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + Ok(Profile { + name: self.given_name.map(|gn| ProfileName { + given_name: gn, + family_name: self.family_name, + }), + about: self.about, + about_emoji: self.about_emoji, + avatar: self.avatar, + }) + } +} From 1cdddfc5841c361f36d2df458b9c4d4dfcce3b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Fri, 25 Oct 2024 12:28:18 +0200 Subject: [PATCH 09/25] Remove DummyIter struct --- presage-store-sqlite/src/content.rs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 7d8e0ad77..994a8e3f5 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -25,14 +25,16 @@ impl ContentsStore for SqliteStore { type ContactsIter = Box>>; - type GroupsIter = DummyIter>; + type GroupsIter = + Box>>; - type MessagesIter = DummyIter>; + type MessagesIter = Box>>; - type StickerPacksIter = DummyIter>; + type StickerPacksIter = Box>>; async fn clear_profiles(&mut self) -> Result<(), Self::ContentsStoreError> { - todo!() + query!("DELETE FROM profiles").execute(&self.db).await?; + Ok(()) } async fn clear_contents(&mut self) -> Result<(), Self::ContentsStoreError> { @@ -325,18 +327,6 @@ impl ContentsStore for SqliteStore { } } -pub struct DummyIter { - _data: PhantomData, -} - -impl Iterator for DummyIter { - type Item = T; - - fn next(&mut self) -> Option { - todo!() - } -} - struct SqlContact { uuid: String, phone_number: Option, From 1c2cd62d934d8bc06e24252a16c82f5cad2312e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 11:53:20 +0100 Subject: [PATCH 10/25] Exclude .sqlx files --- ...c8480806af402afaa06c5556b55d2aa0695c7.json | 20 ---- ...04470b6a61278a8edc257b324ecf8e20e8af2.json | 20 ---- ...c07b339ad028dcfad92c928dd381d891e3ad0.json | 12 --- ...01338bc61cdcc34a4cc78279c284711ab1028.json | 20 ---- ...f98a3f663a822ae69a4ad00114ab31f1596e2.json | 12 --- ...6151cead304e35b7b0fb01ee0fb65a4102fa4.json | 12 --- ...4a7f6a0f387be690a380a276a109daf2a726d.json | 12 --- ...6e0292eb9baa57ba51d3ca9798573a2c8697e.json | 12 --- ...66a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json | 20 ---- ...541ca9a896f85dabaad6e76d67402cbc82b68.json | 12 --- ...3eeef7d5c19d2e373a31ed56ea853ed57690e.json | 12 --- ...482a82f00197519fd9b4b6aceeb6a0850ccfd.json | 20 ---- ...c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json | 12 --- ...181f12233ad20a6af32514c25fcd646b7ff19.json | 20 ---- ...64f0a13c34eb5a4048a3ebbfe5e4069d15719.json | 12 --- ...f6f78a45867816ea459e8cb2cc2bacf66812a.json | 12 --- ...e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json | 20 ---- ...c76168dcb5054032e3a217cc125c567abc33c.json | 12 --- ...364e76f5668266c7b2eb956bb9d7feb18f195.json | 26 ------ ...82c34186cb05df09af183ab87b627cebc6895.json | 26 ------ ...d367a4755ec5555e85945bb12fc1fc94772d3.json | 92 ------------------- ...20b59a8fb880969b56537f00fc8a9f396957a.json | 12 --- ...371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json | 26 ------ ...f5b62ec49534742a292116f74ea9672f85c87.json | 12 --- ...556a38d4d52d5fd4b9e16b6d81f6f42188922.json | 12 --- ...71790fb09f691f52a1d533ef3e3d4bd82a651.json | 38 -------- ...ecd0b63612b882306dce24e4057dd54454af8.json | 20 ---- .../20241024072558_Initial_data_model.sql | 2 +- 28 files changed, 1 insertion(+), 537 deletions(-) delete mode 100644 presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json delete mode 100644 presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json delete mode 100644 presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json delete mode 100644 presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json delete mode 100644 presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json delete mode 100644 presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json delete mode 100644 presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json delete mode 100644 presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json delete mode 100644 presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json delete mode 100644 presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json delete mode 100644 presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json delete mode 100644 presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json delete mode 100644 presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json delete mode 100644 presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json delete mode 100644 presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json delete mode 100644 presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json delete mode 100644 presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json delete mode 100644 presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json delete mode 100644 presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json delete mode 100644 presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json delete mode 100644 presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json delete mode 100644 presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json delete mode 100644 presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json delete mode 100644 presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json delete mode 100644 presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json delete mode 100644 presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json delete mode 100644 presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json diff --git a/presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json b/presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json deleted file mode 100644 index 35ec23090..000000000 --- a/presage-store-sqlite/.sqlx/query-02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT MAX(id) FROM prekeys", - "describe": { - "columns": [ - { - "name": "MAX(id)", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - true - ] - }, - "hash": "02dacd272b081cb93daacfd9fc0c8480806af402afaa06c5556b55d2aa0695c7" -} diff --git a/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json b/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json deleted file mode 100644 index a489e97c4..000000000 --- a/presage-store-sqlite/.sqlx/query-068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT record FROM identities WHERE address = $1 AND identity = $2", - "describe": { - "columns": [ - { - "name": "record", - "ordinal": 0, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 2 - }, - "nullable": [ - false - ] - }, - "hash": "068728e31158d57c330eafc0e3604470b6a61278a8edc257b324ecf8e20e8af2" -} diff --git a/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json b/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json deleted file mode 100644 index 6de08a22a..000000000 --- a/presage-store-sqlite/.sqlx/query-113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO sender_keys (address, device, distribution_id, record, identity) VALUES ($1, $2, $3, $4, $5)", - "describe": { - "columns": [], - "parameters": { - "Right": 5 - }, - "nullable": [] - }, - "hash": "113b7ed248bfc820dc2a9a90354c07b339ad028dcfad92c928dd381d891e3ad0" -} diff --git a/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json b/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json deleted file mode 100644 index 1ee8847dd..000000000 --- a/presage-store-sqlite/.sqlx/query-11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT record FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3 LIMIT 1", - "describe": { - "columns": [ - { - "name": "record", - "ordinal": 0, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 3 - }, - "nullable": [ - false - ] - }, - "hash": "11a6b9df71ebff7347e15979dd801338bc61cdcc34a4cc78279c284711ab1028" -} diff --git a/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json b/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json deleted file mode 100644 index 361aef933..000000000 --- a/presage-store-sqlite/.sqlx/query-15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO sessions ( address, device_id, identity, record ) VALUES ( $1, $2, $3, $4 )", - "describe": { - "columns": [], - "parameters": { - "Right": 4 - }, - "nullable": [] - }, - "hash": "15a7004e49da052f9be07e473eff98a3f663a822ae69a4ad00114ab31f1596e2" -} diff --git a/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json b/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json deleted file mode 100644 index 19eaf5570..000000000 --- a/presage-store-sqlite/.sqlx/query-16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO contacts_verification_state(destination_aci, identity_key, is_verified)\n VALUES($1, $2, $3)", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "16dd565987c37fc48f734ebe0d06151cead304e35b7b0fb01ee0fb65a4102fa4" -} diff --git a/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json b/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json deleted file mode 100644 index 17de1601a..000000000 --- a/presage-store-sqlite/.sqlx/query-1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO kyber_prekeys( id, record, is_last_resort, identity )\n VALUES( $1, $2, true, $4 )", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "1b116b1419c2b61eb2b50c16b584a7f6a0f387be690a380a276a109daf2a726d" -} diff --git a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json b/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json deleted file mode 100644 index d0f40687f..000000000 --- a/presage-store-sqlite/.sqlx/query-21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM kyber_prekeys WHERE id = $1 AND identity = $2", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "21238545aba782562f8c1ebf61b6e0292eb9baa57ba51d3ca9798573a2c8697e" -} diff --git a/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json b/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json deleted file mode 100644 index e1e47d5db..000000000 --- a/presage-store-sqlite/.sqlx/query-22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT MAX(id) as 'max_id: u32' FROM kyber_prekeys", - "describe": { - "columns": [ - { - "name": "max_id: u32", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - true - ] - }, - "hash": "22a6170a4e33163a53257befd2466a7278e5ca2b9debf11a0e0d8f20c7fffeb4" -} diff --git a/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json b/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json deleted file mode 100644 index 17b2c6cc3..000000000 --- a/presage-store-sqlite/.sqlx/query-261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM sessions WHERE address = $1 AND identity = $3", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "261e68e9014907ffe1981465782541ca9a896f85dabaad6e76d67402cbc82b68" -} diff --git a/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json b/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json deleted file mode 100644 index cdb551951..000000000 --- a/presage-store-sqlite/.sqlx/query-3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO kyber_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "3a0ea4bcd1be0c9f302463487473eeef7d5c19d2e373a31ed56ea853ed57690e" -} diff --git a/presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json b/presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json deleted file mode 100644 index ef3bbe38a..000000000 --- a/presage-store-sqlite/.sqlx/query-3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT MAX(id) FROM signed_prekeys", - "describe": { - "columns": [ - { - "name": "MAX(id)", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - true - ] - }, - "hash": "3bc26672839257680903803812b482a82f00197519fd9b4b6aceeb6a0850ccfd" -} diff --git a/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json b/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json deleted file mode 100644 index a915fd113..000000000 --- a/presage-store-sqlite/.sqlx/query-4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO signed_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "4fa3dbd779a06f9ab22934a8176c372bf2cf6fe9fd60bec68f1ecec0206eacb2" -} diff --git a/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json b/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json deleted file mode 100644 index d7fe9b2e6..000000000 --- a/presage-store-sqlite/.sqlx/query-55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT record FROM sender_keys WHERE address = $1 AND device = $2 AND distribution_id = $3 AND identity = $4", - "describe": { - "columns": [ - { - "name": "record", - "ordinal": 0, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 4 - }, - "nullable": [ - false - ] - }, - "hash": "55deb2155c89853ac179f0cf85b181f12233ad20a6af32514c25fcd646b7ff19" -} diff --git a/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json b/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json deleted file mode 100644 index c378d3d37..000000000 --- a/presage-store-sqlite/.sqlx/query-5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM contacts", - "describe": { - "columns": [], - "parameters": { - "Right": 0 - }, - "nullable": [] - }, - "hash": "5b76d0a4e70c0ca0353359d81fb64f0a13c34eb5a4048a3ebbfe5e4069d15719" -} diff --git a/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json b/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json deleted file mode 100644 index c5a54ec91..000000000 --- a/presage-store-sqlite/.sqlx/query-75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM groups", - "describe": { - "columns": [], - "parameters": { - "Right": 0 - }, - "nullable": [] - }, - "hash": "75843c68da0d7af5503404586bcf6f78a45867816ea459e8cb2cc2bacf66812a" -} diff --git a/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json b/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json deleted file mode 100644 index ee147c710..000000000 --- a/presage-store-sqlite/.sqlx/query-7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT COUNT(id) FROM kyber_prekeys", - "describe": { - "columns": [ - { - "name": "COUNT(id)", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false - ] - }, - "hash": "7a58899603d533e8448b066c598e2e2c5bd899ba44641afc0aa4f9cccd599a4a" -} diff --git a/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json b/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json deleted file mode 100644 index 51c86cd60..000000000 --- a/presage-store-sqlite/.sqlx/query-9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM sessions WHERE address = $1 AND device_id = $2 AND identity = $3", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "9321df68b4ba3651be2192cd89cc76168dcb5054032e3a217cc125c567abc33c" -} diff --git a/presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json b/presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json deleted file mode 100644 index 35ab2d811..000000000 --- a/presage-store-sqlite/.sqlx/query-9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT id, record FROM signed_prekeys WHERE id = $1 LIMIT 1", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "record", - "ordinal": 1, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false - ] - }, - "hash": "9b028a96067cf022af14f3a0a85364e76f5668266c7b2eb956bb9d7feb18f195" -} diff --git a/presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json b/presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json deleted file mode 100644 index 90245c039..000000000 --- a/presage-store-sqlite/.sqlx/query-aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT id, record FROM prekeys WHERE id = $1 LIMIT 1", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "record", - "ordinal": 1, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false - ] - }, - "hash": "aa0a27350cfa1011de379da455a82c34186cb05df09af183ab87b627cebc6895" -} diff --git a/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json b/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json deleted file mode 100644 index a37789268..000000000 --- a/presage-store-sqlite/.sqlx/query-b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3.json +++ /dev/null @@ -1,92 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT *\n FROM contacts c\n LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci \n ORDER BY inbox_position\n ", - "describe": { - "columns": [ - { - "name": "uuid", - "ordinal": 0, - "type_info": "Text" - }, - { - "name": "phone_number", - "ordinal": 1, - "type_info": "Text" - }, - { - "name": "name", - "ordinal": 2, - "type_info": "Text" - }, - { - "name": "color", - "ordinal": 3, - "type_info": "Text" - }, - { - "name": "profile_key", - "ordinal": 4, - "type_info": "Blob" - }, - { - "name": "expire_timer", - "ordinal": 5, - "type_info": "Integer" - }, - { - "name": "expire_timer_version", - "ordinal": 6, - "type_info": "Integer" - }, - { - "name": "inbox_position", - "ordinal": 7, - "type_info": "Integer" - }, - { - "name": "archived", - "ordinal": 8, - "type_info": "Bool" - }, - { - "name": "avatar", - "ordinal": 9, - "type_info": "Blob" - }, - { - "name": "destination_aci", - "ordinal": 10, - "type_info": "Text" - }, - { - "name": "identity_key", - "ordinal": 11, - "type_info": "Blob" - }, - { - "name": "is_verified", - "ordinal": 12, - "type_info": "Bool" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false, - true, - false, - true, - false, - false, - false, - false, - false, - true, - true, - true, - true - ] - }, - "hash": "b73e99a97f153db2509dff2dbc1d367a4755ec5555e85945bb12fc1fc94772d3" -} diff --git a/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json b/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json deleted file mode 100644 index b40661b49..000000000 --- a/presage-store-sqlite/.sqlx/query-bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "DELETE FROM prekeys WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Right": 1 - }, - "nullable": [] - }, - "hash": "bcf0eaf3c345ef16349623a2d2b20b59a8fb880969b56537f00fc8a9f396957a" -} diff --git a/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json b/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json deleted file mode 100644 index 44e0107a2..000000000 --- a/presage-store-sqlite/.sqlx/query-bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT id, record FROM kyber_prekeys WHERE id = $1 LIMIT 1", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "record", - "ordinal": 1, - "type_info": "Blob" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false - ] - }, - "hash": "bfd1ee08a2c988c68aff8a85723371ddbc9c5cd7b910e46bf3c9a6ef4ee90a1a" -} diff --git a/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json b/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json deleted file mode 100644 index fbd57c55c..000000000 --- a/presage-store-sqlite/.sqlx/query-cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO identities ( address, record, identity ) VALUES ( $1, $2, $3 )", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "cef653d4d400e9e153b4dcf281ef5b62ec49534742a292116f74ea9672f85c87" -} diff --git a/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json b/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json deleted file mode 100644 index 6134279da..000000000 --- a/presage-store-sqlite/.sqlx/query-de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "INSERT INTO prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", - "describe": { - "columns": [], - "parameters": { - "Right": 3 - }, - "nullable": [] - }, - "hash": "de0e86d2a8653fb0a1c41f86dc7556a38d4d52d5fd4b9e16b6d81f6f42188922" -} diff --git a/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json b/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json deleted file mode 100644 index 7d15757f7..000000000 --- a/presage-store-sqlite/.sqlx/query-eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT * FROM kyber_prekeys WHERE is_last_resort = true AND identity = $1", - "describe": { - "columns": [ - { - "name": "id", - "ordinal": 0, - "type_info": "Integer" - }, - { - "name": "record", - "ordinal": 1, - "type_info": "Blob" - }, - { - "name": "is_last_resort", - "ordinal": 2, - "type_info": "Bool" - }, - { - "name": "identity", - "ordinal": 3, - "type_info": "Text" - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false, - false - ] - }, - "hash": "eeb94589e57d9e1119ebff607b571790fb09f691f52a1d533ef3e3d4bd82a651" -} diff --git a/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json b/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json deleted file mode 100644 index cf7d09d59..000000000 --- a/presage-store-sqlite/.sqlx/query-f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "db_name": "SQLite", - "query": "SELECT COUNT(id) FROM signed_prekeys", - "describe": { - "columns": [ - { - "name": "COUNT(id)", - "ordinal": 0, - "type_info": "Integer" - } - ], - "parameters": { - "Right": 0 - }, - "nullable": [ - false - ] - }, - "hash": "f91cfeddee973ae3870df37f73fecd0b63612b882306dce24e4057dd54454af8" -} diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 90c3bc120..a26055b43 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -4,7 +4,7 @@ CREATE TABLE sessions ( record BLOB NOT NULL, identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', - PRIMARY KEY(address, device_id, identity) + PRIMARY KEY(address, device_id, identity) ON CONFLICT REPLACE ); CREATE TABLE identities ( From c730030ef1daf9097b8062069e1a3862af7ccef0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 13:24:38 +0100 Subject: [PATCH 11/25] Adjust schema --- presage-store-sqlite/.env | 1 + .../20241024072558_Initial_data_model.sql | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 presage-store-sqlite/.env diff --git a/presage-store-sqlite/.env b/presage-store-sqlite/.env new file mode 100644 index 000000000..c73c61c99 --- /dev/null +++ b/presage-store-sqlite/.env @@ -0,0 +1 @@ +DATABASE_URL="sqlite:presage.sqlite" \ No newline at end of file diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index a26055b43..2fc6dd4c0 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -18,22 +18,28 @@ CREATE TABLE identities ( ); CREATE TABLE prekeys ( - id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + id INTEGER NOT NULL, record BLOB NOT NULL, - identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL, + + PRIMARY KEY(id, identity) ON CONFLICT REPLACE ); CREATE TABLE signed_prekeys ( - id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + id INTEGER, record BLOB NOT NULL, - identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci' + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', + + PRIMARY KEY(id, identity) ON CONFLICT REPLACE ); CREATE TABLE kyber_prekeys ( - id INTEGER PRIMARY KEY ON CONFLICT REPLACE NOT NULL, + id INTEGER, record BLOB NOT NULL, is_last_resort BOOLEAN DEFAULT FALSE NOT NULL, - identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL + identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL, + + PRIMARY KEY(id, identity) ON CONFLICT REPLACE ); CREATE TABLE sender_keys ( @@ -44,8 +50,7 @@ CREATE TABLE sender_keys ( created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, identity TEXT CHECK(identity IN ('aci', 'pni')) NOT NULL DEFAULT 'aci', - PRIMARY KEY(address, device, distribution_id), - UNIQUE(address, device, distribution_id) ON CONFLICT REPLACE + PRIMARY KEY(address, device, distribution_id) ON CONFLICT REPLACE ); -- Groups From 22a5497d14f45f5d737b12cd7d4488076b6cf749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 13:28:58 +0100 Subject: [PATCH 12/25] Add CI to generate .sqlx files --- .github/workflows/build.yml | 20 +++++++++++++++++++- presage-store-sqlite/.env | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cda6da1f4..72b61e0a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,6 +37,15 @@ jobs: - name: Configure CI cache uses: Swatinem/rust-cache@v2 + - name: Prepare .sqlx files + working-directory: presage-store-sqlite + env: + DATABASE_URL: sqlite:presage.sqlite + run: | + cargo install --locked sqlx-cli + yes | cargo sqlx database reset + cargo sqlx prepare + - name: Build run: cargo build --all-targets @@ -80,8 +89,17 @@ jobs: sudo apt-get update sudo apt-get install -y protobuf-compiler - - name: Setup CI cache + - name: Configure CI cache uses: Swatinem/rust-cache@v2 + - name: Prepare .sqlx files + working-directory: presage-store-sqlite + env: + DATABASE_URL: sqlite:presage.sqlite + run: | + cargo install --locked sqlx-cli + yes | cargo sqlx database reset + cargo sqlx prepare + - name: Run clippy lints run: cargo clippy diff --git a/presage-store-sqlite/.env b/presage-store-sqlite/.env index c73c61c99..62df85634 100644 --- a/presage-store-sqlite/.env +++ b/presage-store-sqlite/.env @@ -1 +1 @@ -DATABASE_URL="sqlite:presage.sqlite" \ No newline at end of file +DATABASE_URL="sqlite:presage.sqlite" From 5f748454b73bd00c691c3fa3d3ed7b22b389ba9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 13:36:48 +0100 Subject: [PATCH 13/25] Merge steps --- .github/workflows/build.yml | 43 +++++-------------------------------- 1 file changed, 5 insertions(+), 38 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 72b61e0a5..3052837dc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ concurrency: jobs: build_and_test: - name: cargo ${{ matrix.cargo_flags }} + name: cargo clippy + test runs-on: ubuntu-latest env: RUSTFLAGS: -D warnings @@ -31,8 +31,8 @@ jobs: - name: Install protobuf run: | - sudo apt-get update - sudo apt-get install -y protobuf-compiler + sudo apt-get update -qq + sudo apt-get install -yqq protobuf-compiler - name: Configure CI cache uses: Swatinem/rust-cache@v2 @@ -46,8 +46,8 @@ jobs: yes | cargo sqlx database reset cargo sqlx prepare - - name: Build - run: cargo build --all-targets + - name: Clippy + run: cargo clippy --all-targets - name: Test run: cargo test --all-targets @@ -70,36 +70,3 @@ jobs: - name: Check code format run: cargo fmt -- --check - - clippy: - name: clippy - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Setup Rust toolchain - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: stable - components: clippy - - - name: Install protobuf - run: | - sudo apt-get update - sudo apt-get install -y protobuf-compiler - - - name: Configure CI cache - uses: Swatinem/rust-cache@v2 - - - name: Prepare .sqlx files - working-directory: presage-store-sqlite - env: - DATABASE_URL: sqlite:presage.sqlite - run: | - cargo install --locked sqlx-cli - yes | cargo sqlx database reset - cargo sqlx prepare - - - name: Run clippy lints - run: cargo clippy From 3c13b5602f87343b989f2225e35caa2be4d11bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 14:59:17 +0100 Subject: [PATCH 14/25] Add schema for threads and thread messages --- presage-store-sqlite/Cargo.toml | 1 + .../20241024072558_Initial_data_model.sql | 27 +++++++++++++++++++ presage-store-sqlite/src/content.rs | 14 +++++----- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index bc50d9bd3..350a8b664 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -13,3 +13,4 @@ presage-store-cipher = { path = "../presage-store-cipher", optional = true } sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } thiserror = "1.0.65" tracing = "0.1.40" +uuid = { version = "1.11.0", features = ["v4"] } diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 2fc6dd4c0..de0ec894a 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -123,4 +123,31 @@ CREATE TABLE profiles( FOREIGN KEY(uuid) REFERENCES profile_keys(uuid) ON UPDATE CASCADE PRIMARY KEY(uuid) ON CONFLICT REPLACE +); + +-- Threads +CREATE TABLE threads ( + id INTEGER NOT NULL, + group_id VARCHAR(64), + recipient_id VARCHAR(36), + + PRIMARY KEY(id, group_id, recipient_id) ON CONFLICT IGNORE, + FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE, + FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE CASCADE +); + +CREATE TABLE thread_messages( + id INTEGER NOT NULL, + thread_id INTEGER NOT NULL, + + sender_service_id TEXT NOT NULL, + -- destination_service_id TEXT NOT NULL, + received_at TIMESTAMP NOT NULL, + needs_receipt BOOLEAN NOT NULL, + unidentified_sender BOOLEAN NOT NULL, + + content_body BLOB NOT NULL, + + PRIMARY KEY(id, thread_id) ON CONFLICT REPLACE, + FOREIGN KEY(thread_id) REFERENCES threads(id) ON UPDATE CASCADE ); \ No newline at end of file diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 994a8e3f5..e06f7360f 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -95,7 +95,7 @@ impl ContentsStore for SqliteStore { query!( "INSERT INTO contacts - VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", + VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", contact.uuid, phone_number, contact.name, @@ -124,7 +124,7 @@ impl ContentsStore for SqliteStore { query!( "INSERT INTO contacts_verification_state(destination_aci, identity_key, is_verified) - VALUES($1, $2, $3)", + VALUES(?, ?, ?)", destination_aci, identity_key, verified_state, @@ -163,7 +163,7 @@ impl ContentsStore for SqliteStore { "SELECT * FROM contacts c LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci - WHERE c.uuid = $1 + WHERE c.uuid = ? ORDER BY inbox_position LIMIT 1 ", @@ -222,7 +222,7 @@ impl ContentsStore for SqliteStore { let profile_key_bytes = key.get_bytes(); let profile_key_slice = profile_key_bytes.as_slice(); let rows_upserted = query!( - "INSERT INTO profile_keys VALUES($1, $2)", + "INSERT INTO profile_keys VALUES(?, ?)", uuid, profile_key_slice ) @@ -237,7 +237,7 @@ impl ContentsStore for SqliteStore { uuid: &Uuid, ) -> Result, Self::ContentsStoreError> { let profile_key = - query_scalar!("SELECT key FROM profile_keys WHERE uuid = $1 LIMIT 1", uuid) + query_scalar!("SELECT key FROM profile_keys WHERE uuid = ? LIMIT 1", uuid) .fetch_optional(&self.db) .await? .and_then(|key_bytes| key_bytes.try_into().ok().map(ProfileKey::create)); @@ -253,7 +253,7 @@ impl ContentsStore for SqliteStore { let given_name = profile.name.clone().map(|n| n.given_name); let family_name = profile.name.map(|n| n.family_name).flatten(); query!( - "INSERT INTO profiles VALUES($1, $2, $3, $4, $5, $6)", + "INSERT INTO profiles VALUES(?, ?, ?, ?, ?, ?)", uuid, given_name, family_name, @@ -277,7 +277,7 @@ impl ContentsStore for SqliteStore { SqlProfile, "SELECT pk.key, p.* FROM profile_keys pk LEFT JOIN profiles p ON pk.uuid = p.uuid - WHERE pk.uuid = $1 + WHERE pk.uuid = ? LIMIT 1", uuid ) From 4276d30490228d3785b8ea9f31da2d17aedb89e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 15:14:11 +0100 Subject: [PATCH 15/25] Upsert threads --- .../20241024072558_Initial_data_model.sql | 19 ++++++------ presage-store-sqlite/src/content.rs | 30 +++++++++++++++++-- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index de0ec894a..0f245bb38 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -57,7 +57,7 @@ CREATE TABLE sender_keys ( CREATE TABLE groups ( id VARCHAR(64) PRIMARY KEY NOT NULL, name TEXT NOT NULL, - master_key VARCHAR(64) NOT NULL, + master_key BLOB NOT NULL, revision INTEGER NOT NULL DEFAULT 0, invite_link_password BLOB, access_required_for_attributes INTEGER NOT NULL DEFAULT 0, @@ -75,7 +75,7 @@ CREATE TABLE group_members ( role INTEGER NOT NULL, FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE, - FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE RESTRICT, + -- FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE RESTRICT, PRIMARY KEY(group_id, recipient_id) ); CREATE INDEX group_member_recipient_id ON group_members(recipient_id DESC); @@ -127,17 +127,16 @@ CREATE TABLE profiles( -- Threads CREATE TABLE threads ( - id INTEGER NOT NULL, - group_id VARCHAR(64), - recipient_id VARCHAR(36), + group_id VARCHAR(64) DEFAULT NULL, + recipient_id VARCHAR(36) DEFAULT NULL, - PRIMARY KEY(id, group_id, recipient_id) ON CONFLICT IGNORE, - FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE, - FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE CASCADE + PRIMARY KEY(group_id, recipient_id) ON CONFLICT IGNORE, + FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE + -- FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE CASCADE ); CREATE TABLE thread_messages( - id INTEGER NOT NULL, + ts TIMESTAMP NOT NULL, thread_id INTEGER NOT NULL, sender_service_id TEXT NOT NULL, @@ -148,6 +147,6 @@ CREATE TABLE thread_messages( content_body BLOB NOT NULL, - PRIMARY KEY(id, thread_id) ON CONFLICT REPLACE, + PRIMARY KEY(ts, thread_id) ON CONFLICT REPLACE, FOREIGN KEY(thread_id) REFERENCES threads(id) ON UPDATE CASCADE ); \ No newline at end of file diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index e06f7360f..8d3f0eed9 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -52,9 +52,35 @@ impl ContentsStore for SqliteStore { async fn save_message( &self, thread: &Thread, - message: Content, + Content { metadata, body }: Content, ) -> Result<(), Self::ContentsStoreError> { - todo!() + let mut tx = self.db.begin().await?; + + match thread { + Thread::Contact(uuid) => { + query!( + "INSERT INTO threads(recipient_id, group_id) VALUES (?, NULL)", + metadata.sender.uuid, + ) + .execute(&mut *tx) + .await? + } + Thread::Group(master_key_bytes) => { + let master_key_bytes = master_key_bytes.as_slice(); + query!( + "INSERT INTO threads(group_id) + SELECT id FROM groups + WHERE groups.master_key = ? + ", + master_key_bytes + ) + .execute(&mut *tx) + .await? + } + }; + + tx.commit().await?; + Ok(()) } async fn delete_message( From 03bfe523469c2d689662ec6127c61cc22fbdaea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 29 Oct 2024 15:35:01 +0100 Subject: [PATCH 16/25] Save message --- presage-store-sqlite/Cargo.toml | 1 + .../20241024072558_Initial_data_model.sql | 5 +- presage-store-sqlite/src/content.rs | 46 +++++++++++++++---- 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index 350a8b664..003c337b8 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -9,6 +9,7 @@ bytes = "1.8.0" chrono = "0.4.38" presage = { path = "../presage" } presage-store-cipher = { path = "../presage-store-cipher", optional = true } +prost = "0.13.3" sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } thiserror = "1.0.65" diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 0f245bb38..0caf60dad 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -127,21 +127,20 @@ CREATE TABLE profiles( -- Threads CREATE TABLE threads ( + id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, group_id VARCHAR(64) DEFAULT NULL, recipient_id VARCHAR(36) DEFAULT NULL, - PRIMARY KEY(group_id, recipient_id) ON CONFLICT IGNORE, FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE -- FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE CASCADE ); CREATE TABLE thread_messages( - ts TIMESTAMP NOT NULL, + ts INTEGER NOT NULL, thread_id INTEGER NOT NULL, sender_service_id TEXT NOT NULL, -- destination_service_id TEXT NOT NULL, - received_at TIMESTAMP NOT NULL, needs_receipt BOOLEAN NOT NULL, unidentified_sender BOOLEAN NOT NULL, diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 8d3f0eed9..e3b5653ac 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use bytes::Bytes; use presage::{ libsignal_service::{ + content::Metadata, models::Attachment, prelude::{ phonenumber::{self, PhoneNumber}, @@ -56,29 +57,54 @@ impl ContentsStore for SqliteStore { ) -> Result<(), Self::ContentsStoreError> { let mut tx = self.db.begin().await?; - match thread { + let thread_id = match thread { Thread::Contact(uuid) => { - query!( - "INSERT INTO threads(recipient_id, group_id) VALUES (?, NULL)", + query_scalar!( + "INSERT INTO threads(recipient_id, group_id) VALUES (?, NULL) RETURNING id", metadata.sender.uuid, ) - .execute(&mut *tx) + .fetch_one(&mut *tx) .await? } Thread::Group(master_key_bytes) => { let master_key_bytes = master_key_bytes.as_slice(); - query!( - "INSERT INTO threads(group_id) - SELECT id FROM groups - WHERE groups.master_key = ? - ", + query_scalar!( + "INSERT INTO threads(group_id) SELECT id FROM groups WHERE groups.master_key = ? RETURNING id", master_key_bytes ) - .execute(&mut *tx) + .fetch_one(&mut *tx) .await? } }; + let Metadata { + sender, + destination, + sender_device, + timestamp, + needs_receipt, + unidentified_sender, + server_guid, + } = metadata; + + let proto_bytes = prost::Message::encode_to_vec(&body.into_proto()); + + let timestamp = timestamp as i64; // danger + + query!( + "INSERT INTO + thread_messages(ts, thread_id, sender_service_id, needs_receipt, unidentified_sender, content_body) + VALUES(?, ?, ?, ?, ?, ?)", + timestamp, + thread_id, + sender.uuid, + needs_receipt, + unidentified_sender, + proto_bytes + ) + .execute(&mut *tx) + .await?; + tx.commit().await?; Ok(()) } From fb2f0628b530d3c59e8ee8802406bdb2d2c6c899 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Wed, 30 Oct 2024 14:00:25 +0100 Subject: [PATCH 17/25] Initial draft for groups and messages --- presage-store-sqlite/Cargo.toml | 2 + .../20241024072558_Initial_data_model.sql | 34 +-- presage-store-sqlite/src/content.rs | 257 +++++++++++++++++- presage-store-sqlite/src/error.rs | 9 + 4 files changed, 267 insertions(+), 35 deletions(-) diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index 003c337b8..dbce7c79d 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -7,9 +7,11 @@ edition = "2021" async-trait = "0.1.83" bytes = "1.8.0" chrono = "0.4.38" +hex = "0.4.3" presage = { path = "../presage" } presage-store-cipher = { path = "../presage-store-cipher", optional = true } prost = "0.13.3" +serde_json = "1.0.132" sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } thiserror = "1.0.65" diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 0caf60dad..d1183a423 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -54,32 +54,22 @@ CREATE TABLE sender_keys ( ); -- Groups -CREATE TABLE groups ( - id VARCHAR(64) PRIMARY KEY NOT NULL, - name TEXT NOT NULL, +CREATE TABLE groups( + id INTEGER PRIMARY KEY AUTOINCREMENT, master_key BLOB NOT NULL, + title TEXT NOT NULL, revision INTEGER NOT NULL DEFAULT 0, invite_link_password BLOB, access_required_for_attributes INTEGER NOT NULL DEFAULT 0, access_required_for_members INTEGER NOT NULL DEFAULT 0, access_required_for_add_from_invite_link INTEGER NOT NULL DEFAULT 0, - avatar TEXT, - description TEXT + avatar TEXT NOT NULL, + description TEXT, + members BLOB NOT NULL, + pending_members BLOB NOT NULL, + requesting_members BLOB NOT NULL ); -CREATE TABLE group_members ( - group_id VARCHAR(64) NOT NULL, - recipient_id INTEGER NOT NULL, - member_since TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - joined_at_revision INTEGER NOT NULL, - role INTEGER NOT NULL, - - FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE, - -- FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE RESTRICT, - PRIMARY KEY(group_id, recipient_id) -); -CREATE INDEX group_member_recipient_id ON group_members(recipient_id DESC); -CREATE INDEX group_member_id ON group_members(group_id); CREATE TABLE contacts( uuid VARCHAR(36) NOT NULL, @@ -128,11 +118,10 @@ CREATE TABLE profiles( -- Threads CREATE TABLE threads ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, - group_id VARCHAR(64) DEFAULT NULL, + group_id BLOB DEFAULT NULL, recipient_id VARCHAR(36) DEFAULT NULL, - FOREIGN KEY(group_id) REFERENCES groups(id) ON UPDATE CASCADE - -- FOREIGN KEY(recipient_id) REFERENCES recipients(id) ON UPDATE CASCADE + FOREIGN KEY(id) REFERENCES groups(id) ON DELETE CASCADE ); CREATE TABLE thread_messages( @@ -140,7 +129,8 @@ CREATE TABLE thread_messages( thread_id INTEGER NOT NULL, sender_service_id TEXT NOT NULL, - -- destination_service_id TEXT NOT NULL, + sender_device_id INTEGER NOT NULL, + destination_service_id TEXT NOT NULL, needs_receipt BOOLEAN NOT NULL, unidentified_sender BOOLEAN NOT NULL, diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index e3b5653ac..9f78d037c 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -3,21 +3,27 @@ use std::marker::PhantomData; use bytes::Bytes; use presage::{ libsignal_service::{ - content::Metadata, + self, + content::{ContentBody, Metadata}, models::Attachment, prelude::{ phonenumber::{self, PhoneNumber}, - Content, ProfileKey, + AccessControl, Content, GroupMasterKey, Member, ProfileKey, ServiceError, }, profile_name::ProfileName, + protocol::ServiceId, zkgroup::{self, GroupMasterKeyBytes}, - Profile, + Profile, ServiceAddress, }, - model::{contacts::Contact, groups::Group}, - proto::{verified, Verified}, + model::{ + contacts::Contact, + groups::{Group, PendingMember, RequestingMember}, + }, + proto::{self, verified, Verified}, store::{ContentsStore, StickerPack, Thread}, }; use sqlx::{query, query_as, query_scalar, types::Uuid}; +use uuid::timestamp; use crate::{SqliteStore, SqliteStoreError}; @@ -89,10 +95,10 @@ impl ContentsStore for SqliteStore { let proto_bytes = prost::Message::encode_to_vec(&body.into_proto()); - let timestamp = timestamp as i64; // danger + let timestamp: i64 = timestamp.try_into()?; query!( - "INSERT INTO + "INSERT INTO thread_messages(ts, thread_id, sender_service_id, needs_receipt, unidentified_sender, content_body) VALUES(?, ?, ?, ?, ?, ?)", timestamp, @@ -114,7 +120,37 @@ impl ContentsStore for SqliteStore { thread: &Thread, timestamp: u64, ) -> Result { - todo!() + let timestamp: i64 = timestamp.try_into()?; + let deleted: u64 = match thread { + Thread::Contact(uuid) => query_scalar!( + " + DELETE FROM thread_messages WHERE ts = ? AND thread_id IN ( + SELECT thread_id FROM threads + WHERE recipient_id = ? + )", + timestamp, + uuid + ) + .execute(&self.db) + .await? + .rows_affected(), + Thread::Group(master_key) => { + let master_key = master_key.as_slice(); + query_scalar!( + " + DELETE FROM thread_messages WHERE ts = ? AND thread_id IN ( + SELECT thread_id FROM threads + WHERE group_id = ? + )", + timestamp, + master_key + ) + .execute(&self.db) + .await? + .rows_affected() + } + }; + Ok(deleted > 0) } async fn message( @@ -122,7 +158,36 @@ impl ContentsStore for SqliteStore { thread: &Thread, timestamp: u64, ) -> Result, Self::ContentsStoreError> { - todo!() + let timestamp: i64 = timestamp.try_into()?; + let message: Option = match thread { + Thread::Contact(uuid) => { + query_as!( + SqlMessage, + "SELECT * FROM thread_messages WHERE ts = ? AND thread_id = ( + SELECT thread_id FROM threads WHERE recipient_id = ? LIMIT 1 + )", + timestamp, + uuid + ) + .fetch_optional(&self.db) + .await? + } + Thread::Group(master_key) => { + let master_key = master_key.as_slice(); + query_as!( + SqlMessage, + "SELECT * FROM thread_messages WHERE ts = ? AND thread_id = ( + SELECT thread_id FROM threads WHERE group_id = ? LIMIT 1 + )", + timestamp, + master_key + ) + .fetch_optional(&self.db) + .await? + } + }; + + message.map(TryInto::try_into).transpose() } async fn messages( @@ -194,7 +259,7 @@ impl ContentsStore for SqliteStore { SqlContact, "SELECT * FROM contacts c - LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci + LEFT JOIN contacts_verification_state cv ON c.uuid = cv.destination_aci ORDER BY inbox_position " ) @@ -237,18 +302,65 @@ impl ContentsStore for SqliteStore { master_key: zkgroup::GroupMasterKeyBytes, group: impl Into, ) -> Result<(), Self::ContentsStoreError> { - todo!() + let group = SqlGroup::from_group(master_key, group.into())?; + query_as!( + SqlGroup, + "INSERT INTO groups( + id, + master_key, + title, + revision, + invite_link_password, + access_required_for_attributes, + access_required_for_members, + access_required_for_add_from_invite_link, + avatar, + description, + members, + pending_members, + requesting_members + ) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + group.master_key, + group.title, + group.revision, + group.invite_link_password, + group.access_required_for_attributes, + group.access_required_for_members, + group.access_required_for_add_from_invite_link, + group.avatar, + group.description, + group.members, + group.pending_members, + group.requesting_members, + ) + .execute(&self.db) + .await?; + Ok(()) } async fn groups(&self) -> Result { - todo!() + let groups = query_as!(SqlGroup, "SELECT * FROM groups") + .fetch_all(&self.db) + .await? + .into_iter() + .map(|g| { + let group_master_key_bytes: GroupMasterKeyBytes = + g.master_key.clone().try_into().expect("invalid master key"); + let group = g.into_group()?; + Ok((group_master_key_bytes, group)) + }); + Ok(Box::new(groups)) } async fn group( &self, master_key: zkgroup::GroupMasterKeyBytes, ) -> Result, Self::ContentsStoreError> { - todo!() + query_as!(SqlGroup, "SELECT * FROM groups") + .fetch_optional(&self.db) + .await? + .map(|g| g.into_group()) + .transpose() } async fn save_group_avatar( @@ -458,3 +570,122 @@ impl TryInto for SqlProfile { }) } } + +fn thread_key(thread: &Thread) -> String { + match thread { + Thread::Contact(uuid) => format!("contact:{uuid}"), + Thread::Group(ref master_key_bytes) => format!("group:{}", hex::encode(master_key_bytes)), + } +} + +struct SqlMessage { + ts: i64, + thread_id: i64, + + sender_service_id: String, + sender_device_id: i64, + destination_service_id: String, + needs_receipt: bool, + unidentified_sender: bool, + + content_body: Vec, +} + +impl TryInto for SqlMessage { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + let body: proto::Content = prost::Message::decode(&self.content_body[..]).unwrap(); + let sender_service_id = + ServiceId::parse_from_service_id_string(&self.sender_service_id).unwrap(); + let destination_service_id = + ServiceId::parse_from_service_id_string(&self.destination_service_id).unwrap(); + Content::from_proto( + body, + Metadata { + sender: sender_service_id.into(), + destination: destination_service_id.into(), + sender_device: self.sender_device_id.try_into().unwrap(), + timestamp: self.ts.try_into().unwrap(), + needs_receipt: self.needs_receipt, + unidentified_sender: self.unidentified_sender, + server_guid: None, + }, + ) + .map_err(|err| SqliteStoreError::InvalidFormat) + } +} + +struct SqlGroup { + pub id: Option, + pub master_key: Vec, + pub title: String, + pub revision: i64, + pub invite_link_password: Option>, + pub access_required_for_attributes: i64, + pub access_required_for_members: i64, + pub access_required_for_add_from_invite_link: i64, + pub avatar: String, + pub description: Option, + pub members: Vec, + pub pending_members: Vec, + pub requesting_members: Vec, +} + +impl SqlGroup { + fn from_group( + master_key: GroupMasterKeyBytes, + group: Group, + ) -> Result { + let ( + access_required_for_attributes, + access_required_for_members, + access_required_for_add_from_invite_link, + ) = match group.access_control { + Some(AccessControl { + attributes, + members, + add_from_invite_link, + }) => { + // TODO: talk to Ruben about making AccessRequired some indexed enum? with repr(u8) + (0, 0, 0) + } + None => (0, 0, 0), + }; + + Ok(SqlGroup { + id: None, + master_key: master_key.to_vec(), + title: group.title, + revision: group.revision as i64, + invite_link_password: Some(group.invite_link_password), + access_required_for_attributes: 0, + access_required_for_members: 0, + access_required_for_add_from_invite_link: 0, + avatar: group.avatar, + description: group.description, + members: serde_json::to_vec(&group.members)?, + pending_members: serde_json::to_vec(&group.pending_members)?, + requesting_members: serde_json::to_vec(&group.requesting_members)?, + }) + } + + fn into_group(self) -> Result { + let members: Vec = serde_json::from_slice(&self.members)?; + let pending_members: Vec = serde_json::from_slice(&self.pending_members)?; + let requesting_members: Vec = + serde_json::from_slice(&self.requesting_members)?; + Ok(Group { + title: self.title, + avatar: self.avatar, + disappearing_messages_timer: None, + access_control: None, + revision: self.revision.try_into()?, + members, + pending_members, + requesting_members, + invite_link_password: self.invite_link_password.unwrap_or_default(), + description: self.description, + }) + } +} diff --git a/presage-store-sqlite/src/error.rs b/presage-store-sqlite/src/error.rs index 32bc5ee51..0263da6f1 100644 --- a/presage-store-sqlite/src/error.rs +++ b/presage-store-sqlite/src/error.rs @@ -11,6 +11,15 @@ pub enum SqliteStoreError { PhoneNumber(#[from] phonenumber::ParseError), #[error("error parsing UUID: {0}")] Uuid(#[from] uuid::Error), + + #[error("failed to convert int: {0}")] + TryFromInt(#[from] std::num::TryFromIntError), + + #[error("invalid format")] + InvalidFormat, + + #[error("serde_json error: {0}")] + Json(#[from] serde_json::Error), } impl StoreError for SqliteStoreError {} From 96ae380d46a1bedd3f6e5aea2befd2aac57bd450 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Wed, 30 Oct 2024 14:10:14 +0100 Subject: [PATCH 18/25] Extract thread_id --- presage-store-sqlite/src/content.rs | 86 ++++++++++++++++------------- 1 file changed, 49 insertions(+), 37 deletions(-) diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 9f78d037c..f93e86c57 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -23,6 +23,7 @@ use presage::{ store::{ContentsStore, StickerPack, Thread}, }; use sqlx::{query, query_as, query_scalar, types::Uuid}; +use tracing::warn; use uuid::timestamp; use crate::{SqliteStore, SqliteStoreError}; @@ -45,15 +46,22 @@ impl ContentsStore for SqliteStore { } async fn clear_contents(&mut self) -> Result<(), Self::ContentsStoreError> { - todo!() + Ok(()) } async fn clear_messages(&mut self) -> Result<(), Self::ContentsStoreError> { - todo!() + query!("DELETE FROM threads").execute(&self.db).await?; + Ok(()) } async fn clear_thread(&mut self, thread: &Thread) -> Result<(), Self::ContentsStoreError> { - todo!() + if let Some(thread_id) = self.thread_id(thread).await? { + query!("DELETE FROM thread_messages WHERE thread_id = ?", thread_id) + .execute(&self.db) + .await?; + }; + + Ok(()) } async fn save_message( @@ -159,35 +167,22 @@ impl ContentsStore for SqliteStore { timestamp: u64, ) -> Result, Self::ContentsStoreError> { let timestamp: i64 = timestamp.try_into()?; - let message: Option = match thread { - Thread::Contact(uuid) => { - query_as!( - SqlMessage, - "SELECT * FROM thread_messages WHERE ts = ? AND thread_id = ( - SELECT thread_id FROM threads WHERE recipient_id = ? LIMIT 1 - )", - timestamp, - uuid - ) - .fetch_optional(&self.db) - .await? - } - Thread::Group(master_key) => { - let master_key = master_key.as_slice(); - query_as!( - SqlMessage, - "SELECT * FROM thread_messages WHERE ts = ? AND thread_id = ( - SELECT thread_id FROM threads WHERE group_id = ? LIMIT 1 - )", - timestamp, - master_key - ) - .fetch_optional(&self.db) - .await? - } + let Some(thread_id) = self.thread_id(thread).await? else { + warn!("no thread found"); + // TODO: return error? + return Ok(None); }; - message.map(TryInto::try_into).transpose() + query_as!( + SqlMessage, + "SELECT * FROM thread_messages WHERE ts = ? AND thread_id = ?", + timestamp, + thread_id + ) + .fetch_optional(&self.db) + .await? + .map(TryInto::try_into) + .transpose() } async fn messages( @@ -491,6 +486,30 @@ impl ContentsStore for SqliteStore { } } +impl SqliteStore { + async fn thread_id(&self, thread: &Thread) -> Result, SqliteStoreError> { + Ok(match thread { + Thread::Contact(uuid) => { + query_scalar!( + "SELECT id FROM threads WHERE recipient_id = ? LIMIT 1", + uuid + ) + .fetch_optional(&self.db) + .await? + } + Thread::Group(master_key) => { + let master_key = master_key.as_slice(); + query_scalar!( + "SELECT id FROM threads WHERE group_id = ? LIMIT 1", + master_key + ) + .fetch_optional(&self.db) + .await? + } + }) + } +} + struct SqlContact { uuid: String, phone_number: Option, @@ -571,13 +590,6 @@ impl TryInto for SqlProfile { } } -fn thread_key(thread: &Thread) -> String { - match thread { - Thread::Contact(uuid) => format!("contact:{uuid}"), - Thread::Group(ref master_key_bytes) => format!("group:{}", hex::encode(master_key_bytes)), - } -} - struct SqlMessage { ts: i64, thread_id: i64, From cc22572af62a1dc0a26b34e67597d0c0b7c81c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Wed, 30 Oct 2024 16:44:28 +0100 Subject: [PATCH 19/25] Only one todo! left --- .../20241024072558_Initial_data_model.sql | 26 +++- presage-store-sqlite/src/content.rs | 129 ++++++++++++++++-- presage-store-sqlite/src/lib.rs | 45 +++++- presage-store-sqlite/src/protocol.rs | 10 +- 4 files changed, 189 insertions(+), 21 deletions(-) diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index d1183a423..61183e908 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -1,3 +1,8 @@ +CREATE TABLE config( + key TEXT PRIMARY KEY NOT NULL, + value BLOB NOT NULL +); + CREATE TABLE sessions ( address VARCHAR(36) NOT NULL, device_id INTEGER NOT NULL, @@ -70,6 +75,12 @@ CREATE TABLE groups( requesting_members BLOB NOT NULL ); +CREATE TABLE group_avatars( + id INTEGER PRIMARY KEY AUTOINCREMENT, + bytes BLOB NOT NULL, + + FOREIGN KEY(id) REFERENCES groups(id) ON DELETE CASCADE +); CREATE TABLE contacts( uuid VARCHAR(36) NOT NULL, @@ -115,6 +126,13 @@ CREATE TABLE profiles( PRIMARY KEY(uuid) ON CONFLICT REPLACE ); +CREATE TABLE profile_avatars( + uuid VARCHAR(36) NOT NULL, + bytes BLOB NOT NULL, + + FOREIGN KEY(uuid) REFERENCES profile_keys(uuid) ON UPDATE CASCADE +); + -- Threads CREATE TABLE threads ( id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, @@ -138,4 +156,10 @@ CREATE TABLE thread_messages( PRIMARY KEY(ts, thread_id) ON CONFLICT REPLACE, FOREIGN KEY(thread_id) REFERENCES threads(id) ON UPDATE CASCADE -); \ No newline at end of file +); + +CREATE TABLE sticker_packs( + id BLOB PRIMARY KEY NOT NULL, + key BLOB NOT NULL, + manifest BLOB NOT NULL +); diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index f93e86c57..6412fc3e3 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -22,7 +22,7 @@ use presage::{ proto::{self, verified, Verified}, store::{ContentsStore, StickerPack, Thread}, }; -use sqlx::{query, query_as, query_scalar, types::Uuid}; +use sqlx::{query, query_as, query_scalar, types::Uuid, QueryBuilder, Sqlite}; use tracing::warn; use uuid::timestamp; @@ -190,7 +190,44 @@ impl ContentsStore for SqliteStore { thread: &Thread, range: impl std::ops::RangeBounds, ) -> Result { - todo!() + let Some(thread_id) = self.thread_id(thread).await? else { + warn!("no thread found"); + // TODO: return error? + return Ok(Box::new(std::iter::empty())); + }; + + let start = range.start_bound(); + + let end = range.end_bound(); + + let mut query_builder: QueryBuilder = + QueryBuilder::new("SELECT * FROM thread_messages WHERE thread_id = "); + query_builder.push_bind(thread_id); + match range.start_bound() { + std::ops::Bound::Included(ts) => { + query_builder.push("AND ts >= "); + query_builder.push_bind(*ts as i64); + } + std::ops::Bound::Excluded(ts) => { + query_builder.push("AND ts > "); + query_builder.push_bind(*ts as i64); + } + std::ops::Bound::Unbounded => (), + } + match range.end_bound() { + std::ops::Bound::Included(ts) => { + query_builder.push("AND ts <= "); + query_builder.push_bind(*ts as i64); + } + std::ops::Bound::Excluded(ts) => { + query_builder.push("AND ts < "); + query_builder.push_bind(*ts as i64); + } + std::ops::Bound::Unbounded => (), + } + + let messages: Vec = query_builder.build_query_as().fetch_all(&self.db).await?; + Ok(Box::new(messages.into_iter().map(TryInto::try_into))) } async fn clear_contacts(&mut self) -> Result<(), Self::ContentsStoreError> { @@ -363,14 +400,31 @@ impl ContentsStore for SqliteStore { master_key: zkgroup::GroupMasterKeyBytes, avatar: &presage::AvatarBytes, ) -> Result<(), Self::ContentsStoreError> { - todo!() + let mut tx = self.db.begin().await?; + + let group_id = self.group_id(&master_key).await?; + query!( + "INSERT INTO group_avatars(id, bytes) VALUES(?, ?)", + group_id, + avatar + ) + .execute(&mut *tx) + .await?; + + tx.commit().await?; + + Ok(()) } async fn group_avatar( &self, master_key: zkgroup::GroupMasterKeyBytes, ) -> Result, Self::ContentsStoreError> { - todo!() + let group_id = self.group_id(&master_key).await?; + query_scalar!("SELECT bytes FROM group_avatars WHERE id = ?", group_id) + .fetch_optional(&self.db) + .await + .map_err(Into::into) } async fn upsert_profile_key( @@ -422,7 +476,7 @@ impl ContentsStore for SqliteStore { ) .execute(&self.db) .await?; - todo!() + Ok(()) } async fn profile( @@ -449,10 +503,18 @@ impl ContentsStore for SqliteStore { async fn save_profile_avatar( &mut self, uuid: Uuid, - key: ProfileKey, + _key: ProfileKey, profile: &presage::AvatarBytes, ) -> Result<(), Self::ContentsStoreError> { - todo!() + query!( + "INSERT INTO profile_avatars(uuid, bytes) VALUES(?, ?)", + uuid, + profile + ) + .execute(&self.db) + .await?; + + Ok(()) } async fn profile_avatar( @@ -460,33 +522,75 @@ impl ContentsStore for SqliteStore { uuid: Uuid, key: ProfileKey, ) -> Result, Self::ContentsStoreError> { - todo!() + query_scalar!("SELECT bytes FROM profile_avatars WHERE uuid = ?", uuid) + .fetch_optional(&self.db) + .await + .map_err(Into::into) } async fn add_sticker_pack( &mut self, pack: &StickerPack, ) -> Result<(), Self::ContentsStoreError> { - todo!() + let manifest_json = serde_json::to_vec(&pack.manifest)?; + query!( + "INSERT INTO sticker_packs(id, key, manifest) VALUES(?, ?, ?)", + pack.id, + pack.key, + manifest_json, + ) + .execute(&self.db) + .await?; + + Ok(()) } async fn sticker_pack( &self, id: &[u8], ) -> Result, Self::ContentsStoreError> { - todo!() + query_scalar!("SELECT manifest FROM sticker_packs WHERE id = ?", id) + .fetch_optional(&self.db) + .await? + .map(|bytes| serde_json::from_slice(&bytes).map_err(Into::into)) + .transpose() } async fn remove_sticker_pack(&mut self, id: &[u8]) -> Result { - todo!() + query!("DELETE FROM sticker_packs WHERE id = ?", id) + .execute(&self.db) + .await + .map_err(Into::into) + .map(|r| r.rows_affected() > 0) } async fn sticker_packs(&self) -> Result { - todo!() + let sticker_packs = query!("SELECT * FROM sticker_packs") + .fetch_all(&self.db) + .await? + .into_iter() + .map(|r| { + Ok(StickerPack { + id: r.id, + key: r.key, + manifest: serde_json::from_slice(&r.manifest)?, + }) + }); + Ok(Box::new(sticker_packs)) } } impl SqliteStore { + async fn group_id(&self, master_key: &[u8]) -> Result { + query_scalar!( + "SELECT id FROM groups WHERE groups.master_key = ?", + master_key + ) + .fetch_one(&self.db) + .await + .map_err(Into::into) + } + async fn thread_id(&self, thread: &Thread) -> Result, SqliteStoreError> { Ok(match thread { Thread::Contact(uuid) => { @@ -590,6 +694,7 @@ impl TryInto for SqlProfile { } } +#[derive(sqlx::FromRow)] struct SqlMessage { ts: i64, thread_id: i64, diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index f77b8364b..9ce0d033e 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -8,7 +8,9 @@ use presage::{ store::{StateStore, Store}, }; use protocol::SqliteProtocolStore; -use sqlx::{migrate::MigrateDatabase, sqlite::SqliteConnectOptions, Sqlite, SqlitePool}; +use sqlx::{ + migrate::MigrateDatabase, query, query_scalar, sqlite::SqliteConnectOptions, Sqlite, SqlitePool, +}; mod content; mod error; @@ -80,35 +82,64 @@ impl StateStore for SqliteStore { async fn load_registration_data( &self, ) -> Result, Self::StateStoreError> { - todo!() + query_scalar!("SELECT value FROM config WHERE key = 'registration'") + .fetch_optional(&self.db) + .await? + .map(|value: Vec| serde_json::from_slice(&value).map_err(Into::into)) + .transpose() } async fn set_aci_identity_key_pair( &self, key_pair: presage::libsignal_service::protocol::IdentityKeyPair, ) -> Result<(), Self::StateStoreError> { - todo!() + let key_pair_bytes = key_pair.serialize(); + query!( + "INSERT INTO config(key, value) VALUES('aci_identity_key_pair', ?)", + key_pair_bytes + ) + .execute(&self.db) + .await?; + Ok(()) } async fn set_pni_identity_key_pair( &self, key_pair: presage::libsignal_service::protocol::IdentityKeyPair, ) -> Result<(), Self::StateStoreError> { - todo!() + let key_pair_bytes = key_pair.serialize(); + query!( + "INSERT INTO config(key, value) VALUES('pni_identity_key_pair', ?)", + key_pair_bytes + ) + .execute(&self.db) + .await?; + Ok(()) } async fn save_registration_data( &mut self, state: &presage::manager::RegistrationData, ) -> Result<(), Self::StateStoreError> { - todo!() + let registration_data_json = serde_json::to_vec(&state)?; + query!( + "INSERT INTO config(key, value) VALUES('registration', ?)", + registration_data_json + ) + .execute(&self.db) + .await?; + + Ok(()) } async fn is_registered(&self) -> bool { - todo!() + self.load_registration_data().await.ok().is_some() } async fn clear_registration(&mut self) -> Result<(), Self::StateStoreError> { - todo!() + query!("DELETE FROM config WHERE key = 'registration'") + .execute(&self.db) + .await?; + Ok(()) } } diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 59b5921c0..bb6871734 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -12,6 +12,7 @@ use presage::libsignal_service::{ SignalProtocolError as ProtocolError, SignedPreKeyId, SignedPreKeyRecord, SignedPreKeyStore, }, + push_service::DEFAULT_DEVICE_ID, ServiceAddress, }; use sqlx::{query, query_scalar, Executor}; @@ -82,7 +83,14 @@ impl SessionStoreExt for SqliteProtocolStore { &self, name: &ServiceAddress, ) -> Result, ProtocolError> { - todo!() + query_scalar!( + "SELECT device_id AS 'id: u32' FROM sessions WHERE address = ? AND device_id != ?", + name.uuid, + DEFAULT_DEVICE_ID + ) + .fetch_all(&self.store.db) + .await + .into_protocol_error() } /// Remove a session record for a recipient ID + device ID tuple. From 57b4599821c3858209c6c62f8584e207b8c22a2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Wed, 30 Oct 2024 16:54:27 +0100 Subject: [PATCH 20/25] Finished --- .vscode/settings.json | 1 + presage-store-sqlite/src/lib.rs | 3 +- presage-store-sqlite/src/protocol.rs | 42 ++++++++++++++++++---------- 3 files changed, 31 insertions(+), 15 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index 9ce0d033e..eb723db9d 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -58,7 +58,8 @@ impl Store for SqliteStore { type PniStore = SqliteProtocolStore; async fn clear(&mut self) -> Result<(), SqliteStoreError> { - todo!() + query!("DELETE FROM config").execute(&self.db).await?; + Ok(()) } fn aci_protocol_store(&self) -> Self::AciStore { diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index bb6871734..4328d3458 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -2,20 +2,23 @@ use std::fmt::{self, Formatter}; use async_trait::async_trait; use chrono::{DateTime, Utc}; -use presage::libsignal_service::{ - pre_keys::{KyberPreKeyStoreExt, PreKeysStore}, - prelude::{IdentityKeyStore, SessionStoreExt, Uuid}, - protocol::{ - Direction, GenericSignedPreKey, IdentityKey, IdentityKeyPair, KyberPreKeyId, - KyberPreKeyRecord, KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, ProtocolAddress, - ProtocolStore, SenderKeyRecord, SenderKeyStore, SessionRecord, SessionStore, - SignalProtocolError as ProtocolError, SignedPreKeyId, SignedPreKeyRecord, - SignedPreKeyStore, +use presage::{ + libsignal_service::{ + pre_keys::{KyberPreKeyStoreExt, PreKeysStore}, + prelude::{IdentityKeyStore, SessionStoreExt, Uuid}, + protocol::{ + Direction, GenericSignedPreKey, IdentityKey, IdentityKeyPair, KyberPreKeyId, + KyberPreKeyRecord, KyberPreKeyStore, PreKeyId, PreKeyRecord, PreKeyStore, + ProtocolAddress, ProtocolStore, SenderKeyRecord, SenderKeyStore, SessionRecord, + SessionStore, SignalProtocolError as ProtocolError, SignedPreKeyId, SignedPreKeyRecord, + SignedPreKeyStore, + }, + push_service::DEFAULT_DEVICE_ID, + ServiceAddress, }, - push_service::DEFAULT_DEVICE_ID, - ServiceAddress, + store::StateStore, }; -use sqlx::{query, query_scalar, Executor}; +use sqlx::{query, query_scalar, Executor, QueryBuilder}; use tracing::trace; use crate::{SqliteStore, SqlxErrorExt}; @@ -390,7 +393,12 @@ impl KyberPreKeyStoreExt for SqliteProtocolStore { impl IdentityKeyStore for SqliteProtocolStore { /// Return the single specific identity the store is assumed to represent, with private key. async fn get_identity_key_pair(&self) -> Result { - todo!() + let key = format!("{}_identity_key_pair", self.identity_type); + let key_pair_bytes = query_scalar!("SELECT value FROM config WHERE key = ?", key) + .fetch_one(&self.store.db) + .await + .into_protocol_error()?; + IdentityKeyPair::try_from(key_pair_bytes.as_slice()) } /// Return a [u32] specific to this store instance. @@ -402,7 +410,13 @@ impl IdentityKeyStore for SqliteProtocolStore { /// may be the same, but the store registration id returned by this method should /// be regenerated. async fn get_local_registration_id(&self) -> Result { - todo!() + let registration_id = self + .store + .load_registration_data() + .await + .map_err(|error| ProtocolError::InvalidState("sqlite", error.to_string()))? + .map(|data| data.registration_id); + Ok(registration_id.unwrap_or_default()) } // TODO: make this into an enum instead of a bool! From 423b4b8dc304b8a78d744fd7baab01dfd2955983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 31 Oct 2024 09:03:14 +0100 Subject: [PATCH 21/25] Use postcard --- presage-store-sqlite/Cargo.toml | 2 +- presage-store-sqlite/src/content.rs | 18 +++++++++--------- presage-store-sqlite/src/error.rs | 4 ++-- presage-store-sqlite/src/lib.rs | 4 ++-- presage-store-sqlite/src/protocol.rs | 6 +++--- 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index dbce7c79d..bb8d1aa74 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -8,10 +8,10 @@ async-trait = "0.1.83" bytes = "1.8.0" chrono = "0.4.38" hex = "0.4.3" +postcard = { version = "1.0.10", features = ["alloc"] } presage = { path = "../presage" } presage-store-cipher = { path = "../presage-store-cipher", optional = true } prost = "0.13.3" -serde_json = "1.0.132" sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } thiserror = "1.0.65" diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 6412fc3e3..9d9055b24 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -532,7 +532,7 @@ impl ContentsStore for SqliteStore { &mut self, pack: &StickerPack, ) -> Result<(), Self::ContentsStoreError> { - let manifest_json = serde_json::to_vec(&pack.manifest)?; + let manifest_json = postcard::to_allocvec(&pack.manifest)?; query!( "INSERT INTO sticker_packs(id, key, manifest) VALUES(?, ?, ?)", pack.id, @@ -552,7 +552,7 @@ impl ContentsStore for SqliteStore { query_scalar!("SELECT manifest FROM sticker_packs WHERE id = ?", id) .fetch_optional(&self.db) .await? - .map(|bytes| serde_json::from_slice(&bytes).map_err(Into::into)) + .map(|bytes| postcard::from_bytes(&bytes).map_err(Into::into)) .transpose() } @@ -573,7 +573,7 @@ impl ContentsStore for SqliteStore { Ok(StickerPack { id: r.id, key: r.key, - manifest: serde_json::from_slice(&r.manifest)?, + manifest: postcard::from_bytes(&r.manifest)?, }) }); Ok(Box::new(sticker_packs)) @@ -781,17 +781,17 @@ impl SqlGroup { access_required_for_add_from_invite_link: 0, avatar: group.avatar, description: group.description, - members: serde_json::to_vec(&group.members)?, - pending_members: serde_json::to_vec(&group.pending_members)?, - requesting_members: serde_json::to_vec(&group.requesting_members)?, + members: postcard::to_allocvec(&group.members)?, + pending_members: postcard::to_allocvec(&group.pending_members)?, + requesting_members: postcard::to_allocvec(&group.requesting_members)?, }) } fn into_group(self) -> Result { - let members: Vec = serde_json::from_slice(&self.members)?; - let pending_members: Vec = serde_json::from_slice(&self.pending_members)?; + let members: Vec = postcard::from_bytes(&self.members)?; + let pending_members: Vec = postcard::from_bytes(&self.pending_members)?; let requesting_members: Vec = - serde_json::from_slice(&self.requesting_members)?; + postcard::from_bytes(&self.requesting_members)?; Ok(Group { title: self.title, avatar: self.avatar, diff --git a/presage-store-sqlite/src/error.rs b/presage-store-sqlite/src/error.rs index 0263da6f1..d3d856858 100644 --- a/presage-store-sqlite/src/error.rs +++ b/presage-store-sqlite/src/error.rs @@ -18,8 +18,8 @@ pub enum SqliteStoreError { #[error("invalid format")] InvalidFormat, - #[error("serde_json error: {0}")] - Json(#[from] serde_json::Error), + #[error(transparent)] + Postcard(#[from] postcard::Error), } impl StoreError for SqliteStoreError {} diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index eb723db9d..8b7cc271d 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -86,7 +86,7 @@ impl StateStore for SqliteStore { query_scalar!("SELECT value FROM config WHERE key = 'registration'") .fetch_optional(&self.db) .await? - .map(|value: Vec| serde_json::from_slice(&value).map_err(Into::into)) + .map(|value: Vec| postcard::from_bytes(&value).map_err(Into::into)) .transpose() } @@ -122,7 +122,7 @@ impl StateStore for SqliteStore { &mut self, state: &presage::manager::RegistrationData, ) -> Result<(), Self::StateStoreError> { - let registration_data_json = serde_json::to_vec(&state)?; + let registration_data_json = postcard::to_allocvec(&state)?; query!( "INSERT INTO config(key, value) VALUES('registration', ?)", registration_data_json diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 4328d3458..72ac35d6e 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -410,13 +410,13 @@ impl IdentityKeyStore for SqliteProtocolStore { /// may be the same, but the store registration id returned by this method should /// be regenerated. async fn get_local_registration_id(&self) -> Result { - let registration_id = self + Ok(self .store .load_registration_data() .await .map_err(|error| ProtocolError::InvalidState("sqlite", error.to_string()))? - .map(|data| data.registration_id); - Ok(registration_id.unwrap_or_default()) + .map(|data| data.registration_id) + .unwrap_or_default()) } // TODO: make this into an enum instead of a bool! From 1317f6a5661dbc5ba31def97283f8a80e8a99052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 31 Oct 2024 09:08:48 +0100 Subject: [PATCH 22/25] Serialize AccessAttributes --- .../20241024072558_Initial_data_model.sql | 4 +- presage-store-sqlite/src/content.rs | 37 ++++--------------- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 61183e908..7051b7094 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -65,9 +65,7 @@ CREATE TABLE groups( title TEXT NOT NULL, revision INTEGER NOT NULL DEFAULT 0, invite_link_password BLOB, - access_required_for_attributes INTEGER NOT NULL DEFAULT 0, - access_required_for_members INTEGER NOT NULL DEFAULT 0, - access_required_for_add_from_invite_link INTEGER NOT NULL DEFAULT 0, + access_required BLOB, avatar TEXT NOT NULL, description TEXT, members BLOB NOT NULL, diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 9d9055b24..1f4e93a06 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -343,22 +343,18 @@ impl ContentsStore for SqliteStore { title, revision, invite_link_password, - access_required_for_attributes, - access_required_for_members, - access_required_for_add_from_invite_link, + access_required, avatar, description, members, pending_members, requesting_members - ) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", + ) VALUES (NULL, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", group.master_key, group.title, group.revision, group.invite_link_password, - group.access_required_for_attributes, - group.access_required_for_members, - group.access_required_for_add_from_invite_link, + group.access_required, group.avatar, group.description, group.members, @@ -739,9 +735,7 @@ struct SqlGroup { pub title: String, pub revision: i64, pub invite_link_password: Option>, - pub access_required_for_attributes: i64, - pub access_required_for_members: i64, - pub access_required_for_add_from_invite_link: i64, + pub access_required: Option>, pub avatar: String, pub description: Option, pub members: Vec, @@ -754,31 +748,16 @@ impl SqlGroup { master_key: GroupMasterKeyBytes, group: Group, ) -> Result { - let ( - access_required_for_attributes, - access_required_for_members, - access_required_for_add_from_invite_link, - ) = match group.access_control { - Some(AccessControl { - attributes, - members, - add_from_invite_link, - }) => { - // TODO: talk to Ruben about making AccessRequired some indexed enum? with repr(u8) - (0, 0, 0) - } - None => (0, 0, 0), - }; - Ok(SqlGroup { id: None, master_key: master_key.to_vec(), title: group.title, revision: group.revision as i64, invite_link_password: Some(group.invite_link_password), - access_required_for_attributes: 0, - access_required_for_members: 0, - access_required_for_add_from_invite_link: 0, + access_required: group + .access_control + .map(|ac| postcard::to_allocvec(&ac)) + .transpose()?, avatar: group.avatar, description: group.description, members: postcard::to_allocvec(&group.members)?, From 8df7e3f14a4e39bbefb603fd29ba60563969ed5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 31 Oct 2024 09:18:28 +0100 Subject: [PATCH 23/25] Move files --- presage-store-sqlite/src/content.rs | 181 +------------------------ presage-store-sqlite/src/data.rs | 198 ++++++++++++++++++++++++++++ presage-store-sqlite/src/lib.rs | 1 + 3 files changed, 203 insertions(+), 177 deletions(-) create mode 100644 presage-store-sqlite/src/data.rs diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 1f4e93a06..57ef445c7 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -26,7 +26,10 @@ use sqlx::{query, query_as, query_scalar, types::Uuid, QueryBuilder, Sqlite}; use tracing::warn; use uuid::timestamp; -use crate::{SqliteStore, SqliteStoreError}; +use crate::{ + data::{SqlContact, SqlGroup, SqlMessage, SqlProfile}, + SqliteStore, SqliteStoreError, +}; impl ContentsStore for SqliteStore { type ContentsStoreError = SqliteStoreError; @@ -609,179 +612,3 @@ impl SqliteStore { }) } } - -struct SqlContact { - uuid: String, - phone_number: Option, - name: String, - color: Option, - profile_key: Vec, - expire_timer: i64, - expire_timer_version: i64, - inbox_position: i64, - archived: bool, - avatar: Option>, - - destination_aci: Option, - identity_key: Option>, - is_verified: Option, -} - -impl TryInto for SqlContact { - type Error = SqliteStoreError; - - fn try_into(self) -> Result { - Ok(Contact { - uuid: self.uuid.parse()?, - phone_number: self - .phone_number - .map(|p| phonenumber::parse(None, &p)) - .transpose()?, - name: self.name, - color: self.color, - verified: Verified { - destination_aci: self.destination_aci, - identity_key: self.identity_key, - state: self.is_verified.map(|v| { - match v { - true => verified::State::Verified, - false => verified::State::Unverified, - } - .into() - }), - null_message: None, - }, - profile_key: self.profile_key, - expire_timer: self.expire_timer as u32, - expire_timer_version: self.expire_timer_version as u32, - inbox_position: self.inbox_position as u32, - archived: self.archived, - avatar: self.avatar.map(|b| Attachment { - content_type: "application/octet-stream".into(), - reader: Bytes::from(b), - }), - }) - } -} - -struct SqlProfile { - uuid: String, - key: Vec, - given_name: Option, - family_name: Option, - about: Option, - about_emoji: Option, - avatar: Option, -} - -impl TryInto for SqlProfile { - type Error = SqliteStoreError; - - fn try_into(self) -> Result { - Ok(Profile { - name: self.given_name.map(|gn| ProfileName { - given_name: gn, - family_name: self.family_name, - }), - about: self.about, - about_emoji: self.about_emoji, - avatar: self.avatar, - }) - } -} - -#[derive(sqlx::FromRow)] -struct SqlMessage { - ts: i64, - thread_id: i64, - - sender_service_id: String, - sender_device_id: i64, - destination_service_id: String, - needs_receipt: bool, - unidentified_sender: bool, - - content_body: Vec, -} - -impl TryInto for SqlMessage { - type Error = SqliteStoreError; - - fn try_into(self) -> Result { - let body: proto::Content = prost::Message::decode(&self.content_body[..]).unwrap(); - let sender_service_id = - ServiceId::parse_from_service_id_string(&self.sender_service_id).unwrap(); - let destination_service_id = - ServiceId::parse_from_service_id_string(&self.destination_service_id).unwrap(); - Content::from_proto( - body, - Metadata { - sender: sender_service_id.into(), - destination: destination_service_id.into(), - sender_device: self.sender_device_id.try_into().unwrap(), - timestamp: self.ts.try_into().unwrap(), - needs_receipt: self.needs_receipt, - unidentified_sender: self.unidentified_sender, - server_guid: None, - }, - ) - .map_err(|err| SqliteStoreError::InvalidFormat) - } -} - -struct SqlGroup { - pub id: Option, - pub master_key: Vec, - pub title: String, - pub revision: i64, - pub invite_link_password: Option>, - pub access_required: Option>, - pub avatar: String, - pub description: Option, - pub members: Vec, - pub pending_members: Vec, - pub requesting_members: Vec, -} - -impl SqlGroup { - fn from_group( - master_key: GroupMasterKeyBytes, - group: Group, - ) -> Result { - Ok(SqlGroup { - id: None, - master_key: master_key.to_vec(), - title: group.title, - revision: group.revision as i64, - invite_link_password: Some(group.invite_link_password), - access_required: group - .access_control - .map(|ac| postcard::to_allocvec(&ac)) - .transpose()?, - avatar: group.avatar, - description: group.description, - members: postcard::to_allocvec(&group.members)?, - pending_members: postcard::to_allocvec(&group.pending_members)?, - requesting_members: postcard::to_allocvec(&group.requesting_members)?, - }) - } - - fn into_group(self) -> Result { - let members: Vec = postcard::from_bytes(&self.members)?; - let pending_members: Vec = postcard::from_bytes(&self.pending_members)?; - let requesting_members: Vec = - postcard::from_bytes(&self.requesting_members)?; - Ok(Group { - title: self.title, - avatar: self.avatar, - disappearing_messages_timer: None, - access_control: None, - revision: self.revision.try_into()?, - members, - pending_members, - requesting_members, - invite_link_password: self.invite_link_password.unwrap_or_default(), - description: self.description, - }) - } -} diff --git a/presage-store-sqlite/src/data.rs b/presage-store-sqlite/src/data.rs new file mode 100644 index 000000000..9b11f1788 --- /dev/null +++ b/presage-store-sqlite/src/data.rs @@ -0,0 +1,198 @@ +use bytes::Bytes; +use presage::{ + libsignal_service::{ + content::Metadata, + models::Attachment, + prelude::{phonenumber, Content}, + profile_name::ProfileName, + protocol::ServiceId, + zkgroup::GroupMasterKeyBytes, + Profile, + }, + model::{ + contacts::Contact, + groups::{Group, Member, PendingMember, RequestingMember}, + }, + proto::{self, verified, Verified}, +}; + +use crate::SqliteStoreError; + +#[derive(sqlx::FromRow)] +pub struct SqlContact { + pub uuid: String, + pub phone_number: Option, + pub name: String, + pub color: Option, + pub profile_key: Vec, + pub expire_timer: i64, + pub expire_timer_version: i64, + pub inbox_position: i64, + pub archived: bool, + pub avatar: Option>, + + pub destination_aci: Option, + pub identity_key: Option>, + pub is_verified: Option, +} + +impl TryInto for SqlContact { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + Ok(Contact { + uuid: self.uuid.parse()?, + phone_number: self + .phone_number + .map(|p| phonenumber::parse(None, &p)) + .transpose()?, + name: self.name, + color: self.color, + verified: Verified { + destination_aci: self.destination_aci, + identity_key: self.identity_key, + state: self.is_verified.map(|v| { + match v { + true => verified::State::Verified, + false => verified::State::Unverified, + } + .into() + }), + null_message: None, + }, + profile_key: self.profile_key, + expire_timer: self.expire_timer as u32, + expire_timer_version: self.expire_timer_version as u32, + inbox_position: self.inbox_position as u32, + archived: self.archived, + avatar: self.avatar.map(|b| Attachment { + content_type: "application/octet-stream".into(), + reader: Bytes::from(b), + }), + }) + } +} + +#[derive(sqlx::FromRow)] +pub struct SqlProfile { + pub uuid: String, + pub key: Vec, + pub given_name: Option, + pub family_name: Option, + pub about: Option, + pub about_emoji: Option, + pub avatar: Option, +} + +impl TryInto for SqlProfile { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + Ok(Profile { + name: self.given_name.map(|gn| ProfileName { + given_name: gn, + family_name: self.family_name, + }), + about: self.about, + about_emoji: self.about_emoji, + avatar: self.avatar, + }) + } +} + +#[derive(sqlx::FromRow)] +pub struct SqlGroup { + pub id: Option, + pub master_key: Vec, + pub title: String, + pub revision: i64, + pub invite_link_password: Option>, + pub access_required: Option>, + pub avatar: String, + pub description: Option, + pub members: Vec, + pub pending_members: Vec, + pub requesting_members: Vec, +} + +impl SqlGroup { + pub fn from_group( + master_key: GroupMasterKeyBytes, + group: Group, + ) -> Result { + Ok(SqlGroup { + id: None, + master_key: master_key.to_vec(), + title: group.title, + revision: group.revision as i64, + invite_link_password: Some(group.invite_link_password), + access_required: group + .access_control + .map(|ac| postcard::to_allocvec(&ac)) + .transpose()?, + avatar: group.avatar, + description: group.description, + members: postcard::to_allocvec(&group.members)?, + pending_members: postcard::to_allocvec(&group.pending_members)?, + requesting_members: postcard::to_allocvec(&group.requesting_members)?, + }) + } + + pub fn into_group(self) -> Result { + let members: Vec = postcard::from_bytes(&self.members)?; + let pending_members: Vec = postcard::from_bytes(&self.pending_members)?; + let requesting_members: Vec = + postcard::from_bytes(&self.requesting_members)?; + Ok(Group { + title: self.title, + avatar: self.avatar, + disappearing_messages_timer: None, + access_control: None, + revision: self.revision.try_into()?, + members, + pending_members, + requesting_members, + invite_link_password: self.invite_link_password.unwrap_or_default(), + description: self.description, + }) + } +} + +#[derive(sqlx::FromRow)] +pub struct SqlMessage { + pub ts: i64, + pub thread_id: i64, + + pub sender_service_id: String, + pub sender_device_id: i64, + pub destination_service_id: String, + pub needs_receipt: bool, + pub unidentified_sender: bool, + + pub content_body: Vec, +} + +impl TryInto for SqlMessage { + type Error = SqliteStoreError; + + fn try_into(self) -> Result { + let body: proto::Content = prost::Message::decode(&self.content_body[..]).unwrap(); + let sender_service_id = + ServiceId::parse_from_service_id_string(&self.sender_service_id).unwrap(); + let destination_service_id = + ServiceId::parse_from_service_id_string(&self.destination_service_id).unwrap(); + Content::from_proto( + body, + Metadata { + sender: sender_service_id.into(), + destination: destination_service_id.into(), + sender_device: self.sender_device_id.try_into().unwrap(), + timestamp: self.ts.try_into().unwrap(), + needs_receipt: self.needs_receipt, + unidentified_sender: self.unidentified_sender, + server_guid: None, + }, + ) + .map_err(|err| SqliteStoreError::InvalidFormat) + } +} diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index 8b7cc271d..eed4946de 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -13,6 +13,7 @@ use sqlx::{ }; mod content; +pub(crate) mod data; mod error; mod protocol; From 60aca1f1e720c7a6e5e46805f73996b6fd4b30c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 31 Oct 2024 10:15:52 +0100 Subject: [PATCH 24/25] Getting there --- presage-cli/Cargo.toml | 8 ++++- presage-cli/src/main.rs | 16 ++++++--- presage-store-sqlite/Cargo.toml | 2 +- .../20241024072558_Initial_data_model.sql | 2 +- presage-store-sqlite/src/content.rs | 33 ++++++++++++------- presage-store-sqlite/src/data.rs | 13 +++++--- presage-store-sqlite/src/error.rs | 5 +-- presage-store-sqlite/src/lib.rs | 26 +++++++++++++-- presage-store-sqlite/src/protocol.rs | 2 +- presage/src/manager/registered.rs | 7 +++- presage/src/model/groups.rs | 25 ++++++++++++-- presage/src/serde.rs | 3 ++ 12 files changed, 111 insertions(+), 31 deletions(-) diff --git a/presage-cli/Cargo.toml b/presage-cli/Cargo.toml index 738d810ac..fcf070838 100644 --- a/presage-cli/Cargo.toml +++ b/presage-cli/Cargo.toml @@ -5,9 +5,15 @@ edition = "2021" authors = ["Gabriel FĂ©ron "] license = "AGPL-3.0-only" +[features] +default = ["sqlite"] +sled = ["presage-store-sled"] +sqlite = ["presage-store-sqlite"] + [dependencies] presage = { path = "../presage" } -presage-store-sled = { path = "../presage-store-sled" } +presage-store-sled = { path = "../presage-store-sled", optional = true } +presage-store-sqlite = { path = "../presage-store-sqlite", optional = true } anyhow = { version = "1.0", features = ["backtrace"] } base64 = "0.22" diff --git a/presage-cli/src/main.rs b/presage-cli/src/main.rs index 9f4e70409..3a8e5b7ad 100644 --- a/presage-cli/src/main.rs +++ b/presage-cli/src/main.rs @@ -39,8 +39,6 @@ use presage::{ store::{Store, Thread}, Manager, }; -use presage_store_sled::MigrationConflictStrategy; -use presage_store_sled::SledStore; use tempfile::Builder; use tokio::task; use tokio::{ @@ -223,14 +221,22 @@ async fn main() -> anyhow::Result<()> { .config_dir() .into() }); - debug!(db_path =% db_path.display(), "opening config database"); - let config_store = SledStore::open_with_passphrase( + debug!(dir =% db_path.display(), "opening database in dir"); + + #[cfg(feature = "sled")] + let config_store = presage_store_sled::SledStore::open_with_passphrase( db_path, args.passphrase, - MigrationConflictStrategy::Raise, + presage_store_sled::MigrationConflictStrategy::Raise, OnNewIdentity::Trust, ) .await?; + + #[cfg(feature = "sqlite")] + let config_store = + presage_store_sqlite::SqliteStore::open(db_path.join("db.sqlite"), OnNewIdentity::Trust) + .await?; + run(args.subcommand, config_store).await } diff --git a/presage-store-sqlite/Cargo.toml b/presage-store-sqlite/Cargo.toml index bb8d1aa74..e562c1ecd 100644 --- a/presage-store-sqlite/Cargo.toml +++ b/presage-store-sqlite/Cargo.toml @@ -13,7 +13,7 @@ presage = { path = "../presage" } presage-store-cipher = { path = "../presage-store-cipher", optional = true } prost = "0.13.3" -sqlx = { version = "0.8.2", features = ["sqlite", "uuid"] } +sqlx = { version = "0.8.2", features = ["sqlite", "uuid", "runtime-tokio"] } thiserror = "1.0.65" tracing = "0.1.40" uuid = { version = "1.11.0", features = ["v4"] } diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index 7051b7094..de0b2582d 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -1,5 +1,5 @@ CREATE TABLE config( - key TEXT PRIMARY KEY NOT NULL, + key TEXT PRIMARY KEY NOT NULL ON CONFLICT REPLACE, value BLOB NOT NULL ); diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 57ef445c7..7e1547f75 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -49,11 +49,23 @@ impl ContentsStore for SqliteStore { } async fn clear_contents(&mut self) -> Result<(), Self::ContentsStoreError> { + let mut tx = self.db.begin().await?; + + query!("DELETE FROM groups").execute(&mut *tx).await; + query!("DELETE FROM contacts").execute(&mut *tx).await; + + tx.commit().await?; Ok(()) } async fn clear_messages(&mut self) -> Result<(), Self::ContentsStoreError> { - query!("DELETE FROM threads").execute(&self.db).await?; + let mut tx = self.db.begin().await?; + query!("DELETE FROM thread_messages") + .execute(&mut *tx) + .await?; + query!("DELETE FROM threads").execute(&mut *tx).await?; + tx.commit().await?; + Ok(()) } @@ -134,11 +146,10 @@ impl ContentsStore for SqliteStore { let timestamp: i64 = timestamp.try_into()?; let deleted: u64 = match thread { Thread::Contact(uuid) => query_scalar!( - " - DELETE FROM thread_messages WHERE ts = ? AND thread_id IN ( - SELECT thread_id FROM threads - WHERE recipient_id = ? - )", + "DELETE FROM thread_messages WHERE ts = ? AND thread_id IN ( + SELECT thread_id FROM threads + WHERE recipient_id = ? + )", timestamp, uuid ) @@ -171,8 +182,7 @@ impl ContentsStore for SqliteStore { ) -> Result, Self::ContentsStoreError> { let timestamp: i64 = timestamp.try_into()?; let Some(thread_id) = self.thread_id(thread).await? else { - warn!("no thread found"); - // TODO: return error? + warn!(%thread, "thread not found"); return Ok(None); }; @@ -194,8 +204,7 @@ impl ContentsStore for SqliteStore { range: impl std::ops::RangeBounds, ) -> Result { let Some(thread_id) = self.thread_id(thread).await? else { - warn!("no thread found"); - // TODO: return error? + warn!(%thread, "thread not found"); return Ok(Box::new(std::iter::empty())); }; @@ -229,6 +238,8 @@ impl ContentsStore for SqliteStore { std::ops::Bound::Unbounded => (), } + query_builder.push("ORDER BY ts DESC"); + let messages: Vec = query_builder.build_query_as().fetch_all(&self.db).await?; Ok(Box::new(messages.into_iter().map(TryInto::try_into))) } @@ -284,7 +295,7 @@ impl ContentsStore for SqliteStore { .execute(&mut *tx) .await?; - tx.commit().await; + tx.commit().await?; Ok(()) } diff --git a/presage-store-sqlite/src/data.rs b/presage-store-sqlite/src/data.rs index 9b11f1788..33a7c26ad 100644 --- a/presage-store-sqlite/src/data.rs +++ b/presage-store-sqlite/src/data.rs @@ -18,7 +18,7 @@ use presage::{ use crate::SqliteStoreError; -#[derive(sqlx::FromRow)] +#[derive(Debug, sqlx::FromRow)] pub struct SqlContact { pub uuid: String, pub phone_number: Option, @@ -39,6 +39,7 @@ pub struct SqlContact { impl TryInto for SqlContact { type Error = SqliteStoreError; + #[tracing::instrument] fn try_into(self) -> Result { Ok(Contact { uuid: self.uuid.parse()?, @@ -73,7 +74,7 @@ impl TryInto for SqlContact { } } -#[derive(sqlx::FromRow)] +#[derive(Debug, sqlx::FromRow)] pub struct SqlProfile { pub uuid: String, pub key: Vec, @@ -87,6 +88,7 @@ pub struct SqlProfile { impl TryInto for SqlProfile { type Error = SqliteStoreError; + #[tracing::instrument] fn try_into(self) -> Result { Ok(Profile { name: self.given_name.map(|gn| ProfileName { @@ -100,7 +102,7 @@ impl TryInto for SqlProfile { } } -#[derive(sqlx::FromRow)] +#[derive(Debug, sqlx::FromRow)] pub struct SqlGroup { pub id: Option, pub master_key: Vec, @@ -116,6 +118,7 @@ pub struct SqlGroup { } impl SqlGroup { + #[tracing::instrument] pub fn from_group( master_key: GroupMasterKeyBytes, group: Group, @@ -138,6 +141,7 @@ impl SqlGroup { }) } + #[tracing::instrument] pub fn into_group(self) -> Result { let members: Vec = postcard::from_bytes(&self.members)?; let pending_members: Vec = postcard::from_bytes(&self.pending_members)?; @@ -158,7 +162,7 @@ impl SqlGroup { } } -#[derive(sqlx::FromRow)] +#[derive(Debug, sqlx::FromRow)] pub struct SqlMessage { pub ts: i64, pub thread_id: i64, @@ -175,6 +179,7 @@ pub struct SqlMessage { impl TryInto for SqlMessage { type Error = SqliteStoreError; + #[tracing::instrument] fn try_into(self) -> Result { let body: proto::Content = prost::Message::decode(&self.content_body[..]).unwrap(); let sender_service_id = diff --git a/presage-store-sqlite/src/error.rs b/presage-store-sqlite/src/error.rs index d3d856858..eaea67e17 100644 --- a/presage-store-sqlite/src/error.rs +++ b/presage-store-sqlite/src/error.rs @@ -3,10 +3,11 @@ use sqlx::types::uuid; #[derive(Debug, thiserror::Error)] pub enum SqliteStoreError { - #[error("database migration is not supported")] - MigrationConflict, + #[error("database migration failed: {0}")] + Migration(#[from] sqlx::migrate::MigrateError), #[error("data store error: {0}")] Db(#[from] sqlx::Error), + #[error("error parsing phonenumber: {0}")] PhoneNumber(#[from] phonenumber::ParseError), #[error("error parsing UUID: {0}")] diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index eed4946de..0d750861d 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -1,6 +1,6 @@ #![allow(warnings)] -use std::path::Path; +use std::{future::Future, path::Path, pin::Pin}; use presage::{ libsignal_service::protocol::SignalProtocolError, @@ -9,7 +9,10 @@ use presage::{ }; use protocol::SqliteProtocolStore; use sqlx::{ - migrate::MigrateDatabase, query, query_scalar, sqlite::SqliteConnectOptions, Sqlite, SqlitePool, + migrate::{MigrateDatabase, Migration, MigrationSource, Migrator}, + query, query_scalar, + sqlite::SqliteConnectOptions, + Sqlite, SqlitePool, }; mod content; @@ -18,6 +21,9 @@ mod error; mod protocol; pub use error::SqliteStoreError; +use tracing::{debug, trace}; + +static MIGRATOR: Migrator = sqlx::migrate!(); #[derive(Debug, Clone)] pub struct SqliteStore { @@ -31,9 +37,21 @@ impl SqliteStore { db_path: impl AsRef, trust_new_identities: OnNewIdentity, ) -> Result { + let db_path = db_path.as_ref(); + let db_path_str = db_path.to_str().unwrap(); + + // Create database if it doesn't exist + if !Sqlite::database_exists(db_path_str).await.unwrap_or(false) { + debug!(path = db_path_str, "creating sqlite database"); + Sqlite::create_database(db_path_str).await?; + } + let connect_options = SqliteConnectOptions::new().filename(db_path); let pool = SqlitePool::connect_with(connect_options).await?; + debug!("applying sqlite migrations"); + MIGRATOR.run(&pool).await?; + Ok(Self { db: pool, trust_new_identities, @@ -81,6 +99,7 @@ impl Store for SqliteStore { impl StateStore for SqliteStore { type StateStoreError = SqliteStoreError; + #[tracing::instrument(skip(self))] async fn load_registration_data( &self, ) -> Result, Self::StateStoreError> { @@ -95,6 +114,7 @@ impl StateStore for SqliteStore { &self, key_pair: presage::libsignal_service::protocol::IdentityKeyPair, ) -> Result<(), Self::StateStoreError> { + trace!("setting ACI identity key pair"); let key_pair_bytes = key_pair.serialize(); query!( "INSERT INTO config(key, value) VALUES('aci_identity_key_pair', ?)", @@ -109,6 +129,7 @@ impl StateStore for SqliteStore { &self, key_pair: presage::libsignal_service::protocol::IdentityKeyPair, ) -> Result<(), Self::StateStoreError> { + trace!("setting PNI identity key pair"); let key_pair_bytes = key_pair.serialize(); query!( "INSERT INTO config(key, value) VALUES('pni_identity_key_pair', ?)", @@ -123,6 +144,7 @@ impl StateStore for SqliteStore { &mut self, state: &presage::manager::RegistrationData, ) -> Result<(), Self::StateStoreError> { + trace!("saving registration data"); let registration_data_json = postcard::to_allocvec(&state)?; query!( "INSERT INTO config(key, value) VALUES('registration', ?)", diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 72ac35d6e..1f4ed7b50 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -335,7 +335,7 @@ impl KyberPreKeyStoreExt for SqliteProtocolStore { let record_data = record.serialize()?; query!( "INSERT INTO kyber_prekeys( id, record, is_last_resort, identity ) - VALUES( $1, $2, true, $4 )", + VALUES( ?, ?, TRUE, ? )", id, record_data, self.identity_type, diff --git a/presage/src/manager/registered.rs b/presage/src/manager/registered.rs index 4e6e4f8ef..522df9043 100644 --- a/presage/src/manager/registered.rs +++ b/presage/src/manager/registered.rs @@ -3,6 +3,7 @@ use std::pin::pin; use std::sync::{Arc, OnceLock}; use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use derivative::Derivative; use futures::{future, AsyncReadExt, Stream, StreamExt}; use libsignal_service::attachment_cipher::decrypt_in_place; use libsignal_service::configuration::{ServiceConfiguration, SignalServers, SignalingKey}; @@ -95,14 +96,18 @@ impl Registered { } /// Registration data like device name, and credentials to connect to Signal -#[derive(Serialize, Deserialize, Clone)] +#[derive(Derivative, Serialize, Deserialize, Clone)] +#[derivative(Debug)] pub struct RegistrationData { pub signal_servers: SignalServers, pub device_name: Option, pub phone_number: PhoneNumber, #[serde(flatten)] + #[derivative(Debug = "ignore")] pub service_ids: ServiceIds, + #[derivative(Debug = "ignore")] pub(crate) password: String, + #[derivative(Debug = "ignore")] #[serde(with = "serde_signaling_key")] pub(crate) signaling_key: SignalingKey, pub device_id: Option, diff --git a/presage/src/model/groups.rs b/presage/src/model/groups.rs index 124d355e3..2fa99c650 100644 --- a/presage/src/model/groups.rs +++ b/presage/src/model/groups.rs @@ -1,7 +1,7 @@ use derivative::Derivative; use libsignal_service::{ groups_v2::Role, - prelude::{AccessControl, Member, ProfileKey, Timer, Uuid}, + prelude::{AccessControl, ProfileKey, Timer, Uuid}, }; use serde::{Deserialize, Serialize}; @@ -21,6 +21,16 @@ pub struct Group { pub description: Option, } +#[derive(Derivative, Clone, Deserialize, Serialize)] +#[derivative(Debug)] +pub struct Member { + pub uuid: Uuid, + pub role: Role, + #[derivative(Debug = "ignore")] + pub profile_key: ProfileKey, + pub joined_at_revision: u32, +} + #[derive(Debug, PartialEq, Eq, Deserialize, Serialize)] pub struct PendingMember { // for backwards compatibility @@ -48,7 +58,7 @@ impl From for Group { disappearing_messages_timer: val.disappearing_messages_timer, access_control: val.access_control, revision: val.revision, - members: val.members, + members: val.members.into_iter().map(Into::into).collect(), pending_members: val.pending_members.into_iter().map(Into::into).collect(), requesting_members: val.requesting_members.into_iter().map(Into::into).collect(), invite_link_password: val.invite_link_password, @@ -57,6 +67,17 @@ impl From for Group { } } +impl From for Member { + fn from(val: libsignal_service::groups_v2::Member) -> Self { + Member { + uuid: val.uuid, + role: val.role, + profile_key: val.profile_key, + joined_at_revision: val.joined_at_revision, + } + } +} + impl From for PendingMember { fn from(val: libsignal_service::groups_v2::PendingMember) -> Self { PendingMember { diff --git a/presage/src/serde.rs b/presage/src/serde.rs index 4beed7371..1141978dc 100644 --- a/presage/src/serde.rs +++ b/presage/src/serde.rs @@ -3,11 +3,13 @@ pub(crate) mod serde_profile_key { use base64::{engine::general_purpose, Engine}; use libsignal_service::prelude::ProfileKey; use serde::{Deserialize, Deserializer, Serializer}; + use tracing::trace; pub(crate) fn serialize(profile_key: &ProfileKey, serializer: S) -> Result where S: Serializer, { + trace!("serializing profile key"); serializer.serialize_str(&general_purpose::STANDARD.encode(profile_key.bytes)) } @@ -15,6 +17,7 @@ pub(crate) mod serde_profile_key { where D: Deserializer<'de>, { + trace!("deserializing profile key"); let bytes: [u8; 32] = general_purpose::STANDARD .decode(String::deserialize(deserializer)?) .map_err(serde::de::Error::custom)? From 3ef936a5db43342d096ae594c9375be31b977c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Thu, 31 Oct 2024 10:35:29 +0100 Subject: [PATCH 25/25] Registration works --- .../20241024072558_Initial_data_model.sql | 1 + presage-store-sqlite/src/content.rs | 22 ++++----- presage-store-sqlite/src/lib.rs | 13 +++-- presage-store-sqlite/src/protocol.rs | 14 +++--- presage/src/manager/confirmation.rs | 3 +- presage/src/manager/linking.rs | 5 +- presage/src/manager/registered.rs | 49 ++++++++++--------- 7 files changed, 59 insertions(+), 48 deletions(-) diff --git a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql index de0b2582d..0854fc2e0 100644 --- a/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql +++ b/presage-store-sqlite/migrations/20241024072558_Initial_data_model.sql @@ -139,6 +139,7 @@ CREATE TABLE threads ( FOREIGN KEY(id) REFERENCES groups(id) ON DELETE CASCADE ); +CREATE UNIQUE INDEX threads_target ON threads(group_id, recipient_id); CREATE TABLE thread_messages( ts INTEGER NOT NULL, diff --git a/presage-store-sqlite/src/content.rs b/presage-store-sqlite/src/content.rs index 7e1547f75..83bc3a1e7 100644 --- a/presage-store-sqlite/src/content.rs +++ b/presage-store-sqlite/src/content.rs @@ -89,7 +89,7 @@ impl ContentsStore for SqliteStore { let thread_id = match thread { Thread::Contact(uuid) => { query_scalar!( - "INSERT INTO threads(recipient_id, group_id) VALUES (?, NULL) RETURNING id", + "INSERT INTO threads(recipient_id, group_id) VALUES (?, NULL) ON CONFLICT DO NOTHING RETURNING id", metadata.sender.uuid, ) .fetch_one(&mut *tx) @@ -98,7 +98,7 @@ impl ContentsStore for SqliteStore { Thread::Group(master_key_bytes) => { let master_key_bytes = master_key_bytes.as_slice(); query_scalar!( - "INSERT INTO threads(group_id) SELECT id FROM groups WHERE groups.master_key = ? RETURNING id", + "INSERT INTO threads(group_id) SELECT id FROM groups WHERE groups.master_key = ? ON CONFLICT DO NOTHING RETURNING id", master_key_bytes ) .fetch_one(&mut *tx) @@ -121,7 +121,7 @@ impl ContentsStore for SqliteStore { let timestamp: i64 = timestamp.try_into()?; query!( - "INSERT INTO + "INSERT OR REPLACE INTO thread_messages(ts, thread_id, sender_service_id, needs_receipt, unidentified_sender, content_body) VALUES(?, ?, ?, ?, ?, ?)", timestamp, @@ -257,7 +257,7 @@ impl ContentsStore for SqliteStore { let mut tx = self.db.begin().await?; query!( - "INSERT INTO contacts + "INSERT OR REPLACE INTO contacts VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", contact.uuid, phone_number, @@ -286,7 +286,7 @@ impl ContentsStore for SqliteStore { }; query!( - "INSERT INTO contacts_verification_state(destination_aci, identity_key, is_verified) + "INSERT OR REPLACE INTO contacts_verification_state(destination_aci, identity_key, is_verified) VALUES(?, ?, ?)", destination_aci, identity_key, @@ -351,7 +351,7 @@ impl ContentsStore for SqliteStore { let group = SqlGroup::from_group(master_key, group.into())?; query_as!( SqlGroup, - "INSERT INTO groups( + "INSERT OR REPLACE INTO groups( id, master_key, title, @@ -414,7 +414,7 @@ impl ContentsStore for SqliteStore { let group_id = self.group_id(&master_key).await?; query!( - "INSERT INTO group_avatars(id, bytes) VALUES(?, ?)", + "INSERT OR REPLACE INTO group_avatars(id, bytes) VALUES(?, ?)", group_id, avatar ) @@ -445,7 +445,7 @@ impl ContentsStore for SqliteStore { let profile_key_bytes = key.get_bytes(); let profile_key_slice = profile_key_bytes.as_slice(); let rows_upserted = query!( - "INSERT INTO profile_keys VALUES(?, ?)", + "INSERT OR REPLACE INTO profile_keys VALUES(?, ?)", uuid, profile_key_slice ) @@ -476,7 +476,7 @@ impl ContentsStore for SqliteStore { let given_name = profile.name.clone().map(|n| n.given_name); let family_name = profile.name.map(|n| n.family_name).flatten(); query!( - "INSERT INTO profiles VALUES(?, ?, ?, ?, ?, ?)", + "INSERT OR REPLACE INTO profiles VALUES(?, ?, ?, ?, ?, ?)", uuid, given_name, family_name, @@ -517,7 +517,7 @@ impl ContentsStore for SqliteStore { profile: &presage::AvatarBytes, ) -> Result<(), Self::ContentsStoreError> { query!( - "INSERT INTO profile_avatars(uuid, bytes) VALUES(?, ?)", + "INSERT OR REPLACE INTO profile_avatars(uuid, bytes) VALUES(?, ?)", uuid, profile ) @@ -544,7 +544,7 @@ impl ContentsStore for SqliteStore { ) -> Result<(), Self::ContentsStoreError> { let manifest_json = postcard::to_allocvec(&pack.manifest)?; query!( - "INSERT INTO sticker_packs(id, key, manifest) VALUES(?, ?, ?)", + "INSERT OR REPLACE INTO sticker_packs(id, key, manifest) VALUES(?, ?, ?)", pack.id, pack.key, manifest_json, diff --git a/presage-store-sqlite/src/lib.rs b/presage-store-sqlite/src/lib.rs index 0d750861d..233546b88 100644 --- a/presage-store-sqlite/src/lib.rs +++ b/presage-store-sqlite/src/lib.rs @@ -3,7 +3,12 @@ use std::{future::Future, path::Path, pin::Pin}; use presage::{ - libsignal_service::protocol::SignalProtocolError, + libsignal_service::{ + configuration::SignalServers, + prelude::{phonenumber::PhoneNumber, ProfileKey, SignalingKey}, + protocol::SignalProtocolError, + push_service::ServiceIds, + }, model::identity::OnNewIdentity, store::{StateStore, Store}, }; @@ -117,7 +122,7 @@ impl StateStore for SqliteStore { trace!("setting ACI identity key pair"); let key_pair_bytes = key_pair.serialize(); query!( - "INSERT INTO config(key, value) VALUES('aci_identity_key_pair', ?)", + "INSERT OR REPLACE INTO config(key, value) VALUES('aci_identity_key_pair', ?)", key_pair_bytes ) .execute(&self.db) @@ -132,7 +137,7 @@ impl StateStore for SqliteStore { trace!("setting PNI identity key pair"); let key_pair_bytes = key_pair.serialize(); query!( - "INSERT INTO config(key, value) VALUES('pni_identity_key_pair', ?)", + "INSERT OR REPLACE INTO config(key, value) VALUES('pni_identity_key_pair', ?)", key_pair_bytes ) .execute(&self.db) @@ -147,7 +152,7 @@ impl StateStore for SqliteStore { trace!("saving registration data"); let registration_data_json = postcard::to_allocvec(&state)?; query!( - "INSERT INTO config(key, value) VALUES('registration', ?)", + "INSERT OR REPLACE INTO config(key, value) VALUES('registration', ?)", registration_data_json ) .execute(&self.db) diff --git a/presage-store-sqlite/src/protocol.rs b/presage-store-sqlite/src/protocol.rs index 1f4ed7b50..1150cb181 100644 --- a/presage-store-sqlite/src/protocol.rs +++ b/presage-store-sqlite/src/protocol.rs @@ -63,7 +63,7 @@ impl SessionStore for SqliteProtocolStore { let device_id: u32 = address.device_id().into(); let record_data = record.serialize()?; query!( - "INSERT INTO sessions ( address, device_id, identity, record ) VALUES ( $1, $2, $3, $4 )", + "INSERT OR REPLACE INTO sessions ( address, device_id, identity, record ) VALUES ( $1, $2, $3, $4 )", uuid, device_id, self.identity_type, @@ -154,7 +154,7 @@ impl PreKeyStore for SqliteProtocolStore { let id: u32 = prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "INSERT OR REPLACE INTO prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", id, record_data, self.identity_type, @@ -252,7 +252,7 @@ impl SignedPreKeyStore for SqliteProtocolStore { let id: u32 = signed_prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO signed_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "INSERT OR REPLACE INTO signed_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", id, record_data, self.identity_type @@ -292,7 +292,7 @@ impl KyberPreKeyStore for SqliteProtocolStore { let id: u32 = kyber_prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO kyber_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", + "INSERT OR REPLACE INTO kyber_prekeys( id, record, identity ) VALUES( ?1, ?2, ?3 )", id, record_data, self.identity_type, @@ -334,7 +334,7 @@ impl KyberPreKeyStoreExt for SqliteProtocolStore { let id: u32 = kyber_prekey_id.into(); let record_data = record.serialize()?; query!( - "INSERT INTO kyber_prekeys( id, record, is_last_resort, identity ) + "INSERT OR REPLACE INTO kyber_prekeys( id, record, is_last_resort, identity ) VALUES( ?, ?, TRUE, ? )", id, record_data, @@ -435,7 +435,7 @@ impl IdentityKeyStore for SqliteProtocolStore { let address = address.name(); let record_data = identity_key.serialize(); query!( - "INSERT INTO identities ( address, record, identity ) VALUES ( $1, $2, $3 )", + "INSERT OR REPLACE INTO identities ( address, record, identity ) VALUES ( $1, $2, $3 )", address, record_data, self.identity_type @@ -496,7 +496,7 @@ impl SenderKeyStore for SqliteProtocolStore { let device_id: u32 = sender.device_id().into(); let record_data = record.serialize()?; query!( - "INSERT INTO sender_keys (address, device, distribution_id, record, identity) VALUES ($1, $2, $3, $4, $5)", + "INSERT OR REPLACE INTO sender_keys (address, device, distribution_id, record, identity) VALUES ($1, $2, $3, $4, $5)", address, device_id, distribution_id, diff --git a/presage/src/manager/confirmation.rs b/presage/src/manager/confirmation.rs index 01b8a89fb..48a215611 100644 --- a/presage/src/manager/confirmation.rs +++ b/presage/src/manager/confirmation.rs @@ -132,7 +132,8 @@ impl Manager { signal_servers: self.state.signal_servers, device_name: None, phone_number, - service_ids: ServiceIds { aci, pni }, + aci, + pni, password, signaling_key, device_id: None, diff --git a/presage/src/manager/linking.rs b/presage/src/manager/linking.rs index a954a6b6f..1db9f5558 100644 --- a/presage/src/manager/linking.rs +++ b/presage/src/manager/linking.rs @@ -129,7 +129,8 @@ impl Manager { signal_servers, device_name: Some(device_name), phone_number, - service_ids, + aci: service_ids.aci, + pni: service_ids.pni, password, signaling_key, device_id: Some(device_id.into()), @@ -154,7 +155,7 @@ impl Manager { store.save_registration_data(®istration_data).await?; info!( "successfully registered device {}", - ®istration_data.service_ids + ®istration_data.service_ids() ); let mut manager = Manager { diff --git a/presage/src/manager/registered.rs b/presage/src/manager/registered.rs index 522df9043..27d8c34b3 100644 --- a/presage/src/manager/registered.rs +++ b/presage/src/manager/registered.rs @@ -96,18 +96,14 @@ impl Registered { } /// Registration data like device name, and credentials to connect to Signal -#[derive(Derivative, Serialize, Deserialize, Clone)] -#[derivative(Debug)] +#[derive(Serialize, Deserialize, Clone)] pub struct RegistrationData { pub signal_servers: SignalServers, pub device_name: Option, pub phone_number: PhoneNumber, - #[serde(flatten)] - #[derivative(Debug = "ignore")] - pub service_ids: ServiceIds, - #[derivative(Debug = "ignore")] + pub aci: Uuid, + pub pni: Uuid, pub(crate) password: String, - #[derivative(Debug = "ignore")] #[serde(with = "serde_signaling_key")] pub(crate) signaling_key: SignalingKey, pub device_id: Option, @@ -119,14 +115,21 @@ pub struct RegistrationData { } impl RegistrationData { + pub fn service_ids(&self) -> ServiceIds { + ServiceIds { + aci: self.aci, + pni: self.pni, + } + } + /// Account identity pub fn aci(&self) -> Uuid { - self.service_ids.aci + self.aci } /// Phone number identity pub fn pni(&self) -> Uuid { - self.service_ids.pni + self.pni } /// Our own profile key @@ -332,7 +335,7 @@ impl Manager { if self.state.data.pni_registration_id.is_none() { debug!("fetching PNI UUID and updating state"); let whoami = self.whoami().await?; - self.state.data.service_ids.pni = whoami.pni; + self.state.data.pni = whoami.pni; self.store.save_registration_data(&self.state.data).await?; } @@ -382,7 +385,7 @@ impl Manager { .as_millis() as u64; self.send_message( - ServiceAddress::from_aci(self.state.data.service_ids.aci), + ServiceAddress::from_aci(self.state.data.aci), sync_message, timestamp, ) @@ -450,7 +453,7 @@ impl Manager { /// Fetches the profile (name, about, status emoji) of the registered user. pub async fn retrieve_profile(&mut self) -> Result> { - self.retrieve_profile_by_uuid(self.state.data.service_ids.aci, self.state.data.profile_key) + self.retrieve_profile_by_uuid(self.state.data.aci, self.state.data.profile_key) .await } @@ -606,7 +609,7 @@ impl Manager { let groups_credentials_cache = InMemoryCredentialsCache::default(); let groups_manager = GroupsManager::new( - self.state.data.service_ids.clone(), + self.state.data.service_ids(), self.identified_push_service(), groups_credentials_cache, server_public_params, @@ -887,7 +890,7 @@ impl Manager { // save the message let content = Content { metadata: Metadata { - sender: ServiceAddress::from_aci(self.state.data.service_ids.aci), + sender: ServiceAddress::from_aci(self.state.data.aci), sender_device: self.state.device_id(), destination: recipient, server_guid: None, @@ -952,7 +955,7 @@ impl Manager { for member in group .members .into_iter() - .filter(|m| m.uuid != self.state.data.service_ids.aci) + .filter(|m| m.uuid != self.state.data.aci) { let unidentified_access = self.store @@ -992,8 +995,8 @@ impl Manager { let content = Content { metadata: Metadata { - sender: ServiceAddress::from_aci(self.state.data.service_ids.aci), - destination: ServiceAddress::from_aci(self.state.data.service_ids.aci), + sender: ServiceAddress::from_aci(self.state.data.aci), + destination: ServiceAddress::from_aci(self.state.data.aci), sender_device: self.state.device_id(), server_guid: None, timestamp, @@ -1172,8 +1175,8 @@ impl Manager { fn credentials(&self) -> Option { Some(ServiceCredentials { - aci: Some(self.state.data.service_ids.aci), - pni: Some(self.state.data.service_ids.pni), + aci: Some(self.state.data.aci), + pni: Some(self.state.data.pni), phonenumber: self.state.data.phone_number.clone(), password: Some(self.state.data.password.clone()), signaling_key: Some(self.state.data.signaling_key), @@ -1201,8 +1204,8 @@ impl Manager { self.new_service_cipher_aci(), self.rng.clone(), aci_protocol_store, - ServiceAddress::from_aci(self.state.data.service_ids.aci), - ServiceAddress::from_pni(self.state.data.service_ids.pni), + ServiceAddress::from_aci(self.state.data.aci), + ServiceAddress::from_pni(self.state.data.pni), aci_identity_keypair, Some(pni_identity_keypair), self.state.device_id().into(), @@ -1216,7 +1219,7 @@ impl Manager { self.state .service_configuration() .unidentified_sender_trust_root, - self.state.data.service_ids.aci, + self.state.data.aci, self.state.device_id(), ) } @@ -1228,7 +1231,7 @@ impl Manager { self.state .service_configuration() .unidentified_sender_trust_root, - self.state.data.service_ids.pni, + self.state.data.pni, self.state.device_id(), ) }