From 5a288d4b0806157fa8d41e9e6881d508b6906b01 Mon Sep 17 00:00:00 2001 From: Donovan Date: Tue, 16 Dec 2025 09:20:08 -0600 Subject: [PATCH] implement client app --- src/app/client.rs | 136 +++++++++++------------------ src/models/app.rs | 18 +++- src/repository/client_app/mod.rs | 1 + src/repository/client_app/repos.rs | 12 +++ src/repository/mod.rs | 1 + 5 files changed, 80 insertions(+), 88 deletions(-) create mode 100644 src/repository/client_app/mod.rs create mode 100644 src/repository/client_app/repos.rs diff --git a/src/app/client.rs b/src/app/client.rs index ef58a40..c42bba2 100644 --- a/src/app/client.rs +++ b/src/app/client.rs @@ -1,88 +1,54 @@ +use std::marker::PhantomData; use nkode_rs::nkode_core::keypad::Keypad; -use crate::models::app::{CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ICON_ID_SIZE}; +use crate::models::app::{CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ServerAPI, ICON_ID_SIZE}; use crate::models::email::Email; use crate::models::opaque::UserSecretKey; use anyhow::Result; use nkode_rs::nkode_core::nkode_cipher::NKodeCipher; -use nkode_rs::nkode_core::policy::NKodePolicy; use nkode_rs::from_bytes::FromBytes; use nkode_rs::nkode_core::chacha20prng::Nonce; +use crate::repository::client_app::repos::ClientRepo; -pub trait ServerAPI { - async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>; - async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, 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 get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result, String>; - async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result; - async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result; - async fn get_policy(&self) -> Result; -} +pub struct Login; +pub struct Register; -pub struct RegisterKey; -impl RegisterKey { - pub async fn register(api: S, email: Email, user_secret_key: &UserSecretKey) -> Result, String> { - todo!() - } -} - -pub struct KeyLogin { +pub struct ClientAppKey { api: S, + repo: R, email: Email, - user_secret_key: UserSecretKey -} - -impl KeyLogin { - pub async fn login_register_code(self) -> RegisterCode { - todo!() - } - - pub async fn login_with_data(self, data: CodeLoginData) -> CodeLogin { - todo!() - } - - pub async fn login_without_data(self) -> CodeLogin { - todo!() - } -} - -pub struct RegisterCode { - api: S, user_secret_key: UserSecretKey, - key_login_session: KeyLoginSession, + _state: PhantomData } -impl RegisterCode { - pub async fn get_new_icons(&self) -> Result, String> { - todo!() - } - - pub async fn register(self, email: Email, passcode: &[u64]) -> Result { - todo!() +impl ClientAppKey { + pub async fn register(self) -> Result, String> { + self.repo.set_secret_key(&self.email, &self.user_secret_key).await?; + self.api.register_key(&self.email, &self.user_secret_key).await?; + Ok(ClientAppKey { + api: self.api, + repo: self.repo, + email: self.email, + user_secret_key: self.user_secret_key, + _state: PhantomData::, + }) } } -pub struct CodeLogin { - api: S, -} - -impl CodeLogin { - pub async fn login(self, email: Email, passcode: &[u64]) -> Result { - todo!() +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{ + repo: self.repo, + api: self.api, + email: self.email, + user_secret_key: self.user_secret_key, + key_login + }) } } -pub trait ClientRepo { - async fn get_secret_key(&self) -> Result; - async fn set_secret_key(&self, email: &Email,user_secret_key: &UserSecretKey) -> Result<(),String>; - async fn get_login_data(&self) -> Result; - async fn set_login_data(&self, data: CodeLoginData) -> Result<(), String>; - async fn set_email(&self, email: &Email) -> Result<(), String>; - async fn get_email(&self) -> Result; -} - -pub struct ClientAppKey { +pub struct ClientAppKeyLoggedIn { repo: R, api: S, email: Email, @@ -90,20 +56,7 @@ pub struct ClientAppKey { key_login: KeyLoginSession, } -impl ClientAppKey { - pub async fn new_register(email: Email, user_secret_key: UserSecretKey, repo: R, api: S) -> Result { - repo.set_secret_key(&email, &user_secret_key).await?; - api.register_key(&email, &user_secret_key).await?; - let key_login = api.login_key(&email, &user_secret_key).await?; - Ok(Self { - repo, - api, - email, - user_secret_key, - key_login, - }) - } - +impl ClientAppKeyLoggedIn { pub async fn register_code(self) -> Result, String> { let icon_nonce = Nonce::new(); let icons = self.get_icons(&icon_nonce).await?; @@ -132,7 +85,21 @@ impl ClientAppKey { } pub async fn login_code(self) -> Result, String> { - todo!() + 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?; + 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( + ClientAppCodeLogin{ + api: self.api, + email: self.email, + mask: login_data.mask, + icons, + keypad: login_data.keypad, + cipher, + } + ) } } @@ -158,18 +125,17 @@ impl ClientAppCodeRegister { .collect(); let ciphered_nkode = cipher.encipher(&passcode_idx).unwrap(); let data = CodeLoginData{ - mask: ciphered_nkode.mask.clone(), - icons: self.icons.clone(), + mask: ciphered_nkode.mask, cipher_nonce, - icon_nonce: self.icon_nonce.clone(), - keypad: keypad.clone(), + icon_nonce: self.icon_nonce, + keypad, }; self.api.register_code(&self.email, &ciphered_nkode.passcode, &self.key_login, &data).await?; Ok(ClientAppCodeLogin{ api: self.api, - mask: ciphered_nkode.mask, + mask: data.mask, email: self.email, - keypad, + keypad: data.keypad, cipher, icons: self.icons }) diff --git a/src/models/app.rs b/src/models/app.rs index ce2cc7d..0e27968 100644 --- a/src/models/app.rs +++ b/src/models/app.rs @@ -3,8 +3,9 @@ use serde::{Deserialize, Serialize}; use uuid::Uuid; use getset::Getters; use nkode_rs::from_bytes::FromBytes; +use nkode_rs::nkode_core::policy::NKodePolicy; use crate::models::email::Email; -use crate::models::opaque::OpaqueSessionKey; +use crate::models::opaque::{OpaqueSessionKey, UserSecretKey}; #[allow(dead_code)] struct LoginSession { @@ -44,8 +45,8 @@ impl Icon { pub struct CodeLoginData { #[get = "pub"] pub(crate) mask: Vec, - #[get = "pub"] - pub(crate) icons: Vec, + // #[get = "pub"] + // pub(crate) icons: Vec, #[get = "pub"] pub(crate) cipher_nonce: Nonce, #[get = "pub"] @@ -53,3 +54,14 @@ pub struct CodeLoginData { #[get = "pub"] pub(crate) keypad: Keypad, } + +pub trait ServerAPI { + async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>; + async fn register_code(&self, email: &Email, passcode: &[u64], key_login_session: &KeyLoginSession, 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 get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result, String>; + async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result; + async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result; + async fn get_policy(&self) -> Result; +} \ No newline at end of file diff --git a/src/repository/client_app/mod.rs b/src/repository/client_app/mod.rs new file mode 100644 index 0000000..8723567 --- /dev/null +++ b/src/repository/client_app/mod.rs @@ -0,0 +1 @@ +pub mod repos; \ No newline at end of file diff --git a/src/repository/client_app/repos.rs b/src/repository/client_app/repos.rs new file mode 100644 index 0000000..0951e99 --- /dev/null +++ b/src/repository/client_app/repos.rs @@ -0,0 +1,12 @@ +use crate::models::app::CodeLoginData; +use crate::models::email::Email; +use crate::models::opaque::UserSecretKey; + +pub trait ClientRepo { + async fn get_secret_key(&self) -> anyhow::Result; + async fn set_secret_key(&self, email: &Email,user_secret_key: &UserSecretKey) -> anyhow::Result<(),String>; + async fn get_login_data(&self) -> anyhow::Result; + async fn set_login_data(&self, data: CodeLoginData) -> anyhow::Result<(), String>; + async fn set_email(&self, email: &Email) -> anyhow::Result<(), String>; + async fn get_email(&self) -> anyhow::Result; +} \ No newline at end of file diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 5517533..e37d699 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -1 +1,2 @@ pub mod opaque; +pub(crate) mod client_app;