refactor(server): actors reorganization & linter fixes
This commit is contained in:
@@ -10,10 +10,10 @@ pub mod proto {
|
||||
|
||||
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> {
|
||||
static ARBITER_HOME: &'static str = ".arbiter";
|
||||
static ARBITER_HOME: &str = ".arbiter";
|
||||
let home_dir = std::env::home_dir().ok_or(std::io::Error::new(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
"can not get home directory",
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
pub mod v1;
|
||||
@@ -42,12 +42,12 @@ impl<'a> TryFrom<&'a [u8]> for Nonce {
|
||||
return Err(());
|
||||
}
|
||||
let mut nonce = [0u8; NONCE_LENGTH];
|
||||
nonce.copy_from_slice(&value);
|
||||
nonce.copy_from_slice(value);
|
||||
Ok(Self(nonce))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KeyCell(pub(super) MemSafe<Key>);
|
||||
pub struct KeyCell(pub MemSafe<Key>);
|
||||
impl From<MemSafe<Key>> for KeyCell {
|
||||
fn from(value: MemSafe<Key>) -> Self {
|
||||
Self(value)
|
||||
@@ -85,10 +85,6 @@ impl KeyCell {
|
||||
key.into()
|
||||
}
|
||||
|
||||
pub fn into_inner(self) -> MemSafe<Key> {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub fn encrypt_in_place(
|
||||
&mut self,
|
||||
nonce: &Nonce,
|
||||
@@ -130,7 +126,7 @@ impl KeyCell {
|
||||
|
||||
|
||||
let ciphertext = cipher.encrypt(
|
||||
&nonce,
|
||||
nonce,
|
||||
Payload {
|
||||
msg: plaintext.as_ref(),
|
||||
aad: associated_data,
|
||||
@@ -142,7 +138,7 @@ impl KeyCell {
|
||||
|
||||
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 rng = StdRng::try_from_rng(&mut SysRng).unwrap();
|
||||
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...
|
||||
/// 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 hasher = Argon2::new(Algorithm::Argon2id, argon2::Version::V0x13, params);
|
||||
let mut key = MemSafe::new(Key::default()).unwrap();
|
||||
@@ -9,15 +9,16 @@ use strum::{EnumDiscriminants, IntoDiscriminant};
|
||||
use tracing::{error, info};
|
||||
|
||||
use crate::{
|
||||
actors::keyholder::v1::{KeyCell, Nonce},
|
||||
db::{
|
||||
self,
|
||||
models::{self, RootKeyHistory},
|
||||
schema::{self},
|
||||
},
|
||||
};
|
||||
use encryption::v1::{self, KeyCell, Nonce};
|
||||
|
||||
pub mod encryption;
|
||||
|
||||
pub mod v1;
|
||||
|
||||
#[derive(Default, EnumDiscriminants)]
|
||||
#[strum_discriminants(derive(Reply), vis(pub))]
|
||||
@@ -10,7 +10,7 @@ use arbiter_proto::proto::{
|
||||
};
|
||||
use chacha20poly1305::{AeadInPlace, XChaCha20Poly1305, XNonce, aead::KeyInit};
|
||||
use diesel::{ExpressionMethods as _, OptionalExtension as _, QueryDsl, dsl::update};
|
||||
use diesel_async::{AsyncConnection, RunQueryDsl};
|
||||
use diesel_async::{RunQueryDsl};
|
||||
use ed25519_dalek::VerifyingKey;
|
||||
use kameo::{Actor, actor::ActorRef, error::SendError, messages};
|
||||
use memsafe::MemSafe;
|
||||
@@ -25,7 +25,7 @@ use crate::{
|
||||
bootstrap::{Bootstrapper, ConsumeToken},
|
||||
keyholder::{self, KeyHolder, TryUnseal},
|
||||
user_agent::state::{
|
||||
AuthRequestContext, ChallengeContext, DummyContext, UnsealContext, UserAgentEvents,
|
||||
ChallengeContext, DummyContext, UnsealContext, UserAgentEvents,
|
||||
UserAgentStateMachine, UserAgentStates,
|
||||
},
|
||||
},
|
||||
@@ -129,7 +129,7 @@ impl UserAgentActor {
|
||||
let nonce: Option<i32> = {
|
||||
let mut db_conn = self.db.get().await.to_status()?;
|
||||
db_conn
|
||||
.transaction(|conn| {
|
||||
.exclusive_transaction(|conn| {
|
||||
Box::pin(async move {
|
||||
let current_nonce = schema::useragent_client::table
|
||||
.filter(
|
||||
@@ -162,7 +162,7 @@ impl UserAgentActor {
|
||||
|
||||
let challenge = auth::AuthChallenge {
|
||||
pubkey: pubkey_bytes,
|
||||
nonce: nonce,
|
||||
nonce,
|
||||
};
|
||||
|
||||
self.transition(UserAgentEvents::SentChallenge(ChallengeContext {
|
||||
@@ -237,7 +237,6 @@ impl UserAgentActor {
|
||||
let client_public_key = PublicKey::from(client_pubkey_bytes);
|
||||
|
||||
self.transition(UserAgentEvents::UnsealRequest(UnsealContext {
|
||||
server_public_key: public_key,
|
||||
secret: Mutex::new(Some(secret)),
|
||||
client_public_key,
|
||||
}))?;
|
||||
@@ -325,9 +324,9 @@ impl UserAgentActor {
|
||||
Err(err) => {
|
||||
error!(?err, "Failed to decrypt unseal key");
|
||||
self.transition(UserAgentEvents::ReceivedInvalidKey)?;
|
||||
return Ok(unseal_response(UserAgentResponsePayload::UnsealResult(
|
||||
Ok(unseal_response(UserAgentResponsePayload::UnsealResult(
|
||||
UnsealResult::InvalidKey.into(),
|
||||
)));
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,10 +341,7 @@ impl UserAgentActor {
|
||||
Status::invalid_argument("Failed to convert pubkey to VerifyingKey")
|
||||
})?;
|
||||
|
||||
self.transition(UserAgentEvents::AuthRequest(AuthRequestContext {
|
||||
pubkey,
|
||||
bootstrap_token: req.bootstrap_token.clone(),
|
||||
}))?;
|
||||
self.transition(UserAgentEvents::AuthRequest)?;
|
||||
|
||||
match req.bootstrap_token {
|
||||
Some(token) => self.auth_with_bootstrap_token(pubkey, token).await,
|
||||
@@ -12,17 +12,9 @@ pub struct ChallengeContext {
|
||||
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 server_public_key: PublicKey,
|
||||
pub client_public_key: PublicKey,
|
||||
pub secret: Mutex<Option<EphemeralSecret>>,
|
||||
}
|
||||
@@ -33,10 +25,10 @@ smlang::statemachine!(
|
||||
name: UserAgent,
|
||||
custom_error: false,
|
||||
transitions: {
|
||||
*Init + AuthRequest(AuthRequestContext) / auth_request_context = ReceivedAuthRequest(AuthRequestContext),
|
||||
ReceivedAuthRequest(AuthRequestContext) + ReceivedBootstrapToken = Idle,
|
||||
*Init + AuthRequest = ReceivedAuthRequest,
|
||||
ReceivedAuthRequest + ReceivedBootstrapToken = Idle,
|
||||
|
||||
ReceivedAuthRequest(AuthRequestContext) + SentChallenge(ChallengeContext) / move_challenge = WaitingForChallengeSolution(ChallengeContext),
|
||||
ReceivedAuthRequest + SentChallenge(ChallengeContext) / move_challenge = WaitingForChallengeSolution(ChallengeContext),
|
||||
|
||||
WaitingForChallengeSolution(ChallengeContext) + ReceivedGoodSolution = Idle,
|
||||
WaitingForChallengeSolution(ChallengeContext) + ReceivedBadSolution = AuthError, // block further transitions, but connection should close anyway
|
||||
@@ -49,28 +41,15 @@ smlang::statemachine!(
|
||||
|
||||
pub struct 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(clippy::unused_unit)]
|
||||
fn generate_temp_keypair(&mut self, event_data: UnsealContext) -> Result<UnsealContext, ()> {
|
||||
Ok(event_data)
|
||||
}
|
||||
|
||||
#[allow(missing_docs)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
fn move_challenge< >(&mut self,event_data:ChallengeContext) -> Result<ChallengeContext,()> {
|
||||
Ok(event_data)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ pub type DatabasePool = diesel_async::pooled_connection::bb8::Pool<DatabaseConne
|
||||
pub type PoolInitError = diesel_async::pooled_connection::PoolError;
|
||||
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");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user