diff --git a/src/client/app.rs b/src/client/app.rs index c6507cd..3c9f4fe 100644 --- a/src/client/app.rs +++ b/src/client/app.rs @@ -1,7 +1,9 @@ -use async_trait::async_trait; +use std::collections::HashMap; use crate::client::client_auth_api::ClientAuth; use crate::client::opaque::{ServerConnectionLogin, ServerConnectionRegister}; -use crate::shared::models::app::AuthAPI; +use crate::client::repo::ClientRepo; +use crate::client::states::{KeyRegister, UserStateCodeLogin, UserStateCodeRegister, UserStateKey}; +use crate::shared::models::app::{Icon, IconID}; use crate::shared::email::Email; use crate::shared::opaque::UserSecretKey; use crate::shared::user_api::UserAPI; @@ -15,34 +17,54 @@ where { auth_api: ClientAuth<'a, R, U>, client_repo: C, + new_user: HashMap, + user_login: HashMap } impl <'a, R, U, C>ClientApp<'a, R, U, C> where R: ServerConnectionRegister + ServerConnectionLogin, U: UserAPI, - C: ClientRepo + C: ClientRepo, { - fn new(auth_api: ClientAuth<'a, R, U>, client_repo: C) -> Self { + pub fn new(auth_api: ClientAuth<'a, R, U>, client_repo: C) -> Self { Self { auth_api, - client_repo + client_repo, + new_user: HashMap::new(), + user_login: HashMap::new() } } - async fn new_user(&self, email: Email) -> Result { - let secret_key = UserSecretKey::new(); + async fn new_user(&mut self, email: Email, secret_key: UserSecretKey) -> Result, String> { + let key_register = UserStateKey::::new(email.clone(), secret_key.clone()); 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) + let key_login = match key_register.register(&self.auth_api).await.map_err(|e| format!("error: {e:?}")) { + Ok(s) => {s} + Err(e) => { + self.client_repo.remove_secret_key(&email).await.expect("couldn't delete"); + return Err(format!("error registering key {}", e)) + } + }; + let key_logged_in = key_login.login(&self.auth_api).await.map_err(|e| format!("error: {e:?}"))?; + let code_register = key_logged_in.register_code(&self.auth_api).await?; + let icons = code_register.get_icons(); + self.new_user.insert(email, code_register); + Ok(icons) } -} + async fn new_user_register_code(&mut self, email: Email, selected_icons: Vec) -> Result>, String> { + let code_register = self.new_user.remove(&email).unwrap(); // Todo should be an error + let code_login = code_register.register(&self.auth_api,selected_icons).await?; + let keypad = code_login.get_keypad().await; + self.user_login.insert(email, code_login); + Ok(keypad) + } -#[async_trait] -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 + async fn user_login(&mut self, email: Email, selected_keys: &Vec) -> Result<(), String> { + let mut code_login = self.user_login.remove(&email).unwrap(); // Todo should be an error + let code_logged_in = code_login.login(&self.auth_api, &selected_keys).await?; + self.client_repo.add_code_logged_in(&email, code_logged_in).await?; + Ok(()) + } +} diff --git a/src/client/client_auth_api.rs b/src/client/client_auth_api.rs index 74e2ef8..0cf4039 100644 --- a/src/client/client_auth_api.rs +++ b/src/client/client_auth_api.rs @@ -3,6 +3,7 @@ use crate::shared::email::Email; use crate::shared::opaque::UserSecretKey; use anyhow::Result; use async_trait::async_trait; +use nkode_rs::nkode_core::keypad::Keypad; use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY}; use crate::client::opaque::{OpaqueAuthData, OpaqueAuth, ServerConnectionLogin, ServerConnectionRegister}; use crate::shared::signed_session_data::SignedSessionData; @@ -48,8 +49,14 @@ where Ok(KeyLoggedInSession(session)) } - async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result { + async fn login_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, keypad: Keypad) -> Result { let auth_data = OpaqueAuthData::from_code(email.as_str(), passcode); + let signed_session = SignedSessionData::new( + key_login_session.0.session_id, + keypad, + &key_login_session.0.session_key + ).map_err(|e| format!("error: {e:?}"))?; + self.user_api.update_keypad(signed_session).await?; let session = self.opaque_code_login.login(&auth_data).await.map_err(|e| format!("error: {}", e))?; Ok(CodeLoggedInSession(session)) } diff --git a/src/client/mod.rs b/src/client/mod.rs index a651f21..d02dd81 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -1,4 +1,5 @@ -mod client_auth_api; +pub mod client_auth_api; pub mod opaque; -mod states; -mod app; \ No newline at end of file +pub mod states; +pub mod app; +mod repo; \ No newline at end of file diff --git a/src/client/repo.rs b/src/client/repo.rs new file mode 100644 index 0000000..1f61c16 --- /dev/null +++ b/src/client/repo.rs @@ -0,0 +1,11 @@ +use async_trait::async_trait; +use crate::shared::email::Email; +use crate::shared::models::app::CodeLoggedInSession; +use crate::shared::opaque::UserSecretKey; + +#[async_trait] +pub 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>; + async fn add_code_logged_in(&self, email: &Email, login_session: CodeLoggedInSession) -> Result<(), String>; +} \ No newline at end of file diff --git a/src/client/states.rs b/src/client/states.rs index bf4d12d..884124b 100644 --- a/src/client/states.rs +++ b/src/client/states.rs @@ -7,22 +7,27 @@ use crate::shared::models::app::{AuthAPI, CodeLoggedInSession, CodeLoginData, Ic use crate::shared::email::Email; use crate::shared::opaque::UserSecretKey; -struct KeyLogin; +pub struct KeyLogin; +pub struct KeyRegister; -struct KeyRegister; - -pub struct UserStateKey { - api: S, +pub struct UserStateKey { email: Email, user_secret_key: UserSecretKey, _state: PhantomData } -impl UserStateKey { - pub async fn register(self) -> Result, String> { - self.api.register_key(&self.email, &self.user_secret_key).await?; +impl UserStateKey { + pub fn new(email: Email, user_secret_key: UserSecretKey) -> Self { + Self { + email, + user_secret_key, + _state: PhantomData + } + } + + pub async fn register(self, api: &dyn AuthAPI ) -> Result, String> { + 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::, @@ -30,11 +35,10 @@ impl UserStateKey { } } -impl UserStateKey { - pub async fn login(self) -> Result,String> { - let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?; +impl UserStateKey { + pub async fn login(self, api: &dyn AuthAPI) -> Result { + let key_login = api.login_key(&self.email, &self.user_secret_key).await?; Ok(UserStateKeyLoggedIn { - api: self.api, email: self.email, user_secret_key: self.user_secret_key, key_login @@ -42,33 +46,29 @@ impl UserStateKey { } } -pub struct UserStateKeyLoggedIn { - api: S, +pub struct UserStateKeyLoggedIn { email: Email, user_secret_key: UserSecretKey, key_login: KeyLoggedInSession, } -impl UserStateKeyLoggedIn { - pub async fn register_code(self) -> Result, String> { +impl UserStateKeyLoggedIn { + pub async fn register_code(self, api: &dyn AuthAPI) -> Result { let icon_nonce = Nonce::new(); - let icons = self.get_icons(&icon_nonce).await?; - let policy = self.api.get_policy().await?; + let icons = self.get_icons(api, &icon_nonce).await?; Ok(UserStateCodeRegister { - api: self.api, email: self.email, user_secret_key: self.user_secret_key, key_login: self.key_login, icons, icon_nonce, - keypad: Keypad::new(policy), }) } - async fn get_icons(&self, icon_nonce: &Nonce) -> Result, String> { + async fn get_icons(&self, api: &dyn AuthAPI, 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().await?; + let mut icons = api.get_new_icons().await?; for icon in &mut icons { let bytes = chacha_cipher.read_u8(ICON_ID_SIZE)?; let new_id = IconID::from_bytes(bytes.as_slice()).unwrap(); @@ -77,38 +77,37 @@ impl UserStateKeyLoggedIn { Ok(icons) } - 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?; + pub async fn login_code(self, api: &dyn AuthAPI) -> Result { + let login_data = api.get_login_data(&self.key_login).await?; + let icons = self.get_icons(api, &login_data.icon_nonce()).await?; + let policy = api.get_policy().await?; let nkode_secret_key = self.user_secret_key.chacha20_secret_key(); let cipher = NKodeCipher::from_nonce(policy, &nkode_secret_key, login_data.icon_nonce())?; Ok( UserStateCodeLogin { - api: self.api, email: self.email, mask: login_data.mask, icons, keypad: login_data.keypad, cipher, + key_login: self.key_login } ) } } -pub struct UserStateCodeRegister { - api: S, +pub struct UserStateCodeRegister { email: Email, user_secret_key: UserSecretKey, key_login: KeyLoggedInSession, icon_nonce: Nonce, icons: Vec, - keypad: Keypad, } -impl UserStateCodeRegister { - pub async fn register(self, selected_icons: Vec) -> Result, String> { - let policy = self.api.get_policy().await?; +impl UserStateCodeRegister { + pub async fn register(self, api: &dyn AuthAPI, selected_icons: Vec) -> Result + { + let policy = api.get_policy().await?; let keypad = Keypad::new(policy.clone()); let secret_key = self.user_secret_key.chacha20_secret_key(); let (cipher, cipher_nonce) = NKodeCipher::new(policy, &secret_key); @@ -123,28 +122,32 @@ impl UserStateCodeRegister { icon_nonce: self.icon_nonce, keypad, }; - self.api.register_code(&self.email, &ciphered_nkode.passcode, &self.key_login, data.clone()).await?; + api.register_code(&self.email, &ciphered_nkode.passcode, &self.key_login, data.clone()).await?; Ok(UserStateCodeLogin { - api: self.api, mask: data.mask, email: self.email, keypad: data.keypad, cipher, - icons: self.icons + icons: self.icons, + key_login: self.key_login }) } + + pub fn get_icons(&self) -> Vec { + self.icons.clone() + } } -pub struct UserStateCodeLogin { - api: S, +pub struct UserStateCodeLogin { email: Email, mask: Vec, icons: Vec, keypad: Keypad, - cipher: NKodeCipher + cipher: NKodeCipher, + key_login: KeyLoggedInSession, } -impl UserStateCodeLogin { +impl UserStateCodeLogin { pub fn sort_icons(&self) -> Vec { nkode_rs::tensor::reorder( &self.icons, @@ -152,8 +155,14 @@ impl UserStateCodeLogin { ).unwrap().to_vec() } - pub async fn login(&self, selected_keys: &Vec) -> Result { + pub async fn login(&mut self, api: &dyn AuthAPI, 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 + self.keypad.login_shuffle(); + api.login_code(&self.email, &passcode,&self.key_login ,self.keypad.clone()).await?; + todo!() + } + + pub async fn get_keypad(&self) -> Vec> { + todo!() } } \ No newline at end of file diff --git a/src/server/app.rs b/src/server/app.rs index 149829f..c310f17 100644 --- a/src/server/app.rs +++ b/src/server/app.rs @@ -5,7 +5,7 @@ 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::UserRepo::UserRepo; +use crate::server::repository::user_repo::UserRepo; use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession, LoggedInSession}; use crate::shared::email::Email; use crate::shared::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, OpaqueSessionKey, PasswordFile}; 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 080f1bb..e53ec01 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::UserRepo::UserRepo; +use crate::server::repository::user_repo::UserRepo; use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession}; use crate::shared::email::Email; diff --git a/src/server/repository/mod.rs b/src/server/repository/mod.rs index c632124..a35bfb1 100644 --- a/src/server/repository/mod.rs +++ b/src/server/repository/mod.rs @@ -1,3 +1,3 @@ pub mod in_memory; pub mod opaque_repo; -pub mod UserRepo; +pub mod user_repo; diff --git a/src/server/repository/UserRepo.rs b/src/server/repository/user_repo.rs similarity index 100% rename from src/server/repository/UserRepo.rs rename to src/server/repository/user_repo.rs diff --git a/src/shared/models/app.rs b/src/shared/models/app.rs index 72d2cdf..cb04ddc 100644 --- a/src/shared/models/app.rs +++ b/src/shared/models/app.rs @@ -62,7 +62,7 @@ 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 fn login_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoggedInSession, keypad: Keypad) -> Result; async fn get_new_icons(&self) -> Result, String>; async fn get_login_data(&self, key_login_session: &KeyLoggedInSession) -> Result; diff --git a/src/shared/user_api.rs b/src/shared/user_api.rs index f3f7c45..561fbee 100644 --- a/src/shared/user_api.rs +++ b/src/shared/user_api.rs @@ -1,4 +1,5 @@ use async_trait::async_trait; +use nkode_rs::nkode_core::keypad::Keypad; use crate::shared::email::Email; use crate::shared::models::app::{CodeLoginData, Icon}; use crate::shared::signed_session_data::SignedSessionData; @@ -10,4 +11,5 @@ pub trait UserAPI: Sync + Send { async fn get_login_data(&self, session: SignedSessionData) -> Result; async fn is_code_registered(&self, session: SignedSessionData) -> Result; async fn set_code_login_data(&self, session: SignedSessionData) -> Result<(), String>; + async fn update_keypad(&self, keypad: SignedSessionData) -> Result<(), String>; } \ No newline at end of file