fix: signer-scoped DirectV1 routing (#162)

Core is no longer account-aware: the client resolves an account address
to signer ids via the account directory, and the signer's verifying-key
hex serves as registry key, inbox subscription, and Welcome routing
target end to end. The MLS credential stays the full id().

- GroupV2 reads the de-mls member id from the fetched key package and
  maps it to the signer id the welcome is delivered to.
- All account machinery (directory trait, bundle codec, resolution)
  moves out of core into logos-account; the RegistrationService
  supertrait and Core::account_directory() are gone, and the client
  holds its own directory handle.
- The account exposes functionality, never a signer: add_delegate_signer
  does the lamport upsert and signs internally.
- Every client acts for an account (ChatClientBuilder::new(account)).
  DelegateSigner is a pure keypair; the client composes the wire
  credential from the signer and the account, so the association is
  client state. addr() is the account address.
- resolve_device_ids fails fast (NotAnAccountKey / NoDeviceBundle /
  Directory) instead of falling back to treating an unresolved address
  as a signer id. LogosChatClient::open and chat-cli mint and publish a
  dev account each launch.
- EphemeralRegistry keys key packages by hex pubkey like HttpRegistry.

Supersedes #155 (routing_id).
This commit is contained in:
osmaczko
2026-07-03 23:18:10 +02:00
committed by GitHub
parent d131a69583
commit c09459c0a0
34 changed files with 692 additions and 500 deletions
@@ -5,10 +5,8 @@ use std::{
};
use crypto::Ed25519VerifyingKey;
use libchat::{
AccountDirectory, DeviceSet, IdentityProvider, RegistrationService, SignedDeviceBundle,
verify_bundle,
};
use libchat::{IdentityProvider, RegistrationService};
use logos_account::{AccountDirectory, DeviceSet, SignedDeviceBundle, verify_bundle};
/// A Contact Registry used for Tests.
/// This implementation stores bundle bytes and then returns them when
@@ -61,10 +59,12 @@ impl RegistrationService for EphemeralRegistry {
identity: &dyn IdentityProvider,
key_bundle: Vec<u8>,
) -> Result<(), <Self as RegistrationService>::Error> {
// Keyed by device id — the hex of the signer's verifying key — exactly
// like the HTTP registry, so tests exercise the deployed keying.
self.key_packages
.lock()
.unwrap()
.insert(identity.id().to_string(), key_bundle);
.insert(hex::encode(identity.public_key().as_ref()), key_bundle);
Ok(())
}
@@ -4,10 +4,8 @@ use std::time::{Duration, SystemTime, UNIX_EPOCH};
use base64::Engine;
use base64::engine::general_purpose::STANDARD as BASE64;
use crypto::{Ed25519Signature, Ed25519VerifyingKey};
use libchat::{
AccountDirectory, BundleError, DeviceSet, IdentityProvider, RegistrationService,
SignedDeviceBundle, verify_bundle,
};
use libchat::{IdentityProvider, RegistrationService};
use logos_account::{AccountDirectory, BundleError, DeviceSet, SignedDeviceBundle, verify_bundle};
use serde::{Deserialize, Serialize};
/// HTTP client for the testnet KeyPackage Registry service.