refactor mutibility
This commit is contained in:
@@ -23,7 +23,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
}
|
||||
|
||||
pub async fn reg_start<K: CredKind>(
|
||||
&mut self,
|
||||
&self,
|
||||
identifier: &[u8],
|
||||
request: RegistrationRequest<NKodeCipherSuite>,
|
||||
) -> Result<OpaqueRegisterSession, String> {
|
||||
@@ -42,7 +42,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
}
|
||||
|
||||
pub async fn reg_finish<K: CredKind>(
|
||||
&mut self,
|
||||
&self,
|
||||
session_id: &Uuid,
|
||||
password_file: PasswordFile,
|
||||
) -> Result<(), String> {
|
||||
@@ -51,7 +51,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
.map_err(|e| format!("get reg session: {e}"))?;
|
||||
K::prereq_for_register(&self.opaque_db, sess.identifier.as_slice()).await
|
||||
.map_err(|e| format!("registration prereq failed: {e:?}"))?;
|
||||
K::set_password_file(&mut self.opaque_db, sess.identifier.as_slice(), password_file).await
|
||||
K::set_password_file(&self.opaque_db, sess.identifier.as_slice(), password_file).await
|
||||
.map_err(|e| format!("repo write: {e:?}"))?;
|
||||
self.opaque_sess
|
||||
.clear_reg_session(session_id).await
|
||||
@@ -59,7 +59,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
}
|
||||
|
||||
pub async fn login_start<K: CredKind>(
|
||||
&mut self,
|
||||
&self,
|
||||
identifier: &[u8],
|
||||
request: CredentialRequest<NKodeCipherSuite>,
|
||||
) -> Result<OpaqueLoginSession, String> {
|
||||
@@ -85,7 +85,7 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
}
|
||||
|
||||
pub async fn login_finish(
|
||||
&mut self,
|
||||
&self,
|
||||
session_id: &Uuid,
|
||||
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||
) -> Result<LoggedInSession, String> {
|
||||
@@ -108,39 +108,39 @@ impl<R: OpaqueDatabaseRepo, S: OpaqueSessionRepo, U: UserRepo> ServerApp<R, S, U
|
||||
}
|
||||
|
||||
pub async fn key_login_finish(
|
||||
&mut self,
|
||||
&self,
|
||||
session_id: &Uuid,
|
||||
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||
) -> Result<KeyLoggedInSession, String> {
|
||||
let session = KeyLoggedInSession(self.login_finish(session_id, finalize).await?);
|
||||
self.user_db.set_key_session(session.clone())?;
|
||||
self.user_db.set_key_session(session.clone()).await?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub async fn code_login_finish(
|
||||
&mut self,
|
||||
&self,
|
||||
session_id: &Uuid,
|
||||
finalize: CredentialFinalization<NKodeCipherSuite>,
|
||||
) -> Result<CodeLoggedInSession, String> {
|
||||
let session = CodeLoggedInSession(self.login_finish(session_id, finalize).await?);
|
||||
self.user_db.set_code_session(session.clone())?;
|
||||
self.user_db.set_code_session(session.clone()).await?;
|
||||
Ok(session)
|
||||
}
|
||||
|
||||
pub async fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||
self.user_db.get_key_session(session_id)
|
||||
pub async fn get_key_session(&self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||
self.user_db.get_key_session(session_id).await
|
||||
}
|
||||
|
||||
pub async fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||
self.user_db.get_code_session(session_id)
|
||||
pub async fn get_code_session(&self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||
self.user_db.get_code_session(session_id).await
|
||||
}
|
||||
|
||||
pub async fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String> {
|
||||
self.user_db.get_code_login_data(email)
|
||||
pub async fn get_code_login_data(&self, email: &Email) -> Result<CodeLoginData, String> {
|
||||
self.user_db.get_code_login_data(email).await
|
||||
}
|
||||
|
||||
pub async fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||
self.user_db.set_code_login_data(email, data)
|
||||
pub async fn set_code_login_data(&self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||
self.user_db.set_code_login_data(email, data).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ impl CredKind for Key {
|
||||
async fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
||||
repo.get_key_passcode_file(id).await
|
||||
}
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||
repo.new_key(id, pf).await
|
||||
}
|
||||
}
|
||||
@@ -171,7 +171,7 @@ impl CredKind for Code {
|
||||
async fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError> {
|
||||
repo.get_code_passcode_file(id).await
|
||||
}
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError> {
|
||||
repo.new_code(id, pf).await
|
||||
}
|
||||
async fn prereq_for_register<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<(), AuthRepoError> {
|
||||
|
||||
@@ -19,7 +19,7 @@ pub struct LoginCache {
|
||||
pub trait CredKind {
|
||||
async fn has<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> bool;
|
||||
async fn get_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8]) -> Result<PasswordFile, AuthRepoError>;
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &mut R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError>;
|
||||
async fn set_password_file<R: OpaqueDatabaseRepo>(repo: &R, id: &[u8], pf: PasswordFile) -> Result<(), AuthRepoError>;
|
||||
async fn prereq_for_register<R: OpaqueDatabaseRepo>(_repo: &R, _id: &[u8]) -> Result<(), AuthRepoError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
use async_trait::async_trait;
|
||||
use std::marker::PhantomData;
|
||||
use tokio::sync::Mutex;
|
||||
use std::sync::Arc;
|
||||
use uuid::Uuid;
|
||||
use opaque_ke::{CredentialFinalization, CredentialRequest, RegistrationRequest};
|
||||
use crate::shared::models::opaque::{NKodeCipherSuite, NKodeServerSetup, OpaqueLoginSession, OpaqueRegisterSession, PasswordFile};
|
||||
@@ -14,23 +12,20 @@ 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;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct InMemoryServer<K: CredKind> {
|
||||
auth_db: Arc<Mutex<ServerApp<InMemoryOpaqueDB, InMemoryOpaqueSession, InMemoryUserDB>>>,
|
||||
auth_db: ServerApp<InMemoryOpaqueDB, InMemoryOpaqueSession, InMemoryUserDB>,
|
||||
_kind: PhantomData<K>,
|
||||
}
|
||||
|
||||
impl<K: CredKind> InMemoryServer<K> {
|
||||
pub fn new(server_setup: NKodeServerSetup) -> Self {
|
||||
Self {
|
||||
auth_db: Arc::new(Mutex::new(
|
||||
ServerApp::new(
|
||||
server_setup,
|
||||
InMemoryOpaqueDB::new(),
|
||||
InMemoryOpaqueSession::new(),
|
||||
InMemoryUserDB::new()
|
||||
)
|
||||
)),
|
||||
auth_db: ServerApp::new(
|
||||
server_setup,
|
||||
InMemoryOpaqueDB::new(),
|
||||
InMemoryOpaqueSession::new(),
|
||||
InMemoryUserDB::new()
|
||||
),
|
||||
_kind: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -51,7 +46,7 @@ where
|
||||
) -> Result<OpaqueRegisterSession, ClientAuthError> {
|
||||
// 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.
|
||||
self.auth_db.lock().await
|
||||
self.auth_db
|
||||
.reg_start::<K>(identifier, message.clone())
|
||||
.await
|
||||
.map_err(|e| ClientAuthError::Transport(e))
|
||||
@@ -62,8 +57,7 @@ where
|
||||
session_id: &Uuid,
|
||||
password_file: PasswordFile,
|
||||
) -> Result<(), ClientAuthError> {
|
||||
self.auth_db.lock().await
|
||||
.reg_finish::<K>(session_id, password_file)
|
||||
self.auth_db.reg_finish::<K>(session_id, password_file)
|
||||
.await
|
||||
.map_err(|e| ClientAuthError::Transport(e))
|
||||
}
|
||||
@@ -79,7 +73,7 @@ where
|
||||
identifier: &[u8],
|
||||
request: &CredentialRequest<NKodeCipherSuite>,
|
||||
) -> Result<OpaqueLoginSession, ClientAuthError> {
|
||||
self.auth_db.lock().await
|
||||
self.auth_db
|
||||
.login_start::<K>(identifier, request.clone())
|
||||
.await
|
||||
.map_err(|e| ClientAuthError::Transport(e))
|
||||
@@ -91,7 +85,7 @@ where
|
||||
message: &CredentialFinalization<NKodeCipherSuite>,
|
||||
) -> Result<LoggedInSession, ClientAuthError> {
|
||||
Ok(self
|
||||
.auth_db.lock().await
|
||||
.auth_db
|
||||
.login_finish(session_id, message.clone())
|
||||
.await
|
||||
.map_err(|e| ClientAuthError::Transport(e))?
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use async_trait::async_trait;
|
||||
use tokio::sync::Mutex;
|
||||
use uuid::Uuid;
|
||||
use crate::server::repository::user_repo::UserRepo;
|
||||
use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession};
|
||||
use crate::shared::models::email::Email;
|
||||
|
||||
pub struct InMemoryUserDB {
|
||||
key_session: HashMap<Uuid, KeyLoggedInSession>,
|
||||
code_session: HashMap<Uuid, CodeLoggedInSession>,
|
||||
code_data: HashMap<Email, CodeLoginData>,
|
||||
key_session: Arc<Mutex<HashMap<Uuid, KeyLoggedInSession>>>,
|
||||
code_session: Arc<Mutex<HashMap<Uuid, CodeLoggedInSession>>>,
|
||||
code_data: Arc<Mutex<HashMap<Email, CodeLoginData>>>,
|
||||
}
|
||||
|
||||
impl InMemoryUserDB {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
key_session: HashMap::new(),
|
||||
code_session: HashMap::new(),
|
||||
code_data: HashMap::new(),
|
||||
key_session: Arc::new(Mutex::new(HashMap::new())),
|
||||
code_session: Arc::new(Mutex::new(HashMap::new())),
|
||||
code_data: Arc::new(Mutex::new(HashMap::new())),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,40 +29,39 @@ impl Default for InMemoryUserDB {
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl UserRepo for InMemoryUserDB {
|
||||
fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||
self.key_session
|
||||
async fn get_key_session(&self, session_id: &Uuid) -> Result<KeyLoggedInSession, String> {
|
||||
self.key_session.lock().await
|
||||
.get(&session_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("key session not found for session_id={}", session_id))
|
||||
}
|
||||
|
||||
fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||
self.code_session
|
||||
async fn get_code_session(&self, session_id: &Uuid) -> Result<CodeLoggedInSession, String> {
|
||||
self.code_session.lock().await
|
||||
.get(&session_id)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("code session not found for session_id={}", session_id))
|
||||
}
|
||||
|
||||
fn set_key_session(&mut self, session: KeyLoggedInSession) -> Result<(), String> {
|
||||
// Assumes KeyLoggedInSession has a session_id: Uuid field (common pattern)
|
||||
self.key_session.insert(session.0.session_id, session);
|
||||
async fn set_key_session(&self, session: KeyLoggedInSession) -> Result<(), String> {
|
||||
self.key_session.lock().await.insert(session.0.session_id, session);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_code_session(&mut self, session: CodeLoggedInSession) -> Result<(), String> {
|
||||
// Assumes CodeLoggedInSession has a session_id: Uuid field (common pattern)
|
||||
self.code_session.insert(session.0.session_id, session);
|
||||
async fn set_code_session(&self, session: CodeLoggedInSession) -> Result<(), String> {
|
||||
self.code_session.lock().await.insert(session.0.session_id, session);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||
self.code_data.insert(email, data);
|
||||
async fn set_code_login_data(&self, email: Email, data: CodeLoginData) -> Result<(), String> {
|
||||
self.code_data.lock().await.insert(email, data);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String> {
|
||||
self.code_data
|
||||
async fn get_code_login_data(&self, email: &Email) -> Result<CodeLoginData, String> {
|
||||
self.code_data.lock().await
|
||||
.get(email)
|
||||
.cloned()
|
||||
.ok_or_else(|| "code login data not found for email".to_string())
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use async_trait::async_trait;
|
||||
use uuid::Uuid;
|
||||
use crate::shared::models::app::{CodeLoggedInSession, CodeLoginData, KeyLoggedInSession};
|
||||
use crate::shared::models::email::Email;
|
||||
|
||||
#[async_trait]
|
||||
pub trait UserRepo {
|
||||
fn get_key_session(&mut self, session_id: &Uuid) -> Result<KeyLoggedInSession, String>;
|
||||
fn get_code_session(&mut self, session_id: &Uuid) -> Result<CodeLoggedInSession, String>;
|
||||
async fn get_key_session(&self, session_id: &Uuid) -> Result<KeyLoggedInSession, String>;
|
||||
async fn get_code_session(&self, session_id: &Uuid) -> Result<CodeLoggedInSession, String>;
|
||||
|
||||
fn set_key_session(&mut self, session: KeyLoggedInSession) -> Result<(), String>;
|
||||
fn set_code_session(&mut self, session: CodeLoggedInSession) -> Result<(), String>;
|
||||
async fn set_key_session(&self, session: KeyLoggedInSession) -> Result<(), String>;
|
||||
async fn set_code_session(&self, session: CodeLoggedInSession) -> Result<(), String>;
|
||||
|
||||
fn set_code_login_data(&mut self, email: Email, data: CodeLoginData) -> Result<(), String>;
|
||||
fn get_code_login_data(&mut self, email: &Email) -> Result<CodeLoginData, String>;
|
||||
async fn set_code_login_data(&self, email: Email, data: CodeLoginData) -> Result<(), String>;
|
||||
async fn get_code_login_data(&self, email: &Email) -> Result<CodeLoginData, String>;
|
||||
}
|
||||
@@ -8,7 +8,6 @@ use uuid::Uuid;
|
||||
use crate::shared::models::email::Email;
|
||||
use crate::shared::models::opaque::{OpaqueSessionKey, UserSecretKey};
|
||||
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LoggedInSession {
|
||||
pub(crate) session_id: Uuid,
|
||||
@@ -73,4 +72,3 @@ pub trait AuthAPI {
|
||||
async fn is_code_registered(&self, key_login_session: &KeyLoggedInSession) -> Result<bool, String>;
|
||||
async fn get_policy(&self) -> Result<NKodePolicy, String>;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use std::fmt;
|
||||
use email_address::{EmailAddress, Options};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
@@ -18,11 +17,8 @@ impl Email {
|
||||
if s.is_empty() {
|
||||
return Err(EmailError::Empty);
|
||||
}
|
||||
|
||||
// Strict "address only" validation (no "Name <a@b.com>")
|
||||
EmailAddress::parse_with_options(s, Options::default().without_display_text())
|
||||
.map_err(|_| EmailError::InvalidFormat)?;
|
||||
|
||||
Ok(Self(s.to_owned()))
|
||||
}
|
||||
|
||||
@@ -48,63 +44,8 @@ impl Email {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- std traits ---- */
|
||||
|
||||
impl fmt::Display for Email {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(self.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Email {
|
||||
type Err = EmailError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Email::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for Email {
|
||||
type Error = EmailError;
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Email::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Email {
|
||||
type Error = EmailError;
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Email::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for Email {
|
||||
type Error = EmailError;
|
||||
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||
Email::from_bytes(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Vec<u8>> for Email {
|
||||
type Error = EmailError;
|
||||
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
|
||||
Email::from_bytes(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Email {
|
||||
fn as_ref(&self) -> &str {
|
||||
self.as_str()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for Email {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Email> for Vec<u8> {
|
||||
fn from(value: Email) -> Self {
|
||||
value.into_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,13 +8,14 @@ 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.clone());
|
||||
let auth_reg = OpaqueAuthRegister::new(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)
|
||||
.await
|
||||
.expect("login should succeed");
|
||||
// assert!(!session_key.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
Reference in New Issue
Block a user