Added the add_certificate
and attach
methods
This commit is contained in:
parent
cdc3921a83
commit
766c472cbf
|
@ -113,39 +113,21 @@ impl NotSignedInUser {
|
||||||
if self.manager.users.contains_key(username.as_str())? {
|
if self.manager.users.contains_key(username.as_str())? {
|
||||||
Err(super::UserManagerError::UsernameNotUnique)
|
Err(super::UserManagerError::UsernameNotUnique)
|
||||||
} else {
|
} else {
|
||||||
let cert_hash = UserManager::hash_certificate(&self.certificate);
|
let mut newser = RegisteredUser::new(
|
||||||
|
username,
|
||||||
let newser = RegisteredUser::new(
|
|
||||||
username.clone(),
|
|
||||||
Some(self.certificate.clone()),
|
Some(self.certificate.clone()),
|
||||||
self.manager,
|
self.manager,
|
||||||
PartialUser {
|
PartialUser {
|
||||||
data: UserData::default(),
|
data: UserData::default(),
|
||||||
certificates: vec![cert_hash],
|
certificates: Vec::with_capacity(1),
|
||||||
pass_hash: None,
|
pass_hash: None,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
let cert_info = CertificateData {
|
// As a nice bonus, calling add_certificate with a user not yet in the
|
||||||
certificate: self.certificate,
|
// database creates the user and adds the certificate in a single transaction.
|
||||||
owner_username: username,
|
// Because of this, we can delegate here ^^
|
||||||
};
|
newser.add_certificate(self.certificate)?;
|
||||||
|
|
||||||
let newser_serialized = bincode::serialize(&newser.inner)?;
|
|
||||||
let cert_info_serialized = bincode::serialize(&cert_info)?;
|
|
||||||
|
|
||||||
(&newser.manager.users, &newser.manager.certificates)
|
|
||||||
.transaction(|(tx_usr, tx_crt)| {
|
|
||||||
tx_usr.insert(
|
|
||||||
newser.username.as_str(),
|
|
||||||
newser_serialized.clone(),
|
|
||||||
)?;
|
|
||||||
tx_crt.insert(
|
|
||||||
cert_hash.to_le_bytes().as_ref(),
|
|
||||||
cert_info_serialized.clone(),
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
})?; //TODO
|
|
||||||
|
|
||||||
Ok(newser)
|
Ok(newser)
|
||||||
}
|
}
|
||||||
|
@ -158,8 +140,19 @@ impl NotSignedInUser {
|
||||||
/// log in with either this certificate or any of the certificates they already had
|
/// log in with either this certificate or any of the certificates they already had
|
||||||
/// registered.
|
/// registered.
|
||||||
///
|
///
|
||||||
|
/// This method can check the user's password to ensure that they match before
|
||||||
|
/// registering. If you want to skip this verification, perhaps because you've
|
||||||
|
/// already verified that this user owns this account, then you can pass [`None`] as
|
||||||
|
/// the password to skip the password check.
|
||||||
|
///
|
||||||
/// This method returns the new RegisteredUser instance representing the now-attached
|
/// This method returns the new RegisteredUser instance representing the now-attached
|
||||||
/// user.
|
/// user, or [`None`] if the username and password didn't match.
|
||||||
|
///
|
||||||
|
/// Because this method both performs a bcrypt verification and a database access, it
|
||||||
|
/// should be considered expensive.
|
||||||
|
///
|
||||||
|
/// If you already have a [`RegisteredUser`] that you would like to attach a
|
||||||
|
/// certificate to, consider using [`RegisteredUser::add_certificate()`]
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// This will error if the username and password are incorrect, or if the user has yet
|
/// This will error if the username and password are incorrect, or if the user has yet
|
||||||
|
@ -168,10 +161,23 @@ impl NotSignedInUser {
|
||||||
/// Additional errors might occur if an error occurs during database lookup and
|
/// Additional errors might occur if an error occurs during database lookup and
|
||||||
/// deserialization
|
/// deserialization
|
||||||
pub fn attach<UserData: Serialize + DeserializeOwned>(
|
pub fn attach<UserData: Serialize + DeserializeOwned>(
|
||||||
username: impl AsRef<[u8]>,
|
self,
|
||||||
password: impl AsRef<[u8]>,
|
username: impl AsRef<str>,
|
||||||
) -> Result<RegisteredUser<UserData>> {
|
password: Option<impl AsRef<[u8]>>,
|
||||||
todo!()
|
) -> Result<Option<RegisteredUser<UserData>>> {
|
||||||
|
if let Some(mut user) = self.manager.lookup_user(username)? {
|
||||||
|
// Perform password check, if caller wants
|
||||||
|
if let Some(password) = password {
|
||||||
|
if !user.check_password(password)? {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
user.add_certificate(self.certificate)?;
|
||||||
|
Ok(Some(user))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +213,10 @@ impl<UserData: Serialize + DeserializeOwned> RegisteredUser<UserData> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the active certificate
|
/// Update the active certificate
|
||||||
|
///
|
||||||
|
/// This is not to be confused with [`RegisteredUser::add_certificate`], which
|
||||||
|
/// performs the database operations needed to register a new certificate to a user.
|
||||||
|
/// This literally just marks the active certificate.
|
||||||
pub (crate) fn with_cert(mut self, cert: Certificate) -> Self {
|
pub (crate) fn with_cert(mut self, cert: Certificate) -> Self {
|
||||||
self.active_certificate = Some(cert);
|
self.active_certificate = Some(cert);
|
||||||
self
|
self
|
||||||
|
@ -303,6 +313,44 @@ impl<UserData: Serialize + DeserializeOwned> RegisteredUser<UserData> {
|
||||||
self.has_changed = false;
|
self.has_changed = false;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a new certificate to this user
|
||||||
|
///
|
||||||
|
/// This adds a new certificate to this user for use in logins. This requires a
|
||||||
|
/// couple database accesses, one in order to link the user to the certificate, and
|
||||||
|
/// one in order to link the certificate to the user.
|
||||||
|
///
|
||||||
|
/// If you have a [`NotSignedInUser`] and are looking for a way to link them to an
|
||||||
|
/// existing user, consider [`NotSignedInUser::attach()`], which contains facilities for
|
||||||
|
/// password checking and automatically performs the user lookup.
|
||||||
|
pub fn add_certificate(&mut self, certificate: Certificate) -> Result<()> {
|
||||||
|
let cert_hash = UserManager::hash_certificate(&certificate);
|
||||||
|
|
||||||
|
self.inner.certificates.push(cert_hash);
|
||||||
|
|
||||||
|
let cert_info = CertificateData {
|
||||||
|
certificate,
|
||||||
|
owner_username: self.username.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let inner_serialized = bincode::serialize(&self.inner)?;
|
||||||
|
let cert_info_serialized = bincode::serialize(&cert_info)?;
|
||||||
|
|
||||||
|
(&self.manager.users, &self.manager.certificates)
|
||||||
|
.transaction(|(tx_usr, tx_crt)| {
|
||||||
|
tx_usr.insert(
|
||||||
|
self.username.as_str(),
|
||||||
|
inner_serialized.clone(),
|
||||||
|
)?;
|
||||||
|
tx_crt.insert(
|
||||||
|
cert_hash.to_le_bytes().as_ref(),
|
||||||
|
cert_info_serialized.clone(),
|
||||||
|
)?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<UserData: Serialize + DeserializeOwned> std::ops::Drop for RegisteredUser<UserData> {
|
impl<UserData: Serialize + DeserializeOwned> std::ops::Drop for RegisteredUser<UserData> {
|
||||||
|
|
Loading…
Reference in a new issue