diff --git a/docs/api.md b/docs/api.md index a03fe00..da8a270 100644 --- a/docs/api.md +++ b/docs/api.md @@ -12,6 +12,6 @@ - [X] `POST` /new - [ ] `GET` /list - /relay - - [ ] `POST` /create + - [X] `POST` /create - [ ] `POST` /join - [ ] `POST` /leave \ No newline at end of file diff --git a/src/api/endpoints/mod.rs b/src/api/endpoints/mod.rs index b0edc6c..3c22c61 100644 --- a/src/api/endpoints/mod.rs +++ b/src/api/endpoints/mod.rs @@ -1 +1,2 @@ pub mod account; +pub mod relay; diff --git a/src/api/endpoints/relay.rs b/src/api/endpoints/relay.rs new file mode 100644 index 0000000..ca6826c --- /dev/null +++ b/src/api/endpoints/relay.rs @@ -0,0 +1,28 @@ +use crate::backend::Backend; +use actix_web::{post, web, HttpResponse, Responder}; +use actix_web_httpauth::extractors::bearer::BearerAuth; +use log::error; +use serde::Serialize; + +#[derive(Debug, Serialize)] +struct CreateResponse { + id: String, + secret: String, +} + +#[post("/relay/create")] +pub async fn create(backend: web::Data, auth: BearerAuth) -> impl Responder { + match backend.create_relay(auth.token()).await { + Err(e) => { + error!("{e}"); + HttpResponse::InternalServerError().finish() + } + Ok(res) => match res { + Err(e) => e.into(), + Ok((uuid, secret)) => HttpResponse::Ok().json(CreateResponse { + id: uuid.to_string(), + secret, + }), + }, + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs index 8820788..18786c0 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -13,6 +13,7 @@ pub async fn start(config: &Config, backend: Backend) -> Result<()> { .service(endpoints::account::register) .service(endpoints::account::auth) .service(endpoints::account::invite::new) + .service(endpoints::relay::create) }) .bind((config.addr.as_str(), config.port))?; diff --git a/src/backend/mod.rs b/src/backend/mod.rs index 5ddf351..f715217 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -235,4 +235,31 @@ impl Backend { Ok(Ok(token)) } + + pub async fn create_relay(&self, user: impl IntoUser) -> Result> { + let _user = match user.into_user(&self).await? { + Ok(user) => user, + Err(e) => return Ok(Err(e)), + }; + + let relay_id = Uuid::new_v4(); + let secret = rand::distributions::Alphanumeric.sample_string(&mut OsRng, 48); + + let salt = SaltString::generate(&mut OsRng); + + let secret_hash = Argon2::default() + .hash_password(secret.as_bytes(), &salt) + .map_err(|_| anyhow::Error::msg("Failed to hash the relay secret"))? + .to_string(); + + sqlx::query!( + r#"INSERT INTO Relays VALUES (?, ?);"#, + relay_id.as_bytes().as_slice(), + secret_hash + ) + .execute(&self.pool) + .await?; + + Ok(Ok((relay_id, secret))) + } }