initial commit

This commit is contained in:
William Casarin 2024-07-07 22:29:29 -05:00
commit 24a1c0dfc2
15 changed files with 509 additions and 0 deletions

5
src/filters/mod.rs Normal file
View file

@ -0,0 +1,5 @@
mod rate_limit;
mod whitelist;
pub use rate_limit::RateLimit;
pub use whitelist::Whitelist;

54
src/filters/rate_limit.rs Normal file
View file

@ -0,0 +1,54 @@
use crate::{Action, InputMessage, NoteFilter, OutputMessage};
use serde::Deserialize;
use std::collections::HashMap;
use std::time::{Duration, Instant};
pub struct RateInfo {
pub last_note: Instant,
}
#[derive(Deserialize, Default)]
pub struct RateLimit {
pub notes_per_second: u64,
pub whitelist: Option<Vec<String>>,
#[serde(skip)]
pub sources: HashMap<String, RateInfo>,
}
impl NoteFilter for RateLimit {
fn filter_note(&mut self, msg: &InputMessage) -> OutputMessage {
if let Some(whitelist) = &self.whitelist {
if whitelist.contains(&msg.source_info) {
return OutputMessage::new(msg.event.id.clone(), Action::Accept, None);
}
}
if self.sources.contains_key(&msg.source_info) {
let now = Instant::now();
let entry = self.sources.get_mut(&msg.source_info).expect("impossiburu");
if now - entry.last_note < Duration::from_secs(self.notes_per_second) {
return OutputMessage::new(
msg.event.id.clone(),
Action::Reject,
Some("rate-limited: you are noting too fast".to_string()),
);
} else {
entry.last_note = Instant::now();
return OutputMessage::new(msg.event.id.clone(), Action::Accept, None);
}
} else {
self.sources.insert(
msg.source_info.to_owned(),
RateInfo {
last_note: Instant::now(),
},
);
return OutputMessage::new(msg.event.id.clone(), Action::Accept, None);
}
}
fn name(&self) -> &'static str {
"ratelimit"
}
}

26
src/filters/whitelist.rs Normal file
View file

@ -0,0 +1,26 @@
use crate::{Action, InputMessage, NoteFilter, OutputMessage};
use serde::Deserialize;
#[derive(Deserialize)]
pub struct Whitelist {
pub pubkeys: Vec<String>,
pub ips: Vec<String>,
}
impl NoteFilter for Whitelist {
fn filter_note(&mut self, msg: &InputMessage) -> OutputMessage {
if self.pubkeys.contains(&msg.event.pubkey) || self.ips.contains(&msg.source_info) {
OutputMessage::new(msg.event.id.clone(), Action::Accept, None)
} else {
OutputMessage::new(
msg.event.id.clone(),
Action::Reject,
Some("blocked: pubkey not on the whitelist".to_string()),
)
}
}
fn name(&self) -> &'static str {
"whitelist"
}
}