mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-08-26 07:31:09 +00:00
feat: http server based key package registry (#124)
* feat: http server based key package registry * chore: instructions on running the registration service * chore: remove duplicate post param * chore: revert out sourced account id for multi devices support * feat: signature on account id and key packages * chore: include http registry in contact registry module * refactor: use device id for retrieve key package * chore: use string for device id * feat: server verification on the register * chore: doc the smoke test * chore: fix data folder non exist * chore: use payload for register and retrieve * chore: fix clippy
This commit is contained in:
@@ -15,14 +15,18 @@ pub struct LogosAccount {
|
||||
}
|
||||
|
||||
impl LogosAccount {
|
||||
/// Create a test LogosAccount using a pre-defined identifier.
|
||||
/// Create a test LogosAccount. The `AccountId` is derived from the
|
||||
/// generated Ed25519 verifying key (hex-encoded) so signatures over the
|
||||
/// id can be verified by anyone holding the id alone.
|
||||
/// The supplied `_display_name` is currently ignored — id is the key.
|
||||
/// 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 {
|
||||
pub fn new_test(_display_name: impl Into<String>) -> Self {
|
||||
let signing_key = Ed25519SigningKey::generate();
|
||||
let verifying_key = signing_key.verifying_key();
|
||||
let id = AccountId::new(hex::encode(verifying_key.as_ref()));
|
||||
Self {
|
||||
id: AccountId::new(explicit_id.into()),
|
||||
id,
|
||||
signing_key,
|
||||
verifying_key,
|
||||
}
|
||||
|
||||
@@ -164,6 +164,13 @@ where
|
||||
self.identity.public_key()
|
||||
}
|
||||
|
||||
/// Submit the local account's MLS KeyPackage to the registration service.
|
||||
/// Idempotent on the server side (registries that retain history will keep
|
||||
/// the most recent N submissions; older entries are pruned).
|
||||
pub fn register_keypackage(&mut self) -> Result<(), ChatError> {
|
||||
self.pq_inbox.register()
|
||||
}
|
||||
|
||||
pub fn create_private_convo(
|
||||
&mut self,
|
||||
remote_bundle: &Introduction,
|
||||
|
||||
@@ -193,10 +193,15 @@ where
|
||||
}
|
||||
|
||||
fn key_package_for_account(&self, ident: &AccountId) -> Result<KeyPackage, ChatError> {
|
||||
// INTERIM: the key package registry is keyed by `DeviceId`, but resolving an
|
||||
// `AccountId` to its device(s) is a future task. For now (single device
|
||||
// per account) we use the account-id string directly as the device id.
|
||||
// When account->device resolution lands, only this conversion changes.
|
||||
let device_id = ident.to_string();
|
||||
let retrieved_bytes = self
|
||||
.keypkg_provider
|
||||
.borrow()
|
||||
.retrieve(ident)
|
||||
.retrieve(&device_id)
|
||||
.map_err(|e: KP::Error| ChatError::Generic(e.to_string()))?;
|
||||
|
||||
// dbg!(ctx.contact_registry());
|
||||
|
||||
@@ -105,7 +105,7 @@ where
|
||||
// "LastResort" package or publish multiple
|
||||
self.reg_service
|
||||
.borrow_mut()
|
||||
.register(self.account_id().as_str(), keypackage_bytes)
|
||||
.register(&*self.account.borrow(), keypackage_bytes)
|
||||
.map_err(ChatError::generic)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,23 +22,32 @@ pub trait DeliveryService: Debug {
|
||||
///
|
||||
/// Implement this to provide a contact registry — ach participant publishes their key package
|
||||
/// on registration; others fetch it to initiate a conversation.
|
||||
///
|
||||
/// `register` receives an [`IdentityProvider`] (not just a name) so
|
||||
/// implementations that need to authenticate the submission — e.g. a network
|
||||
/// service that verifies the bundle is signed by the correct account — can
|
||||
/// sign or attest with the caller's key material.
|
||||
pub trait RegistrationService: Debug {
|
||||
type Error: Display + Debug;
|
||||
fn register(&mut self, identity: &str, key_bundle: Vec<u8>) -> Result<(), Self::Error>;
|
||||
fn retrieve(&self, identity: &AccountId) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
fn register(
|
||||
&mut self,
|
||||
identity: &dyn IdentityProvider,
|
||||
key_bundle: Vec<u8>,
|
||||
) -> Result<(), Self::Error>;
|
||||
fn retrieve(&self, device_id: &str) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
}
|
||||
|
||||
/// Read-only view of a contact registry. Not part of the public API.
|
||||
/// Satisfied automatically by any `RegistrationService` implementation.
|
||||
pub trait KeyPackageProvider: Debug {
|
||||
type Error: Display + Debug;
|
||||
fn retrieve(&self, identity: &AccountId) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
fn retrieve(&self, device_id: &str) -> Result<Option<Vec<u8>>, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T: RegistrationService> KeyPackageProvider for T {
|
||||
type Error = T::Error;
|
||||
fn retrieve(&self, identity: &AccountId) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
RegistrationService::retrieve(self, identity)
|
||||
fn retrieve(&self, device_id: &str) -> Result<Option<Vec<u8>>, Self::Error> {
|
||||
RegistrationService::retrieve(self, device_id)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,6 +68,12 @@ impl Ed25519VerifyingKey {
|
||||
.verify_strict(msg, &ed25519_dalek::Signature::from_bytes(&inner_signature))
|
||||
.map_err(|_| SignatureVerificationError {})
|
||||
}
|
||||
|
||||
pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, SignatureVerificationError> {
|
||||
ed25519_dalek::VerifyingKey::from_bytes(bytes)
|
||||
.map(Self)
|
||||
.map_err(|_| SignatureVerificationError {})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ed25519_dalek::VerifyingKey> for Ed25519VerifyingKey {
|
||||
|
||||
Reference in New Issue
Block a user