Compare commits

..

No commits in common. "1daec804307b9833b27b1dad9f25d901d6f400c8" and "478464ac0537b47db83ea39317133ea25b3fd2fa" have entirely different histories.

4 changed files with 13 additions and 61 deletions

40
Cargo.lock generated
View file

@ -163,12 +163,6 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
[[package]] [[package]]
name = "bytes" name = "bytes"
version = "1.5.0" version = "1.5.0"
@ -385,12 +379,6 @@ dependencies = [
"pin-project-lite", "pin-project-lite",
] ]
[[package]]
name = "http-range-header"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe"
[[package]] [[package]]
name = "httparse" name = "httparse"
version = "1.8.0" version = "1.8.0"
@ -677,7 +665,6 @@ dependencies = [
"serde", "serde",
"thiserror", "thiserror",
"tokio", "tokio",
"tower-http",
"tower-sessions", "tower-sessions",
"unicode-segmentation", "unicode-segmentation",
] ]
@ -727,7 +714,7 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags",
] ]
[[package]] [[package]]
@ -975,31 +962,6 @@ dependencies = [
"tower-service", "tower-service",
] ]
[[package]]
name = "tower-http"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e9cd434a998747dd2c4276bc96ee2e0c7a2eadf3cae88e52be55a05fa9053f5"
dependencies = [
"bitflags 2.4.2",
"bytes",
"futures-util",
"http",
"http-body",
"http-body-util",
"http-range-header",
"httpdate",
"mime",
"mime_guess",
"percent-encoding",
"pin-project-lite",
"tokio",
"tokio-util",
"tower-layer",
"tower-service",
"tracing",
]
[[package]] [[package]]
name = "tower-layer" name = "tower-layer"
version = "0.3.2" version = "0.3.2"

View file

@ -11,6 +11,5 @@ justerror = { version = "1" }
serde = { version = "1", default-features = false, features = ["derive"] } serde = { version = "1", default-features = false, features = ["derive"] }
thiserror = { version = "1" } thiserror = { version = "1" }
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] }
tower-http = { version = "0.5.2", default-features = false, features = ["fs"] }
tower-sessions = { version = "0.10", default-features = false, features = ["axum-core", "memory-store"] } tower-sessions = { version = "0.10", default-features = false, features = ["axum-core", "memory-store"] }
unicode-segmentation = { version = "1", default-features = false } unicode-segmentation = { version = "1", default-features = false }

View file

