client.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{collections::HashSet, sync::Arc};
  19. use darkfi::{
  20. event_graph::{model::Event, EventMsg},
  21. system::Subscription,
  22. Error, Result,
  23. };
  24. use futures::FutureExt;
  25. use log::{debug, error, info, warn};
  26. use smol::{
  27. io::{AsyncBufReadExt, AsyncRead, AsyncWrite, AsyncWriteExt, BufReader, ReadHalf, WriteHalf},
  28. lock::Mutex,
  29. net::SocketAddr,
  30. };
  31. use crate::{
  32. crypto::saltbox::{decrypt_privmsg, decrypt_target, encrypt_privmsg},
  33. settings,
  34. settings::{Nick, UserMode, RPL},
  35. ChannelInfo, PrivMsgEvent,
  36. };
  37. use super::{ClientSubMsg, IrcConfig, NotifierMsg};
  38. pub struct IrcClient<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> {
  39. // network stream
  40. write_stream: WriteHalf<C>,
  41. read_stream: BufReader<ReadHalf<C>>,
  42. pub address: SocketAddr,
  43. // irc config
  44. irc_config: IrcConfig,
  45. /// Joined channels, mapped here for better SIGHUP UX.
  46. channels_joined: HashSet<String>,
  47. server_notifier: smol::channel::Sender<(NotifierMsg, usize)>,
  48. subscription: Subscription<ClientSubMsg>,
  49. missed_events: Arc<Mutex<Vec<Event<PrivMsgEvent>>>>,
  50. }
  51. impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
  52. pub fn new(
  53. write_stream: WriteHalf<C>,
  54. read_stream: BufReader<ReadHalf<C>>,
  55. address: SocketAddr,
  56. irc_config: IrcConfig,
  57. server_notifier: smol::channel::Sender<(NotifierMsg, usize)>,
  58. subscription: Subscription<ClientSubMsg>,
  59. missed_events: Arc<Mutex<Vec<Event<PrivMsgEvent>>>>,
  60. ) -> Self {
  61. Self {
  62. write_stream,
  63. read_stream,
  64. address,
  65. irc_config,
  66. channels_joined: HashSet::new(),
  67. subscription,
  68. server_notifier,
  69. missed_events,
  70. }
  71. }
  72. /// Start listening for messages came from View or irc client
  73. pub async fn listen(&mut self) {
  74. loop {
  75. let mut line = String::new();
  76. futures::select! {
  77. // Process msg from View or other client connnected to the same irc server
  78. msg = self.subscription.receive().fuse() => {
  79. match msg {
  80. ClientSubMsg::Privmsg(m) => {
  81. if let Err(e) = self.process_msg(&m).await {
  82. error!("[CLIENT {}] Process msg: {}", self.address, e);
  83. break
  84. }
  85. }
  86. ClientSubMsg::Config(c) => self.update_config(c).await,
  87. }
  88. }
  89. // Process msg from IRC client
  90. err = self.read_stream.read_line(&mut line).fuse() => {
  91. if let Err(e) = err {
  92. error!("[CLIENT {}] Read line error: {}", self.address, e);
  93. break
  94. }
  95. if let Err(e) = self.process_line(line).await {
  96. error!("[CLIENT {}] Process line failed: {}", self.address, e);
  97. break
  98. }
  99. }
  100. }
  101. }
  102. warn!("[CLIENT {}] Close connection", self.address);
  103. self.subscription.unsubscribe().await;
  104. }
  105. pub async fn update_config(&mut self, new_config: IrcConfig) {
  106. info!("[CLIENT {}] Updating config...", self.address);
  107. let old_config = self.irc_config.clone();
  108. let mut _chans_to_replay = HashSet::new();
  109. let mut _contacts_to_replay = HashSet::new();
  110. for (name, new_info) in new_config.channels.iter() {
  111. let Some(old_info) = old_config.channels.get(name) else {
  112. // New channel wasn't in old config, replay it
  113. _chans_to_replay.insert(name);
  114. continue
  115. };
  116. // TODO: Maybe if the salt_box changed, replay it, although
  117. // kinda hard to do since there's no Eq/PartialEq on there,
  118. // and we probably shouldn't keep the secret key laying around.
  119. // We got some secret key for this channel, replay it
  120. if old_info.salt_box.is_none() && new_info.salt_box.is_some() {
  121. _chans_to_replay.insert(name);
  122. continue
  123. }
  124. }
  125. for (name, _new_info) in new_config.contacts.iter() {
  126. let Some(_old_info) = old_config.contacts.get(name) else {
  127. // New contact wasn't in old config, replay it
  128. _contacts_to_replay.insert(name);
  129. continue
  130. };
  131. }
  132. self.irc_config.channels.extend(new_config.channels);
  133. self.irc_config.contacts.extend(new_config.contacts);
  134. self.irc_config.pass = new_config.pass;
  135. if self.on_receive_join(self.irc_config.channels.keys().cloned().collect()).await.is_err() {
  136. warn!("Error joining updated channels");
  137. } else {
  138. info!("[CLIENT {}] Config updated", self.address);
  139. }
  140. }
  141. pub async fn process_msg(&mut self, msg: &PrivMsgEvent) -> Result<()> {
  142. debug!("[CLIENT {}] msg from View: {:?}", self.address, msg.to_string());
  143. let mut msg = msg.clone();
  144. let mut contact = String::new();
  145. decrypt_target(
  146. &mut contact,
  147. &mut msg,
  148. &self.irc_config.channels,
  149. &self.irc_config.contacts,
  150. );
  151. // The message is a channel message
  152. if msg.target.starts_with('#') {
  153. // Try to potentially decrypt the incoming message.
  154. if !self.irc_config.channels.contains_key(&msg.target) {
  155. return Ok(())
  156. }
  157. // Skip everything if we're not joined in the channel
  158. if !self.channels_joined.contains(&msg.target) {
  159. return Ok(())
  160. }
  161. let chan_info = self.irc_config.channels.get_mut(&msg.target).unwrap();
  162. // We use this flag to mark if the message has been encrypted or not.
  163. // Depending on it, we set a specific usermode to the nickname in the
  164. // channel so in UI we can tell who is sending encrypted messages.
  165. let mut encrypted = false;
  166. if let Some(salt_box) = &chan_info.salt_box {
  167. decrypt_privmsg(salt_box, &mut msg);
  168. encrypted = true;
  169. debug!("[P2P] Decrypted received message: {:?}", msg);
  170. }
  171. // Add the nickname to the channel's names
  172. let mut nick: Nick = msg.nick.clone().into();
  173. let _mode_change = if chan_info.names.contains(&nick) {
  174. let mut n = chan_info.names.get(&nick).unwrap().clone();
  175. let mode_change = if encrypted {
  176. n.set_mode(UserMode::Voice)
  177. } else {
  178. n.unset_mode(UserMode::Voice)
  179. };
  180. chan_info.names.insert(n);
  181. mode_change
  182. } else {
  183. let mode_change = if encrypted { nick.set_mode(UserMode::Voice) } else { None };
  184. chan_info.names.insert(nick);
  185. mode_change
  186. };
  187. self.reply(&msg.to_string()).await?;
  188. return Ok(())
  189. }
  190. // The message is not a channel message, handle accordingly.
  191. if self.irc_config.is_cap_end && self.irc_config.is_nick_init {
  192. if !self.irc_config.contacts.contains_key(&contact) {
  193. return Ok(())
  194. }
  195. let contact_info = self.irc_config.contacts.get(&contact).unwrap();
  196. if let Some(salt_box) = &contact_info.salt_box {
  197. decrypt_privmsg(salt_box, &mut msg);
  198. // This is for /query
  199. msg.nick = contact;
  200. debug!("[P2P] Decrypted received message: {:?}", msg);
  201. }
  202. self.reply(&msg.to_string()).await?;
  203. return Ok(())
  204. }
  205. Ok(())
  206. }
  207. pub async fn process_line(&mut self, line: String) -> Result<()> {
  208. let irc_msg = match clean_input_line(line) {
  209. Ok(msg) => msg,
  210. Err(e) => {
  211. warn!("[CLIENT {}] Connection error: {}", self.address, e);
  212. return Err(Error::ChannelStopped)
  213. }
  214. };
  215. debug!("[CLIENT {}] Process msg: {}", self.address, irc_msg);
  216. if let Err(e) = self.update(irc_msg).await {
  217. warn!("[CLIENT {}] Connection error: {}", self.address, e);
  218. return Err(Error::ChannelStopped)
  219. }
  220. Ok(())
  221. }
  222. async fn update(&mut self, line: String) -> Result<()> {
  223. if line.len() > settings::MAXIMUM_LENGTH_OF_MESSAGE {
  224. return Err(Error::MalformedPacket)
  225. }
  226. let (command, value) = parse_line(&line)?;
  227. let (command, value) = (command.as_str(), value.as_str());
  228. match command {
  229. "PASS" => self.on_receive_pass(value).await?,
  230. "USER" => self.on_receive_user().await?,
  231. "NAMES" => self.on_receive_names(value.split(',').map(String::from).collect()).await?,
  232. "NICK" => self.on_receive_nick(value).await?,
  233. "JOIN" => self.on_receive_join(value.split(',').map(String::from).collect()).await?,
  234. "PART" => self.on_receive_part(value.split(',').map(String::from).collect()).await?,
  235. "TOPIC" => self.on_receive_topic(&line, value).await?,
  236. "PING" => self.on_ping(value).await?,
  237. "PRIVMSG" => self.on_receive_privmsg(&line, value).await?,
  238. "CAP" => self.on_receive_cap(&line, &value.to_uppercase()).await?,
  239. "QUIT" => self.on_quit()?,
  240. _ => warn!("[CLIENT {}] Unimplemented `{}` command", self.address, command),
  241. }
  242. self.register().await?;
  243. Ok(())
  244. }
  245. async fn register(&mut self) -> Result<()> {
  246. if !self.irc_config.is_pass_init && self.irc_config.pass.is_empty() {
  247. self.irc_config.is_pass_init = true
  248. }
  249. if !self.irc_config.is_registered &&
  250. self.irc_config.is_cap_end &&
  251. self.irc_config.is_nick_init &&
  252. self.irc_config.is_user_init
  253. {
  254. debug!("Initializing peer connection");
  255. let register_reply =
  256. format!(":darkfi 001 {} :Let there be dark\r\n", self.irc_config.nick);
  257. self.reply(&register_reply).await?;
  258. self.irc_config.is_registered = true;
  259. // join all channels
  260. self.on_receive_join(self.irc_config.auto_channels.clone()).await?;
  261. self.on_receive_join(self.irc_config.channels.keys().cloned().collect()).await?;
  262. }
  263. Ok(())
  264. }
  265. async fn reply(&mut self, message: &str) -> Result<()> {
  266. self.write_stream.write_all(message.as_bytes()).await?;
  267. debug!("Sent {}", message.trim_end());
  268. Ok(())
  269. }
  270. fn on_quit(&self) -> Result<()> {
  271. // Close the connection
  272. Err(Error::NetworkServiceStopped)
  273. }
  274. async fn on_receive_user(&mut self) -> Result<()> {
  275. // We can stuff any extra things like public keys in here.
  276. // Ignore it for now.
  277. if self.irc_config.is_pass_init {
  278. self.irc_config.is_user_init = true;
  279. } else {
  280. // Close the connection
  281. warn!("[CLIENT {}] Password is required", self.address);
  282. return self.on_quit()
  283. }
  284. Ok(())
  285. }
  286. async fn on_receive_pass(&mut self, pass: &str) -> Result<()> {
  287. if self.irc_config.pass == pass {
  288. self.irc_config.is_pass_init = true
  289. } else {
  290. // Close the connection
  291. warn!("[CLIENT {}] Password is not correct!", self.address);
  292. return self.on_quit()
  293. }
  294. Ok(())
  295. }
  296. async fn on_receive_nick(&mut self, nickname: &str) -> Result<()> {
  297. if nickname.len() >= settings::MAXIMUM_LENGTH_OF_NICK_CHAN_CNT {
  298. return Ok(())
  299. }
  300. self.irc_config.is_nick_init = true;
  301. let old_nick = std::mem::replace(&mut self.irc_config.nick, nickname.to_string());
  302. let nick_reply = format!(":{}!anon@dark.fi NICK {}\r\n", old_nick, self.irc_config.nick);
  303. self.reply(&nick_reply).await
  304. }
  305. async fn on_receive_part(&mut self, channels: Vec<String>) -> Result<()> {
  306. for chan in channels.iter() {
  307. let part_reply = format!(":{}!anon@dark.fi PART {}\r\n", self.irc_config.nick, chan);
  308. self.reply(&part_reply).await?;
  309. self.channels_joined.remove(chan);
  310. }
  311. Ok(())
  312. }
  313. async fn on_receive_topic(&mut self, line: &str, channel: &str) -> Result<()> {
  314. if let Some(substr_idx) = line.find(':') {
  315. // Client is setting the topic
  316. if substr_idx >= line.len() {
  317. return Err(Error::MalformedPacket)
  318. }
  319. let topic = &line[substr_idx + 1..];
  320. let chan_info = self.irc_config.channels.get_mut(channel).unwrap();
  321. chan_info.topic = Some(topic.to_string());
  322. let topic_reply =
  323. format!(":{}!anon@dark.fi TOPIC {} :{}\r\n", self.irc_config.nick, channel, topic);
  324. self.reply(&topic_reply).await?;
  325. } else {
  326. // Client is asking or the topic
  327. let chan_info = self.irc_config.channels.get(channel).unwrap();
  328. let topic_reply = if let Some(topic) = &chan_info.topic {
  329. format!("{} {} {} :{}\r\n", RPL::Topic as u32, self.irc_config.nick, channel, topic)
  330. } else {
  331. const TOPIC: &str = "No topic is set";
  332. format!(
  333. "{} {} {} :{}\r\n",
  334. RPL::NoTopic as u32,
  335. self.irc_config.nick,
  336. channel,
  337. TOPIC
  338. )
  339. };
  340. self.reply(&topic_reply).await?;
  341. }
  342. Ok(())
  343. }
  344. async fn on_ping(&mut self, value: &str) -> Result<()> {
  345. let pong = format!("PONG {}\r\n", value);
  346. self.reply(&pong).await
  347. }
  348. async fn on_receive_cap(&mut self, line: &str, subcommand: &str) -> Result<()> {
  349. self.irc_config.is_cap_end = false;
  350. let caps_keys: Vec<String> = self.irc_config.caps.keys().cloned().collect();
  351. match subcommand {
  352. "LS" => {
  353. let cap_ls_reply = format!(
  354. ":{}!anon@dark.fi CAP * LS :{}\r\n",
  355. self.irc_config.nick,
  356. caps_keys.join(" ")
  357. );
  358. self.reply(&cap_ls_reply).await?;
  359. }
  360. "REQ" => {
  361. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  362. if substr_idx >= line.len() {
  363. return Err(Error::MalformedPacket)
  364. }
  365. let cap: Vec<&str> = line[substr_idx + 1..].split(' ').collect();
  366. let mut ack_list = vec![];
  367. let mut nak_list = vec![];
  368. for c in cap {
  369. if self.irc_config.caps.contains_key(c) {
  370. self.irc_config.caps.insert(c.to_string(), true);
  371. ack_list.push(c);
  372. } else {
  373. nak_list.push(c);
  374. }
  375. }
  376. let cap_ack_reply = format!(
  377. ":{}!anon@dark.fi CAP * ACK :{}\r\n",
  378. self.irc_config.nick,
  379. ack_list.join(" ")
  380. );
  381. let cap_nak_reply = format!(
  382. ":{}!anon@dark.fi CAP * NAK :{}\r\n",
  383. self.irc_config.nick,
  384. nak_list.join(" ")
  385. );
  386. self.reply(&cap_ack_reply).await?;
  387. self.reply(&cap_nak_reply).await?;
  388. }
  389. "LIST" => {
  390. let enabled_caps: Vec<String> = self
  391. .irc_config
  392. .caps
  393. .clone()
  394. .into_iter()
  395. .filter(|(_, v)| *v)
  396. .map(|(k, _)| k)
  397. .collect();
  398. let cap_list_reply = format!(
  399. ":{}!anon@dark.fi CAP * LIST :{}\r\n",
  400. self.irc_config.nick,
  401. enabled_caps.join(" ")
  402. );
  403. self.reply(&cap_list_reply).await?;
  404. }
  405. "END" => {
  406. self.irc_config.is_cap_end = true;
  407. }
  408. _ => {}
  409. }
  410. Ok(())
  411. }
  412. async fn on_receive_names(&mut self, channels: Vec<String>) -> Result<()> {
  413. for chan in channels.iter() {
  414. if !chan.starts_with('#') {
  415. continue
  416. }
  417. if self.irc_config.channels.contains_key(chan) {
  418. let chan_info = self.irc_config.channels.get(chan).unwrap();
  419. if chan_info.names.is_empty() {
  420. return Ok(())
  421. }
  422. let names_reply = format!(
  423. ":{}!anon@dark.fi {} = {} : {}\r\n",
  424. self.irc_config.nick,
  425. RPL::NameReply as u32,
  426. chan,
  427. chan_info.names()
  428. );
  429. self.reply(&names_reply).await?;
  430. let end_of_names = format!(
  431. ":DarkFi {:03} {} {} :End of NAMES list\r\n",
  432. RPL::EndOfNames as u32,
  433. self.irc_config.nick,
  434. chan
  435. );
  436. self.reply(&end_of_names).await?;
  437. }
  438. }
  439. Ok(())
  440. }
  441. async fn on_receive_privmsg(&mut self, line: &str, target: &str) -> Result<()> {
  442. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  443. if substr_idx >= line.len() {
  444. return Err(Error::MalformedPacket)
  445. }
  446. let message = line[substr_idx + 1..].to_string();
  447. debug!("[CLIENT {}] (Plain) PRIVMSG {} :{}", self.address, target, message,);
  448. let mut privmsg = PrivMsgEvent::new();
  449. privmsg.nick = self.irc_config.nick.clone();
  450. privmsg.target = target.to_string();
  451. privmsg.msg = message.clone();
  452. if target.starts_with('#') {
  453. if !self.irc_config.channels.contains_key(target) {
  454. return Ok(())
  455. }
  456. if !self.channels_joined.contains(target) {
  457. return Ok(())
  458. }
  459. let channel_info = self.irc_config.channels.get(target).unwrap();
  460. if let Some(salt_box) = &channel_info.salt_box {
  461. encrypt_privmsg(salt_box, &mut privmsg);
  462. debug!("[CLIENT {}] (Encrypted) PRIVMSG: {:?}", self.address, privmsg);
  463. }
  464. } else {
  465. if !self.irc_config.contacts.contains_key(target) {
  466. return Ok(())
  467. }
  468. let contact_info = self.irc_config.contacts.get(target).unwrap();
  469. if let Some(salt_box) = &contact_info.salt_box {
  470. encrypt_privmsg(salt_box, &mut privmsg);
  471. debug!("[CLIENT {}] (Encrypted) PRIVMSG: {:?}", self.address, privmsg);
  472. }
  473. }
  474. self.server_notifier
  475. .send((NotifierMsg::Privmsg(privmsg), self.subscription.get_id()))
  476. .await?;
  477. Ok(())
  478. }
  479. async fn on_receive_join(&mut self, channels: Vec<String>) -> Result<()> {
  480. for chan in channels.iter() {
  481. if !chan.starts_with('#') {
  482. continue
  483. }
  484. if !self.irc_config.channels.contains_key(chan) {
  485. let mut chan_info = ChannelInfo::new()?;
  486. chan_info.topic = Some("n/a".to_string());
  487. self.irc_config.channels.insert(chan.to_string(), chan_info);
  488. }
  489. if !self.channels_joined.insert(chan.to_string()) {
  490. return Ok(())
  491. }
  492. let chan_info = self.irc_config.channels.get_mut(chan).unwrap();
  493. let topic =
  494. if let Some(topic) = chan_info.topic.clone() { topic } else { "n/a".to_string() };
  495. chan_info.topic = Some(topic.to_string());
  496. {
  497. let j = format!(":{}!anon@dark.fi JOIN {}\r\n", self.irc_config.nick, chan);
  498. let t = format!(":DarkFi TOPIC {} :{}\r\n", chan, topic);
  499. self.reply(&j).await?;
  500. self.reply(&t).await?;
  501. }
  502. }
  503. if *self.irc_config.caps.get("no-history").unwrap() {
  504. return Ok(())
  505. }
  506. // Process missed messages if any (sorted by event's timestamp)
  507. let mut hash_vec = self.missed_events.lock().await.clone();
  508. hash_vec.sort_by(|a, b| a.timestamp.0.cmp(&b.timestamp.0));
  509. for event in hash_vec {
  510. if let Err(e) = self.process_msg(&event.action).await {
  511. error!("[CLIENT {}] Process msg: {}", self.address, e);
  512. continue
  513. }
  514. }
  515. Ok(())
  516. }
  517. }
  518. //
  519. // Helper functions
  520. //
  521. fn clean_input_line(mut line: String) -> Result<String> {
  522. if line.is_empty() {
  523. return Err(Error::ChannelStopped)
  524. }
  525. if line == "\n" || line == "\r\n" {
  526. return Err(Error::ChannelStopped)
  527. }
  528. if &line[(line.len() - 2)..] == "\r\n" {
  529. // Remove CRLF
  530. line.pop();
  531. line.pop();
  532. } else if &line[(line.len() - 1)..] == "\n" {
  533. line.pop();
  534. } else {
  535. return Err(Error::ChannelStopped)
  536. }
  537. Ok(line.clone())
  538. }
  539. fn parse_line(line: &str) -> Result<(String, String)> {
  540. let mut tokens = line.split_ascii_whitespace();
  541. // Commands can begin with :garbage but we will reject clients doing
  542. // that for now to keep the protocol simple and focused.
  543. let command = tokens.next().ok_or(Error::MalformedPacket)?.to_uppercase();
  544. let value = tokens.next().ok_or(Error::MalformedPacket)?;
  545. Ok((command, value.to_owned()))
  546. }