diff --git a/core/conversations/Cargo.toml b/core/conversations/Cargo.toml index b265823..f5492c4 100644 --- a/core/conversations/Cargo.toml +++ b/core/conversations/Cargo.toml @@ -20,6 +20,8 @@ safer-ffi = "0.1.13" thiserror = "2.0.17" x25519-dalek = { version = "2.0.1", features = ["static_secrets", "reusable_secrets", "getrandom"] } storage = { path = "../storage" } +openmls = { version = "0.8.1", features = ["libcrux-provider"] } +openmls_traits = "0.5.0" [dev-dependencies] tempfile = "3" diff --git a/core/conversations/src/account.rs b/core/conversations/src/account.rs new file mode 100644 index 0000000..25cda53 --- /dev/null +++ b/core/conversations/src/account.rs @@ -0,0 +1,40 @@ +use crypto::{Ed25519SigningKey, Ed25519VerifyingKey}; +use openmls::prelude::SignatureScheme; +use openmls_traits::signatures::Signer; + +use crate::types::AccountId; + +/// Logos Account provides represents a single account across +/// multiple installations and services. +pub struct LogosAccount { + id: AccountId, + signing_key: Ed25519SigningKey, + verifying_key: Ed25519VerifyingKey, +} + +impl LogosAccount { + pub fn new_test(explicit_id: impl Into) -> Self { + let signing_key = Ed25519SigningKey::generate(); + let verifying_key = signing_key.verifying_key(); + Self { + id: AccountId::new(explicit_id.into()), + signing_key, + verifying_key, + } + } + + pub fn account_id(&self) -> &AccountId { + &self.id + } +} + +impl Signer for LogosAccount { + // TODO: (P2) Remove OpenMLS references + fn sign(&self, payload: &[u8]) -> Result, openmls_traits::signatures::SignerError> { + Ok(self.signing_key.sign(payload).as_ref().to_vec()) + } + + fn signature_scheme(&self) -> SignatureScheme { + SignatureScheme::ED25519 + } +} diff --git a/core/conversations/src/context.rs b/core/conversations/src/context.rs index 3ca0873..399d57d 100644 --- a/core/conversations/src/context.rs +++ b/core/conversations/src/context.rs @@ -4,6 +4,7 @@ use std::{cell::RefCell, rc::Rc}; use crypto::{Identity, PublicKey}; use storage::{ChatStore, ConversationKind}; +use crate::account::LogosAccount; use crate::{ conversation::{Conversation, ConversationId, Convo, Id, PrivateV1Convo}, errors::ChatError, @@ -21,6 +22,7 @@ pub struct Context { _identity: Rc, inbox: Inbox, store: Rc>, + account: LogosAccount, } impl Context { @@ -48,6 +50,7 @@ impl Context { _identity: identity, inbox, store, + account: LogosAccount::new_test(name.as_str()), }) } @@ -70,6 +73,7 @@ impl Context { _identity: identity, inbox, store: chat_store, + account: LogosAccount::new_test(name.as_str()), } } diff --git a/core/conversations/src/lib.rs b/core/conversations/src/lib.rs index b571e17..ef30fc2 100644 --- a/core/conversations/src/lib.rs +++ b/core/conversations/src/lib.rs @@ -1,3 +1,4 @@ +mod account; mod context; mod conversation; mod crypto; diff --git a/core/conversations/src/types.rs b/core/conversations/src/types.rs index 72b7188..e8ecc70 100644 --- a/core/conversations/src/types.rs +++ b/core/conversations/src/types.rs @@ -1,3 +1,5 @@ +use std::fmt; + use crate::proto::{self, Message}; // FFI Type definitions @@ -41,3 +43,31 @@ impl AddressedEncryptedPayload { } } } + +/// This represents an Identifier for an account. +/// Its a thin wrapper around a string, but providers extra functionality, +/// and ensures type consistency +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct AccountId(String); + +impl AccountId { + pub fn new(id: impl Into) -> Self { + Self(id.into()) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl fmt::Display for AccountId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + std::fmt::Display::fmt(&self.0, f) + } +} + +impl AsRef for AccountId { + fn as_ref(&self) -> &str { + &self.0 + } +}