@ -1,4 +1,4 @@
use std::{error::Error, fmt::Debug, ops::RangeInclusive}; use std::{error::Error, fmt::Debug, ops::Range};
use axum::{ use axum::{
extract::{Form, Path}, extract::{Form, Path},
@ -13,11 +13,6 @@ use crate::{templates::*, User};
const SIGNUP_KEY: &str = "meow"; const SIGNUP_KEY: &str = "meow";
const PASSWORD_LEN: RangeInclusive<usize> = 4..=100;
const USERNAME_LEN: RangeInclusive<usize> = 1..=50;
const DISPLAYNAME_LEN: RangeInclusive<usize> = 0..=100;
const EMAIL_LEN: RangeInclusive<usize> = 4..=50;
#[Error(desc = "Could not create user.")] #[Error(desc = "Could not create user.")]
#[non_exhaustive] #[non_exhaustive]
pub struct CreateUserError(#[from] CreateUserErrorKind); pub struct CreateUserError(#[from] CreateUserErrorKind);
@ -32,10 +27,10 @@ impl IntoResponse for CreateUserError {
#[non_exhaustive] #[non_exhaustive]
pub enum CreateUserErrorKind { pub enum CreateUserErrorKind {
AlreadyExists, AlreadyExists,
#[error(desc = "Usernames must be between 1 and 50 characters long")] #[error(desc = "Usernames must be between 1 and 20 characters long")]
BadUsername, BadUsername,
PasswordMismatch, PasswordMismatch,
#[error(desc = "Password must have at least 4 and at most 100 characters")] #[error(desc = "Password must have at least 4 and at most 50 characters")]
BadPassword, BadPassword,
#[error(desc = "Display name must be less than 100 characters long")] #[error(desc = "Display name must be less than 100 characters long")]
BadDisplayname, BadDisplayname,
@ -65,7 +60,7 @@ pub async fn post_signup(
session: Session, session: Session,
Form(form): Form<SignupForm>, Form(form): Form<SignupForm>,
) -> Result<impl IntoResponse, CreateUserError> { ) -> Result<impl IntoResponse, CreateUserError> {
let user = validate_signup(&form).await?; let user = verify_user(&form).await?;
session.insert(SIGNUP_KEY, user).await.unwrap(); session.insert(SIGNUP_KEY, user).await.unwrap();
Ok(Redirect::to( Ok(Redirect::to(
@ -101,14 +96,14 @@ pub async fn signup_success(session: Session, receipt: Option<Path<String>>) ->
//-************************************************************************ //-************************************************************************
// helpers // helpers
//-************************************************************************ //-************************************************************************
async fn validate_signup(form: &SignupForm) -> Result<User, CreateUserError> { async fn verify_user(form: &SignupForm) -> Result<User, CreateUserError> {
let username = form.username.trim(); let username = form.username.trim();
let password = form.password.trim(); let password = form.password.trim();
let verify = form.pw_verify.trim(); let verify = form.pw_verify.trim();
let name_len = username.graphemes(true).size_hint().1.unwrap(); let name_len = username.graphemes(true).size_hint().1.unwrap();
// we are not ascii exclusivists around here // we are not ascii exclusivists around here
if !USERNAME_LEN.contains(&name_len) { if !(1..=20).contains(&name_len) {
return Err(CreateUserErrorKind::BadUsername.into()); return Err(CreateUserErrorKind::BadUsername.into());
} }
@ -116,18 +111,18 @@ async fn validate_signup(form: &SignupForm) -> Result<User, CreateUserError> {
return Err(CreateUserErrorKind::PasswordMismatch.into()); return Err(CreateUserErrorKind::PasswordMismatch.into());
} }
let pwlen = password.graphemes(true).size_hint().1.unwrap_or(0); let pwlen = password.graphemes(true).size_hint().1.unwrap_or(0);
if !PASSWORD_LEN.contains(&pwlen) { if !(4..=50).contains(&pwlen) {
return Err(CreateUserErrorKind::BadPassword.into()); return Err(CreateUserErrorKind::BadPassword.into());
} }
// clean up the optionals // clean up the optionals
let displayname = validate_optional_length( let displayname = validate_optional_length(
&form.displayname, &form.displayname,
DISPLAYNAME_LEN, 0..100,
CreateUserErrorKind::BadDisplayname, CreateUserErrorKind::BadDisplayname,
)?; )?;
let email = validate_length(&form.email, EMAIL_LEN, CreateUserErrorKind::BadEmail)?; let email = validate_length(&form.email, 5..30, CreateUserErrorKind::BadEmail)?;
let user = User { let user = User {
username: username.to_string(), username: username.to_string(),
@ -157,7 +152,7 @@ where
pub(crate) fn validate_optional_length<E: Error>( pub(crate) fn validate_optional_length<E: Error>(
opt: &Option<String>, opt: &Option<String>,
len_range: RangeInclusive<usize>, len_range: Range<usize>,
err: E, err: E,
) -> Result<Option<String>, E> { ) -> Result<Option<String>, E> {
if let Some(opt) = opt { if let Some(opt) = opt {
@ -175,7 +170,7 @@ pub(crate) fn validate_optional_length<E: Error>(
pub(crate) fn validate_length<E: Error>( pub(crate) fn validate_length<E: Error>(
thing: &str, thing: &str,
len_range: RangeInclusive<usize>, len_range: Range<usize>,
err: E, err: E,
) -> Result<String, E> { ) -> Result<String, E> {
let thing = thing.trim(); let thing = thing.trim();

View file

@ -5,7 +5,6 @@ use std::{
use axum::{routing::get, Router}; use axum::{routing::get, Router};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use tower_http::services::ServeDir;
use tower_sessions::{MemoryStore, SessionManagerLayer}; use tower_sessions::{MemoryStore, SessionManagerLayer};
#[macro_use] #[macro_use]
@ -21,11 +20,8 @@ async fn main() {
let session_store = MemoryStore::default(); let session_store = MemoryStore::default();
let session_layer = SessionManagerLayer::new(session_store).with_secure(false); let session_layer = SessionManagerLayer::new(session_store).with_secure(false);
let assets_dir = std::env::current_dir().unwrap().join("assets");
let assets_svc = ServeDir::new(assets_dir.as_path());
let app = Router::new() let app = Router::new()
.nest_service("/assets", assets_svc) //.nest_service("/assets", assets_svc)
.route("/signup", get(get_signup).post(post_signup)) .route("/signup", get(get_signup).post(post_signup))
.route("/signup_success/:receipt", get(signup_success)) .route("/signup_success/:receipt", get(signup_success))
.layer(session_layer); .layer(session_layer);