client.rs 20 KB

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