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