diff --git a/Cargo.toml b/Cargo.toml index f4cfea7..68f4c0b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,6 @@ lto = true codegen-units = 1 [dependencies] -actix-cors = "0.7.1" actix-web = "4.10" argon2 = { version = "0.5.3", features = ["std"] } clap = { version = "4.5.37", features = ["derive"] } @@ -22,7 +21,6 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" simple_logger = "5.0.0" sqlx = { version = "0.8", features = ["runtime-tokio", "tls-native-tls", "postgres"] } -redis = { version = "0.30", features= ["tokio-comp"] } tokio-tungstenite = { version = "0.26", features = ["native-tls", "url"] } toml = "0.8" url = { version = "2.5", features = ["serde"] } diff --git a/Dockerfile b/Dockerfile index d9a0389..7867f8b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,12 +18,6 @@ RUN useradd --create-home --home-dir /gorb gorb USER gorb -ENV DATABASE_USERNAME="gorb" \ -DATABASE_PASSWORD="gorb" \ -DATABASE="gorb" \ -DATABASE_HOST="database" \ -DATABASE_PORT="5432" \ -CACHE_DB_HOST="valkey" \ -CACHE_DB_PORT="6379" +ENV DATABASE_USERNAME="gorb" DATABASE_PASSWORD="gorb" DATABASE="gorb" DATABASE_HOST="localhost" DATABASE_PORT="5432" ENTRYPOINT ["/usr/bin/entrypoint.sh"] diff --git a/compose.dev.yml b/compose.dev.yml index d064beb..02f46a3 100644 --- a/compose.dev.yml +++ b/compose.dev.yml @@ -34,8 +34,3 @@ services: - POSTGRES_USER=gorb - POSTGRES_PASSWORD=gorb - POSTGRES_DB=gorb - valkey: - image: valkey/valkey - restart: always - networks: - - gorb diff --git a/compose.yml b/compose.yml index 84e6695..4544dea 100644 --- a/compose.yml +++ b/compose.yml @@ -32,8 +32,3 @@ services: - POSTGRES_USER=gorb - POSTGRES_PASSWORD=gorb - POSTGRES_DB=gorb - valkey: - image: valkey/valkey - restart: always - networks: - - gorb diff --git a/entrypoint.sh b/entrypoint.sh index a212f8e..63bfa84 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -16,10 +16,6 @@ password = "${DATABASE_PASSWORD}" database = "${DATABASE}" host = "${DATABASE_HOST}" port = ${DATABASE_PORT} - -[cache_database] -host = "${CACHE_DB_HOST}" -port = ${CACHE_DB_PORT} EOF fi diff --git a/src/api/v1/auth/login.rs b/src/api/v1/auth/login.rs index bc6af8c..0ea3d83 100644 --- a/src/api/v1/auth/login.rs +++ b/src/api/v1/auth/login.rs @@ -7,7 +7,7 @@ use log::error; use serde::Deserialize; use crate::{ - api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, utils::{generate_access_token, generate_refresh_token, refresh_token_cookie}, Data + api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, crypto::{generate_access_token, generate_refresh_token}, utils::refresh_token_cookie, Data }; use super::Response; diff --git a/src/api/v1/auth/mod.rs b/src/api/v1/auth/mod.rs index 25910de..bfd32af 100644 --- a/src/api/v1/auth/mod.rs +++ b/src/api/v1/auth/mod.rs @@ -25,7 +25,8 @@ static EMAIL_REGEX: LazyLock = LazyLock::new(|| { Regex::new(r"[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+(?:\.[-A-Za-z0-9!#$%&'*+/=?^_`{|}~]+)*@(?:[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?\.)+[A-Za-z0-9](?:[-A-Za-z0-9]*[A-Za-z0-9])?").unwrap() }); -static USERNAME_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"^[a-z0-9_.-]+$").unwrap()); +// FIXME: This regex doesnt seem to be working +static USERNAME_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"[a-zA-Z0-9.-_]").unwrap()); // Password is expected to be hashed using SHA3-384 static PASSWORD_REGEX: LazyLock = LazyLock::new(|| Regex::new(r"[0-9a-f]{96}").unwrap()); diff --git a/src/api/v1/auth/refresh.rs b/src/api/v1/auth/refresh.rs index 008420b..8c3e7d0 100644 --- a/src/api/v1/auth/refresh.rs +++ b/src/api/v1/auth/refresh.rs @@ -3,7 +3,7 @@ use log::error; use std::time::{SystemTime, UNIX_EPOCH}; use crate::{ - utils::{generate_access_token, generate_refresh_token, refresh_token_cookie}, Data + crypto::{generate_access_token, generate_refresh_token}, utils::refresh_token_cookie, Data }; use super::Response; diff --git a/src/api/v1/auth/register.rs b/src/api/v1/auth/register.rs index a56dd0e..7bbbbae 100644 --- a/src/api/v1/auth/register.rs +++ b/src/api/v1/auth/register.rs @@ -12,7 +12,7 @@ use uuid::Uuid; use super::Response; use crate::{ - api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, utils::{generate_access_token, generate_refresh_token, refresh_token_cookie}, Data + api::v1::auth::{EMAIL_REGEX, PASSWORD_REGEX, USERNAME_REGEX}, crypto::{generate_access_token, generate_refresh_token}, utils::refresh_token_cookie, Data }; #[derive(Deserialize)] diff --git a/src/api/v1/users/uuid.rs b/src/api/v1/users/uuid.rs index 5e4db39..f4c1f13 100644 --- a/src/api/v1/users/uuid.rs +++ b/src/api/v1/users/uuid.rs @@ -5,7 +5,7 @@ use uuid::Uuid; use crate::{Data, api::v1::auth::check_access_token, utils::get_auth_header}; -#[derive(Serialize, Clone)] +#[derive(Serialize)] struct Response { uuid: String, username: String, @@ -34,12 +34,6 @@ pub async fn res( return Ok(error); } - let cache_result = data.get_cache_key(uuid.to_string()).await; - - if let Ok(cache_hit) = cache_result { - return Ok(HttpResponse::Ok().content_type("application/json").body(cache_hit)) - } - let row = sqlx::query_as(&format!( "SELECT username, display_name FROM users WHERE uuid = '{}'", uuid @@ -54,18 +48,9 @@ pub async fn res( let (username, display_name): (String, Option) = row.unwrap(); - let user = Response { + Ok(HttpResponse::Ok().json(Response { uuid: uuid.to_string(), username, display_name: display_name.unwrap_or_default(), - }; - - let cache_result = data.set_cache_key(uuid.to_string(), user.clone(), 1800).await; - - if let Err(error) = cache_result { - error!("{}", error); - return Ok(HttpResponse::InternalServerError().finish()); - } - - Ok(HttpResponse::Ok().json(user)) + })) } diff --git a/src/config.rs b/src/config.rs index 65a5965..a2a6192 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,6 @@ use tokio::fs::read_to_string; #[derive(Debug, Deserialize)] pub struct ConfigBuilder { database: Database, - cache_database: CacheDatabase, web: Option, } @@ -20,15 +19,6 @@ pub struct Database { port: u16, } -#[derive(Debug, Deserialize, Clone)] -pub struct CacheDatabase { - username: Option, - password: Option, - host: String, - database: Option, - port: u16, -} - #[derive(Debug, Deserialize)] struct WebBuilder { url: Option, @@ -61,7 +51,6 @@ impl ConfigBuilder { Config { database: self.database, - cache_database: self.cache_database, web, } } @@ -70,7 +59,6 @@ impl ConfigBuilder { #[derive(Debug, Clone)] pub struct Config { pub database: Database, - pub cache_database: CacheDatabase, pub web: Web, } @@ -90,33 +78,3 @@ impl Database { .port(self.port) } } - -impl CacheDatabase { - pub fn url(&self) -> String { - let mut url = String::from("redis://"); - - if let Some(username) = &self.username { - url += username; - } - - if let Some(password) = &self.password { - url += ":"; - url += password; - } - - if self.username.is_some() || self.password.is_some() { - url += "@"; - } - - url += &self.host; - url += ":"; - url += &self.port.to_string(); - - if let Some(database) = &self.database { - url += "/"; - url += database; - } - - url - } -} diff --git a/src/crypto.rs b/src/crypto.rs new file mode 100644 index 0000000..c4d96c8 --- /dev/null +++ b/src/crypto.rs @@ -0,0 +1,14 @@ +use getrandom::fill; +use hex::encode; + +pub fn generate_access_token() -> Result { + let mut buf = [0u8; 16]; + fill(&mut buf)?; + Ok(encode(buf)) +} + +pub fn generate_refresh_token() -> Result { + let mut buf = [0u8; 32]; + fill(&mut buf)?; + Ok(encode(buf)) +} diff --git a/src/main.rs b/src/main.rs index d349729..a8e41b7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ -use actix_cors::Cors; use actix_web::{App, HttpServer, web}; use argon2::Argon2; use clap::Parser; @@ -8,7 +7,7 @@ use std::time::SystemTime; mod config; use config::{Config, ConfigBuilder}; mod api; - +pub mod crypto; pub mod utils; type Error = Box; @@ -23,7 +22,6 @@ struct Args { #[derive(Clone)] struct Data { pub pool: Pool, - pub cache_pool: redis::Client, pub _config: Config, pub argon2: Argon2<'static>, pub start_time: SystemTime, @@ -45,8 +43,6 @@ async fn main() -> Result<(), Error> { let pool = PgPool::connect_with(config.database.connect_options()).await?; - let cache_pool = redis::Client::open(config.cache_database.url())?; - /* TODO: Figure out if a table should be used here and if not then what. Also figure out if these should be different types from what they currently are and if we should add more "constraints" @@ -157,45 +153,15 @@ async fn main() -> Result<(), Error> { let data = Data { pool, - cache_pool, _config: config, // TODO: Possibly implement "pepper" into this (thinking it could generate one if it doesnt exist and store it on disk) argon2: Argon2::default(), start_time: SystemTime::now(), }; - HttpServer::new(move || { - // Set CORS headers - let cors = Cors::default() - /* - Set Allowed-Control-Allow-Origin header to whatever - the request's Origin header is. Must be done like this - rather than setting it to "*" due to CORS not allowing - sending of credentials (cookies) with wildcard origin. - */ - .allowed_origin_fn(|_origin, _req_head| { - true - }) - /* - Allows any request method in CORS preflight requests. - This will be restricted to only ones actually in use later. - */ - .allow_any_method() - /* - Allows any header(s) in request in CORS preflight requests. - This wll be restricted to only ones actually in use later. - */ - .allow_any_header() - /* - Allows browser to include cookies in requests. - This is needed for receiving the secure HttpOnly refresh_token cookie. - */ - .supports_credentials(); - App::new() .app_data(web::Data::new(data.clone())) - .wrap(cors) .service(api::web()) }) .bind((web.url, web.port))? diff --git a/src/utils.rs b/src/utils.rs index 15e5e2e..b432d19 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,10 +1,4 @@ use actix_web::{cookie::{time::Duration, Cookie, SameSite}, http::header::HeaderMap, HttpResponse}; -use getrandom::fill; -use hex::encode; -use redis::RedisError; -use serde::Serialize; - -use crate::Data; pub fn get_auth_header(headers: &HeaderMap) -> Result<&str, HttpResponse> { let auth_token = headers.get(actix_web::http::header::AUTHORIZATION); @@ -36,39 +30,4 @@ pub fn refresh_token_cookie(refresh_token: String) -> Cookie<'static> { .path("/api") .max_age(Duration::days(30)) .finish() -} - -pub fn generate_access_token() -> Result { - let mut buf = [0u8; 16]; - fill(&mut buf)?; - Ok(encode(buf)) -} - -pub fn generate_refresh_token() -> Result { - let mut buf = [0u8; 32]; - fill(&mut buf)?; - Ok(encode(buf)) -} - -impl Data { - pub async fn set_cache_key(&self, key: String, value: impl Serialize, expire: u32) -> Result<(), RedisError> { - let mut conn = self.cache_pool.get_multiplexed_tokio_connection().await?; - - let key_encoded = encode(key); - - let value_json = serde_json::to_string(&value).unwrap(); - - redis::cmd("SET",).arg(&[key_encoded.clone(), value_json]).exec_async(&mut conn).await?; - - redis::cmd("EXPIRE").arg(&[key_encoded, expire.to_string()]).exec_async(&mut conn).await - } - - pub async fn get_cache_key(&self, key: String) -> Result { - let mut conn = self.cache_pool.get_multiplexed_tokio_connection().await?; - - let key_encoded = encode(key); - - redis::cmd("GET").arg(key_encoded).query_async(&mut conn).await - } -} - +}