Sanitize messages later to stop the problematic round-trip parsing.
This commit is contained in:
parent
221997007f
commit
7680227222
2 changed files with 26 additions and 26 deletions
|
@ -243,12 +243,9 @@ impl<'a> Client for ClientState {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send<M: Into<Message>>(&self, msg: M) -> error::Result<()> where Self: Sized {
|
fn send<M: Into<Message>>(&self, msg: M) -> error::Result<()> where Self: Sized {
|
||||||
let msg = &msg.into();
|
let msg = msg.into();
|
||||||
self.handle_sent_message(msg)?;
|
self.handle_sent_message(&msg)?;
|
||||||
Ok((&self.outgoing).unbounded_send(
|
Ok(self.outgoing.unbounded_send(msg)?)
|
||||||
ClientState::sanitize(&msg.to_string())
|
|
||||||
.into(),
|
|
||||||
)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stream(&self) -> ClientStream {
|
fn stream(&self) -> ClientStream {
|
||||||
|
@ -302,22 +299,6 @@ impl ClientState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sanitizes the input string by cutting up to (and including) the first occurence of a line
|
|
||||||
/// terminiating phrase (`\r\n`, `\r`, or `\n`). This is used in sending messages back to
|
|
||||||
/// prevent the injection of additional commands.
|
|
||||||
fn sanitize(data: &str) -> &str {
|
|
||||||
// n.b. ordering matters here to prefer "\r\n" over "\r"
|
|
||||||
if let Some((pos, len)) = ["\r\n", "\r", "\n"]
|
|
||||||
.iter()
|
|
||||||
.flat_map(|needle| data.find(needle).map(|pos| (pos, needle.len())))
|
|
||||||
.min_by_key(|&(pos, _)| pos)
|
|
||||||
{
|
|
||||||
data.split_at(pos + len).0
|
|
||||||
} else {
|
|
||||||
data
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the current nickname in use.
|
/// Gets the current nickname in use.
|
||||||
fn current_nickname(&self) -> &str {
|
fn current_nickname(&self) -> &str {
|
||||||
let alt_nicks = self.config().alternate_nicknames();
|
let alt_nicks = self.config().alternate_nicknames();
|
||||||
|
@ -865,7 +846,7 @@ mod test {
|
||||||
use client::data::Config;
|
use client::data::Config;
|
||||||
#[cfg(not(feature = "nochanlists"))]
|
#[cfg(not(feature = "nochanlists"))]
|
||||||
use client::data::User;
|
use client::data::User;
|
||||||
use proto::{ChannelMode, Mode};
|
use proto::{ChannelMode, IrcCodec, Mode};
|
||||||
use proto::command::Command::{PART, PRIVMSG};
|
use proto::command::Command::{PART, PRIVMSG};
|
||||||
|
|
||||||
pub fn test_config() -> Config {
|
pub fn test_config() -> Config {
|
||||||
|
@ -886,7 +867,10 @@ mod test {
|
||||||
// We can't guarantee that everything will have been sent by the time of this call.
|
// We can't guarantee that everything will have been sent by the time of this call.
|
||||||
thread::sleep(Duration::from_millis(100));
|
thread::sleep(Duration::from_millis(100));
|
||||||
client.log_view().sent().unwrap().iter().fold(String::new(), |mut acc, msg| {
|
client.log_view().sent().unwrap().iter().fold(String::new(), |mut acc, msg| {
|
||||||
acc.push_str(&msg.to_string());
|
// NOTE: we have to sanitize here because sanitization happens in IrcCodec after the
|
||||||
|
// messages are converted into strings, but our transport logger catches messages before
|
||||||
|
// they ever reach that point.
|
||||||
|
acc.push_str(&IrcCodec::sanitize(msg.to_string()));
|
||||||
acc
|
acc
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,22 @@ impl IrcCodec {
|
||||||
pub fn new(label: &str) -> error::Result<IrcCodec> {
|
pub fn new(label: &str) -> error::Result<IrcCodec> {
|
||||||
LineCodec::new(label).map(|codec| IrcCodec { inner: codec })
|
LineCodec::new(label).map(|codec| IrcCodec { inner: codec })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sanitizes the input string by cutting up to (and including) the first occurence of a line
|
||||||
|
/// terminiating phrase (`\r\n`, `\r`, or `\n`). This is used in sending messages back to
|
||||||
|
/// prevent the injection of additional commands.
|
||||||
|
pub(crate) fn sanitize(mut data: String) -> String {
|
||||||
|
// n.b. ordering matters here to prefer "\r\n" over "\r"
|
||||||
|
if let Some((pos, len)) = ["\r\n", "\r", "\n"]
|
||||||
|
.iter()
|
||||||
|
.flat_map(|needle| data.find(needle).map(|pos| (pos, needle.len())))
|
||||||
|
.min_by_key(|&(pos, _)| pos)
|
||||||
|
{
|
||||||
|
data.truncate(pos + len);
|
||||||
|
}
|
||||||
|
data
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Decoder for IrcCodec {
|
impl Decoder for IrcCodec {
|
||||||
|
@ -35,6 +51,6 @@ impl Encoder for IrcCodec {
|
||||||
|
|
||||||
|
|
||||||
fn encode(&mut self, msg: Message, dst: &mut BytesMut) -> error::Result<()> {
|
fn encode(&mut self, msg: Message, dst: &mut BytesMut) -> error::Result<()> {
|
||||||
self.inner.encode(msg.to_string(), dst)
|
self.inner.encode(IrcCodec::sanitize(msg.to_string()), dst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue