Add Account Struct (#94)

* Add Account Struct

* Quell Warnings

* Update core/conversations/src/account.rs

Co-authored-by: osmaczko <33099791+osmaczko@users.noreply.github.com>

* Add clarity to todo

* Update test account constructor docs

* Add removal todo

* Resolve cargo.lock conflict

* remove warnings

---------

Co-authored-by: osmaczko <33099791+osmaczko@users.noreply.github.com>
This commit is contained in:
Jazz Turner-Baggs 2026-04-28 07:47:57 -07:00 committed by GitHub
parent 25debdc051
commit 39bf267564
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 1164 additions and 0 deletions

1085
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -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"

View File

@ -0,0 +1,40 @@
use crypto::Ed25519SigningKey;
use openmls::prelude::SignatureScheme;
use openmls_traits::signatures::Signer;
use crate::types::AccountId;
/// Logos Account represents a single account across
/// multiple installations and services.
pub struct LogosAccount {
id: AccountId,
signing_key: Ed25519SigningKey,
}
impl LogosAccount {
/// Create a test LogosAccount using a pre-defined identifier.
/// This should only be used during MLS integration. Not suitable for production use.
/// TODO: (P1) Remove once implementation is ready.
pub fn new_test(explicit_id: impl Into<String>) -> Self {
let signing_key = Ed25519SigningKey::generate();
Self {
id: AccountId::new(explicit_id.into()),
signing_key,
}
}
pub fn account_id(&self) -> &AccountId {
&self.id
}
}
impl Signer for LogosAccount {
// TODO: (P2) Remove OpenMLS dependency to make accounts more portable
fn sign(&self, payload: &[u8]) -> Result<Vec<u8>, openmls_traits::signatures::SignerError> {
Ok(self.signing_key.sign(payload).as_ref().to_vec())
}
fn signature_scheme(&self) -> SignatureScheme {
SignatureScheme::ED25519
}
}

View File

@ -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,8 @@ pub struct Context<S: ChatStore> {
_identity: Rc<Identity>,
inbox: Inbox<S>,
store: Rc<RefCell<S>>,
#[allow(unused)] // TODO: (P2) Remove once Account integrated in future PR.
account: LogosAccount,
}
impl<S: ChatStore> Context<S> {
@ -48,6 +51,7 @@ impl<S: ChatStore> Context<S> {
_identity: identity,
inbox,
store,
account: LogosAccount::new_test(name.as_str()),
})
}
@ -70,6 +74,7 @@ impl<S: ChatStore> Context<S> {
_identity: identity,
inbox,
store: chat_store,
account: LogosAccount::new_test(name.as_str()),
}
}

View File

@ -1,3 +1,4 @@
mod account;
mod context;
mod conversation;
mod crypto;
@ -7,6 +8,7 @@ mod proto;
mod types;
mod utils;
pub use account::LogosAccount;
pub use context::{Context, ConversationIdOwned, Introduction};
pub use errors::ChatError;
pub use sqlite::ChatStorage;

View File

@ -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<String>) -> 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<str> for AccountId {
fn as_ref(&self) -> &str {
&self.0
}
}