client.rs 20 KB

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