use actix_web::error;
use awc::Client;
use once_cell::sync::Lazy;
use serde::Deserialize;
type SpamCheckResult = Result<(), error::Error>;
#[derive(Deserialize)]
struct SpamConfig {
blocklist: Option<String>,
blocking: Option<bool>,
}
#[derive(Deserialize)]
struct SFSEmailResponse {
value: String,
appears: usize,
}
#[derive(Deserialize)]
struct StopForumSpamJsonResponse {
success: u8,
email: SFSEmailResponse,
error: Option<String>,
}
static SPAM_CONFIG: Lazy<SpamConfig> = Lazy::new(|| SpamConfig {
blocking: match std::env::var("FORMULATE_SPAM_BLOCKING") {
Ok(config) => Some(config.to_lowercase().trim() == "true"),
Err(_) => None,
},
blocklist: match std::env::var("FORMULATE_SPAM_BLOCKLIST") {
Ok(list) => Some(list),
Err(_) => None,
},
});
pub async fn check_stop_forum_spam(form_email: &str, error_msg: &str) -> SpamCheckResult {
if SPAM_CONFIG.blocking.is_none() {
return Ok(());
}
if SPAM_CONFIG.blocking.unwrap() {
let sfs_api_url = format!("http://api.stopforumspam.org/api?email={form_email}&json");
let result = Client::new()
.post(&sfs_api_url)
.insert_header(("Content-Type", "application/x-www-form-urlencoded"))
.send()
.await;
if result.is_err() {
return Ok(());
}
let result = result.unwrap().json::<StopForumSpamJsonResponse>().await;
if result.is_err() {
return Ok(());
}
let result = result.unwrap();
if result.error.is_none()
&& result.success == 1
&& result.email.appears > 0
&& result.email.value.eq(form_email)
{
Err(error::ErrorBadRequest(error_msg.to_string()))
} else {
Ok(())
}
} else {
Ok(())
}
}
pub fn check_for_spam(form_message: &str, error_msg: &str) -> SpamCheckResult {
if SPAM_CONFIG.blocklist.is_some() {
let blocklist = SPAM_CONFIG.blocklist.as_ref().unwrap();
let domain_list = blocklist.trim().split(',').collect::<Vec<_>>();
let looks_like_spam = domain_list.iter().any(|url| form_message.contains(url));
if looks_like_spam {
return Err(error::ErrorBadRequest(error_msg.to_string()));
}
}
Ok(())
}