stopping for the night
This commit is contained in:
@@ -1,27 +1,29 @@
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use nkode_rs::nkode_core::keypad::Keypad;
|
use nkode_rs::nkode_core::keypad::Keypad;
|
||||||
use crate::models::app::{CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ClientAuthAPI, ICON_ID_SIZE};
|
use crate::models::app::{OpaqueAPI, AuthAPI, CodeLoginData, CodeLoginSession, Icon, IconID, KeyLoginSession, ICON_ID_SIZE, LoginSession};
|
||||||
use crate::models::email::Email;
|
use crate::models::email::Email;
|
||||||
use crate::models::opaque::UserSecretKey;
|
use crate::models::opaque::{OpaqueLoginSession, UserSecretKey};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use nkode_rs::nkode_core::nkode_cipher::NKodeCipher;
|
use nkode_rs::nkode_core::nkode_cipher::NKodeCipher;
|
||||||
use nkode_rs::from_bytes::FromBytes;
|
use nkode_rs::from_bytes::FromBytes;
|
||||||
use nkode_rs::nkode_core::chacha20prng::Nonce;
|
use nkode_rs::nkode_core::chacha20prng::Nonce;
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use nkode_rs::nkode_core::policy::{NKodePolicy, DEFAULT_POLICY};
|
||||||
|
use crate::opaque::client::{AuthenticationData, OpaqueAuthLogin, OpaqueAuthRegister, ServerConnectionLogin, ServerConnectionRegister};
|
||||||
|
|
||||||
pub struct Login;
|
pub struct Login;
|
||||||
pub struct Register;
|
pub struct Register;
|
||||||
|
|
||||||
|
|
||||||
pub struct ClientAppKey<State, S: ClientAuthAPI> {
|
pub struct ClientAppKey<State, S: OpaqueAPI> {
|
||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
user_secret_key: UserSecretKey,
|
user_secret_key: UserSecretKey,
|
||||||
_state: PhantomData<State>
|
_state: PhantomData<State>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: ClientAuthAPI> ClientAppKey<Register,S> {
|
impl <S: OpaqueAPI> ClientAppKey<Register,S> {
|
||||||
pub async fn register(self) -> Result<ClientAppKey<Login, S>, String> {
|
pub async fn register(self) -> Result<ClientAppKey<Login, S>, String> {
|
||||||
// self.repo.set_secret_key(&self.email, &self.user_secret_key).await?;
|
|
||||||
self.api.register_key(&self.email, &self.user_secret_key).await?;
|
self.api.register_key(&self.email, &self.user_secret_key).await?;
|
||||||
Ok(ClientAppKey {
|
Ok(ClientAppKey {
|
||||||
api: self.api,
|
api: self.api,
|
||||||
@@ -32,7 +34,7 @@ impl <S: ClientAuthAPI> ClientAppKey<Register,S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: ClientAuthAPI> ClientAppKey<Login,S> {
|
impl <S: OpaqueAPI> ClientAppKey<Login,S> {
|
||||||
pub async fn login(self) -> Result<ClientAppKeyLoggedIn<S>,String> {
|
pub async fn login(self) -> Result<ClientAppKeyLoggedIn<S>,String> {
|
||||||
let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?;
|
let key_login = self.api.login_key(&self.email, &self.user_secret_key).await?;
|
||||||
Ok(ClientAppKeyLoggedIn{
|
Ok(ClientAppKeyLoggedIn{
|
||||||
@@ -44,14 +46,14 @@ impl <S: ClientAuthAPI> ClientAppKey<Login,S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientAppKeyLoggedIn<S: ClientAuthAPI> {
|
pub struct ClientAppKeyLoggedIn<S: OpaqueAPI> {
|
||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
user_secret_key: UserSecretKey,
|
user_secret_key: UserSecretKey,
|
||||||
key_login: KeyLoginSession,
|
key_login: KeyLoginSession,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: ClientAuthAPI> ClientAppKeyLoggedIn<S> {
|
impl <S: OpaqueAPI + AuthAPI> ClientAppKeyLoggedIn<S> {
|
||||||
pub async fn register_code(self) -> Result<ClientAppCodeRegister<S>, String> {
|
pub async fn register_code(self) -> Result<ClientAppCodeRegister<S>, String> {
|
||||||
let icon_nonce = Nonce::new();
|
let icon_nonce = Nonce::new();
|
||||||
let icons = self.get_icons(&icon_nonce).await?;
|
let icons = self.get_icons(&icon_nonce).await?;
|
||||||
@@ -98,7 +100,7 @@ impl <S: ClientAuthAPI> ClientAppKeyLoggedIn<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientAppCodeRegister<S: ClientAuthAPI> {
|
pub struct ClientAppCodeRegister<S: OpaqueAPI> {
|
||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
user_secret_key: UserSecretKey,
|
user_secret_key: UserSecretKey,
|
||||||
@@ -108,7 +110,7 @@ pub struct ClientAppCodeRegister<S: ClientAuthAPI> {
|
|||||||
keypad: Keypad,
|
keypad: Keypad,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: ClientAuthAPI>ClientAppCodeRegister<S> {
|
impl <S: OpaqueAPI + AuthAPI>ClientAppCodeRegister<S> {
|
||||||
pub async fn register(self, selected_icons: Vec<IconID>) -> Result<ClientAppCodeLogin<S>, String> {
|
pub async fn register(self, selected_icons: Vec<IconID>) -> Result<ClientAppCodeLogin<S>, String> {
|
||||||
let policy = self.api.get_policy().await?;
|
let policy = self.api.get_policy().await?;
|
||||||
let keypad = Keypad::new(policy.clone());
|
let keypad = Keypad::new(policy.clone());
|
||||||
@@ -137,7 +139,7 @@ impl <S: ClientAuthAPI>ClientAppCodeRegister<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ClientAppCodeLogin<S: ClientAuthAPI> {
|
pub struct ClientAppCodeLogin<S: OpaqueAPI> {
|
||||||
api: S,
|
api: S,
|
||||||
email: Email,
|
email: Email,
|
||||||
mask: Vec<u64>,
|
mask: Vec<u64>,
|
||||||
@@ -146,7 +148,7 @@ pub struct ClientAppCodeLogin<S: ClientAuthAPI> {
|
|||||||
cipher: NKodeCipher
|
cipher: NKodeCipher
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <S: ClientAuthAPI>ClientAppCodeLogin<S> {
|
impl <S: OpaqueAPI>ClientAppCodeLogin<S> {
|
||||||
pub fn sort_icons(&self) -> Vec<Icon> {
|
pub fn sort_icons(&self) -> Vec<Icon> {
|
||||||
nkode_rs::tensor::reorder(
|
nkode_rs::tensor::reorder(
|
||||||
&self.icons,
|
&self.icons,
|
||||||
@@ -159,3 +161,89 @@ impl <S: ClientAuthAPI>ClientAppCodeLogin<S> {
|
|||||||
self.api.login_code(&self.email, &passcode).await
|
self.api.login_code(&self.email, &passcode).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ClientAuth<
|
||||||
|
R: ServerConnectionRegister + Clone,
|
||||||
|
L: ServerConnectionLogin + Clone,
|
||||||
|
K: AuthAPI
|
||||||
|
> {
|
||||||
|
opaque_key_register: OpaqueAuthRegister<R>,
|
||||||
|
opaque_key_login: OpaqueAuthLogin<L>,
|
||||||
|
opaque_code_register: OpaqueAuthRegister<R>,
|
||||||
|
opaque_code_login: OpaqueAuthLogin<L>,
|
||||||
|
nkode_api: K,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<R, L, K> OpaqueAPI for ClientAuth<R, L,K>
|
||||||
|
where
|
||||||
|
R: ServerConnectionRegister + Clone + Sync + Send,
|
||||||
|
L: 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: &KeyLoginSession, 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<KeyLoginSession, String> {
|
||||||
|
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))?;
|
||||||
|
Ok(KeyLoginSession(
|
||||||
|
LoginSession {
|
||||||
|
email: email.clone(),
|
||||||
|
session_key
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
|
||||||
|
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))?;
|
||||||
|
Ok(CodeLoginSession(
|
||||||
|
LoginSession {
|
||||||
|
email: email.clone(),
|
||||||
|
session_key
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<R, L, K> AuthAPI for ClientAuth<R, L, K>
|
||||||
|
where
|
||||||
|
R: ServerConnectionRegister + Clone + Sync + Send,
|
||||||
|
L: ServerConnectionLogin + Clone + Sync + Send,
|
||||||
|
K: AuthAPI + Sync + Send,
|
||||||
|
{
|
||||||
|
async fn get_new_icons(
|
||||||
|
&self,
|
||||||
|
key_login_session: &KeyLoginSession,
|
||||||
|
) -> Result<Vec<Icon>, String> {
|
||||||
|
self.nkode_api
|
||||||
|
.get_new_icons(key_login_session)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_login_data(
|
||||||
|
&self,
|
||||||
|
key_login_session: &KeyLoginSession,
|
||||||
|
) -> Result<CodeLoginData, String> {
|
||||||
|
self.nkode_api
|
||||||
|
.get_login_data(key_login_session)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String> {
|
||||||
|
self.nkode_api.is_code_registered(key_login_session).await
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_policy(&self) -> Result<NKodePolicy, String> {
|
||||||
|
Ok(DEFAULT_POLICY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,197 +0,0 @@
|
|||||||
// // in_memory_server.rs
|
|
||||||
// use std::collections::HashMap;
|
|
||||||
// use std::hash::Hash;
|
|
||||||
// use std::sync::Arc;
|
|
||||||
// use nkode_rs::nkode_core::policy::NKodePolicy;
|
|
||||||
// use tokio::sync::RwLock;
|
|
||||||
//
|
|
||||||
// use crate::models::app::{
|
|
||||||
// CodeLoginData, CodeLoginSession, Icon, KeyLoginSession, ClientAuthAPI,
|
|
||||||
// };
|
|
||||||
// use crate::models::email::Email;
|
|
||||||
// use crate::models::opaque::UserSecretKey;
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// #[derive(Clone)]
|
|
||||||
// pub struct InMemoryServer<FKeySess, FCodeSess> {
|
|
||||||
// state: Arc<RwLock<State>>,
|
|
||||||
// policy: NKodePolicy,
|
|
||||||
// icon_pool: Vec<Icon>,
|
|
||||||
// new_key_session: FKeySess,
|
|
||||||
// new_code_session: FCodeSess,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// struct State {
|
|
||||||
// users: HashMap<Email, UserRecord>,
|
|
||||||
// key_sessions: HashMap<KeyLoginSession, Email>,
|
|
||||||
// code_sessions: HashMap<CodeLoginSession, Email>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// struct UserRecord {
|
|
||||||
// secret_key: UserSecretKey,
|
|
||||||
// code: Option<StoredCode>,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// struct StoredCode {
|
|
||||||
// passcode: Vec<u64>,
|
|
||||||
// data: CodeLoginData,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Default for State {
|
|
||||||
// fn default() -> Self {
|
|
||||||
// Self {
|
|
||||||
// users: HashMap::new(),
|
|
||||||
// key_sessions: HashMap::new(),
|
|
||||||
// code_sessions: HashMap::new(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<FKeySess, FCodeSess> InMemoryServer<FKeySess, FCodeSess> {
|
|
||||||
// /// `icon_pool` is what `get_new_icons()` returns (cloned) each time.
|
|
||||||
// /// `new_key_session` and `new_code_session` let you decide how sessions are created
|
|
||||||
// /// without changing the ServerAPI trait or guessing constructors.
|
|
||||||
// pub fn new(
|
|
||||||
// policy: NKodePolicy,
|
|
||||||
// icon_pool: Vec<Icon>,
|
|
||||||
// new_key_session: FKeySess,
|
|
||||||
// new_code_session: FCodeSess,
|
|
||||||
// ) -> Self {
|
|
||||||
// Self {
|
|
||||||
// state: Arc::new(RwLock::new(State::default())),
|
|
||||||
// policy,
|
|
||||||
// icon_pool,
|
|
||||||
// new_key_session,
|
|
||||||
// new_code_session,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<FKeySess, FCodeSess> InMemoryServer<FKeySess, FCodeSess>
|
|
||||||
// where
|
|
||||||
// // bounds needed for HashMap keys/values and cloning across calls
|
|
||||||
// Email: Eq + Hash + Clone,
|
|
||||||
// UserSecretKey: Clone + PartialEq,
|
|
||||||
// Icon: Clone,
|
|
||||||
// CodeLoginData: Clone,
|
|
||||||
// KeyLoginSession: Eq + Hash + Clone,
|
|
||||||
// CodeLoginSession: Eq + Hash + Clone,
|
|
||||||
// FKeySess: Fn() -> KeyLoginSession + Send + Sync + 'static,
|
|
||||||
// FCodeSess: Fn() -> CodeLoginSession + Send + Sync + 'static,
|
|
||||||
// {
|
|
||||||
// fn err(msg: impl Into<String>) -> Result<(), String> {
|
|
||||||
// Err(msg.into())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn ok<T>(v: T) -> Result<T, String> {
|
|
||||||
// Ok(v)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn email_from_key_session(&self, sess: &KeyLoginSession) -> Result<Email, String> {
|
|
||||||
// let st = self.state.read().await;
|
|
||||||
// st.key_sessions
|
|
||||||
// .get(sess)
|
|
||||||
// .cloned()
|
|
||||||
// .ok_or_else(|| "invalid key login session".to_string())
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl<FKeySess, FCodeSess> ClientAuthAPI for InMemoryServer<FKeySess, FCodeSess>
|
|
||||||
// where
|
|
||||||
// Email: Eq + Hash + Clone,
|
|
||||||
// UserSecretKey: Clone + PartialEq,
|
|
||||||
// Icon: Clone,
|
|
||||||
// CodeLoginData: Clone,
|
|
||||||
// KeyLoginSession: Eq + Hash + Clone,
|
|
||||||
// CodeLoginSession: Eq + Hash + Clone,
|
|
||||||
//
|
|
||||||
// FKeySess: Fn() -> KeyLoginSession + Send + Sync + 'static,
|
|
||||||
// FCodeSess: Fn() -> CodeLoginSession + Send + Sync + 'static,
|
|
||||||
// {
|
|
||||||
// async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String> {
|
|
||||||
// let mut st = self.state.write().await;
|
|
||||||
//
|
|
||||||
// if st.users.contains_key(email) {
|
|
||||||
// return Err("email already registered".to_string());
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// st.users.insert(
|
|
||||||
// email.clone(),
|
|
||||||
// UserRecord {
|
|
||||||
// secret_key: secret_key.clone(),
|
|
||||||
// code: None,
|
|
||||||
// },
|
|
||||||
// );
|
|
||||||
//
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn login_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String> {
|
|
||||||
// let mut st = self.state.write().await;
|
|
||||||
//
|
|
||||||
// let user = st.users.get(email).ok_or_else(|| "unknown email".to_string())?;
|
|
||||||
// if &user.secret_key != secret_key {
|
|
||||||
// return Err("invalid secret key".to_string());
|
|
||||||
// }
|
|
||||||
// let sess = (self.new_key_session)();
|
|
||||||
// st.key_sessions.insert(sess.clone(), email.clone());
|
|
||||||
// Ok(sess)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String> {
|
|
||||||
// let email = self.email_from_key_session(key_login_session).await?;
|
|
||||||
// let st = self.state.read().await;
|
|
||||||
// let user = st.users.get(&email).ok_or_else(|| "unknown email".to_string())?;
|
|
||||||
// Ok(user.code.is_some())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn get_policy(&self) -> Result<NKodePolicy, String> {
|
|
||||||
// Ok(self.policy.clone())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String> {
|
|
||||||
// // Validate session (mimics auth gate)
|
|
||||||
// let _email = self.email_from_key_session(key_login_session).await?;
|
|
||||||
// Ok(self.icon_pool.clone())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn register_code(
|
|
||||||
// &self,
|
|
||||||
// email: &Email,
|
|
||||||
// passcode: &[u64],
|
|
||||||
// key_login_session: &KeyLoginSession,
|
|
||||||
// data: &CodeLoginData,
|
|
||||||
// ) -> Result<(), String> {
|
|
||||||
// let sess_email = self.email_from_key_session(key_login_session).await?;
|
|
||||||
// if &sess_email != email {
|
|
||||||
// return Err("session email mismatch".to_string());
|
|
||||||
// }
|
|
||||||
// let mut st = self.state.write().await;
|
|
||||||
// let user = st.users.get_mut(email).ok_or_else(|| "unknown email".to_string())?;
|
|
||||||
// user.code = Some(StoredCode {
|
|
||||||
// passcode: passcode.to_vec(),
|
|
||||||
// data: data.clone(),
|
|
||||||
// });
|
|
||||||
// Ok(())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, String> {
|
|
||||||
// let email = self.email_from_key_session(key_login_session).await?;
|
|
||||||
// let st = self.state.read().await;
|
|
||||||
// let user = st.users.get(&email).ok_or_else(|| "unknown email".to_string())?;
|
|
||||||
// let code = user.code.as_ref().ok_or_else(|| "code not registered".to_string())?;
|
|
||||||
// Ok(code.data.clone())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String> {
|
|
||||||
// let mut st = self.state.write().await;
|
|
||||||
// let user = st.users.get(email).ok_or_else(|| "unknown email".to_string())?;
|
|
||||||
// let code = user.code.as_ref().ok_or_else(|| "code not registered".to_string())?;
|
|
||||||
// if code.passcode.as_slice() != passcode {
|
|
||||||
// return Err("invalid passcode".to_string());
|
|
||||||
// }
|
|
||||||
// let sess = (self.new_code_session)();
|
|
||||||
// st.code_sessions.insert(sess.clone(), email.clone());
|
|
||||||
// Ok(sess)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -1,20 +1,18 @@
|
|||||||
|
use async_trait::async_trait;
|
||||||
use nkode_rs::nkode_core::chacha20prng::Nonce; use nkode_rs::nkode_core::keypad::Keypad;
|
use nkode_rs::nkode_core::chacha20prng::Nonce; use nkode_rs::nkode_core::keypad::Keypad;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use uuid::Uuid;
|
|
||||||
use getset::Getters;
|
use getset::Getters;
|
||||||
use nkode_rs::from_bytes::FromBytes;
|
use nkode_rs::from_bytes::FromBytes;
|
||||||
use nkode_rs::nkode_core::policy::NKodePolicy;
|
use nkode_rs::nkode_core::policy::NKodePolicy;
|
||||||
use crate::models::email::Email;
|
use crate::models::email::Email;
|
||||||
use crate::models::opaque::{OpaqueSessionKey, UserSecretKey};
|
use crate::models::opaque::{OpaqueSessionKey, UserSecretKey};
|
||||||
|
pub struct LoginSession {
|
||||||
struct LoginSession {
|
pub(crate) email: Email,
|
||||||
email: Email,
|
pub(crate) session_key: OpaqueSessionKey,
|
||||||
session_id: Uuid,
|
|
||||||
session_key: OpaqueSessionKey,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KeyLoginSession(LoginSession);
|
pub struct KeyLoginSession(pub(crate) LoginSession);
|
||||||
pub struct CodeLoginSession(LoginSession);
|
pub struct CodeLoginSession(pub(crate) LoginSession);
|
||||||
|
|
||||||
pub const ICON_ID_SIZE: usize = 32;
|
pub const ICON_ID_SIZE: usize = 32;
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
@@ -44,8 +42,6 @@ impl Icon {
|
|||||||
pub struct CodeLoginData {
|
pub struct CodeLoginData {
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
pub(crate) mask: Vec<u64>,
|
pub(crate) mask: Vec<u64>,
|
||||||
// #[get = "pub"]
|
|
||||||
// pub(crate) icons: Vec<Icon>,
|
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
pub(crate) cipher_nonce: Nonce,
|
pub(crate) cipher_nonce: Nonce,
|
||||||
#[get = "pub"]
|
#[get = "pub"]
|
||||||
@@ -54,11 +50,16 @@ pub struct CodeLoginData {
|
|||||||
pub(crate) keypad: Keypad,
|
pub(crate) keypad: Keypad,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait ClientAuthAPI {
|
#[async_trait]
|
||||||
|
pub trait OpaqueAPI {
|
||||||
async fn register_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<(), String>;
|
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 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_key(&self, email: &Email, secret_key: &UserSecretKey) -> Result<KeyLoginSession, String>;
|
||||||
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String>;
|
async fn login_code(&self, email: &Email, passcode: &[u64]) -> Result<CodeLoginSession, String>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait AuthAPI {
|
||||||
async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String>;
|
async fn get_new_icons(&self, key_login_session: &KeyLoginSession) -> Result<Vec<Icon>, String>;
|
||||||
async fn get_login_data(&self, key_login_session: &KeyLoginSession) -> Result<CodeLoginData, 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 is_code_registered(&self, key_login_session: &KeyLoginSession) -> Result<bool, String>;
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ use nkode_rs::from_bytes::FromBytes;
|
|||||||
|
|
||||||
const USER_KEY_SIZE: usize = 16;
|
const USER_KEY_SIZE: usize = 16;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
#[derive(PartialEq)]
|
|
||||||
pub struct UserSecretKey(Zeroizing<[u8; USER_KEY_SIZE]>);
|
pub struct UserSecretKey(Zeroizing<[u8; USER_KEY_SIZE]>);
|
||||||
|
|
||||||
impl UserSecretKey {
|
impl UserSecretKey {
|
||||||
@@ -20,6 +19,10 @@ impl UserSecretKey {
|
|||||||
let out = blake3::derive_key("your-app chacha20 secret key v1", &self.0.as_slice());
|
let out = blake3::derive_key("your-app chacha20 secret key v1", &self.0.as_slice());
|
||||||
SecretKey::from_bytes(&out).unwrap()
|
SecretKey::from_bytes(&out).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn as_slice(&self) -> &[u8] {
|
||||||
|
self.0.as_slice()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
|
impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
|
||||||
@@ -30,6 +33,7 @@ impl FromBytes<USER_KEY_SIZE> for UserSecretKey {
|
|||||||
|
|
||||||
const OPAQUE_SESSION_KEY_SIZE: usize = 64;
|
const OPAQUE_SESSION_KEY_SIZE: usize = 64;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct OpaqueSessionKey(Zeroizing<[u8; OPAQUE_SESSION_KEY_SIZE]>);
|
pub struct OpaqueSessionKey(Zeroizing<[u8; OPAQUE_SESSION_KEY_SIZE]>);
|
||||||
|
|
||||||
impl FromBytes<OPAQUE_SESSION_KEY_SIZE> for OpaqueSessionKey {
|
impl FromBytes<OPAQUE_SESSION_KEY_SIZE> for OpaqueSessionKey {
|
||||||
@@ -52,13 +56,13 @@ pub type NKodeServerSetup = ServerSetup<NKodeCipherSuite, PrivateKey<Ristretto25
|
|||||||
pub type PasswordFile = GenericArray<u8, RegistrationUploadLen<NKodeCipherSuite>>;
|
pub type PasswordFile = GenericArray<u8, RegistrationUploadLen<NKodeCipherSuite>>;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct LoginSession {
|
pub struct OpaqueLoginSession {
|
||||||
pub response: CredentialResponse<NKodeCipherSuite>,
|
pub response: CredentialResponse<NKodeCipherSuite>,
|
||||||
pub session_id: Uuid
|
pub session_id: Uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct RegisterSession {
|
pub struct OpaqueRegisterSession {
|
||||||
pub response: RegistrationResponse<NKodeCipherSuite>,
|
pub response: RegistrationResponse<NKodeCipherSuite>,
|
||||||
pub session_id: Uuid
|
pub session_id: Uuid
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
use std::fmt;
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
|
use nkode_rs::from_bytes::FromBytes;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use opaque_ke::rand::rngs::OsRng;
|
use opaque_ke::rand::rngs::OsRng;
|
||||||
use opaque_ke::{
|
use opaque_ke::{
|
||||||
ClientLogin, ClientLoginFinishParameters,
|
ClientLogin, ClientLoginFinishParameters,
|
||||||
@@ -8,10 +9,8 @@ use opaque_ke::{
|
|||||||
CredentialFinalization, CredentialRequest,
|
CredentialFinalization, CredentialRequest,
|
||||||
RegistrationRequest,
|
RegistrationRequest,
|
||||||
};
|
};
|
||||||
|
use crate::models::app::KeyLoginSession;
|
||||||
use crate::models::opaque::{RegisterSession, LoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
|
use crate::models::opaque::{OpaqueRegisterSession, OpaqueLoginSession, NKodeCipherSuite, PasswordFile, OpaqueSessionKey};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ClientAuthError {
|
pub enum ClientAuthError {
|
||||||
@@ -19,6 +18,17 @@ pub enum ClientAuthError {
|
|||||||
Transport(String),
|
Transport(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ClientAuthError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
ClientAuthError::Opaque(msg) => write!(f, "{}", msg),
|
||||||
|
ClientAuthError::Transport(msg) => write!(f, "transport error: {}", msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ClientAuthError {}
|
||||||
|
|
||||||
pub struct AuthenticationData {
|
pub struct AuthenticationData {
|
||||||
pub identifier: Vec<u8>,
|
pub identifier: Vec<u8>,
|
||||||
pub secret: Vec<u8>,
|
pub secret: Vec<u8>,
|
||||||
@@ -32,11 +42,11 @@ impl AuthenticationData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_code(email: &str, code: &[usize]) -> Self {
|
pub fn from_code(email: &str, code: &[u64]) -> Self {
|
||||||
// fixed-width so it's stable across 32-bit vs 64-bit platforms
|
// fixed-width so it's stable across 32-bit vs 64-bit platforms
|
||||||
let mut secret = Vec::with_capacity(code.len() * 8);
|
let mut secret = Vec::with_capacity(code.len() * 8);
|
||||||
for &n in code {
|
for &n in code {
|
||||||
secret.extend_from_slice(&(n as u64).to_le_bytes());
|
secret.extend_from_slice(&(n).to_le_bytes());
|
||||||
}
|
}
|
||||||
Self {
|
Self {
|
||||||
identifier: email.as_bytes().to_vec(),
|
identifier: email.as_bytes().to_vec(),
|
||||||
@@ -51,7 +61,7 @@ pub trait ServerConnectionRegister {
|
|||||||
&self,
|
&self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
message: &RegistrationRequest<NKodeCipherSuite>,
|
message: &RegistrationRequest<NKodeCipherSuite>,
|
||||||
) -> Result<RegisterSession, ClientAuthError>;
|
) -> Result<OpaqueRegisterSession, ClientAuthError>;
|
||||||
|
|
||||||
async fn finish(
|
async fn finish(
|
||||||
&self,
|
&self,
|
||||||
@@ -66,7 +76,7 @@ pub trait ServerConnectionLogin {
|
|||||||
&self,
|
&self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
request: &CredentialRequest<NKodeCipherSuite>,
|
request: &CredentialRequest<NKodeCipherSuite>,
|
||||||
) -> Result<LoginSession, ClientAuthError>;
|
) -> Result<OpaqueLoginSession, ClientAuthError>;
|
||||||
|
|
||||||
async fn finish(
|
async fn finish(
|
||||||
&self,
|
&self,
|
||||||
@@ -99,7 +109,6 @@ impl <R: ServerConnectionRegister + Clone>OpaqueAuthRegister<R> {
|
|||||||
pub async fn register(
|
pub async fn register(
|
||||||
&self,
|
&self,
|
||||||
auth: &AuthenticationData,
|
auth: &AuthenticationData,
|
||||||
// server: &mut impl ServerConnectionRegister,
|
|
||||||
) -> Result<(), ClientAuthError> {
|
) -> Result<(), ClientAuthError> {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let start = ClientRegistration::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
|
let start = ClientRegistration::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
|
||||||
@@ -131,7 +140,7 @@ impl <L: ServerConnectionLogin + Clone>OpaqueAuthLogin<L> {
|
|||||||
pub async fn login(
|
pub async fn login(
|
||||||
&self,
|
&self,
|
||||||
auth: &AuthenticationData,
|
auth: &AuthenticationData,
|
||||||
) -> Result<Vec<u8>, ClientAuthError> {
|
) -> Result<OpaqueSessionKey, ClientAuthError> {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let start = ClientLogin::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
|
let start = ClientLogin::<NKodeCipherSuite>::start(&mut rng, &auth.secret)
|
||||||
.map_err(|e| ClientAuthError::Opaque(format!("client login start: {e:?}")))?;
|
.map_err(|e| ClientAuthError::Opaque(format!("client login start: {e:?}")))?;
|
||||||
@@ -153,6 +162,9 @@ impl <L: ServerConnectionLogin + Clone>OpaqueAuthLogin<L> {
|
|||||||
.finish(&server_start.session_id, &finish.message)
|
.finish(&server_start.session_id, &finish.message)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| ClientAuthError::Transport(format!("server login finish: {e:?}")))?;
|
.map_err(|e| ClientAuthError::Transport(format!("server login finish: {e:?}")))?;
|
||||||
Ok(finish.session_key.to_vec())
|
Ok(
|
||||||
|
OpaqueSessionKey::from_bytes(finish.session_key.as_slice())
|
||||||
|
.map_err(|e| ClientAuthError::Opaque(format!("from bytes error {e:?}")))?
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use opaque_ke::{
|
|||||||
ServerRegistration,
|
ServerRegistration,
|
||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use crate::models::opaque::{LoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, RegisterSession};
|
use crate::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
|
||||||
use crate::repository::opaque::repos::{OpaqueDatabaseRepo, AuthRepoError, OpaqueSessionRepo};
|
use crate::repository::opaque::repos::{OpaqueDatabaseRepo, AuthRepoError, OpaqueSessionRepo};
|
||||||
|
|
||||||
pub struct RegCache {
|
pub struct RegCache {
|
||||||
@@ -79,7 +79,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
request: RegistrationRequest<NKodeCipherSuite>,
|
request: RegistrationRequest<NKodeCipherSuite>,
|
||||||
) -> Result<RegisterSession, String> {
|
) -> Result<OpaqueRegisterSession, String> {
|
||||||
K::prereq_for_register(&self.user_repo, identifier)
|
K::prereq_for_register(&self.user_repo, identifier)
|
||||||
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
||||||
let start = ServerRegistration::<NKodeCipherSuite>::start(
|
let start = ServerRegistration::<NKodeCipherSuite>::start(
|
||||||
@@ -91,7 +91,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
|
|||||||
.new_reg_session(identifier)
|
.new_reg_session(identifier)
|
||||||
.map_err(|e| format!("reg cache: {e}"))?;
|
.map_err(|e| format!("reg cache: {e}"))?;
|
||||||
|
|
||||||
Ok(RegisterSession { session_id: cache.session_id, response: start.message })
|
Ok(OpaqueRegisterSession { session_id: cache.session_id, response: start.message })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn reg_finish<K: CredKind>(
|
pub async fn reg_finish<K: CredKind>(
|
||||||
@@ -115,14 +115,13 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
request: CredentialRequest<NKodeCipherSuite>,
|
request: CredentialRequest<NKodeCipherSuite>,
|
||||||
) -> Result<LoginSession, String> {
|
) -> Result<OpaqueLoginSession, String> {
|
||||||
let password_file = K::get_pf(&self.user_repo, identifier)
|
let password_file = K::get_pf(&self.user_repo, identifier)
|
||||||
.map_err(|e| format!("repo read: {e:?}"))?;
|
.map_err(|e| format!("repo read: {e:?}"))?;
|
||||||
|
|
||||||
let password_file =
|
let password_file =
|
||||||
ServerRegistration::<NKodeCipherSuite>::deserialize(password_file.as_slice())
|
ServerRegistration::<NKodeCipherSuite>::deserialize(password_file.as_slice())
|
||||||
.map_err(|e| format!("pf deserialize: {e:?}"))?;
|
.map_err(|e| format!("pf deserialize: {e:?}"))?;
|
||||||
|
|
||||||
let mut server_rng = OsRng;
|
let mut server_rng = OsRng;
|
||||||
let start = ServerLogin::start(
|
let start = ServerLogin::start(
|
||||||
&mut server_rng,
|
&mut server_rng,
|
||||||
@@ -132,12 +131,10 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo> OpaqueAuth<R, S> {
|
|||||||
identifier,
|
identifier,
|
||||||
ServerLoginParameters::default(),
|
ServerLoginParameters::default(),
|
||||||
).map_err(|e| format!("opaque login start: {e:?}"))?;
|
).map_err(|e| format!("opaque login start: {e:?}"))?;
|
||||||
|
|
||||||
let cache = self.session
|
let cache = self.session
|
||||||
.new_login_session(identifier, start.state)
|
.new_login_session(identifier, start.state)
|
||||||
.map_err(|e| format!("login cache: {e}"))?;
|
.map_err(|e| format!("login cache: {e}"))?;
|
||||||
|
Ok(OpaqueLoginSession { session_id: cache.session_id, response: start.message })
|
||||||
Ok(LoginSession { session_id: cache.session_id, response: start.message })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn login_finish<K: CredKind>(
|
pub async fn login_finish<K: CredKind>(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use tokio::sync::Mutex;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
|
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
|
||||||
use crate::models::opaque::{LoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, RegisterSession};
|
use crate::models::opaque::{OpaqueLoginSession, NKodeCipherSuite, NKodeServerSetup, OpaqueSessionKey, PasswordFile, OpaqueRegisterSession};
|
||||||
use crate::opaque::client::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister};
|
use crate::opaque::client::{ClientAuthError, ServerConnectionLogin, ServerConnectionRegister};
|
||||||
use crate::opaque::server::{OpaqueAuth, CredKind, Key, Code};
|
use crate::opaque::server::{OpaqueAuth, CredKind, Key, Code};
|
||||||
use crate::repository::opaque::in_memory::in_memory_auth_repo::InMemoryAuthRepo;
|
use crate::repository::opaque::in_memory::in_memory_auth_repo::InMemoryAuthRepo;
|
||||||
@@ -31,13 +31,13 @@ pub type InMemoryCodeServer = InMemoryServer<Code>;
|
|||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<K> ServerConnectionRegister for InMemoryServer<K>
|
impl<K> ServerConnectionRegister for InMemoryServer<K>
|
||||||
where
|
where
|
||||||
K: CredKind + Send + Sync,
|
K: CredKind + Sync,
|
||||||
{
|
{
|
||||||
async fn start(
|
async fn start(
|
||||||
&self,
|
&self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
message: &RegistrationRequest<NKodeCipherSuite>,
|
message: &RegistrationRequest<NKodeCipherSuite>,
|
||||||
) -> Result<RegisterSession, ClientAuthError> {
|
) -> Result<OpaqueRegisterSession, ClientAuthError> {
|
||||||
// Server API takes ownership; client trait gives us a reference.
|
// Server API takes ownership; client trait gives us a reference.
|
||||||
// opaque-ke request types are typically Clone; if not, you'll need to adjust signatures.
|
// opaque-ke request types are typically Clone; if not, you'll need to adjust signatures.
|
||||||
self.auth.lock().await
|
self.auth.lock().await
|
||||||
@@ -67,7 +67,7 @@ where
|
|||||||
&self,
|
&self,
|
||||||
identifier: &[u8],
|
identifier: &[u8],
|
||||||
request: &CredentialRequest<NKodeCipherSuite>,
|
request: &CredentialRequest<NKodeCipherSuite>,
|
||||||
) -> Result<LoginSession, ClientAuthError> {
|
) -> Result<OpaqueLoginSession, ClientAuthError> {
|
||||||
self.auth.lock().await
|
self.auth.lock().await
|
||||||
.login_start::<K>(identifier, request.clone())
|
.login_start::<K>(identifier, request.clone())
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ async fn opaque_key_registration_and_login_roundtrip() {
|
|||||||
let auth_data = AuthenticationData::from_secret_key("a@b.com", b"supersecret16bytes");
|
let auth_data = AuthenticationData::from_secret_key("a@b.com", b"supersecret16bytes");
|
||||||
auth_reg.register(&auth_data).await.expect("registration should succeed");
|
auth_reg.register(&auth_data).await.expect("registration should succeed");
|
||||||
let login_reg = OpaqueAuthLogin::new(server);
|
let login_reg = OpaqueAuthLogin::new(server);
|
||||||
let session_key =login_reg.login(&auth_data)
|
let _ =login_reg.login(&auth_data)
|
||||||
.await
|
.await
|
||||||
.expect("login should succeed");
|
.expect("login should succeed");
|
||||||
assert!(!session_key.is_empty());
|
// assert!(!session_key.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -38,9 +38,9 @@ async fn opaque_login_fails_if_not_registered() {
|
|||||||
async fn cannot_register_code_before_key() {
|
async fn cannot_register_code_before_key() {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
let server_setup = NKodeServerSetup::new(&mut rng);
|
let server_setup = NKodeServerSetup::new(&mut rng);
|
||||||
let mut server = InMemoryCodeServer::new(server_setup);
|
let server = InMemoryCodeServer::new(server_setup);
|
||||||
let auth_reg = OpaqueAuthRegister::new(server.clone());
|
let auth_reg = OpaqueAuthRegister::new(server.clone());
|
||||||
let auth = AuthenticationData::from_code("x@y.com", &[1usize,2,3,4]);
|
let auth = AuthenticationData::from_code("x@y.com", &[1u64,2,3,4]);
|
||||||
let err = auth_reg.register(&auth)
|
let err = auth_reg.register(&auth)
|
||||||
.await
|
.await
|
||||||
.expect_err("should fail because key is not registered");
|
.expect_err("should fail because key is not registered");
|
||||||
|
|||||||
Reference in New Issue
Block a user