Merge pull request 'Fix #1121: Check email block list when email sign-up' (#1122) from block-on-email-signup into main

Reviewed-on: https://git.joinplu.me/Plume/Plume/pulls/1122
This commit is contained in:
KitaitiMakoto 2023-01-03 09:11:20 +00:00
commit 85c1bfa300
7 changed files with 120 additions and 44 deletions

View file

@ -126,11 +126,9 @@ pub(crate) mod tests {
.id,
various[1].id
);
assert!(
BlocklistedEmail::matches_blocklist(&conn, no_match)
.unwrap()
.is_none()
);
assert!(BlocklistedEmail::matches_blocklist(&conn, no_match)
.unwrap()
.is_none());
Ok(())
});
}

View file

@ -1,4 +1,5 @@
use crate::{
blocklisted_emails::BlocklistedEmail,
db_conn::DbConn,
schema::email_signups,
users::{NewUser, Role, User},
@ -60,6 +61,8 @@ pub struct NewEmailSignup<'a> {
impl EmailSignup {
pub fn start(conn: &DbConn, email: &str) -> Result<Token> {
Self::ensure_email_not_blocked(conn, email)?;
conn.transaction(|| {
Self::ensure_user_not_exist_by_email(conn, email)?;
let _rows = Self::delete_existings_by_email(conn, email)?;
@ -90,6 +93,8 @@ impl EmailSignup {
}
pub fn confirm(&self, conn: &DbConn) -> Result<()> {
Self::ensure_email_not_blocked(conn, &self.email)?;
conn.transaction(|| {
Self::ensure_user_not_exist_by_email(conn, &self.email)?;
if self.expired() {
@ -101,6 +106,8 @@ impl EmailSignup {
}
pub fn complete(&self, conn: &DbConn, username: String, password: String) -> Result<User> {
Self::ensure_email_not_blocked(conn, &self.email)?;
conn.transaction(|| {
Self::ensure_user_not_exist_by_email(conn, &self.email)?;
let user = NewUser::new_local(
@ -122,6 +129,14 @@ impl EmailSignup {
Ok(())
}
fn ensure_email_not_blocked(conn: &DbConn, email: &str) -> Result<()> {
if let Some(x) = BlocklistedEmail::matches_blocklist(conn, email)? {
Err(Error::Blocklisted(x.notify_user, x.notification_text))
} else {
Ok(())
}
}
fn ensure_user_not_exist_by_email(conn: &DbConn, email: &str) -> Result<()> {
if User::email_used(conn, email)? {
let _rows = Self::delete_existings_by_email(conn, email)?;

View file

@ -107,12 +107,7 @@ impl Follow {
res.notify(conn)?;
let accept = res.build_accept(from, target, follow)?;
broadcast(
target,
accept,
vec![from.clone()],
CONFIG.proxy().cloned(),
);
broadcast(target, accept, vec![from.clone()], CONFIG.proxy().cloned());
Ok(res)
}

View file

@ -133,7 +133,8 @@ impl Post {
.filter(posts::id.eq_any(ids))
.filter(posts::published.eq(true))
.count()
.load(conn)?.first()
.load(conn)?
.first()
.cloned()
.ok_or(Error::NotFound)
}

View file

@ -291,13 +291,7 @@ mod tests {
"all".to_owned(),
)
.unwrap();
List::new(
conn,
"languages I speak",
Some(&users[1]),
ListType::Prefix,
)
.unwrap();
List::new(conn, "languages I speak", Some(&users[1]), ListType::Prefix).unwrap();
let tl2_u1 = Timeline::new_for_user(
conn,
users[0].id,
@ -337,18 +331,14 @@ mod tests {
let tl_instance = Timeline::list_for_user(conn, None).unwrap();
assert_eq!(3, tl_instance.len()); // there are also the local and federated feed by default
assert!(tl_instance
.iter()
.any(|tl| *tl == tl1_instance));
assert!(tl_instance.iter().any(|tl| *tl == tl1_instance));
tl1_u1.name = "My Super TL".to_owned();
let new_tl1_u2 = tl1_u2.update(conn).unwrap();
let tl_u2 = Timeline::list_for_user(conn, Some(users[1].id)).unwrap();
assert_eq!(2, tl_u2.len()); // same here
assert!(tl_u2
.iter()
.any(|tl| *tl == new_tl1_u2));
assert!(tl_u2.iter().any(|tl| *tl == new_tl1_u2));
Ok(())
});

View file

@ -463,20 +463,24 @@ mod tests {
Instance::cache_local(conn);
instance
});
let mut user = NewUser::default();
user.instance_id = instance.id;
user.username = random_hex();
user.ap_url = random_hex();
user.inbox_url = random_hex();
user.outbox_url = random_hex();
user.followers_endpoint = random_hex();
let user = NewUser {
instance_id: instance.id,
username: random_hex(),
ap_url: random_hex(),
inbox_url: random_hex(),
outbox_url: random_hex(),
followers_endpoint: random_hex(),
..Default::default()
};
let user = User::insert(conn, user).unwrap();
let mut blog = NewBlog::default();
blog.instance_id = instance.id;
blog.actor_id = random_hex();
blog.ap_url = random_hex();
blog.inbox_url = random_hex();
blog.outbox_url = random_hex();
let blog = NewBlog {
instance_id: instance.id,
actor_id: random_hex(),
ap_url: random_hex(),
inbox_url: random_hex(),
outbox_url: random_hex(),
..Default::default()
};
let blog = Blog::insert(conn, blog).unwrap();
BlogAuthor::insert(
conn,

View file

@ -3,6 +3,7 @@ use crate::{
routes::{errors::ErrorPage, RespondOrRedirect},
template_utils::{IntoContext, Ructe},
};
use plume_models::{
db_conn::DbConn, email_signups::EmailSignup, instance::Instance, lettre::Transport, signups,
Error, PlumeRocket, CONFIG,
@ -13,7 +14,11 @@ use rocket::{
response::{Flash, Redirect},
State,
};
use std::sync::{Arc, Mutex};
use std::{
borrow::Cow,
collections::HashMap,
sync::{Arc, Mutex},
};
use tracing::warn;
use validator::{Validate, ValidationError, ValidationErrors};
@ -105,6 +110,26 @@ pub fn create(
render!(email_signups::create(&(&conn, &rockets).to_context())).into()
}
Error::NotFound => render!(errors::not_found(&(&conn, &rockets).to_context())).into(),
Error::Blocklisted(show, msg) => {
let mut errors = ValidationErrors::new();
if *show {
errors.add(
"email",
ValidationError {
code: Cow::from("blocklisted"),
message: Some(Cow::from(msg.clone())),
params: HashMap::new(),
},
);
}
render!(email_signups::new(
&(&conn, &rockets).to_context(),
registration_open,
&form,
errors
))
.into()
}
_ => render!(errors::not_found(&(&conn, &rockets).to_context())).into(), // FIXME
});
}
@ -153,6 +178,28 @@ pub fn show(
)))
} // TODO: Flash and redirect
Error::NotFound => return Err(Error::NotFound.into()),
Error::Blocklisted(show, msg) => {
let mut errors = ValidationErrors::new();
if show {
errors.add(
"email",
ValidationError {
code: Cow::from("blocklisted"),
message: Some(Cow::from(msg)),
params: HashMap::new(),
},
);
}
return Ok(render!(email_signups::new(
&(&conn, &rockets).to_context(),
Instance::get_local()?.open_registrations,
&EmailSignupForm {
email: signup.email.clone(),
email_confirmation: signup.email
},
errors
)));
}
_ => return Err(Error::NotFound.into()), // FIXME
}
}
@ -207,12 +254,38 @@ pub fn signup(
err
))));
}
let _user = signup
.complete(&conn, form.username.clone(), form.password.clone())
.map_err(|e| {
let user = signup.complete(&conn, form.username.clone(), form.password.clone());
match user {
Err(Error::Blocklisted(show, msg)) => {
let instance = Instance::get_local().map_err(|_| Status::UnprocessableEntity)?;
let mut errors = ValidationErrors::new();
if show {
errors.add(
"email",
ValidationError {
code: Cow::from("blocklisted"),
message: Some(Cow::from(msg)),
params: HashMap::new(),
},
);
}
return Ok(render!(email_signups::new(
&(&conn, &rockets).to_context(),
instance.open_registrations,
&EmailSignupForm {
email: signup.email.clone(),
email_confirmation: signup.email
},
errors
))
.into());
}
Err(e) => {
warn!("{:?}", e);
Status::UnprocessableEntity
})?;
return Err(Status::UnprocessableEntity);
}
_ => {}
}
Ok(FlashRedirect(Flash::success(
Redirect::to(uri!(super::session::new: m = _)),
i18n!(