diff --git a/Cargo.lock b/Cargo.lock index 2f4398b..7c0c67d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,6 +520,7 @@ dependencies = [ "base64", "rand", "rand_hc", + "regex", "rocket", "rocket_db_pools", "sha256", @@ -1384,13 +1385,13 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.3", + "regex-automata 0.4.5", "regex-syntax 0.8.2", ] @@ -1405,9 +1406,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick", "memchr", diff --git a/Cargo.toml b/Cargo.toml index 9ccac39..620b85d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" base64 = "0.21.7" rand = "0.8.5" rand_hc = "0.3.2" +regex = "1.10.3" rocket = {version="0.5.0",features=["secrets","json"]} rocket_db_pools = {version="0.1.0",features=["sqlx_postgres"]} sha256 = "1.5.0" diff --git a/src/lib.rs b/src/lib.rs index 6add084..38a7df4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,11 @@ pub mod tables; + +pub struct Status { + pub status: StatusTypes, + pub data: T +} + +pub enum StatusTypes { + Success, + Faliure +} diff --git a/src/main.rs b/src/main.rs index 120eabf..773dbf6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +use fossil::StatusTypes; use rocket::fairing::AdHoc; use rocket::fs::FileServer; use rocket::http::Status; @@ -43,27 +44,34 @@ async fn createuser( mut db: Connection, info: Json, cookies: &CookieJar<'_>, -) -> &'static str { +) -> String { let token = cookies.get_private("token"); match token.is_some() { - true => "You're already logged in. Log out before trying to create a new account.", + true => "You're already logged in. Log out before trying to create a new account.".to_string(), false => { match User::get_by_username(&mut db, &info.username).await { - Some(_) => "Username already taken. Please try again.", + Some(_) => "Username already taken. Please try again.".to_string(), None => { - User::create(&mut db, &info.username, &info.password).await; - match User::get_by_username(&mut db, &info.username).await { - Some(user) => match user.set_new_token(&mut db).await { - Ok(t) => { - cookies.add_private(("token", t)); - "Your account has been created and you've been automatically logged in." - }, - Err(why) => { - eprintln!("{why:?}"); - "Couldn't log you in. Your account has been created, though." - }, + let created = User::create(&mut db, &info.username, &info.password).await; + match created.status { + StatusTypes::Success => { + match User::get_by_username(&mut db, &info.username).await { + Some(user) => match user.set_new_token(&mut db).await { + Ok(t) => { + cookies.add_private(("token", t)); + "Your account has been created and you've been automatically logged in.".to_string() + }, + Err(why) => { + eprintln!("{why:?}"); + "Couldn't log you in. Your account has been created, though.".to_string() + }, + }, + None => "Something went really wrong. I don't know what.".to_string() + } }, - None => "Something went really wrong. I don't know what." + StatusTypes::Faliure => { + format!("Couldn't create user: {}", created.data) + } } } } @@ -278,7 +286,7 @@ async fn migrate(rocket: Rocket) -> Rocket { let mut conn: PoolConnection = db.acquire().await.unwrap(); let _ = conn - .fetch_one(sqlx::query_as::<_, Post>( + .execute(sqlx::query_as::<_, Post>( "CREATE TABLE IF NOT EXISTS posts ( id SERIAL PRIMARY KEY, title VARCHAR NOT NULL, @@ -288,7 +296,7 @@ async fn migrate(rocket: Rocket) -> Rocket { )) .await; let _ = conn - .fetch_one(sqlx::query( + .execute(sqlx::query( "CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, username VARCHAR NOT NULL UNIQUE, @@ -298,7 +306,7 @@ async fn migrate(rocket: Rocket) -> Rocket { )) .await; - let _ = conn.fetch_one(sqlx::query( + let _ = conn.execute(sqlx::query( "ALTER TABLE users ADD COLUMN IF NOT EXISTS admin BOOLEAN NOT NULL DEFAULT FALSE, ADD COLUMN IF NOT EXISTS make_posts BOOLEAN NOT NULL DEFAULT FALSE, @@ -326,7 +334,18 @@ async fn migrate(rocket: Rocket) -> Rocket { .await .expect("couldn't create admin user"); } - } + }; + + let _ = conn + .execute(sqlx::query( + "CREATE TABLE IF NOT EXISTS images ( + id SERIAL PRIMARY KEY, + uuid VARCHAR NOT NULL UNIQUE, + owner_name TEXT NOT NULL, + image TEXT NOT NULL + )", + )) + .await; rocket } diff --git a/src/tables.rs b/src/tables.rs index d0f81ff..963bfe3 100644 --- a/src/tables.rs +++ b/src/tables.rs @@ -1,5 +1,6 @@ use base64::{engine::general_purpose, Engine}; use rand::{RngCore, SeedableRng}; +use regex::Regex; use rocket::http::Cookie; use rocket_db_pools::sqlx::Executor; use rocket_db_pools::Connection; @@ -9,6 +10,8 @@ use rocket_db_pools::{ }; use sqlx::FromRow; +use crate::{Status, StatusTypes}; + #[derive(Database)] #[database("fossil_postgres")] pub struct Db(PgPool); @@ -67,23 +70,56 @@ pub struct User { } impl User { - pub async fn create(db: &mut Connection, username: &String, password: &String) { - match db - .execute( - sqlx::query( - r#" - INSERT INTO users (username, password) - VALUES ($1, $2); - "#, - ) - .bind(username) - .bind(sha256::digest(password)), - ) - .await - { - Ok(_) => (), + pub async fn create(db: &mut Connection, username: &String, password: &String) -> Status { + match Regex::new(r"[^A-Za-z0-9_]") { + Ok(r) => { + match r.captures(username) { + Some(_) => Status { + status: StatusTypes::Faliure, + data:"The username contains invalid characters. Only letters, numbers, and underscores are allowed.".to_string() + }, + None => { + if username.len().gt(&32) || username.len().lt(&3) { // i can Never + // remember which symbol is which. this works better for me. + Status { + status: StatusTypes::Faliure, + data: "Please choose a username between 3 and 32 characters.".to_string() + } + } else { + match db + .execute( + sqlx::query( + r#" + INSERT INTO users (username, password) + VALUES ($1, $2); + "#, + ) + .bind(username) + .bind(sha256::digest(password)), + ).await + { + Ok(_) => Status { + status: StatusTypes::Success, + data: "Created user.".to_string() + }, + Err(why) => { + eprintln!("Couldn't create database entry: {why:?}"); + Status { + status: StatusTypes::Faliure, + data: "Failed to create user.".to_string() + } + } + } + } + } + } + } Err(why) => { - eprintln!("Couldn't create database entry: {why:?}"); + eprintln!("Couldn't compile name regex: {why:?}"); + Status { + status: StatusTypes::Faliure, + data: "Couldn't compile name regex.".to_string() + } } } } @@ -195,3 +231,10 @@ impl User { } } } + +pub struct Image { + pub id: i32, + pub uuid: String, + pub owner_name: String, + pub image: String, +}