Преглед изворни кода

darkirc/irc: told you that I can fix her

skoupidi пре 1 година
родитељ
комит
561e74074b

+ 1 - 1
bin/darkirc/src/irc/client.rs

@@ -238,7 +238,7 @@ impl Client {
                     };
 
                     // If successful, potentially decrypt it:
-                    self.server.try_decrypt(&mut privmsg).await;
+                    self.server.try_decrypt(&mut privmsg, self.nickname.read().await.as_ref()).await;
 
                     // We should skip any attempts to contact services from the network.
                     if ["nickserv", "chanserv"].contains(&privmsg.nick.to_lowercase().as_str()) {

+ 1 - 1
bin/darkirc/src/irc/command.rs

@@ -984,7 +984,7 @@ impl Client {
             };
 
             // Potentially decrypt the privmsg
-            self.server.try_decrypt(&mut privmsg).await;
+            self.server.try_decrypt(&mut privmsg, self.nickname.read().await.as_ref()).await;
 
             // If the privmsg is intented for any of the given
             // channels, contacts or oursleves, add it as a reply and

+ 27 - 8
bin/darkirc/src/irc/server.rs

@@ -38,7 +38,7 @@ use smol::{
 };
 use url::Url;
 
-use super::{client::Client, IrcChannel, IrcContact, Priv, Privmsg};
+use super::{client::Client, ChaChaBox, IrcChannel, IrcContact, Priv, Privmsg};
 use crate::{
     crypto::saltbox,
     settings::{parse_autojoin_channels, parse_configured_channels, parse_configured_contacts},
@@ -67,6 +67,8 @@ pub struct IrcServer {
     pub channels: RwLock<HashMap<String, IrcChannel>>,
     /// Configured IRC contacts
     pub contacts: RwLock<HashMap<String, IrcContact>>,
+    /// Saltbox used to encrypt our nick in direct messages
+    saltbox: RwLock<Option<Arc<ChaChaBox>>>,
     /// Active client connections
     clients: Mutex<HashMap<u16, StoppableTaskPtr>>,
     /// IRC server Password
@@ -133,6 +135,7 @@ impl IrcServer {
             autojoin: RwLock::new(Vec::new()),
             channels: RwLock::new(HashMap::new()),
             contacts: RwLock::new(HashMap::new()),
+            saltbox: RwLock::new(None),
             clients: Mutex::new(HashMap::new()),
             password,
         });
@@ -161,13 +164,14 @@ impl IrcServer {
         let channels = parse_configured_channels(&contents)?;
 
         // Parse configured contacts
-        let contacts = parse_configured_contacts(&contents)?;
+        let (contacts, saltbox) = parse_configured_contacts(&contents)?;
 
         // FIXME: This will remove clients' joined channels. They need to stay.
         // Only if everything is fine, replace.
         *self.autojoin.write().await = autojoin;
         *self.channels.write().await = channels;
         *self.contacts.write().await = contacts;
+        *self.saltbox.write().await = saltbox;
 
         Ok(())
     }
@@ -301,7 +305,13 @@ impl IrcServer {
                 // We will use dummy channel and nick values of MAX_NICK_LEN,
                 // since they are not used, so all encrypted messages look the same.
                 *privmsg.channel() = saltbox::encrypt(saltbox, &[0x00; MAX_NICK_LEN]);
-                *privmsg.nick() = saltbox::encrypt(saltbox, &[0x00; MAX_NICK_LEN]);
+                // We will encrypt the dummy nick value using our own self saltbox,
+                // so we can identify our messages. We can safely unwrap here since
+                // we know that if contacts exist, our self saltbox does as well.
+                *privmsg.nick() = saltbox::encrypt(
+                    self.saltbox.read().await.as_ref().unwrap(),
+                    &[0x00; MAX_NICK_LEN],
+                );
                 *privmsg.msg() = saltbox::encrypt(saltbox, privmsg.msg().as_bytes());
                 debug!("Successfully encrypted message for {}", name);
             }
@@ -309,7 +319,7 @@ impl IrcServer {
     }
 
     /// Try decrypting a given potentially encrypted `Privmsg` object.
-    pub async fn try_decrypt(&self, privmsg: &mut Privmsg) {
+    pub async fn try_decrypt(&self, privmsg: &mut Privmsg, self_nickname: &str) {
         // If all fields have base58, then we can consider decrypting.
         let channel_ciphertext = match bs58::decode(&privmsg.channel).into_vec() {
             Ok(v) => v,
@@ -362,9 +372,18 @@ impl IrcServer {
                 continue
             };
 
-            if saltbox::try_decrypt(saltbox, &nick_ciphertext).is_none() {
-                warn!(target: "darkirc::irc::server::try_decrypt", "Could not decrypt channel ciphertext for contact: {name}");
-                continue
+            // Since everyone encrypts the dummy nick value with their self saltbox,
+            // we try to decrypt using our, to identify our messages. We can safely
+            // unwrap here since we know that if contacts exist, our self saltbox does as well.
+            let nick = if saltbox::try_decrypt(
+                self.saltbox.read().await.as_ref().unwrap(),
+                &nick_ciphertext,
+            )
+            .is_some()
+            {
+                String::from(self_nickname)
+            } else {
+                name.to_string()
             };
 
             let Some(msg_dec) = saltbox::try_decrypt(saltbox, &msg_ciphertext) else {
@@ -373,7 +392,7 @@ impl IrcServer {
             };
 
             privmsg.channel = name.to_string();
-            privmsg.nick = name.to_string();
+            privmsg.nick = nick;
             privmsg.msg = String::from_utf8_lossy(&msg_dec).into();
             debug!("Successfully decrypted message from {}", name);
             return

+ 8 - 4
bin/darkirc/src/settings.rs

@@ -21,7 +21,7 @@ use std::{
     sync::Arc,
 };
 
-use crypto_box::PublicKey;
+use crypto_box::{ChaChaBox, PublicKey};
 use darkfi::{Error::ParseFailed, Result};
 use log::info;
 
@@ -132,17 +132,21 @@ pub fn list_configured_contacts(data: &toml::Value) -> Result<HashMap<String, Pu
 }
 
 /// Parse configured contacts from a TOML map.
+/// If contacts exist and our secret key is valid, also return its saltbox.
 ///
 /// ```toml
 /// [contact."anon"]
 /// dm_chacha_public = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"
 /// ```
-pub fn parse_configured_contacts(data: &toml::Value) -> Result<HashMap<String, IrcContact>> {
+#[allow(clippy::type_complexity)]
+pub fn parse_configured_contacts(
+    data: &toml::Value,
+) -> Result<(HashMap<String, IrcContact>, Option<Arc<ChaChaBox>>)> {
     let mut ret = HashMap::new();
 
     let contacts = list_configured_contacts(data)?;
     if contacts.is_empty() {
-        return Ok(ret);
+        return Ok((ret, None));
     }
     let Some(secret) = parse_dm_chacha_secret(data)? else {
         return Err(ParseFailed("You have specified some contacts but you did not set up a valid chacha secret for yourself.  You can generate a keypair with: 'darkirc --gen-chacha-keypair' and then add that keypair to your config toml file."))
@@ -158,7 +162,7 @@ pub fn parse_configured_contacts(data: &toml::Value) -> Result<HashMap<String, I
         ret.insert(name.to_string(), IrcContact { saltbox });
     }
 
-    Ok(ret)
+    Ok((ret, Some(Arc::new(crypto_box::ChaChaBox::new(&secret.public_key(), &secret)))))
 }
 
 /// Parse a TOML string for any configured channels and return