added outbound filter

serve
Avril 4 years ago
parent 2f9f4dbb3a
commit 988829c9b9
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -1,6 +1,6 @@
[package] [package]
name = "markov" name = "markov"
version = "0.6.0" version = "0.6.1"
description = "Generate string of text from Markov chain fed by stdin" description = "Generate string of text from Markov chain fed by stdin"
authors = ["Avril <flanchan@cumallover.me>"] authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018" edition = "2018"

@ -6,4 +6,5 @@ max_gen_size = 256
trust_x_forwarded_for = false trust_x_forwarded_for = false
[filter] [filter]
exclude = "<>)([]/" inbound = "<>)([]/"
outbound = "*"

@ -32,18 +32,28 @@ pub struct Config
#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Hash, Serialize, Deserialize)]
pub struct FilterConfig pub struct FilterConfig
{ {
exclude: String, inbound: String,
#[serde(default)]
outbound: String,
} }
impl FilterConfig impl FilterConfig
{ {
pub fn get_filter(&self) -> sanitise::filter::Filter pub fn get_inbound_filter(&self) -> sanitise::filter::Filter
{
let filt: sanitise::filter::Filter = self.inbound.parse().unwrap();
if !filt.is_empty()
{
info!("Loaded inbound filter: {:?}", filt.iter().collect::<String>());
}
filt
}
pub fn get_outbound_filter(&self) -> sanitise::filter::Filter
{ {
let filt: sanitise::filter::Filter = self.exclude.parse().unwrap(); let filt: sanitise::filter::Filter = self.outbound.parse().unwrap();
if !filt.is_empty() if !filt.is_empty()
{ {
warn!("Loaded exclude filter: {:?}", filt.iter().collect::<String>()); info!("Loaded outbound filter: {:?}", filt.iter().collect::<String>());
} }
filt filt
} }

@ -1,6 +1,7 @@
//! Extensions //! Extensions
use std::{ use std::{
iter, iter,
ops::Range,
}; };
pub trait StringJoinExt: Sized pub trait StringJoinExt: Sized
@ -25,3 +26,71 @@ where I: IntoIterator<Item=T>,
string string
} }
} }
pub trait FindSliceBounds
{
type SliceType: ?Sized;
fn slice_bounds(&self, from: &Self::SliceType) -> Range<usize>;
}
impl<T: ?Sized + AsRef<str>> FindSliceBounds for T
{
type SliceType = str;
fn slice_bounds(&self, from: &Self::SliceType) -> Range<usize>{
let this = self.as_ref();
unsafe {
let sptr = from.as_ptr();
let eptr = sptr.add(from.len());
let ssptr = this.as_ptr();
let septr = ssptr.add(this.len());
let sptr = sptr as usize;
let ssptr = ssptr as usize;
let eptr = eptr as usize;
let septr = septr as usize;
assert!(sptr >= ssptr && sptr <= septr, "Start index of slice is outside the bounds of self");
assert!(eptr >= ssptr && eptr <= septr, "End index of slice is outside the bounds of self");
(sptr - ssptr)..(eptr - ssptr)
}
}
}
pub trait SliceInPlace
{
fn drain_inverse<R: std::ops::RangeBounds<usize>>(&mut self, slice: R);
}
impl SliceInPlace for String
{
fn drain_inverse<R: std::ops::RangeBounds<usize>>(&mut self, slice: R)
{
use std::ops::Bound;
match slice.end_bound() {
Bound::Excluded(&ex) => drop(self.drain(ex..)),
Bound::Included(&inc) => drop(self.drain(inc+1..)),
_ => (),
};
match slice.start_bound() {
Bound::Included(&ex) => drop(self.drain(..ex)),
Bound::Excluded(&ex) => drop(..ex+1),
_ => ()
};
}
}
pub trait TrimInPlace
{
fn trim_in_place(&mut self) -> &mut Self;
}
impl TrimInPlace for String
{
fn trim_in_place(&mut self) -> &mut Self {
let bounds = self.slice_bounds(self.trim());
self.drain_inverse(bounds);
self
}
}

