refactor(server): reorganized client/user_agent actors into separate module peers and added event MessageBus

This commit is contained in:
hdbg
2026-04-07 23:54:29 +02:00
parent f3cf6a9438
commit 1585f90cae
42 changed files with 332 additions and 286 deletions

View File

@@ -7,9 +7,10 @@ use arbiter_proto::transport::{Receiver, Sender};
use arbiter_server::{
actors::{
GlobalActors,
client::{ClientConnection, ClientCredentials, auth, connect_client},
keyholder::Bootstrap,
vault::Bootstrap,
},
peers::client::{ClientConnection, ClientCredentials, auth, connect_client},
crypto::integrity,
db::{self, schema},
};
@@ -58,7 +59,7 @@ async fn insert_registered_client(
integrity::sign_entity(
&mut conn,
&actors.key_holder,
&actors.vault,
&ClientCredentials {
pubkey: pubkey.into(),
nonce: 1,
@@ -103,7 +104,7 @@ async fn spawn_test_actors(db: &db::DatabasePool) -> GlobalActors {
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(b"test-seal-key".to_vec()),
})

View File

@@ -1,7 +1,7 @@
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
use arbiter_proto::transport::{Bi, Error, Receiver, Sender};
use arbiter_server::{
actors::keyholder::KeyHolder,
actors::{GlobalActors, vault::Vault},
db::{self, schema},
};
@@ -11,8 +11,8 @@ use diesel_async::RunQueryDsl;
use tokio::sync::mpsc;
#[allow(dead_code)]
pub async fn bootstrapped_keyholder(db: &db::DatabasePool) -> KeyHolder {
let mut actor = KeyHolder::new(db.clone()).await.unwrap();
pub async fn bootstrapped_vault(db: &db::DatabasePool) -> Vault {
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus()).await.unwrap();
actor
.bootstrap(SafeCell::new(b"test-seal-key".to_vec()))
.await

View File

@@ -1,8 +0,0 @@
mod common;
#[path = "keyholder/concurrency.rs"]
mod concurrency;
#[path = "keyholder/lifecycle.rs"]
mod lifecycle;
#[path = "keyholder/storage.rs"]
mod storage;

View File

@@ -8,9 +8,10 @@ use arbiter_server::{
actors::{
GlobalActors,
bootstrap::GetToken,
keyholder::Bootstrap,
user_agent::{UserAgentConnection, UserAgentCredentials, auth},
vault::Bootstrap,
},
peers::user_agent::{UserAgentConnection, UserAgentCredentials, auth},
crypto::integrity,
db::{self, schema},
};
@@ -38,7 +39,7 @@ pub async fn test_bootstrap_token_auth() {
let db = db::create_test_pool().await;
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(b"test-seal-key".to_vec()),
})
@@ -124,7 +125,7 @@ pub async fn test_challenge_auth() {
let db = db::create_test_pool().await;
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(b"test-seal-key".to_vec()),
})
@@ -147,7 +148,7 @@ pub async fn test_challenge_auth() {
.unwrap();
integrity::sign_entity(
&mut conn,
&actors.key_holder,
&actors.vault,
&UserAgentCredentials {
pubkey: new_key.verifying_key().into(),
nonce: 1,
@@ -213,7 +214,7 @@ pub async fn test_challenge_auth_rejects_integrity_tag_mismatch_when_unsealed()
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(b"test-seal-key".to_vec()),
})
@@ -262,7 +263,7 @@ pub async fn test_challenge_auth_rejects_invalid_signature() {
let db = db::create_test_pool().await;
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(b"test-seal-key".to_vec()),
})
@@ -285,7 +286,7 @@ pub async fn test_challenge_auth_rejects_invalid_signature() {
.unwrap();
integrity::sign_entity(
&mut conn,
&actors.key_holder,
&actors.vault,
&UserAgentCredentials {
pubkey: new_key.verifying_key().into(),
nonce: 1,

View File

@@ -2,12 +2,13 @@ use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
use arbiter_server::{
actors::{
GlobalActors,
keyholder::{Bootstrap, Seal},
user_agent::{
vault::{Bootstrap, Seal},
},
peers::user_agent::{
UserAgentSession,
session::connection::{HandleUnsealEncryptedKey, HandleUnsealRequest, UnsealError},
},
},
db,
};
@@ -22,13 +23,13 @@ async fn setup_sealed_user_agent(
let actors = GlobalActors::spawn(db.clone()).await.unwrap();
actors
.key_holder
.vault
.ask(Bootstrap {
seal_key_raw: SafeCell::new(seal_key.to_vec()),
})
.await
.unwrap();
actors.key_holder.ask(Seal).await.unwrap();
actors.vault.ask(Seal).await.unwrap();
let session = UserAgentSession::spawn(UserAgentSession::new_test(db.clone(), actors));

View File

@@ -0,0 +1,8 @@
mod common;
#[path = "vault/concurrency.rs"]
mod concurrency;
#[path = "vault/lifecycle.rs"]
mod lifecycle;
#[path = "vault/storage.rs"]
mod storage;

View File

@@ -2,7 +2,7 @@ use std::collections::{HashMap, HashSet};
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
use arbiter_server::{
actors::keyholder::{CreateNew, Error, KeyHolder},
actors::{GlobalActors, vault::{CreateNew, Error, Vault}},
db::{self, models, schema},
};
@@ -14,7 +14,7 @@ use tokio::task::JoinSet;
use crate::common;
async fn write_concurrently(
actor: ActorRef<KeyHolder>,
actor: ActorRef<Vault>,
prefix: &'static str,
count: usize,
) -> Vec<(i32, Vec<u8>)> {
@@ -44,7 +44,7 @@ async fn write_concurrently(
#[test_log::test]
async fn concurrent_create_new_no_duplicate_nonces_() {
let db = db::create_test_pool().await;
let actor = KeyHolder::spawn(common::bootstrapped_keyholder(&db).await);
let actor = Vault::spawn(common::bootstrapped_vault(&db).await);
let writes = write_concurrently(actor, "nonce-unique", 32).await;
assert_eq!(writes.len(), 32);
@@ -66,7 +66,7 @@ async fn concurrent_create_new_no_duplicate_nonces_() {
#[test_log::test]
async fn concurrent_create_new_root_nonce_never_moves_backward() {
let db = db::create_test_pool().await;
let actor = KeyHolder::spawn(common::bootstrapped_keyholder(&db).await);
let actor = Vault::spawn(common::bootstrapped_vault(&db).await);
write_concurrently(actor, "root-max", 24).await;
@@ -94,7 +94,7 @@ async fn concurrent_create_new_root_nonce_never_moves_backward() {
#[test_log::test]
async fn insert_failure_does_not_create_partial_row() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let root_key_history_id = common::root_key_history_id(&db).await;
let mut conn = db.get().await.unwrap();
@@ -156,12 +156,12 @@ async fn insert_failure_does_not_create_partial_row() {
#[test_log::test]
async fn decrypt_roundtrip_after_high_concurrency() {
let db = db::create_test_pool().await;
let actor = KeyHolder::spawn(common::bootstrapped_keyholder(&db).await);
let actor = Vault::spawn(common::bootstrapped_vault(&db).await);
let writes = write_concurrently(actor, "roundtrip", 40).await;
let expected: HashMap<i32, Vec<u8>> = writes.into_iter().collect();
let mut decryptor = KeyHolder::new(db.clone()).await.unwrap();
let mut decryptor = Vault::new(db.clone(), GlobalActors::spawn_message_bus()).await.unwrap();
decryptor
.try_unseal(SafeCell::new(b"test-seal-key".to_vec()))
.await

View File

@@ -1,8 +1,12 @@
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
use arbiter_server::{
actors::keyholder::{Error, KeyHolder},
actors::{GlobalActors, vault::{Error, Vault}},
crypto::encryption::v1::{Nonce, ROOT_KEY_TAG},
db::{self, models, schema},
peers::user_agent::{
UserAgentSession,
session::connection::{HandleUnsealEncryptedKey, HandleUnsealRequest, UnsealError},
},
};
use diesel::{QueryDsl, SelectableHelper};
@@ -14,7 +18,7 @@ use crate::common;
#[test_log::test]
async fn test_bootstrap() {
let db = db::create_test_pool().await;
let mut actor = KeyHolder::new(db.clone()).await.unwrap();
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus()).await.unwrap();
let seal_key = SafeCell::new(b"test-seal-key".to_vec());
actor.bootstrap(seal_key).await.unwrap();
@@ -37,7 +41,7 @@ async fn test_bootstrap() {
#[test_log::test]
async fn test_bootstrap_rejects_double() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let seal_key2 = SafeCell::new(b"test-seal-key".to_vec());
let err = actor.bootstrap(seal_key2).await.unwrap_err();
@@ -48,7 +52,7 @@ async fn test_bootstrap_rejects_double() {
#[test_log::test]
async fn test_create_new_before_bootstrap_fails() {
let db = db::create_test_pool().await;
let mut actor = KeyHolder::new(db).await.unwrap();
let mut actor = Vault::new(db, GlobalActors::spawn_message_bus()).await.unwrap();
let err = actor
.create_new(SafeCell::new(b"data".to_vec()))
@@ -61,7 +65,7 @@ async fn test_create_new_before_bootstrap_fails() {
#[test_log::test]
async fn test_decrypt_before_bootstrap_fails() {
let db = db::create_test_pool().await;
let mut actor = KeyHolder::new(db).await.unwrap();
let mut actor = Vault::new(db, GlobalActors::spawn_message_bus()).await.unwrap();
let err = actor.decrypt(1).await.unwrap_err();
assert!(matches!(err, Error::NotBootstrapped));
@@ -71,10 +75,10 @@ async fn test_decrypt_before_bootstrap_fails() {
#[test_log::test]
async fn test_new_restores_sealed_state() {
let db = db::create_test_pool().await;
let actor = common::bootstrapped_keyholder(&db).await;
let actor = common::bootstrapped_vault(&db).await;
drop(actor);
let mut actor2 = KeyHolder::new(db).await.unwrap();
let mut actor2 = Vault::new(db, GlobalActors::spawn_message_bus()).await.unwrap();
let err = actor2.decrypt(1).await.unwrap_err();
assert!(matches!(err, Error::NotBootstrapped));
}
@@ -83,7 +87,7 @@ async fn test_new_restores_sealed_state() {
#[test_log::test]
async fn test_unseal_correct_password() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let plaintext = b"survive a restart";
let aead_id = actor
@@ -92,7 +96,7 @@ async fn test_unseal_correct_password() {
.unwrap();
drop(actor);
let mut actor = KeyHolder::new(db.clone()).await.unwrap();
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus()).await.unwrap();
let seal_key = SafeCell::new(b"test-seal-key".to_vec());
actor.try_unseal(seal_key).await.unwrap();
@@ -104,7 +108,7 @@ async fn test_unseal_correct_password() {
#[test_log::test]
async fn test_unseal_wrong_then_correct_password() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let plaintext = b"important data";
let aead_id = actor
@@ -113,7 +117,7 @@ async fn test_unseal_wrong_then_correct_password() {
.unwrap();
drop(actor);
let mut actor = KeyHolder::new(db.clone()).await.unwrap();
let mut actor = Vault::new(db.clone(), GlobalActors::spawn_message_bus()).await.unwrap();
let bad_key = SafeCell::new(b"wrong-password".to_vec());
let err = actor.try_unseal(bad_key).await.unwrap_err();

View File

@@ -2,7 +2,7 @@ use std::collections::HashSet;
use arbiter_crypto::safecell::{SafeCell, SafeCellHandle as _};
use arbiter_server::{
actors::keyholder::Error,
actors::vault::Error,
crypto::encryption::v1::Nonce,
db::{self, models, schema},
};
@@ -16,7 +16,7 @@ use crate::common;
#[test_log::test]
async fn test_create_decrypt_roundtrip() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let plaintext = b"hello arbiter";
let aead_id = actor
@@ -32,7 +32,7 @@ async fn test_create_decrypt_roundtrip() {
#[test_log::test]
async fn test_decrypt_nonexistent_returns_not_found() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let err = actor.decrypt(9999).await.unwrap_err();
assert!(matches!(err, Error::NotFound));
@@ -42,7 +42,7 @@ async fn test_decrypt_nonexistent_returns_not_found() {
#[test_log::test]
async fn test_ciphertext_differs_across_entries() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let plaintext = b"same content";
let id1 = actor
@@ -80,7 +80,7 @@ async fn test_ciphertext_differs_across_entries() {
#[test_log::test]
async fn test_nonce_never_reused() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let n = 5;
for i in 0..n {
@@ -124,7 +124,7 @@ async fn test_nonce_never_reused() {
#[test_log::test]
async fn broken_db_nonce_format_fails_closed() {
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let root_key_history_id = common::root_key_history_id(&db).await;
let mut conn = db.get().await.unwrap();
@@ -145,7 +145,7 @@ async fn broken_db_nonce_format_fails_closed() {
assert!(matches!(err, Error::BrokenDatabase));
let db = db::create_test_pool().await;
let mut actor = common::bootstrapped_keyholder(&db).await;
let mut actor = common::bootstrapped_vault(&db).await;
let id = actor
.create_new(SafeCell::new(b"decrypt target".to_vec()))
.await