client.rs 20 KB

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