partial implement client app
This commit is contained in:
@@ -1,53 +1,36 @@
|
||||
use uuid::Uuid;
|
||||
use zeroize::Zeroizing;
|
||||
use nkode_rs::nkode_core::keypad::Keypad;
|
||||
use crate::models::app::{CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, 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;
|
||||
|
||||
|
||||
struct LoginSession {
|
||||
identity: Vec<u8>,
|
||||
session_id: Uuid,
|
||||
session_key: Zeroizing<Vec<u8>>,
|
||||
}
|
||||
|
||||
struct KeyLoginSession(LoginSession);
|
||||
struct CodeLoginSession(LoginSession);
|
||||
|
||||
struct IconID(u128);
|
||||
|
||||
struct Icon {
|
||||
id: IconID,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
struct CodeLoginData {
|
||||
mask: Vec<u64>,
|
||||
icons: Vec<Icon>,
|
||||
nonce: Vec<u8>,
|
||||
keypad_indices: Vec<u8>
|
||||
}
|
||||
|
||||
trait ServerAPI {
|
||||
async fn register_key(&self, identity: &[u8], secret_key: &[u8]) -> Result<(), String>;
|
||||
async fn register_code(&self, identity: &[u8], passcode: &[u64]) -> Result<(), String>;
|
||||
async fn login_key(&self, identity: &[u8], secret_key: &[u8]) -> Result<KeyLoginSession, String>;
|
||||
async fn login_code(&self, identity: &[u8], passcode: &[u64]) -> Result<CodeLoginSession, String>;
|
||||
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<KeyLoginSession, String>;
|
||||
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String>;
|
||||
async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String>;
|
||||
async fn set_login_data(&self, key_login_session: &KeyLoginSession, data: &CodeLoginData) -> Result<(), String>;
|
||||
async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, String>;
|
||||
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String>;
|
||||
async fn get_policy(&self) -> Result<NKodePolicy, String>;
|
||||
}
|
||||
|
||||
pub struct RegisterKey;
|
||||
|
||||
impl RegisterKey {
|
||||
pub async fn register<S: ServerAPI>(api: S,identity: &[u8], secret_key: &[u8]) -> Result<KeyLogin<S>, String> {
|
||||
pub async fn register<S: ServerAPI>(api: S, email: Email, user_secret_key: &UserSecretKey) -> Result<KeyLogin<S>, String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KeyLogin<S: ServerAPI> {
|
||||
api: S,
|
||||
identity: Vec<u8>,
|
||||
secret_key: Zeroizing<Vec<u8>>
|
||||
email: Email,
|
||||
user_secret_key: UserSecretKey
|
||||
}
|
||||
|
||||
impl <S: ServerAPI>KeyLogin<S> {
|
||||
@@ -66,7 +49,7 @@ impl <S: ServerAPI>KeyLogin<S> {
|
||||
|
||||
pub struct RegisterCode<S: ServerAPI> {
|
||||
api: S,
|
||||
secret_key: Vec<u8>,
|
||||
user_secret_key: UserSecretKey,
|
||||
key_login_session: KeyLoginSession,
|
||||
}
|
||||
|
||||
@@ -75,7 +58,7 @@ impl <S: ServerAPI>RegisterCode<S> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn register(self, identity: &[u8], passcode: &[u64]) -> Result<CodeLoginData, String> {
|
||||
pub async fn register(self, email: Email, passcode: &[u64]) -> Result<CodeLoginData, String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -85,43 +68,133 @@ pub struct CodeLogin<S: ServerAPI> {
|
||||
}
|
||||
|
||||
impl <S: ServerAPI>CodeLogin<S> {
|
||||
pub async fn login(self, identity: &[u8], passcode: &[u64]) -> Result<CodeLoginSession, String> {
|
||||
pub async fn login(self, email: Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
trait ClientRepo {
|
||||
async fn get_secret_key(&self) -> Result<Vec<u8>, String>;
|
||||
async fn set_secret_key(&mut self, secret_key: &[u8]) -> Result<(),String>;
|
||||
pub trait ClientRepo {
|
||||
async fn get_secret_key(&self) -> Result<UserSecretKey, String>;
|
||||
async fn set_secret_key(&self, email: &Email,user_secret_key: &UserSecretKey) -> Result<(),String>;
|
||||
async fn get_login_data(&self) -> Result<CodeLoginData, String>;
|
||||
async fn set_login_data(&mut self, data: CodeLoginData) -> Result<(), String>;
|
||||
async fn set_identity(&mut self, identity: &[u8]) -> Result<(), String>;
|
||||
async fn get_identity(&self) -> Result<&[u8], String>;
|
||||
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<Email, String>;
|
||||
}
|
||||
|
||||
pub struct ClientApp<S: ServerAPI, R: ClientRepo> {
|
||||
pub struct ClientAppKey<S: ServerAPI, R: ClientRepo> {
|
||||
repo: R,
|
||||
api: S
|
||||
api: S,
|
||||
email: Email,
|
||||
user_secret_key: UserSecretKey,
|
||||
key_login: KeyLoginSession,
|
||||
}
|
||||
|
||||
impl <S: ServerAPI, R: ClientRepo> ClientApp<S, R> {
|
||||
pub fn new_secret() -> Vec<u8> {
|
||||
todo!()
|
||||
impl <S: ServerAPI, R: ClientRepo> ClientAppKey<S, R> {
|
||||
pub async fn new_register(email: Email, user_secret_key: UserSecretKey, repo: R, api: S) -> Result<Self, String> {
|
||||
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,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn register_secret(&mut self, identity: &[u8], secret_key: &[u8]) -> Result<(), String> {
|
||||
todo!()
|
||||
pub async fn register_code(self) -> Result<ClientAppCodeRegister<S>, String> {
|
||||
let icon_nonce = Nonce::new();
|
||||
let icons = self.get_icons(&icon_nonce).await?;
|
||||
let policy = self.api.get_policy().await?;
|
||||
Ok(ClientAppCodeRegister {
|
||||
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),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn get_new_icons(&self) -> Result<Vec<Icon>, String> {
|
||||
todo!()
|
||||
async fn get_icons(&self, icon_nonce: &Nonce) -> Result<Vec<Icon>, 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?;
|
||||
for icon in &mut icons {
|
||||
let bytes = chacha_cipher.read_u8(ICON_ID_SIZE)?;
|
||||
let new_id = IconID::from_bytes(bytes.as_slice()).unwrap();
|
||||
icon.update_id(new_id);
|
||||
}
|
||||
Ok(icons)
|
||||
}
|
||||
|
||||
pub async fn select_icons(&mut self, selected_icons: Vec<IconID>) -> Result<(), String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
pub async fn set_secret(&mut self, secret_key: &[u8]) -> Result<(), String> {
|
||||
pub async fn login_code(self) -> Result<ClientAppCodeLogin<S>, String> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClientAppCodeRegister<S: ServerAPI> {
|
||||
api: S,
|
||||
email: Email,
|
||||
user_secret_key: UserSecretKey,
|
||||
key_login: KeyLoginSession,
|
||||
icon_nonce: Nonce,
|
||||
icons: Vec<Icon>,
|
||||
keypad: Keypad,
|
||||
}
|
||||
|
||||
impl <S: ServerAPI>ClientAppCodeRegister<S> {
|
||||
pub async fn register(self, selected_icons: Vec<IconID>) -> Result<ClientAppCodeLogin<S>, String> {
|
||||
let policy = self.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);
|
||||
let passcode_idx: Vec<usize> = selected_icons
|
||||
.iter()
|
||||
.filter_map(|x1| self.icons.iter().position(|x| x.id() == x1))
|
||||
.collect();
|
||||
let ciphered_nkode = cipher.encipher(&passcode_idx).unwrap();
|
||||
let data = CodeLoginData{
|
||||
mask: ciphered_nkode.mask.clone(),
|
||||
icons: self.icons.clone(),
|
||||
cipher_nonce,
|
||||
icon_nonce: self.icon_nonce.clone(),
|
||||
keypad: keypad.clone(),
|
||||
};
|
||||
self.api.register_code(&self.email, &ciphered_nkode.passcode, &self.key_login, &data).await?;
|
||||
Ok(ClientAppCodeLogin{
|
||||
api: self.api,
|
||||
mask: ciphered_nkode.mask,
|
||||
email: self.email,
|
||||
keypad,
|
||||
cipher,
|
||||
icons: self.icons
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ClientAppCodeLogin<S: ServerAPI> {
|
||||
api: S,
|
||||
email: Email,
|
||||
mask: Vec<u64>,
|
||||
icons: Vec<Icon>,
|
||||
keypad: Keypad,
|
||||
cipher: NKodeCipher
|
||||
}
|
||||
|
||||
impl <S: ServerAPI>ClientAppCodeLogin<S> {
|
||||
pub fn sort_icons(&self) -> Vec<Icon> {
|
||||
nkode_rs::tensor::reorder(
|
||||
&self.icons,
|
||||
self.keypad.indices()
|
||||
).unwrap().to_vec()
|
||||
}
|
||||
|
||||
pub async fn login(&self, selected_keys: &Vec<usize>) -> Result<CodeLoginSession, String> {
|
||||
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user