Some checks failed
Build nomnom / Build-NomNom (push) Failing after 3m59s
132 lines
4.2 KiB
Rust
132 lines
4.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use url::Url;
|
|
use std::ops::DerefMut;
|
|
use std::sync::Arc;
|
|
use std::collections::HashMap;
|
|
|
|
use anyhow::Result;
|
|
use deadpool_postgres::{Manager, ManagerConfig, Pool, RecyclingMethod};
|
|
use handlebars::Handlebars;
|
|
use tokio::sync::RwLock;
|
|
use tokio_postgres::NoTls;
|
|
use webauthn_rs::prelude::{Uuid, PasskeyRegistration, Passkey};
|
|
use webauthn_rs::{Webauthn, WebauthnBuilder};
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
pub struct Configuration {
|
|
pub url: String,
|
|
pub db_host: Option<String>,
|
|
pub db_port: Option<u16>,
|
|
pub db_name: String
|
|
}
|
|
|
|
pub type DbField<T> = Arc<RwLock<T>>;
|
|
|
|
#[derive(Clone)]
|
|
pub struct Db {
|
|
|
|
pub user_keys: DbField<HashMap<Uuid, Passkey>>,
|
|
pub user_uuid_object: DbField<HashMap<Uuid, User>>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct TempSession {
|
|
pub user_registrations: Arc<RwLock<HashMap<Uuid,PendingRegistration>>>
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct PendingRegistration {
|
|
pub user: User,
|
|
pub registration: PasskeyRegistration
|
|
}
|
|
|
|
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
|
pub struct User {
|
|
pub user_name: String,
|
|
pub display_name: String,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct AppState<'a>{
|
|
pub webauthn: Arc<Webauthn>,
|
|
pub db: Pool,
|
|
pub hbs: Arc<Handlebars<'a>>,
|
|
pub session: TempSession
|
|
}
|
|
|
|
mod embedded {
|
|
use refinery::embed_migrations;
|
|
embed_migrations!("src/sql/01-init.sql");
|
|
}
|
|
|
|
impl AppState<'_> {
|
|
pub fn new(args: Configuration) -> Self {
|
|
let rp = "localhost";
|
|
let rp_origin = Url::parse("http://localhost:8000").expect("Invalid URL");
|
|
let builder = WebauthnBuilder::new(rp, &rp_origin).expect("Invalid configuration");
|
|
let builder = builder.rp_name("LocalHost");
|
|
let webauthn = Arc::new(builder.build().expect("Invalid configuration"));
|
|
let db: Db = Db {
|
|
user_keys: Arc::new(RwLock::new(HashMap::new())),
|
|
user_uuid_object: Arc::new(RwLock::new(HashMap::new()))
|
|
};
|
|
let hbs = Arc::new(crate::templates::new().unwrap());
|
|
let session: TempSession = TempSession {
|
|
user_registrations: Arc::new(RwLock::new(HashMap::new()))
|
|
};
|
|
let mut pg_config = tokio_postgres::Config::new();
|
|
pg_config.host_path("/run/postgresql");
|
|
pg_config.host_path("/tmp");
|
|
pg_config.user("deadpool");
|
|
pg_config.dbname("deadpool");
|
|
let mgr_config = ManagerConfig {
|
|
recycling_method: RecyclingMethod::Fast
|
|
};
|
|
let mgr = Manager::from_config(pg_config, NoTls, mgr_config);
|
|
let db = Pool::builder(mgr).max_size(16).build().unwrap();
|
|
|
|
AppState {
|
|
webauthn,
|
|
db,
|
|
hbs,
|
|
session
|
|
}
|
|
}
|
|
|
|
pub async fn run_migrations(&mut self) -> Result<()> {
|
|
let mut conn = self.db.get().await?;
|
|
let client = conn.deref_mut().deref_mut();
|
|
embedded::migrations::runner().run_async(client).await?;
|
|
Ok(())
|
|
}
|
|
|
|
|
|
pub async fn save_user(&self, user: &User) -> Result<()> {
|
|
let mut conn = self.db.get().await?;
|
|
let client = conn.deref_mut();
|
|
let stmt = client.prepare_cached("INSERT INTO Users (user_name, display_name) VALUES ($1, $2, $3)").await?;
|
|
client.query(&stmt, &[&user.user_name, &user.display_name]);
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn save_user_key(&self, uuid: &Uuid, passkey: &Passkey) -> Result<()> {
|
|
let passkey_json: String = serde_json::to_string(&passkey)?;
|
|
let mut conn = self.db.get().await?;
|
|
let client = conn.deref_mut();
|
|
let stmt = client.prepare_cached("INSERT INTO Keys (key_dump, user_id) VALUES ($1,$2)").await?;
|
|
client.query(&stmt, &[&passkey_json, &uuid.to_string()]).await?;
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn get_user_keys(&self, user_uuid: &Uuid) -> Result<Vec<Result<Passkey, serde_json::Error>>> {
|
|
let mut conn = self.db.get().await?;
|
|
let client = conn.deref_mut();
|
|
let stmt = client.prepare_cached("SELECT key_dump FROM Keys WHERE user_id = $1").await?;
|
|
let res = client.query(&stmt, &[&user_uuid.to_string()]).await?;
|
|
let res2 = res.iter().map(|row| {
|
|
serde_json::from_str(row.get(0))
|
|
}).collect();
|
|
Ok(res2)
|
|
}
|
|
}
|