diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/api/ops.rs | 6 | ||||
| -rw-r--r-- | src/api/users.rs | 4 | ||||
| -rw-r--r-- | src/main.rs | 2 | ||||
| -rw-r--r-- | src/services/db.rs | 11 | ||||
| -rw-r--r-- | src/services/secrets.rs | 3 |
5 files changed, 26 insertions, 0 deletions
diff --git a/src/api/ops.rs b/src/api/ops.rs index 9bebc2d..018743c 100644 --- a/src/api/ops.rs +++ b/src/api/ops.rs @@ -6,12 +6,15 @@ use thiserror::Error; use crate::services::db; +/// A request to login #[derive(Debug, Clone, Deserialize)] struct LoginRequest { username: Box<str>, password: Box<str>, } +/// An error occurred when authenticating, because either the username or +/// password was invalid. #[derive(Debug, Clone, Error)] enum LoginFailure { #[error("No user found with the given username")] @@ -29,6 +32,9 @@ impl ResponseError for LoginFailure { } } +/// Returns `200` if login was successful. +/// Returns `404` if the username is invalid. +/// Returns `401` if the password was invalid. #[post("/login")] async fn login( body: web::Json<LoginRequest>, diff --git a/src/api/users.rs b/src/api/users.rs index d62cc27..863d99e 100644 --- a/src/api/users.rs +++ b/src/api/users.rs @@ -10,14 +10,17 @@ use crate::models::User; use crate::services::crypto::PasswordHash; use crate::services::{db, id}; +/// Just a username. No password hash, because that'd be tempting fate. #[derive(Debug, Clone, Serialize)] struct UserResponse { + id: Uuid, username: Box<str>, } impl From<User> for UserResponse { fn from(user: User) -> Self { Self { + id: user.id, username: user.username, } } @@ -107,6 +110,7 @@ async fn get_username( Ok(response) } +/// A request to create or update user information #[derive(Debug, Clone, Deserialize)] struct UserRequest { username: Box<str>, diff --git a/src/main.rs b/src/main.rs index d454a8c..4b8762d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,11 @@ use services::*; #[actix_web::main] async fn main() -> Result<(), RawUnexpected> { + // initialize the database let db_url = secrets::database_url()?; let sql_pool = db::initialize(&db_url).await?; + // start the server HttpServer::new(move || { App::new() .app_data(Data::new(sql_pool.clone())) diff --git a/src/services/db.rs b/src/services/db.rs index 8f9743a..f4da004 100644 --- a/src/services/db.rs +++ b/src/services/db.rs @@ -37,6 +37,7 @@ pub async fn initialize(db_url: &str) -> Result<MySqlPool, RawUnexpected> { MySqlPool::connect(db_url).await.unexpect() } +/// Check if a user with a given user ID exists pub async fn user_id_exists<'c>( conn: impl Executor<'c, Database = MySql>, id: Uuid, @@ -51,6 +52,7 @@ pub async fn user_id_exists<'c>( Ok(exists) } +/// Check if a given username is taken pub async fn username_is_used<'c>( conn: impl Executor<'c, Database = MySql>, username: &str, @@ -65,6 +67,7 @@ pub async fn username_is_used<'c>( Ok(exists) } +/// Get a user from their ID pub async fn get_user<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, @@ -83,6 +86,7 @@ pub async fn get_user<'c>( Ok(Some(record.try_into()?)) } +/// Get a user from their username pub async fn get_user_by_username<'c>( conn: impl Executor<'c, Database = MySql>, username: &str, @@ -101,6 +105,7 @@ pub async fn get_user_by_username<'c>( Ok(Some(record.try_into()?)) } +/// Search the list of users for a given username pub async fn search_users<'c>( conn: impl Executor<'c, Database = MySql>, username: &str, @@ -121,6 +126,7 @@ pub async fn search_users<'c>( .collect::<Result<Box<[User]>, RawUnexpected>>()?) } +/// Search the list of users, only returning a certain range of results pub async fn search_users_limit<'c>( conn: impl Executor<'c, Database = MySql>, username: &str, @@ -147,6 +153,7 @@ pub async fn search_users_limit<'c>( .collect::<Result<Box<[User]>, RawUnexpected>>()?) } +/// Get the username of a user with a certain ID pub async fn get_username<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, @@ -159,6 +166,7 @@ pub async fn get_username<'c>( Ok(username) } +/// Create a new user pub async fn new_user<'c>( conn: impl Executor<'c, Database = MySql>, user: &User, @@ -176,6 +184,7 @@ pub async fn new_user<'c>( .await } +/// Update a user pub async fn update_user<'c>( conn: impl Executor<'c, Database = MySql>, user: &User, @@ -197,6 +206,7 @@ pub async fn update_user<'c>( .await } +/// Update the username of a user with the given ID pub async fn update_username<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, @@ -211,6 +221,7 @@ pub async fn update_username<'c>( .await } +/// Update the password of a user with the given ID pub async fn update_password<'c>( conn: impl Executor<'c, Database = MySql>, user_id: Uuid, diff --git a/src/services/secrets.rs b/src/services/secrets.rs index e4a1ca1..9f8af54 100644 --- a/src/services/secrets.rs +++ b/src/services/secrets.rs @@ -2,12 +2,15 @@ use std::env; use exun::*; +/// This is a secret salt, needed for creating passwords. It's used as an extra +/// layer of security, on top of the salt that's already used. pub fn pepper() -> Result<Box<[u8]>, RawUnexpected> { let pepper = env::var("SECRET_SALT")?; let pepper = hex::decode(pepper)?; Ok(pepper.into_boxed_slice()) } +/// The URL to the MySQL database pub fn database_url() -> Result<String, RawUnexpected> { env::var("DATABASE_URL").unexpect() } |
