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())? {
|
||||
Err(super::UserManagerError::UsernameNotUnique)
|
||||
} else {
|
||||
let cert_hash = UserManager::hash_certificate(&self.certificate);
|
||||
|
||||
let newser = RegisteredUser::new(
|
||||
username.clone(),
|
||||
let mut newser = RegisteredUser::new(
|
||||
username,
|
||||
Some(self.certificate.clone()),
|
||||
self.manager,
|
||||
PartialUser {
|
||||
data: UserData::default(),
|
||||
certificates: vec![cert_hash],
|
||||
certificates: Vec::with_capacity(1),
|
||||
pass_hash: None,
|
||||
},
|
||||
);
|
||||
|
||||
let cert_info = CertificateData {
|
||||
certificate: self.certificate,
|
||||
owner_username: username,
|
||||
};
|
||||
|
||||
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
|
||||
// As a nice bonus, calling add_certificate with a user not yet in the
|
||||
// database creates the user and adds the certificate in a single transaction.
|
||||
// Because of this, we can delegate here ^^
|
||||
newser.add_certificate(self.certificate)?;
|
||||
|
||||
Ok(newser)
|
||||
}
|
||||
|
@ -158,8 +140,19 @@ impl NotSignedInUser {
|
|||
/// log in with either this certificate or any of the certificates they already had
|
||||
/// 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
|
||||
/// 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
|
||||
/// 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
|
||||
/// deserialization
|
||||
pub fn attach<UserData: Serialize + DeserializeOwned>(
|
||||
username: impl AsRef<[u8]>,
|
||||
password: impl AsRef<[u8]>,
|
||||
) -> Result<RegisteredUser<UserData>> {
|
||||
todo!()
|
||||
self,
|
||||
username: impl AsRef<str>,
|
||||
password: Option<impl AsRef<[u8]>>,
|
||||
) -> 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
|
||||
///
|
||||
/// 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 {
|
||||
self.active_certificate = Some(cert);
|
||||
self
|
||||
|
@ -303,6 +313,44 @@ impl<UserData: Serialize + DeserializeOwned> RegisteredUser<UserData> {
|
|||
self.has_changed = false;
|
||||
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> {
|
||||
|
|
Loading…
Reference in a new issue