diff --git a/src/api/mod.rs b/src/api/mod.rs index 5b2ef75..e736ca5 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -6,9 +6,10 @@ use log::info; mod endpoints; pub async fn start(config: &Config, backend: Backend) -> Result<()> { + let data = web::Data::new(backend); let server = HttpServer::new(move || { App::new() - .app_data(web::Data::new(backend.clone())) + .app_data(data.clone()) .service(endpoints::account::register) .service(endpoints::account::auth) .service(endpoints::account::invite::new) diff --git a/src/backend/db_structures.rs b/src/backend/db_structures.rs index 764d029..40281c7 100644 --- a/src/backend/db_structures.rs +++ b/src/backend/db_structures.rs @@ -16,3 +16,15 @@ pub struct UsersRow { pub password: String, pub permissions: u16, } + +pub struct RelaysRow { + pub id: String, + pub secret: String, +} + +pub struct RelayIndexRow { + pub public_id: String, + pub public_key: [u8; 32], + pub auth: String, + pub name: String, +} diff --git a/src/backend/error.rs b/src/backend/error.rs index 5537804..0e71043 100644 --- a/src/backend/error.rs +++ b/src/backend/error.rs @@ -13,6 +13,9 @@ pub enum Error { #[error("Permission denied: {0}")] PermissionDenied(&'static str), + #[error("The given relay id cannot be mapped to a relay")] + RelayNotFound, + #[error("The given token is expired")] TokenExpired, @@ -37,6 +40,7 @@ impl Into for Error { Error::AuthenticationFailure => HttpResponse::Unauthorized().json(body), Error::InvalidToken => HttpResponse::Unauthorized().json(body), Error::PermissionDenied(_) => HttpResponse::Forbidden().json(body), + Error::RelayNotFound => HttpResponse::NotFound().json(body), Error::TokenExpired => HttpResponse::Gone().json(body), Error::UserNotFound => HttpResponse::NotFound().json(body), } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index ed1ecbd..99e872f 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -5,14 +5,17 @@ mod relay; mod tokens; mod user; -use crate::config::Config; +use crate::{backend::relay::Relay, config::Config}; use anyhow::Result; use log::info; use sqlx::MySqlPool; +use std::collections::HashMap; +use uuid::Uuid; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Backend { pub pool: MySqlPool, + pub relays: HashMap, } impl Backend { @@ -59,6 +62,9 @@ impl Backend { info!("Backend initialized"); - Ok(Self { pool }) + Ok(Self { + pool, + relays: HashMap::new(), + }) } } diff --git a/src/backend/relay.rs b/src/backend/relay.rs index 4fb02b6..9ec4545 100644 --- a/src/backend/relay.rs +++ b/src/backend/relay.rs @@ -1,11 +1,37 @@ -use crate::backend::{error::Error, user::IntoUser, Backend}; +use crate::backend::{ + db_structures::{RelayIndexRow, RelaysRow}, + error::Error, + user::IntoUser, + Backend, +}; +use anyhow::{bail, Result}; use argon2::{ password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, Argon2, }; use rand::distributions::DistString; +use std::collections::{HashMap, VecDeque}; use uuid::Uuid; +#[derive(Debug)] +struct EncryptedMessage { + sender: Uuid, + body: Vec, +} + +#[derive(Debug)] +struct UserIndex { + public_key: [u8; 32], + name: String, + messages: VecDeque, +} + +#[derive(Debug)] +pub struct Relay { + user_index: HashMap, + user_map: HashMap, +} + impl Backend { /// Creates the structures for a new relay pub async fn create_relay( @@ -38,7 +64,7 @@ impl Backend { sqlx::query(&format!( "CREATE TABLE RelayIndex_{} ( public_id UUID NOT NULL PRIMARY KEY, - public_key BLOB(4096) NOT NULL, + public_key BINARY(32) NOT NULL, auth VARCHAR(128) NOT NULL, name VARCHAR(32) );", @@ -49,4 +75,36 @@ impl Backend { Ok(Ok((relay_id, secret))) } + + pub async fn get_relay(&mut self, relay_id: Uuid) -> Result> { + // can't use early return pattern, because of the borrow checker :/ + if self.relays.get(&relay_id).is_none() { + match sqlx::query_as!( + RelaysRow, + r#"SELECT * FROM Relays WHERE id = ? LIMIT 1;"#, + relay_id.as_bytes().as_slice() + ) + .fetch_one(&self.pool) + .await + { + Err(sqlx::Error::RowNotFound) => return Ok(Err(Error::RelayNotFound)), + Err(e) => return Err(e.into()), + Ok(_) => { + // the hashmaps will be filled, as soon, as clients subscribe to the relay + let relay = Relay { + user_index: HashMap::new(), + user_map: HashMap::new(), + }; + + self.relays.insert(relay_id, relay); + } + } + } + + if let Some(relay) = self.relays.get(&relay_id) { + Ok(Ok(relay)) + } else { + bail!("!!! This should never happen !!! relay not found in runtime manager, even tho it was there before.") + } + } }