From c24b254b22000597784db3cbbcde68c879ec0d1f Mon Sep 17 00:00:00 2001 From: Donovan Date: Thu, 18 Dec 2025 11:19:11 -0600 Subject: [PATCH] idk what i did --- src/client/app.rs | 102 ++++++------------ src/client/client_auth_api.rs | 79 ++++++++++++++ src/client/mod.rs | 5 +- src/client/opaque.rs | 8 +- src/client/states.rs | 43 ++------ src/server/app.rs | 6 +- .../repository/in_memory/in_memory_user_db.rs | 4 +- src/server/repository/mod.rs | 1 - src/shared/models/mod.rs | 3 +- src/shared/models/opaque.rs | 10 ++ .../user_repo.rs => shared/models/store.rs} | 2 +- tests/in_memory_test.rs | 10 +- 12 files changed, 155 insertions(+), 118 deletions(-) create mode 100644 src/client/client_auth_api.rs rename src/{server/repository/user_repo.rs => shared/models/store.rs} (96%) diff --git a/src/client/app.rs b/src/client/app.rs index b2623b1..5e90741 100644 --- a/src/client/app.rs +++ b/src/client/app.rs @@ -1,75 +1,43 @@ -use crate::shared::models::app::{AuthAPI, CodeLoggedInSession, CodeLoginData, Icon, KeyLoggedInSession}; +use async_trait::async_trait; +use crate::shared::models::app::AuthAPI; use crate::shared::models::email::Email; use crate::shared::models::opaque::UserSecretKey; -use anyhow::Result; -use async_trait::async_trait; -use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY}; -use crate::client::opaque::{AuthenticationData, OpaqueAuth, ServerConnectionLogin, ServerConnectionRegister}; +//https://chatgpt.com/c/69441737-c990-8333-9737-7ac75232da1d - -pub struct ClientAuth<'a, R, K> +struct ClientApp where - R: ServerConnectionRegister + ServerConnectionLogin + Clone, - K: AuthAPI + K: AuthAPI, + C: ClientRepo { - opaque_key_register: OpaqueAuth<'a, R>, - opaque_key_login: OpaqueAuth<'a, R>, - opaque_code_register: OpaqueAuth<'a, R>, - opaque_code_login: OpaqueAuth<'a, R>, - nkode_api: K, + auth_api: K, + client_repo: C, +} + +impl ClientApp +where + K: AuthAPI, + C: ClientRepo +{ + fn new(auth_api: K, client_repo: C) -> Self { + Self { + auth_api, + client_repo + } + } + + async fn new_user(&self, email: Email) -> Result { + let secret_key = UserSecretKey::new(); + self.client_repo.add_secret_key(email.clone(), secret_key.clone()).await?; + if let Err(_) = self.auth_api.register_key(&email, &secret_key).await { + self.client_repo.remove_secret_key(&email).await.expect("couldn't delete"); + } + Ok(secret_key) + } + } #[async_trait] -impl<'a, R, K> AuthAPI for ClientAuth<'a, R, K> -where - R: ServerConnectionRegister + ServerConnectionLogin + Clone + Sync + Send, - K: AuthAPI + Sync + Send, -{ - async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> { - let auth_data = AuthenticationData::from_secret_key(email.as_str(), secret_key.as_slice()); - self.opaque_key_register.register(&auth_data).await.map_err(|e| format!("error: {}", e)) - } - - async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, data: &CodeLoginData) -> Result<(), String> { - let auth_data = AuthenticationData::from_code(email.as_str(), passcode); - self.opaque_code_register.register(&auth_data).await.map_err(|e| format!("error: {}", e)) - } - - async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result { - let auth_data = AuthenticationData::from_secret_key(&email.as_str(), secret_key.as_slice()); - let session = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; - Ok(KeyLoggedInSession(session)) - } - - async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result { - let auth_data = AuthenticationData::from_code(email.as_str(), passcode); - let session = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; - Ok(CodeLoggedInSession(session)) - } - - async fn get_new_icons( - &self, - key_login_session: &KeyLoggedInSession, - ) -> Result, String> { - self.nkode_api - .get_new_icons(key_login_session) - .await - } - - async fn get_login_data( - &self, - key_login_session: &KeyLoggedInSession, - ) -> Result { - self.nkode_api - .get_login_data(key_login_session) - .await - } - - async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result { - self.nkode_api.is_code_registered(key_login_session).await - } - - async fn get_policy(&self) -> Result { - Ok(DEFAULT_POLICY) - } -} +trait ClientRepo { + async fn add_secret_key(&self, email: Email, user_secret_key: UserSecretKey) -> Result<(), String>; + async fn remove_secret_key(&self, email: &Email) -> Result<(), String>; +} \ No newline at end of file diff --git a/src/client/client_auth_api.rs b/src/client/client_auth_api.rs new file mode 100644 index 0000000..86d7630 --- /dev/null +++ b/src/client/client_auth_api.rs @@ -0,0 +1,79 @@ +use crate::shared::models::app::{AuthAPI, CodeLoggedInSession, CodeLoginData, Icon, KeyLoggedInSession}; +use crate::shared::models::email::Email; +use crate::shared::models::opaque::UserSecretKey; +use anyhow::Result; +use async_trait::async_trait; +use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY}; +use crate::client::opaque::{OpaqueAuthData, OpaqueAuth, ServerConnectionLogin, ServerConnectionRegister}; +use crate::shared::models::store::UserAuthStore; + +pub struct ClientAuth<'a, R, U> +where + R: ServerConnectionRegister + ServerConnectionLogin + Clone, + U: UserAuthStore +{ + opaque_key_register: OpaqueAuth<'a, R>, + opaque_key_login: OpaqueAuth<'a, R>, + opaque_code_register: OpaqueAuth<'a, R>, + opaque_code_login: OpaqueAuth<'a, R>, + user_store: U +} + +#[async_trait] +impl<'a, R, U> AuthAPI for ClientAuth<'a, R, U> +where + R: ServerConnectionRegister + ServerConnectionLogin + Clone + Sync + Send, + U: UserAuthStore + Sync + Send, +{ + async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> { + let auth_data = OpaqueAuthData::from_secret_key(email.as_str(), secret_key.as_slice()); + self.opaque_key_register.register(&auth_data).await.map_err(|e| format!("error: {}", e)) + } + + async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, data: &CodeLoginData) -> Result<(), String> { + let auth_data = OpaqueAuthData::from_code(email.as_str(), passcode); + self.opaque_code_register.register(&auth_data).await.map_err(|e| format!("error: {}", e)) + } + + async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result { + let auth_data = OpaqueAuthData::from_secret_key(&email.as_str(), secret_key.as_slice()); + let session = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; + Ok(KeyLoggedInSession(session)) + } + + async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result { + let auth_data = OpaqueAuthData::from_code(email.as_str(), passcode); + let session = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; + Ok(CodeLoggedInSession(session)) + } + + async fn get_new_icons( + &self, + key_login_session: &KeyLoggedInSession, + ) -> Result, String> { + // self.nkode_api + // .get_new_icons(key_login_session) + // .await + // + todo!() + } + + async fn get_login_data( + &self, + key_login_session: &KeyLoggedInSession, + ) -> Result { + // self.nkode_api + // .get_login_data(key_login_session) + // .await + todo!() + } + + async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result { + // self.nkode_api.is_code_registered(key_login_session).await + todo!() + } + + async fn get_policy(&self) -> Result { + Ok(DEFAULT_POLICY) + } +} diff --git a/src/client/mod.rs b/src/client/mod.rs index 77daff7..a651f21 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,3 +1,4 @@ -mod app; +mod client_auth_api; pub mod opaque; -mod states; \ No newline at end of file +mod states; +mod app; \ No newline at end of file diff --git a/src/client/opaque.rs b/src/client/opaque.rs index 9039c2d..de0ebbf 100644 --- a/src/client/opaque.rs +++ b/src/client/opaque.rs @@ -28,12 +28,12 @@ impl fmt::Display for ClientAuthError { impl std::error::Error for ClientAuthError {} -pub struct AuthenticationData { +pub struct OpaqueAuthData { pub identifier: Vec, pub secret: Vec, } -impl AuthenticationData { +impl OpaqueAuthData { pub fn from_secret_key(email: &str, secret_key: &[u8]) -> Self { Self { identifier: email.as_bytes().to_vec(), @@ -96,7 +96,7 @@ impl OpaqueAuth<'_, S> where S: ServerConnectionRegister + ServerConnectionLogin, { - pub async fn register(&self, auth: &AuthenticationData) -> Result<(), ClientAuthError> { + pub async fn register(&self, auth: &OpaqueAuthData) -> Result<(), ClientAuthError> { let mut rng = OsRng; let start = ClientRegistration::::start(&mut rng, &auth.secret) .map_err(|e| ClientAuthError::Opaque(format!("client reg start: {e:?}")))?; @@ -119,7 +119,7 @@ where Ok(()) } - pub async fn login(&self, auth: &AuthenticationData) -> Result { + pub async fn login(&self, auth: &OpaqueAuthData) -> Result { let mut rng = OsRng; let start = ClientLogin::::start(&mut rng, &auth.secret) .map_err(|e| ClientAuthError::Opaque(format!("client login start: {e:?}")))?; diff --git a/src/client/states.rs b/src/client/states.rs index f431104..1d68370 100644 --- a/src/client/states.rs +++ b/src/client/states.rs @@ -7,30 +7,9 @@ use crate::shared::models::app::{AuthAPI, CodeLoggedInSession, CodeLoginData, Ic use crate::shared::models::email::Email; use crate::shared::models::opaque::UserSecretKey; -struct KeyRegister; struct KeyLogin; -struct KeyLoggedIn; -struct CodeRegister; -struct CodeLogIn; -struct CodeLoggedIn; - -pub struct UserState { - api: S, - email: Email, - user_secret_key: UserSecretKey, - key_login: Option, - icon_nonce: Option, - icons: Option>, - keypad: Option, - mask: Option>, - cipher: Option, - _state: PhantomData -} - -struct Login; - -struct Register; +struct KeyRegister; pub struct UserStateKey { api: S, @@ -39,20 +18,20 @@ pub struct UserStateKey { _state: PhantomData } -impl UserStateKey { - pub async fn register(self) -> anyhow::Result, String> { +impl UserStateKey { + pub async fn register(self) -> Result, String> { self.api.register_key(&self.email, &self.user_secret_key).await?; Ok(UserStateKey { api: self.api, email: self.email, user_secret_key: self.user_secret_key, - _state: PhantomData::, + _state: PhantomData::, }) } } -impl UserStateKey { - pub async fn login(self) -> anyhow::Result,String> { +impl UserStateKey { + pub async fn login(self) -> Result,String> { let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?; Ok(UserStateKeyLoggedIn { api: self.api, @@ -71,7 +50,7 @@ pub struct UserStateKeyLoggedIn { } impl UserStateKeyLoggedIn { - pub async fn register_code(self) -> anyhow::Result, String> { + pub async fn register_code(self) -> Result, String> { let icon_nonce = Nonce::new(); let icons = self.get_icons(&icon_nonce).await?; let policy = self.api.get_policy().await?; @@ -86,7 +65,7 @@ impl UserStateKeyLoggedIn { }) } - async fn get_icons(&self, icon_nonce: &Nonce) -> anyhow::Result, String> { + async fn get_icons(&self, icon_nonce: &Nonce) -> Result, String> { let chacha20_key = self.user_secret_key.chacha20_secret_key(); let mut chacha_cipher = nkode_rs::nkode_core::chacha20prng::ChaCha20PRNG::new(&chacha20_key, icon_nonce); let mut icons = self.api.get_new_icons(&self.key_login).await?; @@ -98,7 +77,7 @@ impl UserStateKeyLoggedIn { Ok(icons) } - pub async fn login_code(self) -> anyhow::Result, String> { + pub async fn login_code(self) -> Result, String> { let login_data = self.api.get_login_data(&self.key_login).await?; let icons = self.get_icons(&login_data.icon_nonce()).await?; let policy = self.api.get_policy().await?; @@ -128,7 +107,7 @@ pub struct UserStateCodeRegister { } impl UserStateCodeRegister { - pub async fn register(self, selected_icons: Vec) -> anyhow::Result, String> { + pub async fn register(self, selected_icons: Vec) -> Result, String> { let policy = self.api.get_policy().await?; let keypad = Keypad::new(policy.clone()); let secret_key = self.user_secret_key.chacha20_secret_key(); @@ -173,7 +152,7 @@ impl UserStateCodeLogin { ).unwrap().to_vec() } - pub async fn login(&self, selected_keys: &Vec) -> anyhow::Result { + pub async fn login(&self, selected_keys: &Vec) -> Result { let passcode = self.cipher.decipher(selected_keys, self.keypad.indices(), &self.mask).map_err(|e| format!("invalid keys: {e}"))?; self.api.login_code(&self.email, &passcode).await } diff --git a/src/server/app.rs b/src/server/app.rs index 1560d00..5e20f17 100644 --- a/src/server/app.rs +++ b/src/server/app.rs @@ -5,20 +5,20 @@ use opaque_ke::argon2::password_hash::rand_core::OsRng; use nkode_rs::from_bytes::FromBytes; use crate::server::models::CredKind; use crate::server::repository::opaque_repo::{AuthRepoError, OpaqueDatabaseRepo, OpaqueSessionRepo}; -use crate::server::repository::user_repo::UserRepo; +use crate::shared::models::store::UserAuthStore; use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession, LoggedInSession}; use crate::shared::models::email::Email; use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, OpaqueSessionKey, PasswordFile}; -pub struct ServerApp { +pub struct ServerApp { server_setup: NKodeServerSetup, opaque_db: R, opaque_sess: S, user_db: U, } -impl ServerApp { +impl ServerApp { pub fn new(server_setup: NKodeServerSetup, opaque_db: R, opaque_sess: S, user_db: U) -> Self { Self { server_setup, opaque_db, opaque_sess, user_db} } diff --git a/src/server/repository/in_memory/in_memory_user_db.rs b/src/server/repository/in_memory/in_memory_user_db.rs index dc48b9b..6a0213a 100644 --- a/src/server/repository/in_memory/in_memory_user_db.rs +++ b/src/server/repository/in_memory/in_memory_user_db.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use async_trait::async_trait; use tokio::sync::Mutex; use uuid::Uuid; -use crate::server::repository::user_repo::UserRepo; +use crate::shared::models::store::UserAuthStore; use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession}; use crate::shared::models::email::Email; @@ -30,7 +30,7 @@ impl Default for InMemoryUserDB { } #[async_trait] -impl UserRepo for InMemoryUserDB { +impl UserAuthStore for InMemoryUserDB { async fn get_key_session(&self, session_id: &Uuid) -> Result { self.key_session.lock().await .get(&session_id) diff --git a/src/server/repository/mod.rs b/src/server/repository/mod.rs index a35bfb1..c57c477 100644 --- a/src/server/repository/mod.rs +++ b/src/server/repository/mod.rs @@ -1,3 +1,2 @@ pub mod in_memory; pub mod opaque_repo; -pub mod user_repo; diff --git a/src/shared/models/mod.rs b/src/shared/models/mod.rs index b3406f2..d5a32d5 100644 --- a/src/shared/models/mod.rs +++ b/src/shared/models/mod.rs @@ -1,3 +1,4 @@ pub mod opaque; pub mod app; -pub mod email; \ No newline at end of file +pub mod email; +pub mod store; \ No newline at end of file diff --git a/src/shared/models/opaque.rs b/src/shared/models/opaque.rs index 2fa4641..c92a57d 100644 --- a/src/shared/models/opaque.rs +++ b/src/shared/models/opaque.rs @@ -8,6 +8,8 @@ use uuid::Uuid; use nkode_rs::nkode_core::chacha20prng::SecretKey; use zeroize::Zeroizing; use nkode_rs::from_bytes::FromBytes; +use rand::RngCore; +use rand::rngs::OsRng; const USER_KEY_SIZE: usize = 16; @@ -15,6 +17,14 @@ const USER_KEY_SIZE: usize = 16; pub struct UserSecretKey(Zeroizing<[u8; USER_KEY_SIZE]>); impl UserSecretKey { + + pub fn new() -> Self { + let mut rng = OsRng; + let mut secret_key = [0u8; USER_KEY_SIZE]; + rng.fill_bytes(&mut secret_key); + Self(Zeroizing::new(secret_key)) + } + pub fn chacha20_secret_key(&self) -> SecretKey { let out = blake3::derive_key("your-app chacha20 secret key v1", &self.0.as_slice()); SecretKey::from_bytes(&out).unwrap() diff --git a/src/server/repository/user_repo.rs b/src/shared/models/store.rs similarity index 96% rename from src/server/repository/user_repo.rs rename to src/shared/models/store.rs index aa18e2a..48e7d06 100644 --- a/src/server/repository/user_repo.rs +++ b/src/shared/models/store.rs @@ -4,7 +4,7 @@ use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedIn use crate::shared::models::email::Email; #[async_trait] -pub trait UserRepo { +pub trait UserAuthStore { async fn get_key_session(&self, session_id: &Uuid) -> Result; async fn get_code_session(&self, session_id: &Uuid) -> Result; diff --git a/tests/in_memory_test.rs b/tests/in_memory_test.rs index b100742..8d5af40 100644 --- a/tests/in_memory_test.rs +++ b/tests/in_memory_test.rs @@ -1,6 +1,6 @@ use opaque_ke::rand::rngs::OsRng; -use nkode_protocol::client::opaque::{AuthenticationData, ClientAuthError, OpaqueAuth}; -use nkode_protocol::server::app::{Key, ServerApp}; +use nkode_protocol::client::opaque::{OpaqueAuthData, ClientAuthError, OpaqueAuth}; +use nkode_protocol::server::app::{ServerApp}; use nkode_protocol::server::repository::in_memory::in_memory_opaque_db::InMemoryOpaqueDB; use nkode_protocol::server::repository::in_memory::in_memory_opaque_session::InMemoryOpaqueSession; use nkode_protocol::shared::models::opaque::NKodeServerSetup; @@ -19,7 +19,7 @@ async fn opaque_key_registration_and_login_roundtrip() { ); let key_server: InMemoryKeyServer = InMemoryServer::new(&server); let auth = OpaqueAuth::new(&key_server); - let auth_data = AuthenticationData::from_secret_key("a@b.com", b"supersecret16bytes"); + let auth_data = OpaqueAuthData::from_secret_key("a@b.com", b"supersecret16bytes"); auth.register(&auth_data).await.expect("registration should succeed"); let _ =auth.login(&auth_data) .await @@ -37,7 +37,7 @@ async fn opaque_login_fails_if_not_registered() { InMemoryUserDB::new() ); let key_server = InMemoryKeyServer::new(&server); - let auth = AuthenticationData::from_secret_key("nope@nope.com", b"supersecret16bytes"); + let auth = OpaqueAuthData::from_secret_key("nope@nope.com", b"supersecret16bytes"); let login_reg = OpaqueAuth::new(&key_server); let err = login_reg.login(&auth) .await @@ -60,7 +60,7 @@ async fn cannot_register_code_before_key() { ); let key_server: InMemoryCodeServer = InMemoryServer::new(&server); let auth = OpaqueAuth::new(&key_server); - let auth_data = AuthenticationData::from_code("x@y.com", &[1u64,2,3,4]); + let auth_data = OpaqueAuthData::from_code("x@y.com", &[1u64,2,3,4]); let err = auth.register(&auth_data) .await .expect_err("should fail because key is not registered");