server.rs 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. use std::sync::atomic::Ordering;
  2. use async_std::net::TcpStream;
  3. use futures::{io::WriteHalf, AsyncWriteExt};
  4. use fxhash::FxHashMap;
  5. use log::{debug, info, warn};
  6. use rand::{rngs::OsRng, RngCore};
  7. use darkfi::{Error, Result};
  8. use crate::{crypto::encrypt_message, privmsg::Privmsg, ChannelInfo, SeenMsgIds};
  9. const RPL_NOTOPIC: u32 = 331;
  10. const RPL_TOPIC: u32 = 332;
  11. pub struct IrcServerConnection {
  12. write_stream: WriteHalf<TcpStream>,
  13. is_nick_init: bool,
  14. is_user_init: bool,
  15. is_registered: bool,
  16. nickname: String,
  17. seen_msg_id: SeenMsgIds,
  18. p2p_sender: async_channel::Sender<Privmsg>,
  19. auto_channels: Vec<String>,
  20. pub configured_chans: FxHashMap<String, ChannelInfo>,
  21. }
  22. impl IrcServerConnection {
  23. pub fn new(
  24. write_stream: WriteHalf<TcpStream>,
  25. seen_msg_id: SeenMsgIds,
  26. p2p_sender: async_channel::Sender<Privmsg>,
  27. auto_channels: Vec<String>,
  28. configured_chans: FxHashMap<String, ChannelInfo>,
  29. ) -> Self {
  30. Self {
  31. write_stream,
  32. is_nick_init: false,
  33. is_user_init: false,
  34. is_registered: false,
  35. nickname: "anon".to_string(),
  36. seen_msg_id,
  37. p2p_sender,
  38. auto_channels,
  39. configured_chans,
  40. }
  41. }
  42. pub async fn update(&mut self, line: String) -> Result<()> {
  43. let mut tokens = line.split_ascii_whitespace();
  44. // Commands can begin with :garbage but we will reject clients doing
  45. // that for now to keep the protocol simple and focused.
  46. let command = tokens.next().ok_or(Error::MalformedPacket)?;
  47. info!("IRC server received command: {}", command.to_uppercase());
  48. match command.to_uppercase().as_str() {
  49. "USER" => {
  50. // We can stuff any extra things like public keys in here.
  51. // Ignore it for now.
  52. self.is_user_init = true;
  53. }
  54. "NICK" => {
  55. let nickname = tokens.next().ok_or(Error::MalformedPacket)?;
  56. self.is_nick_init = true;
  57. let old_nick = std::mem::replace(&mut self.nickname, nickname.to_string());
  58. let nick_reply = format!(":{}!anon@dark.fi NICK {}\r\n", old_nick, self.nickname);
  59. self.reply(&nick_reply).await?;
  60. }
  61. "JOIN" => {
  62. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  63. for chan in channels.split(',') {
  64. if !chan.starts_with('#') {
  65. warn!("{} is not a valid name for channel", chan);
  66. continue
  67. }
  68. let join_reply = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, chan);
  69. self.reply(&join_reply).await?;
  70. if !self.configured_chans.contains_key(chan) {
  71. self.configured_chans.insert(chan.to_string(), ChannelInfo::new()?);
  72. } else {
  73. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  74. chan_info.joined.store(true, Ordering::Relaxed);
  75. }
  76. }
  77. }
  78. "PART" => {
  79. let channels = tokens.next().ok_or(Error::MalformedPacket)?;
  80. for chan in channels.split(',') {
  81. let part_reply = format!(":{}!anon@dark.fi PART {}\r\n", self.nickname, chan);
  82. self.reply(&part_reply).await?;
  83. if self.configured_chans.contains_key(chan) {
  84. let chan_info = self.configured_chans.get_mut(chan).unwrap();
  85. chan_info.joined.store(false, Ordering::Relaxed);
  86. }
  87. }
  88. }
  89. "TOPIC" => {
  90. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  91. if let Some(substr_idx) = line.find(':') {
  92. // Client is setting the topic
  93. if substr_idx >= line.len() {
  94. return Err(Error::MalformedPacket)
  95. }
  96. let topic = &line[substr_idx + 1..];
  97. let chan_info = self.configured_chans.get_mut(channel).unwrap();
  98. chan_info.topic = Some(topic.to_string());
  99. let topic_reply =
  100. format!(":{}!anon@dark.fi TOPIC {} :{}\r\n", self.nickname, channel, topic);
  101. self.reply(&topic_reply).await?;
  102. } else {
  103. // Client is asking or the topic
  104. let chan_info = self.configured_chans.get(channel).unwrap();
  105. let topic_reply = if let Some(topic) = &chan_info.topic {
  106. format!("{} {} {} :{}\r\n", RPL_TOPIC, self.nickname, channel, topic)
  107. } else {
  108. const TOPIC: &str = "No topic is set";
  109. format!("{} {} {} :{}\r\n", RPL_NOTOPIC, self.nickname, channel, TOPIC)
  110. };
  111. self.reply(&topic_reply).await?;
  112. }
  113. }
  114. "PING" => {
  115. let line_clone = line.clone();
  116. let split_line: Vec<&str> = line_clone.split_whitespace().collect();
  117. if split_line.len() > 1 {
  118. let pong = format!("PONG {}\r\n", split_line[1]);
  119. self.reply(&pong).await?;
  120. }
  121. }
  122. "PRIVMSG" => {
  123. let channel = tokens.next().ok_or(Error::MalformedPacket)?;
  124. let substr_idx = line.find(':').ok_or(Error::MalformedPacket)?;
  125. if substr_idx >= line.len() {
  126. return Err(Error::MalformedPacket)
  127. }
  128. let message = &line[substr_idx + 1..];
  129. info!("(Plain) PRIVMSG {} :{}", channel, message);
  130. if self.configured_chans.contains_key(channel) {
  131. let channel_info = self.configured_chans.get(channel).unwrap();
  132. if channel_info.joined.load(Ordering::Relaxed) {
  133. let message = if let Some(salt_box) = &channel_info.salt_box {
  134. let encrypted = encrypt_message(salt_box, message);
  135. info!("(Encrypted) PRIVMSG {} :{}", channel, encrypted);
  136. encrypted
  137. } else {
  138. message.to_string()
  139. };
  140. let random_id = OsRng.next_u32();
  141. let protocol_msg = Privmsg {
  142. id: random_id,
  143. nickname: self.nickname.clone(),
  144. channel: channel.to_string(),
  145. message,
  146. };
  147. let mut smi = self.seen_msg_id.lock().await;
  148. smi.push(random_id);
  149. drop(smi);
  150. debug!(target: "ircd", "PRIVMSG to be sent: {:?}", protocol_msg);
  151. self.p2p_sender.send(protocol_msg).await?;
  152. }
  153. }
  154. }
  155. "QUIT" => {
  156. // Close the connection
  157. return Err(Error::NetworkServiceStopped)
  158. }
  159. _ => {
  160. warn!("Unimplemented `{}` command", command);
  161. }
  162. }
  163. if !self.is_registered && self.is_nick_init && self.is_user_init {
  164. debug!("Initializing peer connection");
  165. let register_reply = format!(":darkfi 001 {} :Let there be dark\r\n", self.nickname);
  166. self.reply(&register_reply).await?;
  167. self.is_registered = true;
  168. // Auto-joins
  169. macro_rules! autojoin {
  170. ($channel:expr,$topic:expr) => {
  171. let j = format!(":{}!anon@dark.fi JOIN {}\r\n", self.nickname, $channel);
  172. let t = format!(":DarkFi TOPIC {} :{}\r\n", $channel, $topic);
  173. self.reply(&j).await?;
  174. self.reply(&t).await?;
  175. };
  176. }
  177. for chan in self.auto_channels.clone() {
  178. if self.configured_chans.contains_key(&chan) {
  179. let chan_info = self.configured_chans.get_mut(&chan).unwrap();
  180. let topic = if let Some(topic) = chan_info.topic.clone() {
  181. topic
  182. } else {
  183. "n/a".to_string()
  184. };
  185. chan_info.topic = Some(topic.to_string());
  186. autojoin!(chan, topic);
  187. } else {
  188. let mut chan_info = ChannelInfo::new()?;
  189. chan_info.topic = Some("n/a".to_string());
  190. self.configured_chans.insert(chan.clone(), chan_info);
  191. autojoin!(chan, "n/a");
  192. }
  193. }
  194. }
  195. Ok(())
  196. }
  197. pub async fn reply(&mut self, message: &str) -> Result<()> {
  198. self.write_stream.write_all(message.as_bytes()).await?;
  199. debug!("Sent {}", message);
  200. Ok(())
  201. }
  202. }