Return 400 on bad names.

This commit is contained in:
Luca Palmieri 2020-12-11 15:50:09 +00:00
parent 56ee4e7746
commit 9dd3b0590a
4 changed files with 60 additions and 2 deletions

10
Cargo.lock generated
View file

@ -503,6 +503,15 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "claim"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68ad37958d55b29a7088909368968d2fe876a24c203f8441195130f3b15194b9"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "config" name = "config"
version = "0.10.1" version = "0.10.1"
@ -2888,6 +2897,7 @@ dependencies = [
"actix-rt", "actix-rt",
"actix-web", "actix-web",
"chrono", "chrono",
"claim",
"config", "config",
"lazy_static", "lazy_static",
"reqwest", "reqwest",

View file

@ -33,3 +33,4 @@ unicode-segmentation = "1.7.1"
[dev-dependencies] [dev-dependencies]
reqwest = { version = "0.10.7", features = ["json"] } reqwest = { version = "0.10.7", features = ["json"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
claim = "0.4.0"

View file

@ -5,6 +5,7 @@ pub struct NewSubscriber {
pub name: SubscriberName, pub name: SubscriberName,
} }
#[derive(Debug)]
pub struct SubscriberName(String); pub struct SubscriberName(String);
impl SubscriberName { impl SubscriberName {
@ -36,7 +37,7 @@ impl SubscriberName {
> 0; > 0;
if is_empty_or_whitespace || is_too_long || contains_forbidden_characters { if is_empty_or_whitespace || is_too_long || contains_forbidden_characters {
panic!(format!("{} is not a valid subscriber name.", s)) Err(format!("{} is not a valid subscriber name.", s))
} else { } else {
Ok(Self(s)) Ok(Self(s))
} }
@ -48,3 +49,47 @@ impl AsRef<str> for SubscriberName {
&self.0 &self.0
} }
} }
#[cfg(test)]
mod tests {
use crate::domain::SubscriberName;
use claim::{assert_err, assert_ok};
#[test]
fn a_256_grapheme_long_name_is_valid() {
let name = "".repeat(256);
assert_ok!(SubscriberName::parse(name));
}
#[test]
fn a_name_longer_than_256_graphemes_is_rejected() {
let name = "a".repeat(257);
assert_err!(SubscriberName::parse(name));
}
#[test]
fn whitespace_only_names_are_rejected() {
let name = " ".to_string();
assert_err!(SubscriberName::parse(name));
}
#[test]
fn empty_string_is_rejected() {
let name = "".to_string();
assert_err!(SubscriberName::parse(name));
}
#[test]
fn names_containing_an_invalid_characters_are_rejected() {
for name in vec!['/', '(', ')', '"', '<', '>', '\\', '{', '}'] {
let name = name.to_string();
assert_err!(SubscriberName::parse(name));
}
}
#[test]
fn a_valid_name_is_parsed_successfully() {
let name = "Ursula Le Guin".to_string();
assert_ok!(SubscriberName::parse(name));
}
}

View file

@ -22,9 +22,11 @@ pub async fn subscribe(
form: web::Form<FormData>, form: web::Form<FormData>,
pool: web::Data<PgPool>, pool: web::Data<PgPool>,
) -> Result<HttpResponse, HttpResponse> { ) -> Result<HttpResponse, HttpResponse> {
let name =
SubscriberName::parse(form.0.name).map_err(|_| HttpResponse::BadRequest().finish())?;
let new_subscriber = NewSubscriber { let new_subscriber = NewSubscriber {
email: form.0.email, email: form.0.email,
name: SubscriberName::parse(form.0.name).expect("Name validation failed."), name,
}; };
insert_subscriber(&pool, &new_subscriber) insert_subscriber(&pool, &new_subscriber)
.await .await