feat: log IP address for pending comments

This commit is contained in:
Pascal Engélibert 2022-12-04 15:45:52 +01:00
commit e710e6678f
Signed by: tuxmain
GPG key ID: 3504BC6D362F7DCA
6 changed files with 71 additions and 49 deletions

View file

@ -11,7 +11,7 @@ pub type Time = u64;
pub struct Dbs {
pub comment: Tree<CommentId, Comment>,
pub comment_approved: Tree<(TopicHash, Time, CommentId), ()>,
pub comment_pending: Tree<(TopicHash, Time, CommentId), ()>,
pub comment_pending: Tree<(TopicHash, Time, CommentId), Option<IpAddr>>,
/// client_addr -> (last_mutation, mutation_count)
pub client_mutation: Tree<IpAddr, (Time, u32)>,
}

View file

@ -3,7 +3,11 @@ use crate::{config::Config, db::*, queries::*};
use log::error;
use std::{net::IpAddr, str::FromStr};
pub fn new_pending_comment(comment: &Comment, dbs: &Dbs) -> Result<CommentId, sled::Error> {
pub fn new_pending_comment(
comment: &Comment,
addr: Option<IpAddr>,
dbs: &Dbs,
) -> Result<CommentId, sled::Error> {
let comment_id = CommentId::new();
dbs.comment.insert(&comment_id, comment)?;
dbs.comment_pending.insert(
@ -12,7 +16,7 @@ pub fn new_pending_comment(comment: &Comment, dbs: &Dbs) -> Result<CommentId, sl
comment.post_time,
comment_id.clone(),
),
&(),
&addr,
)?;
Ok(comment_id)
}
@ -47,16 +51,16 @@ pub fn remove_comment(comment_id: CommentId, dbs: &Dbs) -> Result<Option<Comment
Ok(None)
}
pub fn iter_comments_by_topic<'a>(
pub fn iter_comments_by_topic<'a, V: typed_sled::KV>(
topic_hash: TopicHash,
tree: &'a Tree<(TopicHash, Time, CommentId), ()>,
tree: &'a Tree<(TopicHash, Time, CommentId), V>,
dbs: &'a Dbs,
) -> impl Iterator<Item = (CommentId, Comment)> + 'a {
) -> impl Iterator<Item = (CommentId, Comment, V)> + 'a {
tree.range(
(topic_hash.clone(), 0, CommentId::zero())..=(topic_hash, Time::MAX, CommentId::max()),
)
.filter_map(|entry| {
let ((_topic_hash, _time, comment_id), ()) = entry
let ((_topic_hash, _time, comment_id), val) = entry
.map_err(|e| error!("Reading comment_by_topic_and_time: {:?}", e))
.ok()?;
let comment = dbs
@ -68,7 +72,7 @@ pub fn iter_comments_by_topic<'a>(
error!("Comment not found");
None
})?;
Some((comment_id, comment))
Some((comment_id, comment, val))
})
}
@ -77,12 +81,13 @@ pub fn iter_approved_comments_by_topic(
dbs: &Dbs,
) -> impl Iterator<Item = (CommentId, Comment)> + '_ {
iter_comments_by_topic(topic_hash, &dbs.comment_approved, dbs)
.map(|(comment_id, comment, ())| (comment_id, comment))
}
pub fn iter_pending_comments_by_topic(
topic_hash: TopicHash,
dbs: &Dbs,
) -> impl Iterator<Item = (CommentId, Comment)> + '_ {
) -> impl Iterator<Item = (CommentId, Comment, Option<IpAddr>)> + '_ {
iter_comments_by_topic(topic_hash, &dbs.comment_pending, dbs)
}

View file

@ -126,7 +126,8 @@ async fn serve_comments<'a>(
context.insert(
"comments_pending",
&helpers::iter_pending_comments_by_topic(topic_hash.clone(), &dbs)
.map(|(comment_id, comment)| CommentWithId {
.map(|(comment_id, comment, addr)| CommentWithId {
addr: addr.map(|addr| addr.to_string()),
author: comment.author,
editable: admin,
id: comment_id.to_base64(),
@ -142,6 +143,7 @@ async fn serve_comments<'a>(
"comments",
&helpers::iter_approved_comments_by_topic(topic_hash, &dbs)
.map(|(comment_id, comment)| CommentWithId {
addr: None,
author: comment.author,
editable: admin,
id: comment_id.to_base64(),
@ -186,7 +188,7 @@ async fn serve_admin<'a>(
&dbs.comment_pending
.iter()
.filter_map(|entry| {
let ((_topic_hash, _time, comment_id), ()) = entry
let ((_topic_hash, _time, comment_id), addr) = entry
.map_err(|e| error!("Reading comment_pending: {:?}", e))
.ok()?;
let comment = dbs
@ -199,6 +201,7 @@ async fn serve_admin<'a>(
None
})?;
Some(CommentWithId {
addr: addr.map(|addr| addr.to_string()),
author: comment.author,
editable: true,
id: comment_id.to_base64(),
@ -257,27 +260,22 @@ async fn handle_post_comments(
let client_langs = get_client_langs(&req);
let client_addr = if !admin && config.antispam_enable {
match helpers::get_client_addr(config, &req) {
Some(Ok(addr)) => {
if config.antispam_whitelist.contains(&addr) {
None
} else {
Some(addr)
}
}
Some(Err(e)) => {
warn!("Unable to parse client addr: {}", e);
None
}
None => {
warn!("No client addr");
None
}
let client_addr = match helpers::get_client_addr(config, &req) {
Some(Ok(addr)) => Some(addr),
Some(Err(e)) => {
warn!("Unable to parse client addr: {}", e);
None
}
None => {
warn!("No client addr");
None
}
} else {
None
};
let antispam_enabled = !admin
&& config.antispam_enable
&& client_addr
.as_ref()
.map_or(false, |addr| !config.antispam_whitelist.contains(addr));
let mut errors = Vec::new();
let mut context = Context::new();
@ -291,28 +289,32 @@ async fn handle_post_comments(
helpers::check_comment(config, &query.comment, &mut errors);
if let Some(client_addr) = &client_addr {
if let Some(antispam_timeout) =
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap()
{
errors.push(
locales
.tr(
&client_langs,
"error-antispam",
Some(&FluentArgs::from_iter([(
"antispam_timeout",
antispam_timeout,
)])),
)
.unwrap()
.into_owned(),
);
if antispam_enabled {
if let Some(antispam_timeout) =
helpers::antispam_check_client_mutation(client_addr, &dbs, config).unwrap()
{
errors.push(
locales
.tr(
&client_langs,
"error-antispam",
Some(&FluentArgs::from_iter([(
"antispam_timeout",
antispam_timeout,
)])),
)
.unwrap()
.into_owned(),
);
}
}
}
if errors.is_empty() {
if let Some(client_addr) = &client_addr {
helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap();
if antispam_enabled {
helpers::antispam_update_client_mutation(client_addr, &dbs).unwrap();
}
}
let topic_hash = TopicHash::from_topic(topic);
@ -338,7 +340,7 @@ async fn handle_post_comments(
post_time: time,
text: query.comment.text,
};
helpers::new_pending_comment(&comment, &dbs)
helpers::new_pending_comment(&comment, client_addr, &dbs)
.map_err(|e| error!("Adding pending comment: {:?}", e))
.ok();
notify_send

View file

@ -37,6 +37,7 @@ impl Templates {
#[derive(Clone, Debug, Serialize)]
pub struct CommentWithId {
pub addr: Option<String>,
pub author: String,
pub editable: bool,
pub id: String,