Return a full SignedInUser from lookup_user(), restrict access to PartialUser
Okay this is a much nicer API tbh. Why didn't I do this from the start? 'cause I'm bad at planning that's why. We got there eventually though!
This commit is contained in:
parent
1908d0a0d7
commit
2f1196228f
|
@ -73,13 +73,14 @@ impl UserManager {
|
||||||
/// recieved from the database is corrupt
|
/// recieved from the database is corrupt
|
||||||
pub fn lookup_user<UserData>(
|
pub fn lookup_user<UserData>(
|
||||||
&self,
|
&self,
|
||||||
username: impl AsRef<[u8]>
|
username: impl AsRef<str>
|
||||||
) -> Result<Option<PartialUser<UserData>>>
|
) -> Result<Option<SignedInUser<UserData>>>
|
||||||
where
|
where
|
||||||
UserData: Serialize + DeserializeOwned
|
UserData: Serialize + DeserializeOwned
|
||||||
{
|
{
|
||||||
if let Some(bytes) = self.users.get(username)? {
|
if let Some(bytes) = self.users.get(username.as_ref())? {
|
||||||
Ok(Some(bincode::deserialize_from(bytes.as_ref())?))
|
let inner: PartialUser<UserData> = bincode::deserialize_from(bytes.as_ref())?;
|
||||||
|
Ok(Some(SignedInUser::new(username.as_ref().to_owned(), None, self.clone(), inner)))
|
||||||
} else {
|
} else {
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
@ -105,12 +106,7 @@ impl UserManager {
|
||||||
if let Some(certificate_data) = self.lookup_certificate(cert_hash)? {
|
if let Some(certificate_data) = self.lookup_certificate(cert_hash)? {
|
||||||
let user_inner = self.lookup_user(&certificate_data.owner_username)?
|
let user_inner = self.lookup_user(&certificate_data.owner_username)?
|
||||||
.expect("Database corruption: Certificate data refers to non-existant user");
|
.expect("Database corruption: Certificate data refers to non-existant user");
|
||||||
Ok(User::SignedIn(SignedInUser::new(
|
Ok(User::SignedIn(user_inner.with_cert(certificate_data.certificate)))
|
||||||
certificate_data.owner_username,
|
|
||||||
certificate_data.certificate,
|
|
||||||
self.clone(),
|
|
||||||
user_inner,
|
|
||||||
)))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(User::NotSignedIn(NotSignedInUser {
|
Ok(User::NotSignedIn(NotSignedInUser {
|
||||||
certificate: certificate.clone(),
|
certificate: certificate.clone(),
|
||||||
|
|
|
@ -10,14 +10,9 @@
|
||||||
//! information, like the user's username and active certificate.
|
//! information, like the user's username and active certificate.
|
||||||
//!
|
//!
|
||||||
//! [`SignedInUser`] is particularly signifigant in that this is the struct used to modify
|
//! [`SignedInUser`] is particularly signifigant in that this is the struct used to modify
|
||||||
//! the data stored for the current user. This is accomplished through the
|
//! the data stored for almost all users. This is accomplished through the
|
||||||
//! [`as_mut()`](SignedInUser::as_mut) method. Changes made this way must be persisted
|
//! [`as_mut()`](SignedInUser::as_mut) method. Changes made this way must be persisted
|
||||||
//! using [`save()`](SignedInUser::save()) or by dropping the user.
|
//! using [`save()`](SignedInUser::save()) or by dropping the user.
|
||||||
//!
|
|
||||||
//! [`PartialUser`] is the main way of modifying data stored for users who aren't
|
|
||||||
//! currently connecting. These are mainly obtained through the
|
|
||||||
//! [`UserManager::lookup_user()`] method. Unlinke with [`SignedInUser`], these are not
|
|
||||||
//! committed on drop, and [`PartialUser::store()`] must be manually called
|
|
||||||
use rustls::Certificate;
|
use rustls::Certificate;
|
||||||
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
use serde::{Deserialize, Serialize, de::DeserializeOwned};
|
||||||
use sled::Transactional;
|
use sled::Transactional;
|
||||||
|
@ -47,7 +42,7 @@ lazy_static::lazy_static! {
|
||||||
/// In order to generate a full user obj, you need to perform a lookup with a specific
|
/// In order to generate a full user obj, you need to perform a lookup with a specific
|
||||||
/// certificate.
|
/// certificate.
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub struct PartialUser<UserData> {
|
pub (crate) struct PartialUser<UserData> {
|
||||||
pub data: UserData,
|
pub data: UserData,
|
||||||
pub certificates: Vec<u32>,
|
pub certificates: Vec<u32>,
|
||||||
pub pass_hash: Option<(Vec<u8>, [u8; 32])>,
|
pub pass_hash: Option<(Vec<u8>, [u8; 32])>,
|
||||||
|
@ -55,18 +50,11 @@ pub struct PartialUser<UserData> {
|
||||||
|
|
||||||
impl<UserData> PartialUser<UserData> {
|
impl<UserData> PartialUser<UserData> {
|
||||||
|
|
||||||
/// A list of certificate hashes registered to this user
|
|
||||||
///
|
|
||||||
/// Can be looked up using [`UserManager::lookup_certificate()`] to get full information
|
|
||||||
pub const fn certificates(&self) -> &Vec<u32> {
|
|
||||||
&self.certificates
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Write user data to the database
|
/// Write user data to the database
|
||||||
///
|
///
|
||||||
/// This MUST be called if the user data is modified using the AsMut trait, or else
|
/// This MUST be called if the user data is modified using the AsMut trait, or else
|
||||||
/// changes will not be written to the database
|
/// changes will not be written to the database
|
||||||
pub fn store(&self, tree: &sled::Tree, username: impl AsRef<[u8]>) -> Result<()>
|
fn store(&self, tree: &sled::Tree, username: impl AsRef<[u8]>) -> Result<()>
|
||||||
where
|
where
|
||||||
UserData: Serialize
|
UserData: Serialize
|
||||||
{
|
{
|
||||||
|
@ -78,23 +66,6 @@ impl<UserData> PartialUser<UserData> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UserData> AsRef<UserData> for PartialUser<UserData> {
|
|
||||||
/// Access any data the application has stored for the user.
|
|
||||||
fn as_ref(&self) -> &UserData {
|
|
||||||
&self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<UserData> AsMut<UserData> for PartialUser<UserData> {
|
|
||||||
/// Modify the data stored for a user
|
|
||||||
///
|
|
||||||
/// IMPORTANT: Changes will not be written to the database until
|
|
||||||
/// [`PartialUser::store()`] is called
|
|
||||||
fn as_mut(&mut self) -> &mut UserData {
|
|
||||||
&mut self.data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Any information about the connecting user
|
/// Any information about the connecting user
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum User<UserData: Serialize + DeserializeOwned> {
|
pub enum User<UserData: Serialize + DeserializeOwned> {
|
||||||
|
@ -146,7 +117,7 @@ impl NotSignedInUser {
|
||||||
|
|
||||||
let newser = SignedInUser::new(
|
let newser = SignedInUser::new(
|
||||||
username.clone(),
|
username.clone(),
|
||||||
self.certificate.clone(),
|
Some(self.certificate.clone()),
|
||||||
self.manager,
|
self.manager,
|
||||||
PartialUser {
|
PartialUser {
|
||||||
data: UserData::default(),
|
data: UserData::default(),
|
||||||
|
@ -210,7 +181,7 @@ impl NotSignedInUser {
|
||||||
/// For more information about the user lifecycle and sign-in stages, see [`User`]
|
/// For more information about the user lifecycle and sign-in stages, see [`User`]
|
||||||
pub struct SignedInUser<UserData: Serialize + DeserializeOwned> {
|
pub struct SignedInUser<UserData: Serialize + DeserializeOwned> {
|
||||||
username: String,
|
username: String,
|
||||||
active_certificate: Certificate,
|
active_certificate: Option<Certificate>,
|
||||||
manager: UserManager,
|
manager: UserManager,
|
||||||
inner: PartialUser<UserData>,
|
inner: PartialUser<UserData>,
|
||||||
/// Indicates that [`SignedInUser::as_mut()`] has been called, but [`SignedInUser::save()`] has not
|
/// Indicates that [`SignedInUser::as_mut()`] has been called, but [`SignedInUser::save()`] has not
|
||||||
|
@ -222,7 +193,7 @@ impl<UserData: Serialize + DeserializeOwned> SignedInUser<UserData> {
|
||||||
/// Create a new user from parts
|
/// Create a new user from parts
|
||||||
pub (crate) fn new(
|
pub (crate) fn new(
|
||||||
username: String,
|
username: String,
|
||||||
active_certificate: Certificate,
|
active_certificate: Option<Certificate>,
|
||||||
manager: UserManager,
|
manager: UserManager,
|
||||||
inner: PartialUser<UserData>
|
inner: PartialUser<UserData>
|
||||||
) -> Self {
|
) -> Self {
|
||||||
|
@ -235,9 +206,18 @@ impl<UserData: Serialize + DeserializeOwned> SignedInUser<UserData> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Update the active certificate
|
||||||
|
pub (crate) fn with_cert(mut self, cert: Certificate) -> Self {
|
||||||
|
self.active_certificate = Some(cert);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the [`Certificate`] that the user is currently using to connect.
|
/// Get the [`Certificate`] that the user is currently using to connect.
|
||||||
pub fn active_certificate(&self) -> &Certificate {
|
///
|
||||||
&self.active_certificate
|
/// If this user was retrieved by a [`UserManager::lookup_user()`], this will be
|
||||||
|
/// [`None`]. In all other cases, this will be [`Some`].
|
||||||
|
pub fn active_certificate(&self) -> Option<&Certificate> {
|
||||||
|
self.active_certificate.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produce a list of all [`Certificate`]s registered to this account
|
/// Produce a list of all [`Certificate`]s registered to this account
|
||||||
|
|
Loading…
Reference in New Issue