Skip to content

Commit

Permalink
darkirc: upgrade privmsg, added the logic of deserializing old and ne…
Browse files Browse the repository at this point in the history
…w versions

but old version will still be used to send, this should insure compatibility
after some time after enough nodes have upgraded we can switch to send new
  • Loading branch information
dasman committed Nov 20, 2024
1 parent 1288300 commit ef3ebc5
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 22 deletions.
20 changes: 14 additions & 6 deletions bin/darkirc/src/irc/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ use darkfi::{
system::Subscription,
Error, Result,
};
use darkfi_serial::{deserialize_async_partial, serialize_async};
use darkfi_serial::serialize_async;
use futures::FutureExt;
use log::{debug, error, warn};
use sled_overlay::sled;
Expand All @@ -42,7 +42,7 @@ use smol::{

use super::{
server::{IrcServer, MAX_MSG_LEN, MAX_NICK_LEN},
NickServ, Privmsg, SERVER_NAME,
Msg, NickServ, OldPrivmsg, SERVER_NAME,
};

const PENALTY_LIMIT: usize = 5;
Expand Down Expand Up @@ -228,8 +228,9 @@ impl Client {
}

// Try to deserialize the `Event`'s content into a `Privmsg`
let mut privmsg: Privmsg = match deserialize_async_partial(r.content()).await {
Ok((v, _)) => v,
let mut privmsg = match Msg::deserialize(r.content()).await {
Ok(Msg::V1(old_msg)) => old_msg.into_new(),
Ok(Msg::V2(new_msg)) => new_msg,
Err(e) => {
error!("[IRC CLIENT] Failed deserializing incoming Privmsg event: {}", e);
continue
Expand Down Expand Up @@ -432,8 +433,15 @@ impl Client {

// Truncate messages longer than MAX_MSG_LEN
let msg = if msg.len() > MAX_MSG_LEN { msg.split_at(MAX_MSG_LEN).0 } else { msg };
let mut privmsg =
Privmsg { channel, nick: self.nickname.read().await.to_string(), msg: msg.to_string() };

// TODO: This is kept as old version of privmsg, since now we
// can deserialize both old and new versions, after some time
// this will be replaced with Privmsg (new version)
let mut privmsg = OldPrivmsg {
channel,
nick: self.nickname.read().await.to_string(),
msg: msg.to_string(),
};

// Encrypt the Privmsg if an encryption method is available.
self.server.try_encrypt(&mut privmsg).await;
Expand Down
9 changes: 5 additions & 4 deletions bin/darkirc/src/irc/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,13 @@
use std::{collections::HashSet, sync::atomic::Ordering::SeqCst};

use darkfi::Result;
use darkfi_serial::deserialize_async_partial;
use log::{error, info};

use super::{
client::{Client, ReplyType},
rpl::*,
server::MAX_NICK_LEN,
IrcChannel, SERVER_NAME,
IrcChannel, Msg, SERVER_NAME,
};
use crate::crypto::bcrypt::bcrypt_hash_password;

Expand Down Expand Up @@ -978,8 +977,10 @@ impl Client {
}

// Try to deserialize it. (Here we skip errors)
let Ok((mut privmsg, _)) = deserialize_async_partial(event.content()).await else {
continue
let mut privmsg = match Msg::deserialize(event.content()).await {
Ok(Msg::V1(old_msg)) => old_msg.into_new(),
Ok(Msg::V2(new_msg)) => new_msg,
Err(_) => continue,
};

// Potentially decrypt the privmsg
Expand Down
81 changes: 79 additions & 2 deletions bin/darkirc/src/irc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
use std::{collections::HashSet, sync::Arc};

use crypto_box::ChaChaBox;
use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
use darkfi::{Error, Result};
use darkfi_serial::{async_trait, deserialize_async_partial, SerialDecodable, SerialEncodable};

/// IRC client state
pub(crate) mod client;
Expand All @@ -40,14 +41,90 @@ pub(crate) mod rpl;
/// Hardcoded server name
const SERVER_NAME: &str = "irc.dark.fi";

/// IRC PRIVMSG
pub trait Priv {
fn channel(&mut self) -> &mut String;
fn nick(&mut self) -> &mut String;
fn msg(&mut self) -> &mut String;
}

/// IRC PRIVMSG (old version)
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct OldPrivmsg {
pub channel: String,
pub nick: String,
pub msg: String,
}

impl OldPrivmsg {
pub fn into_new(&self) -> Privmsg {
Privmsg {
version: 0,
msg_type: 0,
channel: self.channel.clone(),
nick: self.nick.clone(),
msg: self.msg.clone(),
}
}
}

/// IRC PRIVMSG (new version)
#[derive(Clone, Debug, SerialEncodable, SerialDecodable)]
pub struct Privmsg {
pub version: u8,
pub msg_type: u8,
pub channel: String,
pub nick: String,
pub msg: String,
}

impl Priv for OldPrivmsg {
fn channel(&mut self) -> &mut String {
&mut self.channel
}

fn nick(&mut self) -> &mut String {
&mut self.nick
}

fn msg(&mut self) -> &mut String {
&mut self.msg
}
}
impl Priv for Privmsg {
fn channel(&mut self) -> &mut String {
&mut self.channel
}

fn nick(&mut self) -> &mut String {
&mut self.nick
}

fn msg(&mut self) -> &mut String {
&mut self.msg
}
}

pub enum Msg {
V1(OldPrivmsg),
V2(Privmsg),
}

impl Msg {
pub async fn deserialize(bytes: &[u8]) -> Result<Self> {
let old_privmsg = deserialize_async_partial(bytes).await;
if let Ok((old_msg, _)) = old_privmsg {
return Ok(Msg::V1(old_msg))
}

let new_privmsg = deserialize_async_partial(bytes).await;
if let Ok((new_msg, _)) = new_privmsg {
return Ok(Msg::V2(new_msg))
}

Err(Error::Custom("Unknown message format".into()))
}
}

/// IRC channel definition
#[derive(Clone)]
pub struct IrcChannel {
Expand Down
20 changes: 10 additions & 10 deletions bin/darkirc/src/irc/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use smol::{
};
use url::Url;

use super::{client::Client, IrcChannel, IrcContact, Privmsg};
use super::{client::Client, IrcChannel, IrcContact, Priv, Privmsg};
use crate::{
crypto::saltbox,
settings::{parse_autojoin_channels, parse_configured_channels, parse_configured_contacts},
Expand Down Expand Up @@ -282,24 +282,24 @@ impl IrcServer {
}

/// Try encrypting a given `Privmsg` if there is such a channel/contact.
pub async fn try_encrypt(&self, privmsg: &mut Privmsg) {
if let Some((name, channel)) = self.channels.read().await.get_key_value(&privmsg.channel) {
pub async fn try_encrypt<T: Priv>(&self, privmsg: &mut T) {
if let Some((name, channel)) = self.channels.read().await.get_key_value(privmsg.channel()) {
if let Some(saltbox) = &channel.saltbox {
// We will pad the name and nick to MAX_NICK_LEN so they all look the same.
privmsg.channel = saltbox::encrypt(saltbox, &Self::pad(&privmsg.channel));
privmsg.nick = saltbox::encrypt(saltbox, &Self::pad(&privmsg.nick));
privmsg.msg = saltbox::encrypt(saltbox, privmsg.msg.as_bytes());
*privmsg.channel() = saltbox::encrypt(saltbox, &Self::pad(privmsg.channel()));
*privmsg.nick() = saltbox::encrypt(saltbox, &Self::pad(privmsg.nick()));
*privmsg.msg() = saltbox::encrypt(saltbox, privmsg.msg().as_bytes());
debug!("Successfully encrypted message for {}", name);
return
}
};

if let Some((name, contact)) = self.contacts.read().await.get_key_value(&privmsg.channel) {
if let Some((name, contact)) = self.contacts.read().await.get_key_value(privmsg.channel()) {
if let Some(saltbox) = &contact.saltbox {
// We will pad the nicks to MAX_NICK_LEN so they all look the same.
privmsg.channel = saltbox::encrypt(saltbox, &Self::pad(&privmsg.channel));
privmsg.nick = saltbox::encrypt(saltbox, &Self::pad(&privmsg.nick));
privmsg.msg = saltbox::encrypt(saltbox, privmsg.msg.as_bytes());
*privmsg.channel() = saltbox::encrypt(saltbox, &Self::pad(privmsg.channel()));
*privmsg.nick() = saltbox::encrypt(saltbox, &Self::pad(privmsg.nick()));
*privmsg.msg() = saltbox::encrypt(saltbox, privmsg.msg().as_bytes());
debug!("Successfully encrypted message for {}", name);
}
};
Expand Down

0 comments on commit ef3ebc5

Please sign in to comment.