summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/api/ops.rs6
-rw-r--r--src/api/users.rs4
-rw-r--r--src/main.rs2
-rw-r--r--src/services/db.rs11
-rw-r--r--src/services/secrets.rs3
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()
}