From cf9607b15e1ad5e6fa908d1b71504b3fdd961367 Mon Sep 17 00:00:00 2001 From: Alex Emmet <111742636+Alex-Emmet@users.noreply.github.com> Date: Fri, 28 Aug 2026 13:20:20 +0200 Subject: [PATCH] [Fix] Stability --- Cargo.toml | 1 - src/db/iota_repo.rs | 8 ++++ src/identity.rs | 65 +++++++++++++---------------- src/main.rs | 16 +------ src/transport/omikron_connection.rs | 19 ++++++++- 5 files changed, 55 insertions(+), 54 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 395ad06..b7d4164 100755 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,3 @@ uuid = { version = "1.24.0", features = ["v4", "v7"] } thiserror = "2.0.19" serde = { version = "1.0.229", features = ["derive"] } serde_json = "1.0.151" -zeroize = "1.9" diff --git a/src/db/iota_repo.rs b/src/db/iota_repo.rs index fb50432..e413684 100644 --- a/src/db/iota_repo.rs +++ b/src/db/iota_repo.rs @@ -54,6 +54,14 @@ pub async fn register_complete_iota(id: IotaId, public_key: PublicKeyBundle) -> Ok(()) } +pub async fn change_iota_key(id: IotaId, key: PublicKeyBundle) -> Result<()> { + sqlx::query("UPDATE iotas SET public_key = ? WHERE id = ?") + .bind(key.try_as_bytes()?) + .bind(id.0) + .execute(&pool().await?) + .await?; + Ok(()) +} pub async fn delete_iota(id: IotaId) -> Result<()> { sqlx::query("DELETE FROM iotas WHERE id = ?") .bind(id.0) diff --git a/src/identity.rs b/src/identity.rs index a7a831d..0fb416d 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -1,7 +1,8 @@ use crate::error::{IdentityError, Result}; use mtp::crypto::{Keyring, PublicKeyBundle}; use mtp::files::{ - FileError, load_keyring, load_public_key_bundle, save_keyring, save_public_key_bundle, + FileError, load_keyring_raw, load_public_key_bundle, save_keyring_raw, + save_public_key_bundle, }; use std::{ fs, @@ -22,25 +23,20 @@ pub struct OmegaIdentity { static PUBLIC_BUNDLE_TEMP_COUNTER: AtomicU64 = AtomicU64::new(0); impl OmegaIdentity { - pub fn load_or_create(passphrase: &[u8]) -> Result { - Self::load_or_create_at( - Path::new(KEYRING_PATH), - Path::new(PUBLIC_KEY_PATH), - passphrase, - ) + pub fn load_or_create() -> Result { + Self::load_or_create_at(Path::new(KEYRING_PATH), Path::new(PUBLIC_KEY_PATH)) } pub(crate) fn load_or_create_at( keyring_path: impl AsRef, public_key_path: impl AsRef, - passphrase: &[u8], ) -> Result { let keyring_path = keyring_path.as_ref(); let public_key_path = public_key_path.as_ref(); - let keyring = match load_keyring(keyring_path, passphrase) { + let keyring = match load_keyring_raw(keyring_path) { Ok(keyring) => keyring, Err(FileError::Io(error)) if error.kind() == std::io::ErrorKind::NotFound => { - return Self::create_at(keyring_path, public_key_path, passphrase); + return Self::create_at(keyring_path, public_key_path); } Err(error) => { return Err(IdentityError::Storage { @@ -72,9 +68,9 @@ impl OmegaIdentity { Ok(identity) } - fn create_at(keyring_path: &Path, public_key_path: &Path, passphrase: &[u8]) -> Result { + fn create_at(keyring_path: &Path, public_key_path: &Path) -> Result { let keyring = Keyring::generate(); - save_keyring(&keyring, keyring_path, passphrase).map_err(|error| { + save_keyring_raw(&keyring, keyring_path).map_err(|error| { IdentityError::Storage { path: keyring_path.to_path_buf(), source: error, @@ -188,9 +184,7 @@ mod tests { let directory = test_directory(); let keyring_path = directory.join("omega.mk"); let public_key_path = directory.join("omega.mpkb"); - let passphrase = b"test-passphrase"; - - let first = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) + let first = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) .expect("create identity"); let first_bundle = first.public_key_bundle().try_as_bytes().expect("bundle"); @@ -199,9 +193,8 @@ mod tests { assert_eq!(&keyring_bytes[..4], b"MTMK"); assert_eq!(&bundle_bytes[..4], b"MPKB"); - let restarted = - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) - .expect("reload identity"); + let restarted = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) + .expect("reload identity"); assert_eq!( restarted .public_key_bundle() @@ -227,8 +220,7 @@ mod tests { let public_key_path = directory.join("omega.mpkb"); fs::write(&keyring_path, b"not-a-keyring").expect("write invalid keyring"); - let result = - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, b"test-passphrase"); + let result = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path); assert!(result.is_err()); assert!(!public_key_path.exists()); @@ -240,16 +232,13 @@ mod tests { let directory = test_directory(); let keyring_path = directory.join("omega.mk"); let public_key_path = directory.join("omega.mpkb"); - let passphrase = b"test-passphrase"; - - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) + OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) .expect("create identity"); let original_keyring = fs::read(&keyring_path).expect("read keyring"); fs::remove_file(&public_key_path).expect("remove bundle"); - let repaired = - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) - .expect("repair bundle"); + let repaired = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) + .expect("repair bundle"); assert_eq!( fs::read(&keyring_path).expect("read keyring"), @@ -271,16 +260,14 @@ mod tests { let directory = test_directory(); let keyring_path = directory.join("omega.mk"); let public_key_path = directory.join("omega.mpkb"); - let passphrase = b"test-passphrase"; - - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) + OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) .expect("create identity"); let other_keyring = Keyring::generate(); save_public_key_bundle(&other_keyring.public_key_bundle(), &public_key_path) .expect("save mismatched bundle"); assert!(matches!( - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase), + OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path), Err(crate::OmegaError::Identity( IdentityError::PublicBundleMismatch { .. } )) @@ -290,24 +277,28 @@ mod tests { } #[test] - fn wrong_passphrase_does_not_replace_existing_keyring() { + fn existing_raw_keyring_is_reloaded_without_a_passphrase() { let directory = test_directory(); let keyring_path = directory.join("omega.mk"); let public_key_path = directory.join("omega.mpkb"); - let passphrase = b"test-passphrase"; - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, passphrase) + let first = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) .expect("create identity"); let original_keyring = fs::read(&keyring_path).expect("read keyring"); - assert!( - OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path, b"wrong-passphrase") - .is_err() - ); + let reloaded = OmegaIdentity::load_or_create_at(&keyring_path, &public_key_path) + .expect("reload identity"); assert_eq!( fs::read(&keyring_path).expect("read keyring"), original_keyring ); + assert_eq!( + reloaded + .public_key_bundle() + .try_as_bytes() + .expect("bundle"), + first.public_key_bundle().try_as_bytes().expect("bundle") + ); fs::remove_dir_all(directory).expect("remove test directory"); } diff --git a/src/main.rs b/src/main.rs index e04238c..d302ff6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,6 @@ use std::env; use std::path::Path; use std::time::Duration; use tokio::time::interval; -use zeroize::Zeroizing; #[tokio::main] async fn main() { @@ -38,18 +37,6 @@ async fn main() { log_in!("Incoming messages"); log_out!("Outgoing messages"); - let identity_secret = match env::var("OMEGA_IDENTITY_SECRET") { - Ok(secret) if !secret.is_empty() => secret, - Ok(_) => { - log!("[FATAL] OMEGA_IDENTITY_SECRET must not be empty"); - return; - } - Err(error) => { - log!("[FATAL] Unable to load OMEGA_IDENTITY_SECRET: {}", error); - return; - } - }; - let identity_secret = Zeroizing::new(identity_secret); let config = match OmegaConfig::from_env() { Ok(config) => config, Err(error) => { @@ -61,14 +48,13 @@ async fn main() { log!("[FATAL] Omega rate-limit configuration was initialized more than once"); return; } - let identity = match identity::OmegaIdentity::load_or_create(identity_secret.as_bytes()) { + let identity = match identity::OmegaIdentity::load_or_create() { Ok(identity) => identity, Err(error) => { log!("[FATAL] Omega identity initialization failed: {}", error); return; } }; - drop(identity_secret); let state = OmegaState::new(identity, config); log!("Started"); diff --git a/src/transport/omikron_connection.rs b/src/transport/omikron_connection.rs index 8c536c7..1194a2d 100644 --- a/src/transport/omikron_connection.rs +++ b/src/transport/omikron_connection.rs @@ -764,8 +764,9 @@ pub async fn start(port: u16, state: Arc) -> Result<(), Box