mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-04-01 17:13:13 +00:00
feat: sqlite crate
This commit is contained in:
parent
130578b956
commit
9a90e86cb3
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -108,6 +108,17 @@ dependencies = [
|
|||||||
"prost",
|
"prost",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chat-sqlite"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"crypto",
|
||||||
|
"hex",
|
||||||
|
"storage",
|
||||||
|
"tempfile",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
@ -502,6 +513,7 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"blake2",
|
"blake2",
|
||||||
"chat-proto",
|
"chat-proto",
|
||||||
|
"chat-sqlite",
|
||||||
"crypto",
|
"crypto",
|
||||||
"double-ratchets",
|
"double-ratchets",
|
||||||
"hex",
|
"hex",
|
||||||
@ -512,7 +524,6 @@ dependencies = [
|
|||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"x25519-dalek",
|
"x25519-dalek",
|
||||||
"zeroize",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -930,6 +941,7 @@ dependencies = [
|
|||||||
name = "storage"
|
name = "storage"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"crypto",
|
||||||
"rusqlite",
|
"rusqlite",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
resolver = "3"
|
resolver = "3"
|
||||||
|
|
||||||
members = [
|
members = [
|
||||||
|
"core/chat-sqlite",
|
||||||
"core/conversations",
|
"core/conversations",
|
||||||
"core/crypto",
|
"core/crypto",
|
||||||
"core/double-ratchets",
|
"core/double-ratchets",
|
||||||
|
|||||||
14
core/chat-sqlite/Cargo.toml
Normal file
14
core/chat-sqlite/Cargo.toml
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
[package]
|
||||||
|
name = "chat-sqlite"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
description = "SQLite storage implementation for libchat"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
crypto = { path = "../crypto" }
|
||||||
|
hex = "0.4.3"
|
||||||
|
storage = { path = "../storage" }
|
||||||
|
zeroize = { version = "1.8.2", features = ["derive"] }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3"
|
||||||
@ -1,19 +1,16 @@
|
|||||||
//! Chat-specific storage implementation.
|
//! Chat-specific SQLite storage implementation.
|
||||||
|
|
||||||
mod migrations;
|
mod migrations;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
use crypto::PrivateKey;
|
use crypto::{Identity, PrivateKey};
|
||||||
use storage::{RusqliteError, SqliteDb, StorageConfig, StorageError, params};
|
use storage::{
|
||||||
|
ConversationKind, ConversationMeta, ConversationStore, EphemeralKeyStore, IdentityStore,
|
||||||
|
RusqliteError, SqliteDb, StorageConfig, StorageError, params,
|
||||||
|
};
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
use crate::{
|
use crate::types::IdentityRecord;
|
||||||
identity::Identity,
|
|
||||||
sqlite::types::IdentityRecord,
|
|
||||||
store::{
|
|
||||||
ConversationKind, ConversationMeta, ConversationStore, EphemeralKeyStore, IdentityStore,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Chat-specific storage operations.
|
/// Chat-specific storage operations.
|
||||||
///
|
///
|
||||||
@ -37,7 +34,6 @@ impl ChatStorage {
|
|||||||
migrations::apply_migrations(db.connection_mut())?;
|
migrations::apply_migrations(db.connection_mut())?;
|
||||||
Ok(Self { db })
|
Ok(Self { db })
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentityStore for ChatStorage {
|
impl IdentityStore for ChatStorage {
|
||||||
@ -241,6 +237,11 @@ impl ConversationStore for ChatStorage {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use storage::{
|
||||||
|
ConversationKind, ConversationMeta, ConversationStore, EphemeralKeyStore, IdentityStore,
|
||||||
|
StorageConfig,
|
||||||
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -265,7 +266,7 @@ mod tests {
|
|||||||
let mut storage = ChatStorage::new(StorageConfig::InMemory).unwrap();
|
let mut storage = ChatStorage::new(StorageConfig::InMemory).unwrap();
|
||||||
|
|
||||||
let key1 = PrivateKey::random();
|
let key1 = PrivateKey::random();
|
||||||
let pub1: crate::crypto::PublicKey = (&key1).into();
|
let pub1: crypto::PublicKey = (&key1).into();
|
||||||
let hex1 = hex::encode(pub1.as_bytes());
|
let hex1 = hex::encode(pub1.as_bytes());
|
||||||
|
|
||||||
// Initially not found
|
// Initially not found
|
||||||
@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
use zeroize::{Zeroize, ZeroizeOnDrop};
|
use zeroize::{Zeroize, ZeroizeOnDrop};
|
||||||
|
|
||||||
use crate::crypto::PrivateKey;
|
use crypto::{Identity, PrivateKey};
|
||||||
use crate::identity::Identity;
|
|
||||||
|
|
||||||
/// Record for storing identity (secret key).
|
/// Record for storing identity (secret key).
|
||||||
/// Implements ZeroizeOnDrop to securely clear secret key from memory.
|
/// Implements ZeroizeOnDrop to securely clear secret key from memory.
|
||||||
@ -8,6 +8,7 @@ crate-type = ["rlib","staticlib","dylib"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = "0.22"
|
base64 = "0.22"
|
||||||
|
chat-sqlite = { path = "../chat-sqlite" }
|
||||||
blake2.workspace = true
|
blake2.workspace = true
|
||||||
chat-proto = { git = "https://github.com/logos-messaging/chat_proto" }
|
chat-proto = { git = "https://github.com/logos-messaging/chat_proto" }
|
||||||
crypto = { path = "../crypto" }
|
crypto = { path = "../crypto" }
|
||||||
@ -19,7 +20,6 @@ safer-ffi = "0.1.13"
|
|||||||
thiserror = "2.0.17"
|
thiserror = "2.0.17"
|
||||||
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] }
|
x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] }
|
||||||
storage = { path = "../storage" }
|
storage = { path = "../storage" }
|
||||||
zeroize = { version = "1.8.2", features = ["derive"] }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
|
|||||||
@ -13,12 +13,12 @@ use safer_ffi::{
|
|||||||
prelude::{c_slice, repr_c},
|
prelude::{c_slice, repr_c},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use chat_sqlite::ChatStorage;
|
||||||
use storage::StorageConfig;
|
use storage::StorageConfig;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
context::{Context, Introduction},
|
context::{Context, Introduction},
|
||||||
errors::ChatError,
|
errors::ChatError,
|
||||||
sqlite::ChatStorage,
|
|
||||||
types::ContentData,
|
types::ContentData,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use chat_sqlite::ChatStorage;
|
||||||
|
use crypto::Identity;
|
||||||
use double_ratchets::{RatchetState, RatchetStorage};
|
use double_ratchets::{RatchetState, RatchetStorage};
|
||||||
use storage::StorageConfig;
|
use storage::{
|
||||||
|
ChatStore, ConversationKind, ConversationMeta, IdentityStore, StorageConfig,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
conversation::{ConversationId, Convo, Id, PrivateV1Convo},
|
conversation::{ConversationId, Convo, Id, PrivateV1Convo},
|
||||||
errors::ChatError,
|
errors::ChatError,
|
||||||
identity::Identity,
|
|
||||||
inbox::Inbox,
|
inbox::Inbox,
|
||||||
proto::{EncryptedPayload, EnvelopeV1, Message},
|
proto::{EncryptedPayload, EnvelopeV1, Message},
|
||||||
sqlite::ChatStorage,
|
|
||||||
store::{ChatStore, ConversationKind, ConversationMeta, IdentityStore},
|
|
||||||
types::{AddressedEnvelope, ContentData},
|
types::{AddressedEnvelope, ContentData},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -216,9 +217,9 @@ impl<T: ChatStore> Context<T> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod mock {
|
mod mock {
|
||||||
use crypto::PrivateKey;
|
use crypto::PrivateKey;
|
||||||
use storage::StorageError;
|
use storage::{
|
||||||
|
ConversationStore, EphemeralKeyStore, IdentityStore, StorageError,
|
||||||
use crate::store::{ConversationStore, EphemeralKeyStore, IdentityStore};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@ -315,7 +316,10 @@ mod mock {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::{context::mock::MockChatStore, sqlite::ChatStorage, store::ConversationStore};
|
use chat_sqlite::ChatStorage;
|
||||||
|
use storage::ConversationStore;
|
||||||
|
|
||||||
|
use crate::context::mock::MockChatStore;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crypto::{PrekeyBundle, SymmetricKey32};
|
|||||||
use crate::context::Introduction;
|
use crate::context::Introduction;
|
||||||
use crate::conversation::{ChatError, ConversationId, Convo, Id, PrivateV1Convo};
|
use crate::conversation::{ChatError, ConversationId, Convo, Id, PrivateV1Convo};
|
||||||
use crate::crypto::{CopyBytes, PrivateKey, PublicKey};
|
use crate::crypto::{CopyBytes, PrivateKey, PublicKey};
|
||||||
use crate::identity::Identity;
|
use crypto::Identity;
|
||||||
use crate::inbox::handshake::InboxHandshake;
|
use crate::inbox::handshake::InboxHandshake;
|
||||||
use crate::proto;
|
use crate::proto;
|
||||||
use crate::types::{AddressedEncryptedPayload, ContentData};
|
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||||
@ -239,9 +239,8 @@ impl Id for Inbox {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::sqlite::ChatStorage;
|
use chat_sqlite::ChatStorage;
|
||||||
use crate::store::EphemeralKeyStore;
|
use storage::{EphemeralKeyStore, StorageConfig};
|
||||||
use storage::StorageConfig;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_invite_privatev1_roundtrip() {
|
fn test_invite_privatev1_roundtrip() {
|
||||||
|
|||||||
@ -3,18 +3,15 @@ mod context;
|
|||||||
mod conversation;
|
mod conversation;
|
||||||
mod crypto;
|
mod crypto;
|
||||||
mod errors;
|
mod errors;
|
||||||
mod identity;
|
|
||||||
mod inbox;
|
mod inbox;
|
||||||
mod proto;
|
mod proto;
|
||||||
mod sqlite;
|
|
||||||
mod store;
|
|
||||||
mod types;
|
mod types;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
pub use api::*;
|
pub use api::*;
|
||||||
|
pub use chat_sqlite::ChatStorage;
|
||||||
pub use context::{Context, Introduction};
|
pub use context::{Context, Introduction};
|
||||||
pub use errors::ChatError;
|
pub use errors::ChatError;
|
||||||
pub use sqlite::ChatStorage;
|
|
||||||
pub use storage::StorageConfig;
|
pub use storage::StorageConfig;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use crate::crypto::{PrivateKey, PublicKey};
|
use crate::{PrivateKey, PublicKey};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Identity {
|
pub struct Identity {
|
||||||
@ -1,7 +1,9 @@
|
|||||||
|
mod identity;
|
||||||
mod keys;
|
mod keys;
|
||||||
mod x3dh;
|
mod x3dh;
|
||||||
mod xeddsa_sign;
|
mod xeddsa_sign;
|
||||||
|
|
||||||
|
pub use identity::Identity;
|
||||||
pub use keys::{PrivateKey, PublicKey, SymmetricKey32};
|
pub use keys::{PrivateKey, PublicKey, SymmetricKey32};
|
||||||
pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake};
|
pub use x3dh::{DomainSeparator, PrekeyBundle, X3Handshake};
|
||||||
pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify};
|
pub use xeddsa_sign::{Ed25519Signature, SignatureError, xeddsa_sign, xeddsa_verify};
|
||||||
|
|||||||
@ -5,5 +5,6 @@ edition = "2024"
|
|||||||
description = "Shared storage layer for libchat"
|
description = "Shared storage layer for libchat"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
crypto = { path = "../crypto" }
|
||||||
thiserror = "2"
|
thiserror = "2"
|
||||||
rusqlite = { version = "0.35", features = ["bundled-sqlcipher-vendored-openssl"] }
|
rusqlite = { version = "0.35", features = ["bundled-sqlcipher-vendored-openssl"] }
|
||||||
|
|||||||
@ -7,9 +7,14 @@
|
|||||||
|
|
||||||
mod errors;
|
mod errors;
|
||||||
mod sqlite;
|
mod sqlite;
|
||||||
|
mod store;
|
||||||
|
|
||||||
pub use errors::StorageError;
|
pub use errors::StorageError;
|
||||||
pub use sqlite::{SqliteDb, StorageConfig};
|
pub use sqlite::{SqliteDb, StorageConfig};
|
||||||
|
pub use store::{
|
||||||
|
ChatStore, ConversationKind, ConversationMeta, ConversationStore, EphemeralKeyStore,
|
||||||
|
IdentityStore,
|
||||||
|
};
|
||||||
|
|
||||||
// Re-export rusqlite types that domain crates will need
|
// Re-export rusqlite types that domain crates will need
|
||||||
pub use rusqlite::{Connection, Error as RusqliteError, Transaction, params};
|
pub use rusqlite::{Connection, Error as RusqliteError, Transaction, params};
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
use crypto::PrivateKey;
|
use crypto::{Identity, PrivateKey};
|
||||||
use storage::StorageError;
|
|
||||||
|
|
||||||
use crate::identity::Identity;
|
use crate::StorageError;
|
||||||
|
|
||||||
/// Persistence operations for installation identity data.
|
/// Persistence operations for installation identity data.
|
||||||
pub trait IdentityStore {
|
pub trait IdentityStore {
|
||||||
Loading…
x
Reference in New Issue
Block a user