From 883dfd67ea44185207634b1ae60ade940c5f02fe Mon Sep 17 00:00:00 2001 From: Joe Ardent Date: Sun, 25 Feb 2024 17:58:28 -0800 Subject: [PATCH] prepare for when a username gets snatched between initial signup and having paid --- src/main.rs | 124 ++++++++++++++++++++++------------ templates/signup.html | 3 +- templates/signup_success.html | 2 +- 3 files changed, 83 insertions(+), 46 deletions(-) diff --git a/src/main.rs b/src/main.rs index 343f409..b78866b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,7 +27,9 @@ struct Counter(usize); /// Displays the signup form. async fn get_signup() -> impl IntoResponse { - SignupPage::default() + SignupPage { + ..Default::default() + } } /// Receives the form with the user signup fields filled out. @@ -35,41 +37,7 @@ async fn post_signup( session: Session, Form(form): Form, ) -> Result { - let username = form.username.trim(); - let password = form.password.trim(); - let verify = form.pw_verify.trim(); - - let name_len = username.graphemes(true).size_hint().1.unwrap(); - // we are not ascii exclusivists around here - if !(1..=20).contains(&name_len) { - return Err(CreateUserErrorKind::BadUsername.into()); - } - - if password != verify { - return Err(CreateUserErrorKind::PasswordMismatch.into()); - } - let pwlen = password.graphemes(true).size_hint().1.unwrap_or(0); - if !(4..=50).contains(&pwlen) { - return Err(CreateUserErrorKind::BadPassword.into()); - } - - // clean up the optionals - let displayname = validate_optional_length( - &form.displayname, - 0..100, - CreateUserErrorKind::BadDisplayname, - )?; - - let email = validate_optional_length(&form.email, 5..30, CreateUserErrorKind::BadEmail)?; - - let user = User { - username: username.to_string(), - displayname, - email, - password: password.to_string(), - pw_verify: verify.to_string(), - }; - + let user = verify_user(&form).await?; session.insert(SIGNUP_KEY, user).await.unwrap(); Ok(Redirect::to( @@ -77,14 +45,29 @@ async fn post_signup( )) } +async fn get_edit_signup( + session: Session, + receipt: Option>, +) -> Result { + Ok(()) +} + +async fn post_edit_signup( + session: Session, + Form(form): Form, +) -> Result { + Ok(()) +} + /// Called from Stripe with the receipt of payment. async fn signup_success(session: Session, receipt: Option>) -> impl IntoResponse { let user: User = session.get(SIGNUP_KEY).await.unwrap().unwrap_or_default(); - if user != User::default() { - SignupSuccessPage(user).into_response() - } else { - SignupErrorPage("who you?".to_string()).into_response() + if user == User::default() { + return SignupErrorPage("who you?".to_string()).into_response(); } + + // TODO: check Stripe for the receipt, verify it's legit + SignupSuccessPage(user).into_response() } #[tokio::main] @@ -135,8 +118,7 @@ pub struct SignupForm { pub username: String, #[serde(default, deserialize_with = "empty_string_as_none")] pub displayname: Option, - #[serde(default, deserialize_with = "empty_string_as_none")] - pub email: Option, + pub email: String, pub password: String, pub pw_verify: String, } @@ -149,6 +131,7 @@ pub struct SignupPage { pub email: Option, pub password: String, pub pw_verify: String, + pub receipt: String, } #[derive(Debug, Clone, Template, Default, Deserialize, Serialize, PartialEq, Eq)] @@ -163,7 +146,7 @@ pub struct SignupErrorPage(pub String); pub struct User { pub username: String, pub displayname: Option, - pub email: Option, + pub email: String, pub password: String, pub pw_verify: String, } @@ -192,11 +175,50 @@ impl Display for User { } else { "" }; - let email = if let Some(ref e) = self.email { e } else { "" }; + let email = &self.email; write!(f, "Username: {uname}\nDisplayname: {dname}\nEmail: {email}") } } +async fn verify_user(form: &SignupForm) -> Result { + let username = form.username.trim(); + let password = form.password.trim(); + let verify = form.pw_verify.trim(); + + let name_len = username.graphemes(true).size_hint().1.unwrap(); + // we are not ascii exclusivists around here + if !(1..=20).contains(&name_len) { + return Err(CreateUserErrorKind::BadUsername.into()); + } + + if password != verify { + return Err(CreateUserErrorKind::PasswordMismatch.into()); + } + let pwlen = password.graphemes(true).size_hint().1.unwrap_or(0); + if !(4..=50).contains(&pwlen) { + return Err(CreateUserErrorKind::BadPassword.into()); + } + + // clean up the optionals + let displayname = validate_optional_length( + &form.displayname, + 0..100, + CreateUserErrorKind::BadDisplayname, + )?; + + let email = validate_length(&form.email, 5..30, CreateUserErrorKind::BadEmail)?; + + let user = User { + username: username.to_string(), + displayname, + email, + password: password.to_string(), + pw_verify: verify.to_string(), + }; + + Ok(user) +} + pub(crate) fn empty_string_as_none<'de, D, T>(de: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -229,3 +251,17 @@ pub(crate) fn validate_optional_length( Ok(None) } } + +pub(crate) fn validate_length( + thing: &str, + len_range: Range, + err: E, +) -> Result { + let thing = thing.trim(); + let len = thing.graphemes(true).size_hint().1.unwrap(); + if !len_range.contains(&len) { + Err(err) + } else { + Ok(thing.to_string()) + } +} diff --git a/templates/signup.html b/templates/signup.html index 062f9b3..2a11cae 100644 --- a/templates/signup.html +++ b/templates/signup.html @@ -8,11 +8,12 @@

+

- +

diff --git a/templates/signup_success.html b/templates/signup_success.html index a95224c..9087032 100644 --- a/templates/signup_success.html +++ b/templates/signup_success.html @@ -13,7 +13,7 @@

-

Now, head on over to the login page and get watchin'! +

Now, head on over to the login page and git going!

{% endblock %}