Add UnverifiedSigner

This commit is contained in:
Jazz Turner-Baggs
2026-07-28 16:19:24 -07:00
parent 1efb377de7
commit 68cd44ab86
7 changed files with 45 additions and 12 deletions
+3 -1
View File
@@ -2,6 +2,7 @@ mod direct_v1;
pub mod group_v1; pub mod group_v1;
mod group_v2; mod group_v2;
pub mod mls_extensions; pub mod mls_extensions;
mod mls_utils;
pub use crate::errors::ChatError; pub use crate::errors::ChatError;
use crate::outcomes::ConvoOutcome; use crate::outcomes::ConvoOutcome;
@@ -11,6 +12,7 @@ use crate::types::ConvoMetadata;
pub use direct_v1::DirectV1Convo; pub use direct_v1::DirectV1Convo;
pub use group_v1::GroupV1Convo; pub use group_v1::GroupV1Convo;
pub use group_v2::{GroupV2Clock, GroupV2Convo}; pub use group_v2::{GroupV2Clock, GroupV2Convo};
pub use mls_utils::UnverifiedSender;
use shared_traits::IdentIdRef; use shared_traits::IdentIdRef;
pub type ConversationId = String; pub type ConversationId = String;
@@ -47,7 +49,7 @@ pub(crate) trait GroupConvo<S: ExternalServices>: Convo<S> + std::fmt::Debug + S
/// Each current member's MLS leaf-credential content (hex-encoded), self /// Each current member's MLS leaf-credential content (hex-encoded), self
/// included. /// included.
fn members(&self) -> Result<Vec<Vec<u8>>, ChatError>; fn members(&self) -> Result<Vec<UnverifiedSender>, ChatError>;
// All GroupConvos MUST return ConvoMetadata // All GroupConvos MUST return ConvoMetadata
// the return type is Option<_> to support legacy ConvoTypes which // the return type is Option<_> to support legacy ConvoTypes which
// are being phased out. // are being phased out.
@@ -13,7 +13,7 @@ use std::collections::VecDeque;
use tracing::debug; use tracing::debug;
use crate::conversation::ConversationIdRef; use crate::conversation::ConversationIdRef;
use crate::conversation::mls_utils::signer_for_sender; use crate::conversation::mls_utils::{UnverifiedSender, signer_for_sender};
use crate::inbox_v2::MlsProvider; use crate::inbox_v2::MlsProvider;
use crate::service_context::{ExternalServices, ServiceContext}; use crate::service_context::{ExternalServices, ServiceContext};
@@ -349,11 +349,11 @@ impl<S: ExternalServices> GroupConvo<S> for GroupV1Convo {
self.send_payload(cx, commit.to_bytes()?) self.send_payload(cx, commit.to_bytes()?)
} }
fn members(&self) -> Result<Vec<Vec<u8>>, ChatError> { fn members(&self) -> Result<Vec<UnverifiedSender>, ChatError> {
Ok(self Ok(self
.mls_group .mls_group
.members() .members()
.map(|m| m.credential.serialized_content().to_vec()) .map(|m| UnverifiedSender::from(m))
.collect()) .collect())
} }
@@ -25,13 +25,13 @@ use openmls::prelude::tls_codec::Deserialize as _;
use openmls::prelude::{KeyPackageIn, OpenMlsProvider as _, ProtocolVersion}; use openmls::prelude::{KeyPackageIn, OpenMlsProvider as _, ProtocolVersion};
use openmls_traits::crypto::OpenMlsCrypto; use openmls_traits::crypto::OpenMlsCrypto;
use prost::Message; use prost::Message;
use shared_traits::{IdentId, IdentIdRef}; use shared_traits::{IdentId, IdentIdRef, SignerId};
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, SystemTime, UNIX_EPOCH}; use std::time::{Duration, SystemTime, UNIX_EPOCH};
use tracing::{info, instrument}; use tracing::{info, instrument};
use crate::IdentityProvider; use crate::IdentityProvider;
use crate::conversation::{ConversationIdRef, ExternalServices, ServiceContext}; use crate::conversation::{ConversationIdRef, ExternalServices, ServiceContext, UnverifiedSender};
use crate::{ use crate::{
ConvoOutcome, DeliveryService, RegistrationService, ConvoOutcome, DeliveryService, RegistrationService,
conversation::{ChatError, Convo, GroupConvo, Identified}, conversation::{ChatError, Convo, GroupConvo, Identified},
@@ -376,13 +376,22 @@ where
result.and(flushed) result.and(flushed)
} }
fn members(&self) -> Result<Vec<Vec<u8>>, ChatError> { fn members(&self) -> Result<Vec<UnverifiedSender>, ChatError> {
// Guarantee the local member is listed so callers see the full roster. // Guarantee the local member is listed so callers see the full roster.
let mut members = self.conversation.members()?; let mut members = self.conversation.members()?;
let self_id = self.conversation.member_id_bytes().to_vec(); let self_id = self.conversation.member_id_bytes().to_vec();
if !members.contains(&self_id) { if !members.contains(&self_id) {
members.push(self_id); members.push(self_id);
} }
let members = members
.into_iter()
.map(|cred| UnverifiedSender {
// TODO: (!) Replace is actual SenderId.
signer_id: SignerId::from(b"".as_slice()),
cred,
})
.collect();
Ok(members) Ok(members)
} }
@@ -1,7 +1,9 @@
use openmls::{ use openmls::{
credentials::CredentialType,
framing::{ProcessedMessage, Sender}, framing::{ProcessedMessage, Sender},
group::MlsGroup, group::{Member, MlsGroup},
}; };
use tracing::warn;
use crate::{ChatError, SignerId}; use crate::{ChatError, SignerId};
@@ -25,3 +27,22 @@ pub fn signer_for_sender(
}; };
Ok(sender_sig_key.into()) Ok(sender_sig_key.into())
} }
#[derive(Debug, Clone)]
pub struct UnverifiedSender {
pub signer_id: SignerId,
pub cred: Vec<u8>,
}
impl From<Member> for UnverifiedSender {
fn from(value: Member) -> Self {
if CredentialType::Basic != value.credential.credential_type() {
warn!(credtype = ?value.credential, "Incorrect credentialType");
};
let cred = value.credential.serialized_content().to_vec();
let signer_id = SignerId::from(value.signature_key);
Self { signer_id, cred }
}
}
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::causal_history::{CausalHistoryStore, MissingMessage}; use crate::causal_history::{CausalHistoryStore, MissingMessage};
use crate::conversation::{ use crate::conversation::{
ConversationIdRef, DirectV1Convo, GroupV1Convo, GroupV2Convo, Identified, ConversationIdRef, DirectV1Convo, GroupV1Convo, GroupV2Convo, Identified, UnverifiedSender,
}; };
use crate::service_context::{ExternalServices, ServiceContext}; use crate::service_context::{ExternalServices, ServiceContext};
use crate::service_traits::AuthVerifyService; use crate::service_traits::AuthVerifyService;
@@ -294,7 +294,7 @@ impl<'a, S: ExternalServices + 'static> Core<S> {
/// Each member's MLS leaf-credential content (hex-encoded); errors if /// Each member's MLS leaf-credential content (hex-encoded); errors if
/// `convo_id` names a direct (non-group) conversation. /// `convo_id` names a direct (non-group) conversation.
pub fn group_members(&mut self, convo_id: &str) -> Result<Vec<Vec<u8>>, ChatError> { pub fn group_members(&mut self, convo_id: &str) -> Result<Vec<UnverifiedSender>, ChatError> {
if self.cached_convos.contains_key(convo_id) { if self.cached_convos.contains_key(convo_id) {
let convo = self let convo = self
.cached_convos .cached_convos
+1 -1
View File
@@ -13,7 +13,7 @@ mod utils;
pub use causal_history::{Frontier, MissingMessage}; pub use causal_history::{Frontier, MissingMessage};
pub use chat_sqlite::ChatStorage; pub use chat_sqlite::ChatStorage;
pub use chat_sqlite::StorageConfig; pub use chat_sqlite::StorageConfig;
pub use conversation::GroupV2Clock; pub use conversation::{GroupV2Clock, UnverifiedSender};
pub use core::{ConversationId, Core}; pub use core::{ConversationId, Core};
/// Timing/policy for GroupV2 conversations (de-mls's per-conversation config). /// Timing/policy for GroupV2 conversations (de-mls's per-conversation config).
/// Defaults to the de-mls library defaults; inject via /// Defaults to the de-mls library defaults; inject via
+2 -1
View File
@@ -12,10 +12,11 @@ use crate::{ConversationId, types::AddressedEnvelope};
/// An AuthVerifyService is responsible for verifying that a provided Credential is valid /// An AuthVerifyService is responsible for verifying that a provided Credential is valid
/// for the given signer. Implementations must return AuthResult::Valid only if the two can /// for the given signer. Implementations must return AuthResult::Valid only if the two can
/// be cryptogrpahically bound together. /// be cryptogrpahically bound together.
pub trait AuthVerifyService: Debug { pub trait AuthVerifyService: Debug + Clone {
fn validate(&self, signer: &[u8], credential: &[u8]) -> AuthResult; fn validate(&self, signer: &[u8], credential: &[u8]) -> AuthResult;
} }
#[derive(Debug, PartialEq)]
pub enum AuthResult { pub enum AuthResult {
Valid, Valid,
Mismatch, Mismatch,