Félix Baylac Jacqué
62535ae5cf
All checks were successful
Build nomnom / Build-NomNom (push) Successful in 3m32s
128 lines
4.8 KiB
Rust
128 lines
4.8 KiB
Rust
use super::{UserUuid, RegistrationUuid, User, Key};
|
|
use anyhow::Result;
|
|
use deadpool_postgres::Pool;
|
|
use serde_json::Value;
|
|
use uuid::Uuid;
|
|
use webauthn_rs::prelude::AuthenticationResult;
|
|
|
|
/**
|
|
Generate a new registration uuid for the given `UserUuid` and
|
|
saves it to the DB.
|
|
*/
|
|
pub async fn generate_registration_uuid(db: &Pool, user_id: &UserUuid) -> Result<RegistrationUuid> {
|
|
let registration_uuid = Uuid::new_v4();
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("INSERT INTO PendingRegistrations (id, user_id) VALUES ($1, $2)").await?;
|
|
client.query(&stmt, &[®istration_uuid, &user_id.0]).await?;
|
|
Ok(RegistrationUuid(registration_uuid))
|
|
}
|
|
|
|
/**
|
|
Retrieves the registred `User` attached to the `RegistrationUuid`.
|
|
|
|
Returns `Some` `User` if it can find it, `None` if the `RegistrationUuid`
|
|
doesn't exist in the registration table.
|
|
*/
|
|
pub async fn retrieve_registration_user(db: &Pool, registration_id: &RegistrationUuid) -> Result<Option<User>> {
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("SELECT u.id, u.user_name FROM Users u INNER JOIN PendingRegistrations r ON r.user_id = u.id WHERE r.id=$1").await?;
|
|
let row = client.query_one(&stmt, &[®istration_id.0]).await?;
|
|
let usr = User {
|
|
uuid: row.get(0),
|
|
name: row.get(1),
|
|
};
|
|
Ok(Some(usr))
|
|
}
|
|
|
|
/**
|
|
Deletes the registration `Uuid` attached to the `UserUuid` passed in
|
|
parameter.
|
|
*/
|
|
pub async fn delete_registration_link(db: &Pool, user_id: &RegistrationUuid) -> Result<()> {
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("DELETE FROM PendingRegistrations WHERE id=$1").await?;
|
|
client.query(&stmt, &[&user_id.0]).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_user(db: &Pool, username: &str) -> Result<User> {
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("SELECT id, user_name FROM Users WHERE user_name = $1").await?;
|
|
let row = client.query_one(&stmt, &[&username]).await?;
|
|
Ok(User{ uuid: row.get(0), name: row.get(1) })
|
|
}
|
|
|
|
pub async fn save_user(db: &Pool, user: &User) -> Result<()> {
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("INSERT INTO Users (id, user_name) VALUES ($1, $2)").await?;
|
|
let _ = client.query(&stmt, &[&user.uuid.0, &user.name]).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn save_user_key(db: &Pool, user_id: &UserUuid, passkey: &Key) -> Result<()> {
|
|
let passkey_json: Value = serde_json::to_value(&passkey.key).unwrap();
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("INSERT INTO Keys (user_id, name, key_dump) VALUES ($1, $2, $3)").await?;
|
|
client.query(&stmt, &[&user_id.0, &passkey.name, &passkey_json]).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_user_keys(db: &Pool, user_id: &UserUuid) -> Result<Vec<Key>> {
|
|
let mut conn = db.get().await?;
|
|
let client = conn.as_mut();
|
|
let stmt = client.prepare_cached("SELECT name, key_dump FROM Keys WHERE user_id = $1").await?;
|
|
let res = client.query(&stmt, &[&user_id.0]).await?;
|
|
let res = res.iter().map(|row| {
|
|
let key: Value = row.get(1);
|
|
Key {
|
|
name: row.get(0),
|
|
// We can safely assume the JSON was valid, postgres
|
|
// would reject it if it wasn't. We can safely unwrap
|
|
// here.
|
|
key: serde_json::from_value(key).unwrap()
|
|
}}).collect();
|
|
Ok(res)
|
|
}
|
|
|
|
/**
|
|
Updates the keys for the user `UserUuid` according to the last
|
|
successful login `AuthenticationResult`.
|
|
*/
|
|
pub async fn update_user_keys(db: &Pool, user_id: &UserUuid, auth_res: AuthenticationResult) -> Result<()> {
|
|
let mut conn = db.get().await?;
|
|
let transaction = conn.as_mut().transaction().await?;
|
|
|
|
// Retrieve user keys
|
|
let stmt = transaction.prepare_cached("SELECT name, key_dump FROM Keys WHERE user_id = $1").await?;
|
|
let res = transaction.query(&stmt, &[&user_id.0]).await?;
|
|
let mut keys: Vec<Key> = res.iter().map(|row| {
|
|
let key = row.get(1);
|
|
Key { name: row.get(0), key: serde_json::from_value(key).unwrap() }
|
|
}).collect();
|
|
|
|
// Update keys
|
|
keys.iter_mut().for_each(
|
|
|key| {
|
|
key.key.update_credential(&auth_res);
|
|
}
|
|
);
|
|
|
|
// Delete current keys, save updated keys
|
|
let stmt = transaction.prepare_cached("DELETE FROM Keys WHERE user_id = $1").await?;
|
|
let _ = transaction.execute(&stmt, &[&user_id.0]).await?;
|
|
let stmt = transaction.prepare_cached("INSERT INTO Keys (user_id, name, key_dump) VALUES ($1,$2,$3)").await?;
|
|
for key in keys {
|
|
let passkey_val: Value = serde_json::to_value(&key.key).unwrap();
|
|
let _ = transaction.execute(&stmt, &[&user_id.0, &key.name, &passkey_val]).await?;
|
|
}
|
|
|
|
transaction.commit().await?;
|
|
Ok(())
|
|
}
|