@ -69,7 +69,7 @@ pub async fn full(who: &IpAddr, state: State, body: impl Unpin + Stream<Item = R
} }
} }
let buffer = std::str::from_utf8(&buffer[..]).map_err(|_| FillBodyError)?; let buffer = std::str::from_utf8(&buffer[..]).map_err(|_| FillBodyError)?;
let buffer = state.filter().filter_cow(buffer); let buffer = state.inbound_filter().filter_cow(buffer);
info!("{} -> {:?}", who, buffer); info!("{} -> {:?}", who, buffer);
let mut chain = state.chain().write().await; let mut chain = state.chain().write().await;
cfg_if! { cfg_if! {
@ -92,7 +92,7 @@ pub async fn full(who: &IpAddr, state: State, body: impl Unpin + Stream<Item = R
#[cfg(feature="hog-buffer")] #[cfg(feature="hog-buffer")]
let mut chain = state.chain().write().await; let mut chain = state.chain().write().await;
while let Some(line) = lines.next_line().await.map_err(|_| FillBodyError)? { while let Some(line) = lines.next_line().await.map_err(|_| FillBodyError)? {
let line = state.filter().filter_cow(&line); let line = state.inbound_filter().filter_cow(&line);
let line = line.trim(); let line = line.trim();
if !line.is_empty() { if !line.is_empty() {
#[cfg(not(feature="hog-buffer"))] #[cfg(not(feature="hog-buffer"))]

@ -18,14 +18,15 @@ pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<Str
{ {
let chain = state.chain().read().await; let chain = state.chain().read().await;
if !chain.is_empty() { if !chain.is_empty() {
let filter = state.outbound_filter();
match num { match num {
Some(num) if num < state.config().max_gen_size => { Some(num) if num < state.config().max_gen_size => {
//This could DoS `full_body` and writes, potentially. //This could DoS `full_body` and writes, potentially.
for string in chain.str_iter_for(num) { for string in chain.str_iter_for(num) {
output.send(string).await.map_err(|e| GenBodyError(e.0))?; output.send(filter.filter_owned(string)).await.map_err(|e| GenBodyError(e.0))?;
} }
}, },
_ => output.send(chain.generate_str()).await.map_err(|e| GenBodyError(e.0))?, _ => output.send(filter.filter_owned(chain.generate_str())).await.map_err(|e| GenBodyError(e.0))?,
} }
} }
Ok(()) Ok(())

@ -195,9 +195,14 @@ async fn main() {
async move { async move {
let (tx, rx) = mpsc::channel(state.config().max_gen_size); let (tx, rx) = mpsc::channel(state.config().max_gen_size);
tokio::spawn(gen::body(state, num, tx)); tokio::spawn(gen::body(state, num, tx));
Ok::<_, std::convert::Infallible>(Response::new(Body::wrap_stream(rx.map(move |x| { Ok::<_, std::convert::Infallible>(Response::new(Body::wrap_stream(rx.filter_map(move |mut x| {
info!("{} <- {:?}", host, x); if x.trim_in_place().len() != 0 {
Ok::<_, std::convert::Infallible>(x) info!("{} <- {:?}", host, x);
x.push('\n');
Some(Ok::<_, std::convert::Infallible>(x))
} else {
None
}
})))) }))))
} }
}) })
@ -213,16 +218,14 @@ async fn main() {
async move { async move {
let (tx, rx) = mpsc::channel(state.config().max_gen_size); let (tx, rx) = mpsc::channel(state.config().max_gen_size);
tokio::spawn(sentance::body(state, num, tx)); tokio::spawn(sentance::body(state, num, tx));
Ok::<_, std::convert::Infallible>(Response::new(Body::wrap_stream(rx.map(move |mut x| { Ok::<_, std::convert::Infallible>(Response::new(Body::wrap_stream(rx.filter_map(move |mut x| {
info!("{} (sentance) <- {:?}", host, x); if x.trim_in_place().len() != 0 {
// match x.chars().last() { info!("{} (sentance) <- {:?}", host, x);
// Some(chr) if sanitise::is_sentance_boundary(chr) => { x.push(' ');
// x.push(' '); Some(Ok::<_, std::convert::Infallible>(x))
// }, } else {
// _ => (), None
// } }
x.push(' ');
Ok::<_, std::convert::Infallible>(x)
})))) }))))
} }
}) })

@ -133,7 +133,23 @@ impl Filter
self.0.get(&chr).is_some() self.0.get(&chr).is_some()
} }
pub fn filter<'a, I: IntoIterator<Item=char>>(&'a self, from_iter: I) -> FilterIter<'a, I::IntoIter> pub fn filter_owned(&self, input: impl Into<String>) -> String
{
let mut input = input.into();
self.filter(&mut input);
input
}
pub fn filter<'a>(&self, output: &'a mut String) -> &'a mut String
{
if self.is_empty() {
return output;
}
output.retain(|chr| !self.check(chr));
output
}
pub fn filter_iter<'a, I: IntoIterator<Item=char>>(&'a self, from_iter: I) -> FilterIter<'a, I::IntoIter>
where I::IntoIter: 'a where I::IntoIter: 'a
{ {
FilterIter(&self, from_iter.into_iter().fuse()) FilterIter(&self, from_iter.into_iter().fuse())

@ -16,9 +16,10 @@ pub async fn body(state: State, num: Option<usize>, mut output: mpsc::Sender<Str
}; };
debug!("Taking {:?} from {:?}" ,num, string); debug!("Taking {:?} from {:?}" ,num, string);
let filter = state.outbound_filter();
for sen in sanitise::Sentance::new_iter(&string).take(num.unwrap_or(1)) for sen in sanitise::Sentance::new_iter(&string).take(num.unwrap_or(1))
{ {
output.send(sen.to_owned()).await.map_err(|e| gen::GenBodyError(e.0))?; output.send(filter.filter_owned(sen.to_owned())).await.map_err(|e| gen::GenBodyError(e.0))?;
} }
Ok(()) Ok(())
} }

