darkirc: Implement user modes and set +v for encrypted messages.

This commit is contained in:
parazyd
2023-07-19 18:23:32 +02:00
parent 3c24d42f0e
commit d5b4cd9645
4 changed files with 111 additions and 12 deletions

View File

@@ -93,7 +93,7 @@ pub fn decrypt_target(
}
if let Some(salt_box) = &chan_info.salt_box {
let decrypted_target = try_decrypt(&salt_box, &privmsg.target);
let decrypted_target = try_decrypt(salt_box, &privmsg.target);
if decrypted_target.is_none() {
continue
}
@@ -111,7 +111,7 @@ pub fn decrypt_target(
let cnt_info = configured_contacts.get(cnt_name).unwrap();
if let Some(salt_box) = &cnt_info.salt_box {
let decrypted_target = try_decrypt(&salt_box, &privmsg.target);
let decrypted_target = try_decrypt(salt_box, &privmsg.target);
if decrypted_target.is_none() {
continue
}

View File

@@ -35,7 +35,7 @@ use darkfi::{
use crate::{
crypto::{decrypt_privmsg, decrypt_target, encrypt_privmsg},
settings,
settings::RPL,
settings::{Nick, UserMode, RPL},
ChannelInfo, PrivMsgEvent,
};
@@ -152,15 +152,29 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
return Ok(())
}
let mut encrypted = false;
if let Some(salt_box) = &chan_info.salt_box {
decrypt_privmsg(salt_box, &mut msg);
encrypted = true;
debug!("[P2P] Decrypted received message: {:?}", msg);
}
// add the nickname to the channel's names
if !chan_info.names.contains(&msg.nick) {
chan_info.names.push(msg.nick.clone());
}
// Add the nickname to the channel's names
let mut nick: Nick = msg.nick.clone().into();
let _mode_change = if chan_info.names.contains(&nick) {
let mut n = chan_info.names.get(&nick).unwrap().clone();
let mode_change = if encrypted {
n.set_mode(UserMode::Voice)
} else {
n.unset_mode(UserMode::Voice)
};
chan_info.names.insert(n);
mode_change
} else {
let mode_change = if encrypted { nick.set_mode(UserMode::Voice) } else { None };
chan_info.names.insert(nick);
mode_change
};
self.reply(&msg.to_string()).await?;
} else if self.irc_config.is_cap_end && self.irc_config.is_nick_init {
@@ -453,7 +467,7 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
self.irc_config.nickname,
RPL::NameReply as u32,
chan,
chan_info.names.join(" ")
chan_info.names()
);
self.reply(&names_reply).await?;

View File

@@ -20,7 +20,7 @@ use async_std::sync::Arc;
use crypto_box::ChaChaBox;
use log::{info, warn};
use serde::{self, Deserialize};
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use structopt::StructOpt;
use structopt_toml::StructOptToml;
use toml::Value;
@@ -119,6 +119,86 @@ impl ContactInfo {
}
}
/// Defined user modes
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
pub enum UserMode {
None,
Op,
Voice,
HalfOp,
Admin,
Owner,
}
impl std::fmt::Display for UserMode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
match self {
Self::None => write!(f, ""),
Self::Op => write!(f, "@"),
Self::Voice => write!(f, "+"),
Self::HalfOp => write!(f, "%"),
Self::Admin => write!(f, "&"),
Self::Owner => write!(f, "~"),
}
}
}
/// This struct holds info about a specific nickname within a channel.
/// We usually use it to implement modes.
#[derive(Debug, Clone, Eq)]
pub struct Nick {
name: String,
mode: UserMode,
}
impl Nick {
pub fn new(name: String) -> Self {
Self { name, mode: UserMode::None }
}
pub fn set_mode(&mut self, mode: UserMode) -> Option<String> {
if self.mode == mode {
return None
}
self.mode = mode;
Some(format!("+{}", mode))
}
pub fn unset_mode(&mut self, mode: UserMode) -> Option<String> {
if self.mode != mode {
return None
}
self.mode = mode;
Some(format!("-{}", mode))
}
}
impl PartialEq for Nick {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
}
}
impl From<String> for Nick {
fn from(name: String) -> Self {
Self { name, mode: UserMode::None }
}
}
impl std::hash::Hash for Nick {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
state.write(&self.name.clone().into_bytes());
}
}
impl std::fmt::Display for Nick {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
write!(f, "{}{}", self.mode, self.name)
}
}
/// This struct holds information about preconfigured channels.
/// In the TOML configuration file, we can configure channels as such:
/// ```toml
@@ -141,12 +221,16 @@ pub struct ChannelInfo {
/// Flag indicates whether the user has joined the channel or not
pub joined: bool,
/// All nicknames which are visible on the channel
pub names: Vec<String>,
pub names: HashSet<Nick>,
}
impl ChannelInfo {
pub fn new() -> Result<Self> {
Ok(Self { topic: None, salt_box: None, joined: false, names: vec![] })
Ok(Self { topic: None, salt_box: None, joined: false, names: HashSet::new() })
}
pub fn names(&self) -> String {
self.names.iter().map(|n| n.to_string()).collect::<Vec<String>>().join(" ")
}
}

View File

@@ -70,7 +70,8 @@ impl RngCore for Pcg32 {
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
Ok(self.fill_bytes(dest))
self.fill_bytes(dest);
Ok(())
}
}