use std::collections::HashSet;
use crate::{Error, Result};
#[derive(Serialize, Deserialize, Clone)]
pub enum EmailBlockList {
Disabled,
Custom { domains: HashSet<String> },
#[cfg(feature = "revolt_source_list")]
RevoltSourceList,
}
#[cfg(feature = "revolt_source_list")]
impl Default for EmailBlockList {
fn default() -> EmailBlockList {
EmailBlockList::RevoltSourceList
}
}
#[cfg(not(feature = "revolt_source_list"))]
impl Default for EmailBlockList {
fn default() -> EmailBlockList {
EmailBlockList::Disabled
}
}
#[cfg(feature = "revolt_source_list")]
lazy_static! {
static ref REVOLT_SOURCE_LIST: HashSet<String> = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/assets/revolt_source_list.txt"))
.split('\n')
.map(|x| x.into())
.collect();
}
impl EmailBlockList {
pub fn get_list(&self) -> Option<&HashSet<String>> {
match self {
EmailBlockList::Disabled => None,
EmailBlockList::Custom { domains } => Some(domains),
#[cfg(feature = "revolt_source_list")]
EmailBlockList::RevoltSourceList => Some(&*REVOLT_SOURCE_LIST),
}
}
pub fn validate_email(&self, email: &str) -> Result<()> {
if !validator::validate_email(email) {
return Err(Error::IncorrectData { with: "email" });
}
if let Some(list) = self.get_list() {
if let Some(domain) = email.split('@').last() {
if list.contains(&domain.to_string()) {
return Err(Error::Blacklisted);
}
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::collections::HashSet;
use crate::config::EmailBlockList;
use crate::Error;
#[test]
fn it_accepts_valid_emails() {
let list = EmailBlockList::Disabled;
assert_eq!(list.validate_email("valid@example.com"), Ok(()));
}
#[test]
fn it_rejects_invalid_emails() {
let list = EmailBlockList::Disabled;
assert_eq!(
list.validate_email("invalid"),
Err(Error::IncorrectData { with: "email" })
);
}
#[test]
fn it_rejects_blocked_emails() {
let list = EmailBlockList::Custom {
domains: HashSet::from(["example.com".to_string()]),
};
assert_eq!(
list.validate_email("test@example.com"),
Err(Error::Blacklisted)
);
}
}