diff --git a/src/api/v1/login.rs b/src/api/v1/auth/login.rs similarity index 100% rename from src/api/v1/login.rs rename to src/api/v1/auth/login.rs diff --git a/src/api/v1/auth/mod.rs b/src/api/v1/auth/mod.rs new file mode 100644 index 0000000..d514206 --- /dev/null +++ b/src/api/v1/auth/mod.rs @@ -0,0 +1,12 @@ +use actix_web::{Scope, web}; + +mod register; +mod login; +mod refresh; + +pub fn web() -> Scope { + web::scope("/auth") + .service(register::res) + .service(login::res) + .service(refresh::res) +} diff --git a/src/api/v1/auth/refresh.rs b/src/api/v1/auth/refresh.rs new file mode 100644 index 0000000..a04f454 --- /dev/null +++ b/src/api/v1/auth/refresh.rs @@ -0,0 +1,49 @@ +use std::time::{SystemTime, UNIX_EPOCH}; +use actix_web::{error, post, web, Error, HttpResponse}; +use serde::{Deserialize, Serialize}; +use futures::StreamExt; + +use crate::Data; + +#[derive(Deserialize)] +struct RefreshRequest { + refresh_token: String, +} + +#[derive(Serialize)] +struct Response { + refresh_token: Option, + access_token: String, + expires_in: u64, +} + +const MAX_SIZE: usize = 262_144; + +#[post("/refresh")] +pub async fn res(mut payload: web::Payload, data: web::Data) -> Result { + let mut body = web::BytesMut::new(); + while let Some(chunk) = payload.next().await { + let chunk = chunk?; + // limit max size of in-memory payload + if (body.len() + chunk.len()) > MAX_SIZE { + return Err(error::ErrorBadRequest("overflow")); + } + body.extend_from_slice(&chunk); + } + + let refresh_request = serde_json::from_slice::(&body)?; + + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64; + + let row: (String, i64) = sqlx::query_as("SELECT CAST(uuid as VARCHAR), created FROM refresh_tokens WHERE token = $1") + .bind(refresh_request.refresh_token) + .fetch_one(&data.pool) + .await + .unwrap(); + + let (uuid, created) = row; + + println!("{}, {}", uuid, created); + + Ok(HttpResponse::InternalServerError().finish()) +} diff --git a/src/api/v1/register.rs b/src/api/v1/auth/register.rs similarity index 77% rename from src/api/v1/register.rs rename to src/api/v1/auth/register.rs index ea95ce9..9e8d2fe 100644 --- a/src/api/v1/register.rs +++ b/src/api/v1/auth/register.rs @@ -1,3 +1,5 @@ +use std::time::{SystemTime, UNIX_EPOCH}; + use actix_web::{error, post, web, Error, HttpResponse}; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -49,8 +51,6 @@ impl Default for ResponseError { #[derive(Serialize)] struct Response { access_token: String, - user_id: String, - expires_in: u64, refresh_token: String, } @@ -110,7 +110,7 @@ pub async fn res(mut payload: web::Payload, data: web::Data) -> Result) -> Result { + let refresh_token = todo!(); + let access_token = todo!(); + + let current_time = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64; + + if let Err(error) = sqlx::query(&format!("INSERT INTO refresh_tokens (token, uuid, created) VALUES ($1, '{}', $2 )", uuid)) + .bind(refresh_token) + .bind(current_time) + .execute(&data.pool) + .await { + eprintln!("{}", error); + return Ok(HttpResponse::InternalServerError().finish()) + } + + if let Err(error) = sqlx::query(&format!("INSERT INTO refresh_tokens (token, refresh_token, uuid, created) VALUES ($1, $2, '{}', $3 )", uuid)) + .bind(access_token) + .bind(refresh_token) + .bind(current_time) + .execute(&data.pool) + .await { + eprintln!("{}", error); + return Ok(HttpResponse::InternalServerError().finish()) + } + HttpResponse::Ok().json( Response { - access_token: "bogus".to_string(), - user_id: "bogus".to_string(), - expires_in: 1, - refresh_token: "bogus".to_string(), + access_token, + refresh_token, } ) }, diff --git a/src/api/v1/mod.rs b/src/api/v1/mod.rs index 223008d..368b918 100644 --- a/src/api/v1/mod.rs +++ b/src/api/v1/mod.rs @@ -1,12 +1,10 @@ use actix_web::{Scope, web}; mod stats; -mod register; -mod login; +mod auth; pub fn web() -> Scope { web::scope("/v1") .service(stats::res) - .service(register::res) - .service(login::res) + .service(auth::web()) } diff --git a/src/main.rs b/src/main.rs index deb4c85..55159f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -44,7 +44,7 @@ async fn main() -> Result<(), Error> { CREATE TABLE IF NOT EXISTS users ( uuid uuid PRIMARY KEY UNIQUE NOT NULL, username varchar(32) UNIQUE NOT NULL, - display_name varchar(64), + display_name varchar(64) DEFAULT NULL, password varchar(512) NOT NULL, email varchar(100) UNIQUE NOT NULL, email_verified boolean NOT NULL DEFAULT FALSE @@ -52,6 +52,17 @@ async fn main() -> Result<(), Error> { CREATE TABLE IF NOT EXISTS instance_permissions ( uuid uuid REFERENCES users(uuid), administrator boolean NOT NULL DEFAULT FALSE + ); + CREATE TABLE IF NOT EXISTS refresh_tokens ( + token varchar(64) PRIMARY KEY UNIQUE NOT NULL, + uuid uuid REFERENCES users(uuid), + created int8 NOT NULL + ); + CREATE TABLE IF NOT EXISTS access_tokens ( + token varchar(32) PRIMARY KEY UNIQUE NOT NULL, + refresh_token varchar(64) UNIQUE REFERENCES refresh_tokens(token), + uuid uuid REFERENCES users(uuid), + created int8 NOT NULL ) "#) .execute(&pool)