@ -11,7 +11,7 @@ use config::Config;
pub struct State pub struct State
{ {
config: Arc<Config>, //to avoid cloning config config: Arc<Config>, //to avoid cloning config
exclude: Arc<sanitise::filter::Filter>, exclude: Arc<(sanitise::filter::Filter, sanitise::filter::Filter)>,
chain: Arc<RwLock<Chain<String>>>, chain: Arc<RwLock<Chain<String>>>,
save: Arc<Notify>, save: Arc<Notify>,
@ -21,16 +21,21 @@ pub struct State
impl State impl State
{ {
pub fn filter(&self) -> &sanitise::filter::Filter pub fn inbound_filter(&self) -> &sanitise::filter::Filter
{ {
&self.exclude &self.exclude.0
}
pub fn outbound_filter(&self) -> &sanitise::filter::Filter
{
&self.exclude.1
} }
pub fn new(config: Config, chain: Arc<RwLock<Chain<String>>>, save: Arc<Notify>) -> Self pub fn new(config: Config, chain: Arc<RwLock<Chain<String>>>, save: Arc<Notify>) -> Self
{ {
let (shutdown, shutdown_recv) = watch::channel(false); let (shutdown, shutdown_recv) = watch::channel(false);
Self { Self {
exclude: Arc::new(config.filter.get_filter()), exclude: Arc::new((config.filter.get_inbound_filter(),
config.filter.get_outbound_filter())),
config: Arc::new(config), config: Arc::new(config),
chain, chain,
save, save,

Loading…
Cancel
Save