refactor(server): actors reorganization & linter fixes

This commit is contained in:
hdbg
2026-02-16 21:38:36 +01:00
parent 0805e7a846
commit bdb9f01757
7 changed files with 29 additions and 56 deletions

View File

@@ -10,10 +10,10 @@ pub mod proto {
pub mod transport; pub mod transport;
pub static BOOTSTRAP_TOKEN_PATH: &'static str = "bootstrap_token"; pub static BOOTSTRAP_TOKEN_PATH: &str = "bootstrap_token";
pub fn home_path() -> Result<std::path::PathBuf, std::io::Error> { pub fn home_path() -> Result<std::path::PathBuf, std::io::Error> {
static ARBITER_HOME: &'static str = ".arbiter"; static ARBITER_HOME: &str = ".arbiter";
let home_dir = std::env::home_dir().ok_or(std::io::Error::new( let home_dir = std::env::home_dir().ok_or(std::io::Error::new(
std::io::ErrorKind::PermissionDenied, std::io::ErrorKind::PermissionDenied,
"can not get home directory", "can not get home directory",

View File

@@ -0,0 +1 @@
pub mod v1;

View File

@@ -42,12 +42,12 @@ impl<'a> TryFrom<&'a [u8]> for Nonce {
return Err(()); return Err(());
} }
let mut nonce = [0u8; NONCE_LENGTH]; let mut nonce = [0u8; NONCE_LENGTH];
nonce.copy_from_slice(&value); nonce.copy_from_slice(value);
Ok(Self(nonce)) Ok(Self(nonce))
} }
} }
pub struct KeyCell(pub(super) MemSafe<Key>); pub struct KeyCell(pub MemSafe<Key>);
impl From<MemSafe<Key>> for KeyCell { impl From<MemSafe<Key>> for KeyCell {
fn from(value: MemSafe<Key>) -> Self { fn from(value: MemSafe<Key>) -> Self {
Self(value) Self(value)
@@ -85,10 +85,6 @@ impl KeyCell {
key.into() key.into()
} }
pub fn into_inner(self) -> MemSafe<Key> {
self.0
}
pub fn encrypt_in_place( pub fn encrypt_in_place(
&mut self, &mut self,
nonce: &Nonce, nonce: &Nonce,
@@ -130,7 +126,7 @@ impl KeyCell {
let ciphertext = cipher.encrypt( let ciphertext = cipher.encrypt(
&nonce, nonce,
Payload { Payload {
msg: plaintext.as_ref(), msg: plaintext.as_ref(),
aad: associated_data, aad: associated_data,
@@ -142,7 +138,7 @@ impl KeyCell {
pub type Salt = [u8; ArgonSalt::RECOMMENDED_LENGTH]; pub type Salt = [u8; ArgonSalt::RECOMMENDED_LENGTH];
pub(super) fn generate_salt() -> Salt { pub fn generate_salt() -> Salt {
let mut salt = Salt::default(); let mut salt = Salt::default();
let mut rng = StdRng::try_from_rng(&mut SysRng).unwrap(); let mut rng = StdRng::try_from_rng(&mut SysRng).unwrap();
rng.fill_bytes(&mut salt); rng.fill_bytes(&mut salt);
@@ -151,7 +147,7 @@ pub(super) fn generate_salt() -> Salt {
/// User password might be of different length, have not enough entropy, etc... /// User password might be of different length, have not enough entropy, etc...
/// Derive a fixed-length key from the password using Argon2id, which is designed for password hashing and key derivation. /// Derive a fixed-length key from the password using Argon2id, which is designed for password hashing and key derivation.
pub(super) fn derive_seal_key(mut password: MemSafe<Vec<u8>>, salt: &Salt) -> KeyCell { pub fn derive_seal_key(mut password: MemSafe<Vec<u8>>, salt: &Salt) -> KeyCell {
let params = argon2::Params::new(262_144, 3, 4, None).unwrap(); let params = argon2::Params::new(262_144, 3, 4, None).unwrap();
let hasher = Argon2::new(Algorithm::Argon2id, argon2::Version::V0x13, params); let hasher = Argon2::new(Algorithm::Argon2id, argon2::Version::V0x13, params);
let mut key = MemSafe::new(Key::default()).unwrap(); let mut key = MemSafe::new(Key::default()).unwrap();

View File

@@ -9,15 +9,16 @@ use strum::{EnumDiscriminants, IntoDiscriminant};
use tracing::{error, info}; use tracing::{error, info};
use crate::{ use crate::{
actors::keyholder::v1::{KeyCell, Nonce},
db::{ db::{
self, self,
models::{self, RootKeyHistory}, models::{self, RootKeyHistory},
schema::{self}, schema::{self},
}, },
}; };
use encryption::v1::{self, KeyCell, Nonce};
pub mod encryption;
pub mod v1;
#[derive(Default, EnumDiscriminants)] #[derive(Default, EnumDiscriminants)]
#[strum_discriminants(derive(Reply), vis(pub))] #[strum_discriminants(derive(Reply), vis(pub))]

View File

@@ -10,7 +10,7 @@ use arbiter_proto::proto::{
}; };
use chacha20poly1305::{AeadInPlace, XChaCha20Poly1305, XNonce, aead::KeyInit}; use chacha20poly1305::{AeadInPlace, XChaCha20Poly1305, XNonce, aead::KeyInit};
use diesel::{ExpressionMethods as _, OptionalExtension as _, QueryDsl, dsl::update}; use diesel::{ExpressionMethods as _, OptionalExtension as _, QueryDsl, dsl::update};
use diesel_async::{AsyncConnection, RunQueryDsl}; use diesel_async::{RunQueryDsl};
use ed25519_dalek::VerifyingKey; use ed25519_dalek::VerifyingKey;
use kameo::{Actor, actor::ActorRef, error::SendError, messages}; use kameo::{Actor, actor::ActorRef, error::SendError, messages};
use memsafe::MemSafe; use memsafe::MemSafe;
@@ -25,7 +25,7 @@ use crate::{
bootstrap::{Bootstrapper, ConsumeToken}, bootstrap::{Bootstrapper, ConsumeToken},
keyholder::{self, KeyHolder, TryUnseal}, keyholder::{self, KeyHolder, TryUnseal},
user_agent::state::{ user_agent::state::{
AuthRequestContext, ChallengeContext, DummyContext, UnsealContext, UserAgentEvents, ChallengeContext, DummyContext, UnsealContext, UserAgentEvents,
UserAgentStateMachine, UserAgentStates, UserAgentStateMachine, UserAgentStates,
}, },
}, },
@@ -129,7 +129,7 @@ impl UserAgentActor {
let nonce: Option<i32> = { let nonce: Option<i32> = {
let mut db_conn = self.db.get().await.to_status()?; let mut db_conn = self.db.get().await.to_status()?;
db_conn db_conn
.transaction(|conn| { .exclusive_transaction(|conn| {
Box::pin(async move { Box::pin(async move {
let current_nonce = schema::useragent_client::table let current_nonce = schema::useragent_client::table
.filter( .filter(
@@ -162,7 +162,7 @@ impl UserAgentActor {
let challenge = auth::AuthChallenge { let challenge = auth::AuthChallenge {
pubkey: pubkey_bytes, pubkey: pubkey_bytes,
nonce: nonce, nonce,
}; };
self.transition(UserAgentEvents::SentChallenge(ChallengeContext { self.transition(UserAgentEvents::SentChallenge(ChallengeContext {
@@ -237,7 +237,6 @@ impl UserAgentActor {
let client_public_key = PublicKey::from(client_pubkey_bytes); let client_public_key = PublicKey::from(client_pubkey_bytes);
self.transition(UserAgentEvents::UnsealRequest(UnsealContext { self.transition(UserAgentEvents::UnsealRequest(UnsealContext {
server_public_key: public_key,
secret: Mutex::new(Some(secret)), secret: Mutex::new(Some(secret)),
client_public_key, client_public_key,
}))?; }))?;
@@ -325,9 +324,9 @@ impl UserAgentActor {
Err(err) => { Err(err) => {
error!(?err, "Failed to decrypt unseal key"); error!(?err, "Failed to decrypt unseal key");
self.transition(UserAgentEvents::ReceivedInvalidKey)?; self.transition(UserAgentEvents::ReceivedInvalidKey)?;
return Ok(unseal_response(UserAgentResponsePayload::UnsealResult( Ok(unseal_response(UserAgentResponsePayload::UnsealResult(
UnsealResult::InvalidKey.into(), UnsealResult::InvalidKey.into(),
))); )))
} }
} }
} }
@@ -342,10 +341,7 @@ impl UserAgentActor {
Status::invalid_argument("Failed to convert pubkey to VerifyingKey") Status::invalid_argument("Failed to convert pubkey to VerifyingKey")
})?; })?;
self.transition(UserAgentEvents::AuthRequest(AuthRequestContext { self.transition(UserAgentEvents::AuthRequest)?;
pubkey,
bootstrap_token: req.bootstrap_token.clone(),
}))?;
match req.bootstrap_token { match req.bootstrap_token {
Some(token) => self.auth_with_bootstrap_token(pubkey, token).await, Some(token) => self.auth_with_bootstrap_token(pubkey, token).await,

View File

@@ -12,17 +12,9 @@ pub struct ChallengeContext {
pub key: VerifyingKey, pub key: VerifyingKey,
} }
// Request context with deserialized public key for state machine.
// This intermediate struct is needed because the state machine branches depending on presence of bootstrap token,
// but we want to have the deserialized key in both branches.
#[derive(Clone, Debug)]
pub struct AuthRequestContext {
pub pubkey: VerifyingKey,
pub bootstrap_token: Option<String>,
}
pub struct UnsealContext { pub struct UnsealContext {
pub server_public_key: PublicKey,
pub client_public_key: PublicKey, pub client_public_key: PublicKey,
pub secret: Mutex<Option<EphemeralSecret>>, pub secret: Mutex<Option<EphemeralSecret>>,
} }
@@ -33,10 +25,10 @@ smlang::statemachine!(
name: UserAgent, name: UserAgent,
custom_error: false, custom_error: false,
transitions: { transitions: {
*Init + AuthRequest(AuthRequestContext) / auth_request_context = ReceivedAuthRequest(AuthRequestContext), *Init + AuthRequest = ReceivedAuthRequest,
ReceivedAuthRequest(AuthRequestContext) + ReceivedBootstrapToken = Idle, ReceivedAuthRequest + ReceivedBootstrapToken = Idle,
ReceivedAuthRequest(AuthRequestContext) + SentChallenge(ChallengeContext) / move_challenge = WaitingForChallengeSolution(ChallengeContext), ReceivedAuthRequest + SentChallenge(ChallengeContext) / move_challenge = WaitingForChallengeSolution(ChallengeContext),
WaitingForChallengeSolution(ChallengeContext) + ReceivedGoodSolution = Idle, WaitingForChallengeSolution(ChallengeContext) + ReceivedGoodSolution = Idle,
WaitingForChallengeSolution(ChallengeContext) + ReceivedBadSolution = AuthError, // block further transitions, but connection should close anyway WaitingForChallengeSolution(ChallengeContext) + ReceivedBadSolution = AuthError, // block further transitions, but connection should close anyway
@@ -49,28 +41,15 @@ smlang::statemachine!(
pub struct DummyContext; pub struct DummyContext;
impl UserAgentStateMachineContext for DummyContext { impl UserAgentStateMachineContext for DummyContext {
#[allow(missing_docs)]
#[allow(clippy::unused_unit)]
fn move_challenge(
&mut self,
_state_data: &AuthRequestContext,
event_data: ChallengeContext,
) -> Result<ChallengeContext, ()> {
Ok(event_data)
}
#[allow(missing_docs)]
#[allow(clippy::unused_unit)]
fn auth_request_context(
&mut self,
event_data: AuthRequestContext,
) -> Result<AuthRequestContext, ()> {
Ok(event_data)
}
#[allow(missing_docs)] #[allow(missing_docs)]
#[allow(clippy::unused_unit)] #[allow(clippy::unused_unit)]
fn generate_temp_keypair(&mut self, event_data: UnsealContext) -> Result<UnsealContext, ()> { fn generate_temp_keypair(&mut self, event_data: UnsealContext) -> Result<UnsealContext, ()> {
Ok(event_data) Ok(event_data)
} }
#[allow(missing_docs)]
#[allow(clippy::unused_unit)]
fn move_challenge< >(&mut self,event_data:ChallengeContext) -> Result<ChallengeContext,()> {
Ok(event_data)
}
} }

View File

@@ -21,7 +21,7 @@ pub type DatabasePool = diesel_async::pooled_connection::bb8::Pool<DatabaseConne
pub type PoolInitError = diesel_async::pooled_connection::PoolError; pub type PoolInitError = diesel_async::pooled_connection::PoolError;
pub type PoolError = diesel_async::pooled_connection::bb8::RunError; pub type PoolError = diesel_async::pooled_connection::bb8::RunError;
static DB_FILE: &'static str = "arbiter.sqlite"; static DB_FILE: &str = "arbiter.sqlite";
const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations"); const MIGRATIONS: EmbeddedMigrations = embed_migrations!("migrations");