From 48cd1d0e3127656856a378337dab7f1eb12895cd Mon Sep 17 00:00:00 2001 From: Donovan Date: Wed, 17 Dec 2025 20:23:26 -0600 Subject: [PATCH] implement in-memory server --- src/client/app.rs | 77 +++++++------------ src/client/opaque.rs | 66 +++++----------- src/server/app.rs | 1 + .../in_memory/in_memory_opaque_session.rs | 1 - .../in_memory/in_memory_transport.rs | 27 +++---- src/server/repository/in_memory/mod.rs | 2 +- src/shared/models/app.rs | 5 +- tests/in_memory_test.rs | 48 ++++++++---- 8 files changed, 96 insertions(+), 131 deletions(-) diff --git a/src/client/app.rs b/src/client/app.rs index ee6763a..c6cafb5 100644 --- a/src/client/app.rs +++ b/src/client/app.rs @@ -1,28 +1,28 @@ use std::marker::PhantomData; use nkode_rs::nkode_core::keypad::Keypad; -use crate::shared::models::app::{OpaqueAPI, AuthAPI, CodeLoginData, CodeLoggedInSession, Icon, IconID, KeyLoggedInSession, ICON_ID_SIZE, LoggedInSession}; +use crate::shared::models::app::{AuthAPI, CodeLoginData, CodeLoggedInSession, Icon, IconID, KeyLoggedInSession, ICON_ID_SIZE}; use crate::shared::models::email::Email; -use crate::shared::models::opaque::{OpaqueLoginSession, UserSecretKey}; +use crate::shared::models::opaque::{UserSecretKey}; use anyhow::Result; use nkode_rs::nkode_core::nkode_cipher::NKodeCipher; use nkode_rs::from_bytes::FromBytes; use nkode_rs::nkode_core::chacha20prng::Nonce; use async_trait::async_trait; use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY}; -use crate::client::opaque::{AuthenticationData, OpaqueAuthLogin, OpaqueAuthRegister, ServerConnectionLogin, ServerConnectionRegister}; +use crate::client::opaque::{AuthenticationData, OpaqueAuth, ServerConnectionLogin, ServerConnectionRegister}; -pub struct Login; -pub struct Register; +struct Login; +struct Register; -pub struct ClientAppKey { +pub struct ClientAppKey { api: S, email: Email, user_secret_key: UserSecretKey, _state: PhantomData } -impl ClientAppKey { +impl ClientAppKey { pub async fn register(self) -> Result, String> { self.api.register_key(&self.email, &self.user_secret_key).await?; Ok(ClientAppKey { @@ -34,7 +34,7 @@ impl ClientAppKey { } } -impl ClientAppKey { +impl ClientAppKey { pub async fn login(self) -> Result,String> { let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?; Ok(ClientAppKeyLoggedIn{ @@ -46,14 +46,14 @@ impl ClientAppKey { } } -pub struct ClientAppKeyLoggedIn { +pub struct ClientAppKeyLoggedIn { api: S, email: Email, user_secret_key: UserSecretKey, key_login: KeyLoggedInSession, } -impl ClientAppKeyLoggedIn { +impl ClientAppKeyLoggedIn { pub async fn register_code(self) -> Result, String> { let icon_nonce = Nonce::new(); let icons = self.get_icons(&icon_nonce).await?; @@ -100,7 +100,7 @@ impl ClientAppKeyLoggedIn { } } -pub struct ClientAppCodeRegister { +pub struct ClientAppCodeRegister { api: S, email: Email, user_secret_key: UserSecretKey, @@ -110,7 +110,7 @@ pub struct ClientAppCodeRegister { keypad: Keypad, } -impl ClientAppCodeRegister { +impl ClientAppCodeRegister { pub async fn register(self, selected_icons: Vec) -> Result, String> { let policy = self.api.get_policy().await?; let keypad = Keypad::new(policy.clone()); @@ -139,7 +139,7 @@ impl ClientAppCodeRegister { } } -pub struct ClientAppCodeLogin { +pub struct ClientAppCodeLogin { api: S, email: Email, mask: Vec, @@ -148,7 +148,7 @@ pub struct ClientAppCodeLogin { cipher: NKodeCipher } -impl ClientAppCodeLogin { +impl ClientAppCodeLogin { pub fn sort_icons(&self) -> Vec { nkode_rs::tensor::reorder( &self.icons, @@ -162,23 +162,22 @@ impl ClientAppCodeLogin { } } -pub struct ClientAuth< - R: ServerConnectionRegister + Clone, - L: ServerConnectionLogin + Clone, +pub struct ClientAuth<'a, R, K> +where + R: ServerConnectionRegister + ServerConnectionLogin + Clone, K: AuthAPI -> { - opaque_key_register: OpaqueAuthRegister, - opaque_key_login: OpaqueAuthLogin, - opaque_code_register: OpaqueAuthRegister, - opaque_code_login: OpaqueAuthLogin, +{ + 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, } #[async_trait] -impl OpaqueAPI for ClientAuth +impl<'a, R, K> AuthAPI for ClientAuth<'a, R, K> where - R: ServerConnectionRegister + Clone + Sync + Send, - L: ServerConnectionLogin + Clone + Sync + Send, + R: ServerConnectionRegister + ServerConnectionLogin + Clone + Sync + Send, K: AuthAPI + Sync + Send, { async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> { @@ -193,36 +192,16 @@ where 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_key = self.opaque_key_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; - todo!() - // Ok(KeyLoggedInSession( - // LoggedInSession { - // email: email.clone(), - // session_key - // } - // )) + 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_key = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; - todo!() - // Ok(CodeLoggedInSession( - // LoggedInSession { - // email: email.clone(), - // session_key - // } - // )) + let session = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; + Ok(CodeLoggedInSession(session)) } -} -#[async_trait] -impl AuthAPI for ClientAuth -where - R: ServerConnectionRegister + Clone + Sync + Send, - L: ServerConnectionLogin + Clone + Sync + Send, - K: AuthAPI + Sync + Send, -{ async fn get_new_icons( &self, key_login_session: &KeyLoggedInSession, diff --git a/src/client/opaque.rs b/src/client/opaque.rs index 557d5f9..9039c2d 100644 --- a/src/client/opaque.rs +++ b/src/client/opaque.rs @@ -1,6 +1,5 @@ use std::fmt; use async_trait::async_trait; -use nkode_rs::from_bytes::FromBytes; use uuid::Uuid; use opaque_ke::rand::rngs::OsRng; use opaque_ke::{ @@ -10,7 +9,7 @@ use opaque_ke::{ RegistrationRequest, }; use crate::shared::models::app::LoggedInSession; -use crate::shared::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey}; +use crate::shared::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile}; #[derive(Debug)] pub enum ClientAuthError { @@ -85,86 +84,61 @@ pub trait ServerConnectionLogin { ) -> Result; } +pub struct OpaqueAuth<'a, S>(&'a S); - -pub struct OpaqueAuthRegister(R); - -impl OpaqueAuthRegister { - pub fn new(server: R) -> Self { +impl<'a, S> OpaqueAuth<'a, S> { + pub fn new(server: &'a S) -> Self { Self(server) } } -pub struct OpaqueAuthLogin(L); - -impl OpaqueAuthLogin { - pub fn new(server: L) -> Self { - Self(server) - } -} - - - -impl OpaqueAuthRegister { - pub async fn register( - &self, - auth: &AuthenticationData, - ) -> Result<(), ClientAuthError> { +impl OpaqueAuth<'_, S> +where + S: ServerConnectionRegister + ServerConnectionLogin, +{ + pub async fn register(&self, auth: &AuthenticationData) -> Result<(), ClientAuthError> { let mut rng = OsRng; let start = ClientRegistration::::start(&mut rng, &auth.secret) .map_err(|e| ClientAuthError::Opaque(format!("client reg start: {e:?}")))?; - let server_start = self.0 - .start(&auth.identifier, &start.message) + let server_start = ::start(&self.0, &auth.identifier, &start.message) .await .map_err(|e| ClientAuthError::Transport(format!("server reg start: {e:?}")))?; - let server_msg = server_start.response; let finish = start .state .finish( &mut rng, &auth.secret, - server_msg, + server_start.response, ClientRegistrationFinishParameters::default(), ) .map_err(|e| ClientAuthError::Opaque(format!("client reg finish: {e:?}")))?; let password_file: PasswordFile = finish.message.serialize(); - self.0 - .finish(&server_start.session_id, password_file) + ::finish(&self.0, &server_start.session_id, password_file) .await .map_err(|e| ClientAuthError::Transport(format!("server reg finish: {e:?}")))?; Ok(()) } -} -impl OpaqueAuthLogin { - pub async fn login( - &self, - auth: &AuthenticationData, - ) -> Result { + pub async fn login(&self, auth: &AuthenticationData) -> Result { let mut rng = OsRng; let start = ClientLogin::::start(&mut rng, &auth.secret) .map_err(|e| ClientAuthError::Opaque(format!("client login start: {e:?}")))?; - let server_start = self.0 - .start(&auth.identifier, &start.message) - .await - .map_err(|e| ClientAuthError::Transport(format!("server login start: {e:?}")))?; - let server_msg = server_start.response.clone(); + let server_start = + ::start(&self.0, &auth.identifier, &start.message) + .await + .map_err(|e| ClientAuthError::Transport(format!("server login start: {e:?}")))?; let finish = start .state .finish( &mut rng, &auth.secret, - server_msg, + server_start.response, ClientLoginFinishParameters::default(), ) .map_err(|e| ClientAuthError::Opaque(format!("client login finish: {e:?}")))?; - self.0 - .finish(&server_start.session_id, &finish.message) + let session = ::finish(&self.0, &server_start.session_id, &finish.message) .await .map_err(|e| ClientAuthError::Transport(format!("server login finish: {e:?}")))?; - Ok( - OpaqueSessionKey::from_bytes(finish.session_key.as_slice()) - .map_err(|e| ClientAuthError::Opaque(format!("from bytes error {e:?}")))? - ) + Ok(session) } } diff --git a/src/server/app.rs b/src/server/app.rs index 49441a4..1560d00 100644 --- a/src/server/app.rs +++ b/src/server/app.rs @@ -10,6 +10,7 @@ use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedIn use crate::shared::models::email::Email; use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, OpaqueSessionKey, PasswordFile}; + pub struct ServerApp { server_setup: NKodeServerSetup, opaque_db: R, diff --git a/src/server/repository/in_memory/in_memory_opaque_session.rs b/src/server/repository/in_memory/in_memory_opaque_session.rs index fa999bc..5663e84 100644 --- a/src/server/repository/in_memory/in_memory_opaque_session.rs +++ b/src/server/repository/in_memory/in_memory_opaque_session.rs @@ -1,5 +1,4 @@ use std::collections::HashMap; -use std::rc::Rc; use std::sync::Arc; use async_trait::async_trait; use opaque_ke::ServerLogin; diff --git a/src/server/repository/in_memory/in_memory_transport.rs b/src/server/repository/in_memory/in_memory_transport.rs index d398381..4acd737 100644 --- a/src/server/repository/in_memory/in_memory_transport.rs +++ b/src/server/repository/in_memory/in_memory_transport.rs @@ -2,7 +2,7 @@ use async_trait::async_trait; use std::marker::PhantomData; use uuid::Uuid; use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest}; -use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, PasswordFile}; +use crate::shared::models::opaque::{NKodeCipherSuite, OpaqueLoginSession, OpaqueRegisterSession, PasswordFile}; use crate::client::opaque::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister}; use crate::server::app::{Code, Key}; use crate::server::app::ServerApp; @@ -12,30 +12,25 @@ use crate::server::repository::in_memory::in_memory_opaque_session::InMemoryOpaq use crate::server::repository::in_memory::in_memory_user_db::InMemoryUserDB; use crate::shared::models::app::LoggedInSession; -pub struct InMemoryServer { - auth_db: ServerApp, +pub type InMemoryKeyServer<'a> = InMemoryServer<'a, Key>; +pub type InMemoryCodeServer<'a> = InMemoryServer<'a, Code>; + +pub struct InMemoryServer<'a, K: CredKind> { + auth_db: &'a ServerApp, _kind: PhantomData, } -impl InMemoryServer { - pub fn new(server_setup: NKodeServerSetup) -> Self { +impl<'a, K: CredKind> InMemoryServer<'a, K> { + pub fn new(server_app: &'a ServerApp) -> Self { Self { - auth_db: ServerApp::new( - server_setup, - InMemoryOpaqueDB::new(), - InMemoryOpaqueSession::new(), - InMemoryUserDB::new() - ), + auth_db: server_app, _kind: PhantomData, } } } -pub type InMemoryKeyServer = InMemoryServer; -pub type InMemoryCodeServer = InMemoryServer; - #[async_trait] -impl ServerConnectionRegister for InMemoryServer +impl<'a, K> ServerConnectionRegister for InMemoryServer<'a, K> where K: CredKind + Sync, { @@ -64,7 +59,7 @@ where } #[async_trait] -impl ServerConnectionLogin for InMemoryServer +impl<'a, K> ServerConnectionLogin for InMemoryServer<'a,K> where K: CredKind + Send + Sync, { diff --git a/src/server/repository/in_memory/mod.rs b/src/server/repository/in_memory/mod.rs index 650e2c2..cacbb7b 100644 --- a/src/server/repository/in_memory/mod.rs +++ b/src/server/repository/in_memory/mod.rs @@ -1,4 +1,4 @@ pub mod in_memory_opaque_db; pub mod in_memory_transport; pub mod in_memory_opaque_session; -mod in_memory_user_db; +pub mod in_memory_user_db; diff --git a/src/shared/models/app.rs b/src/shared/models/app.rs index eecdce3..249f6ba 100644 --- a/src/shared/models/app.rs +++ b/src/shared/models/app.rs @@ -58,15 +58,12 @@ pub struct CodeLoginData { } #[async_trait] -pub trait OpaqueAPI { +pub trait AuthAPI { async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>; async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, data: &CodeLoginData) -> Result<(), String>; async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result; async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result; -} -#[async_trait] -pub trait AuthAPI { async fn get_new_icons(&self, key_login_session: &KeyLoggedInSession) -> Result, String>; async fn get_login_data(&self, key_login_session: &KeyLoggedInSession) -> Result; async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result; diff --git a/tests/in_memory_test.rs b/tests/in_memory_test.rs index 7b56fbc..b100742 100644 --- a/tests/in_memory_test.rs +++ b/tests/in_memory_test.rs @@ -1,30 +1,44 @@ use opaque_ke::rand::rngs::OsRng; -use nkode_protocol::client::opaque::{AuthenticationData, ClientAuthError, OpaqueAuthLogin, OpaqueAuthRegister}; +use nkode_protocol::client::opaque::{AuthenticationData, ClientAuthError, OpaqueAuth}; +use nkode_protocol::server::app::{Key, 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; -use nkode_protocol::server::repository::in_memory::in_memory_transport::{InMemoryCodeServer, InMemoryKeyServer}; +use nkode_protocol::server::repository::in_memory::in_memory_transport::{InMemoryCodeServer, InMemoryKeyServer, InMemoryServer}; +use nkode_protocol::server::repository::in_memory::in_memory_user_db::InMemoryUserDB; #[tokio::test] async fn opaque_key_registration_and_login_roundtrip() { let mut rng = OsRng; let server_setup = NKodeServerSetup::new(&mut rng); - let server = InMemoryKeyServer::new(server_setup); - let auth_reg = OpaqueAuthRegister::new(server); + let server = ServerApp::new( + server_setup, + InMemoryOpaqueDB::new(), + InMemoryOpaqueSession::new(), + InMemoryUserDB::new() + ); + 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"); - auth_reg.register(&auth_data).await.expect("registration should succeed"); - let login_reg = OpaqueAuthLogin::new(server); - let _ =login_reg.login(&auth_data) + auth.register(&auth_data).await.expect("registration should succeed"); + let _ =auth.login(&auth_data) .await .expect("login should succeed"); - // assert!(!session_key.is_empty()); } #[tokio::test] async fn opaque_login_fails_if_not_registered() { let mut rng = OsRng; let server_setup = NKodeServerSetup::new(&mut rng); - let server = InMemoryKeyServer::new(server_setup); + let server = ServerApp::new( + server_setup, + InMemoryOpaqueDB::new(), + InMemoryOpaqueSession::new(), + InMemoryUserDB::new() + ); + let key_server = InMemoryKeyServer::new(&server); let auth = AuthenticationData::from_secret_key("nope@nope.com", b"supersecret16bytes"); - let login_reg = OpaqueAuthLogin::new(server); + let login_reg = OpaqueAuth::new(&key_server); let err = login_reg.login(&auth) .await .expect_err("login should fail if user not registered"); @@ -38,10 +52,16 @@ async fn opaque_login_fails_if_not_registered() { async fn cannot_register_code_before_key() { let mut rng = OsRng; let server_setup = NKodeServerSetup::new(&mut rng); - let server = InMemoryCodeServer::new(server_setup); - let auth_reg = OpaqueAuthRegister::new(server.clone()); - let auth = AuthenticationData::from_code("x@y.com", &[1u64,2,3,4]); - let err = auth_reg.register(&auth) + let server = ServerApp::new( + server_setup, + InMemoryOpaqueDB::new(), + InMemoryOpaqueSession::new(), + InMemoryUserDB::new() + ); + 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 err = auth.register(&auth_data) .await .expect_err("should fail because key is not registered"); match err {