command.rs 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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. //! IRC command implemenatations
  19. //!
  20. //! These try to follow the RFCs, modified in order for our P2P stack.
  21. //! Copied from <https://simple.wikipedia.org/wiki/List_of_Internet_Relay_Chat_commands>
  22. //!
  23. //! Unimplemented commands:
  24. //! * `AWAY`
  25. //! * `CONNECT`
  26. //! * `DIE`
  27. //! * `ERROR`
  28. //! * `INVITE`
  29. //! * `ISON`
  30. //! * `KICK`
  31. //! * `KILL`
  32. //! * `NOTICE`
  33. //! * `OPER`
  34. //! * `RESTART`
  35. //! * `SERVICE`
  36. //! * `SERVLIST`
  37. //! * `SERVER`
  38. //! * `SQUERY`
  39. //! * `SQUIT`
  40. //! * `SUMMON`
  41. //! * `TRACE`
  42. //! * `USERHOST`
  43. //! * `WALLOPS`
  44. //! * `WHO`
  45. //! * `WHOIS`
  46. //! * `WHOWAS`
  47. //!
  48. //! Some of the above commands could actually be implemented and could
  49. //! work in respect to the P2P network.
  50. use std::{collections::HashSet, sync::atomic::Ordering::SeqCst};
  51. use darkfi::Result;
  52. use darkfi_serial::deserialize_async_partial;
  53. use log::{error, info};
  54. use super::{
  55. client::{Client, ReplyType},
  56. rpl::*,
  57. server::MAX_NICK_LEN,
  58. IrcChannel, SERVER_NAME,
  59. };
  60. use crate::crypto::bcrypt::bcrypt_hash_password;
  61. impl Client {
  62. /// `ADMIN [<server>]`
  63. ///
  64. /// Asks the server for information about the administrator of the server.
  65. pub async fn handle_cmd_admin(&self, _args: &str) -> Result<Vec<ReplyType>> {
  66. if !self.registered.load(SeqCst) {
  67. self.penalty.fetch_add(1, SeqCst);
  68. return Ok(vec![ReplyType::Server((
  69. ERR_NOTREGISTERED,
  70. format!("* :{}", NOT_REGISTERED),
  71. ))])
  72. }
  73. let nick = self.nickname.read().await.to_string();
  74. let replies = vec![
  75. ReplyType::Server((
  76. RPL_ADMINME,
  77. format!("{} {} :Administrative info", nick, SERVER_NAME),
  78. )),
  79. ReplyType::Server((RPL_ADMINLOC1, format!("{} :", nick))),
  80. ReplyType::Server((RPL_ADMINLOC2, format!("{} :", nick))),
  81. ReplyType::Server((RPL_ADMINEMAIL, format!("{} :anon@darkirc", nick))),
  82. ];
  83. Ok(replies)
  84. }
  85. /// `CAP <args>`
  86. pub async fn handle_cmd_cap(&self, args: &str) -> Result<Vec<ReplyType>> {
  87. let mut tokens = args.split_ascii_whitespace();
  88. let Some(subcommand) = tokens.next() else {
  89. self.penalty.fetch_add(1, SeqCst);
  90. return Ok(vec![ReplyType::Server((
  91. ERR_NEEDMOREPARAMS,
  92. format!("{} CAP :{}", self.nickname.read().await, INVALID_SYNTAX),
  93. ))])
  94. };
  95. let caps_keys: Vec<String> = self.caps.read().await.keys().cloned().collect();
  96. let nick = self.nickname.read().await.to_string();
  97. match subcommand.to_uppercase().as_str() {
  98. "LS" => {
  99. /*
  100. let Some(_version) = tokens.next() else {
  101. return Ok(vec![ReplyType::Server((
  102. ERR_NEEDMOREPARAMS,
  103. format!("{} CAP :{}", self.nickname.read().await, INVALID_SYNTAX),
  104. ))])
  105. };
  106. */
  107. self.reg_paused.store(true, SeqCst);
  108. return Ok(vec![ReplyType::Cap(format!("CAP * LS :{}", caps_keys.join(" ")))])
  109. }
  110. "REQ" => {
  111. let Some(substr_idx) = args.find(':') else {
  112. return Ok(vec![ReplyType::Server((
  113. ERR_NEEDMOREPARAMS,
  114. format!("{} CAP :{}", nick, INVALID_SYNTAX),
  115. ))])
  116. };
  117. if substr_idx >= args.len() {
  118. return Ok(vec![ReplyType::Server((
  119. ERR_NEEDMOREPARAMS,
  120. format!("{} CAP :{}", nick, INVALID_SYNTAX),
  121. ))])
  122. }
  123. let cap_reqs: Vec<&str> = args[substr_idx + 1..].split(' ').collect();
  124. let mut ack_list = vec![];
  125. let mut nak_list = vec![];
  126. let mut available_caps = self.caps.write().await;
  127. for cap in cap_reqs {
  128. if available_caps.contains_key(cap) {
  129. available_caps.insert(cap.to_string(), true);
  130. ack_list.push(cap);
  131. } else {
  132. nak_list.push(cap);
  133. }
  134. }
  135. let mut replies = vec![];
  136. if !ack_list.is_empty() {
  137. replies.push(ReplyType::Cap(format!(
  138. "CAP {} ACK :{}",
  139. nick,
  140. ack_list.join(" ")
  141. )));
  142. }
  143. if !nak_list.is_empty() {
  144. replies.push(ReplyType::Cap(format!(
  145. "CAP {} NAK :{}",
  146. nick,
  147. nak_list.join(" ")
  148. )));
  149. }
  150. return Ok(replies)
  151. }
  152. "LIST" => {
  153. let enabled_caps: Vec<String> = self
  154. .caps
  155. .read()
  156. .await
  157. .clone()
  158. .into_iter()
  159. .filter(|(_, v)| *v)
  160. .map(|(k, _)| k)
  161. .collect();
  162. return Ok(vec![ReplyType::Cap(format!(
  163. "CAP {} LIST :{}",
  164. nick,
  165. enabled_caps.join(" ")
  166. ))])
  167. }
  168. "END" => {
  169. // At CAP END, if we have USER and NICK, we can welcome them.
  170. self.reg_paused.store(false, SeqCst);
  171. if self.registered.load(SeqCst) && !self.is_cap_end.load(SeqCst) {
  172. self.is_cap_end.store(true, SeqCst);
  173. return Ok(self.welcome().await)
  174. }
  175. return Ok(vec![])
  176. }
  177. _ => {}
  178. }
  179. self.penalty.fetch_add(1, SeqCst);
  180. Ok(vec![ReplyType::Server((
  181. ERR_NEEDMOREPARAMS,
  182. format!("{} CAP :{}", nick, INVALID_SYNTAX),
  183. ))])
  184. }
  185. /// `INFO [<target>]`
  186. ///
  187. /// Gives information about the `<target>` server, or the current server if
  188. /// `<target>` is not used. The information includes the server's version,
  189. /// when it was compiled, the patch level, when it was started, and any
  190. /// other information which might be relevant.
  191. pub async fn handle_cmd_info(&self, _args: &str) -> Result<Vec<ReplyType>> {
  192. if !self.registered.load(SeqCst) {
  193. self.penalty.fetch_add(1, SeqCst);
  194. return Ok(vec![ReplyType::Server((
  195. ERR_NOTREGISTERED,
  196. format!("* :{}", NOT_REGISTERED),
  197. ))])
  198. }
  199. let nick = self.nickname.read().await.clone();
  200. let replies = vec![
  201. ReplyType::Server((
  202. RPL_INFO,
  203. format!("{} :DarkIRC {}", nick, env!("CARGO_PKG_VERSION")),
  204. )),
  205. ReplyType::Server((RPL_ENDOFINFO, format!("{} :End of INFO list", nick))),
  206. ];
  207. Ok(replies)
  208. }
  209. /// `JOIN <channels> [<keys>]`
  210. ///
  211. /// Makes the client join the channels in the list `<channels>`.
  212. /// Passwords can be used in the list `<keys>`. If the channels do not
  213. /// exist, they will be created.
  214. pub async fn handle_cmd_join(&self, args: &str, hist: bool) -> Result<Vec<ReplyType>> {
  215. if !self.registered.load(SeqCst) {
  216. self.penalty.fetch_add(1, SeqCst);
  217. return Ok(vec![ReplyType::Server((
  218. ERR_NOTREGISTERED,
  219. format!("* :{}", NOT_REGISTERED),
  220. ))])
  221. }
  222. // Client's (already) active channels
  223. let mut active_channels = self.channels.write().await;
  224. // Here we'll hold valid channel names.
  225. let mut channels = HashSet::new();
  226. // Let's scan through our channels. For now we'll only support
  227. // channel names starting with a single '#' character.
  228. let nick = self.nickname.read().await.to_string();
  229. let tokens = args.split_ascii_whitespace();
  230. for channel in tokens {
  231. if !channel.starts_with('#') {
  232. self.penalty.fetch_add(1, SeqCst);
  233. return Ok(vec![ReplyType::Server((
  234. ERR_NEEDMOREPARAMS,
  235. format!("{} JOIN :{}", nick, INVALID_SYNTAX),
  236. ))])
  237. }
  238. if !active_channels.contains(channel) {
  239. channels.insert(channel.to_string());
  240. }
  241. }
  242. // We need at least one channel.
  243. if channels.is_empty() {
  244. self.penalty.fetch_add(1, SeqCst);
  245. return Ok(vec![ReplyType::Server((
  246. ERR_NEEDMOREPARAMS,
  247. format!("{} JOIN :{}", nick, INVALID_SYNTAX),
  248. ))])
  249. }
  250. // Weechat sends channels as `#chan1,#chan2,#chan3`. Handle it.
  251. if channels.len() == 1 {
  252. let list = channels.iter().next().unwrap().clone();
  253. channels.remove(list.as_str());
  254. for channel in list.split(',') {
  255. if !channel.starts_with('#') || channel.as_bytes().len() > MAX_NICK_LEN {
  256. self.penalty.fetch_add(1, SeqCst);
  257. return Ok(vec![ReplyType::Server((
  258. ERR_NEEDMOREPARAMS,
  259. format!("{} JOIN :{}", nick, INVALID_SYNTAX),
  260. ))])
  261. }
  262. if !active_channels.contains(channel) {
  263. channels.insert(channel.to_string());
  264. }
  265. }
  266. }
  267. // Create new channels for this client and construct replies.
  268. let mut server_channels = self.server.channels.write().await;
  269. let mut replies = vec![];
  270. for channel in channels.iter() {
  271. // Insert the channel name into the set of client's active channels
  272. active_channels.insert(channel.clone());
  273. // Create or update the channel on the server side.
  274. if let Some(server_chan) = server_channels.get_mut(channel) {
  275. server_chan.nicks.insert(nick.clone());
  276. } else {
  277. let chan = IrcChannel {
  278. topic: String::new(),
  279. nicks: HashSet::from([nick.clone()]),
  280. saltbox: None,
  281. };
  282. server_channels.insert(channel.clone(), chan);
  283. }
  284. // Create the replies
  285. replies.push(ReplyType::Client((nick.clone(), format!("JOIN :{}", channel))));
  286. if let Some(chan) = server_channels.get(channel) {
  287. if !chan.topic.is_empty() {
  288. replies.push(ReplyType::Client((
  289. nick.clone(),
  290. format!("TOPIC {} :{}", channel, chan.topic),
  291. )));
  292. }
  293. }
  294. }
  295. // Drop the locks as they're used in get_history()
  296. drop(active_channels);
  297. drop(server_channels);
  298. if hist {
  299. // Potentially extend the replies with channel history
  300. replies.extend(self.get_history(&channels).await.unwrap());
  301. }
  302. Ok(replies)
  303. }
  304. /// `LIST [<channels> [<server>]]`
  305. ///
  306. /// List all channels on the server. If the list `<channels>` is given, it
  307. /// will return the channel topics. If `<server>` is given, the command will
  308. /// be sent to `<server>` for evaluation.
  309. pub async fn handle_cmd_list(&self, _args: &str) -> Result<Vec<ReplyType>> {
  310. if !self.registered.load(SeqCst) {
  311. self.penalty.fetch_add(1, SeqCst);
  312. return Ok(vec![ReplyType::Server((
  313. ERR_NOTREGISTERED,
  314. format!("* :{}", NOT_REGISTERED),
  315. ))])
  316. }
  317. let nick = self.nickname.read().await.to_string();
  318. let mut list = vec![];
  319. for (name, channel) in self.server.channels.read().await.iter() {
  320. list.push(format!("{} {} {} :{}", nick, name, channel.nicks.len(), channel.topic));
  321. }
  322. let mut replies = vec![];
  323. replies.push(ReplyType::Server((RPL_LISTSTART, format!("{} Channel :Users Name", nick))));
  324. for chan in list {
  325. replies.push(ReplyType::Server((RPL_LIST, chan)));
  326. }
  327. replies.push(ReplyType::Server((RPL_LISTEND, format!("{} :End of /LIST", nick))));
  328. Ok(replies)
  329. }
  330. /// `MODE <nickname> <flags>`
  331. /// `MODE <channel> <flags>`
  332. ///
  333. /// The MODE command has two uses. It can be used to set both user and
  334. /// channel modes.
  335. pub async fn handle_cmd_mode(&self, args: &str) -> Result<Vec<ReplyType>> {
  336. if !self.registered.load(SeqCst) {
  337. self.penalty.fetch_add(1, SeqCst);
  338. return Ok(vec![ReplyType::Server((
  339. ERR_NOTREGISTERED,
  340. format!("* :{}", NOT_REGISTERED),
  341. ))])
  342. }
  343. let nick = self.nickname.read().await.to_string();
  344. let mut tokens = args.split_ascii_whitespace();
  345. let Some(target) = tokens.next() else {
  346. self.penalty.fetch_add(1, SeqCst);
  347. return Ok(vec![ReplyType::Server((
  348. ERR_NEEDMOREPARAMS,
  349. format!("{} MODE :{}", nick, INVALID_SYNTAX),
  350. ))])
  351. };
  352. if target == nick {
  353. return Ok(vec![ReplyType::Server((RPL_UMODEIS, format!("{} +", nick)))])
  354. }
  355. if !target.starts_with('#') {
  356. return Ok(vec![ReplyType::Server((
  357. ERR_USERSDONTMATCH,
  358. format!("{} :Can't set/get mode for other users", nick),
  359. ))])
  360. }
  361. if !self.server.channels.read().await.contains_key(target) {
  362. return Ok(vec![ReplyType::Server((
  363. ERR_NOSUCHNICK,
  364. format!("{} {} :No such nick or channel name", nick, target),
  365. ))])
  366. }
  367. Ok(vec![ReplyType::Server((RPL_CHANNELMODEIS, format!("{} {} +", nick, target)))])
  368. }
  369. /// `MOTD [<server>]`
  370. ///
  371. /// Returns the message of the day on `<server>` or the current server if
  372. /// it is not stated.
  373. pub async fn handle_cmd_motd(&self, _args: &str) -> Result<Vec<ReplyType>> {
  374. let nick = self.nickname.read().await.to_string();
  375. Ok(vec![
  376. ReplyType::Server((
  377. RPL_MOTDSTART,
  378. format!("{} :- {} message of the day", nick, SERVER_NAME),
  379. )),
  380. ReplyType::Server((RPL_MOTD, format!("{} :Let there be dark!", nick))),
  381. ReplyType::Server((RPL_ENDOFMOTD, format!("{} :End of /MOTD command.", nick))),
  382. ])
  383. }
  384. /// `NAMES [<channel>]`
  385. ///
  386. /// Returns a list of who is on the list of `<channel>`, by channel name.
  387. /// If `<channel>` is not used, all users are shown. They are grouped by
  388. /// channel name with all users who are not on a channel being shown as
  389. /// part of channel "*".
  390. pub async fn handle_cmd_names(&self, args: &str) -> Result<Vec<ReplyType>> {
  391. if !self.registered.load(SeqCst) {
  392. self.penalty.fetch_add(1, SeqCst);
  393. return Ok(vec![ReplyType::Server((
  394. ERR_NOTREGISTERED,
  395. format!("* :{}", NOT_REGISTERED),
  396. ))])
  397. }
  398. let nick = self.nickname.read().await.to_string();
  399. let mut tokens = args.split_ascii_whitespace();
  400. let mut replies = vec![];
  401. // If a channel was requested, reply only with that one.
  402. // Otherwise, return info for all known channels.
  403. if let Some(req_chan) = tokens.next() {
  404. if let Some(chan) = self.server.channels.read().await.get(req_chan) {
  405. let nicks: Vec<String> = chan.nicks.iter().cloned().collect();
  406. replies.push(ReplyType::Server((
  407. RPL_NAMREPLY,
  408. format!("{} = {} :{}", nick, req_chan, nicks.join(" ")),
  409. )));
  410. }
  411. replies.push(ReplyType::Server((
  412. RPL_ENDOFNAMES,
  413. format!("{} {} :End of NAMES list", nick, req_chan),
  414. )));
  415. Ok(replies)
  416. } else {
  417. for (name, chan) in self.server.channels.read().await.iter() {
  418. let nicks: Vec<String> = chan.nicks.iter().cloned().collect();
  419. replies.push(ReplyType::Server((
  420. RPL_NAMREPLY,
  421. format!("{} = {} :{}", nick, name, nicks.join(" ")),
  422. )));
  423. }
  424. replies.push(ReplyType::Server((
  425. RPL_ENDOFNAMES,
  426. format!("{} * :End of NAMES list", nick),
  427. )));
  428. Ok(replies)
  429. }
  430. }
  431. /// `NICK <nickname>`
  432. ///
  433. /// Allows a client to change their IRC nickname.
  434. pub async fn handle_cmd_nick(&self, args: &str) -> Result<Vec<ReplyType>> {
  435. // Parse the line
  436. let mut tokens = args.split_ascii_whitespace();
  437. // Reference the current nickname
  438. let old_nick = self.nickname.read().await.to_string();
  439. let Some(nickname) = tokens.next() else {
  440. self.penalty.fetch_add(1, SeqCst);
  441. return Ok(vec![ReplyType::Server((
  442. ERR_NEEDMOREPARAMS,
  443. format!("{} NICK :{}", old_nick, INVALID_SYNTAX),
  444. ))])
  445. };
  446. // Forbid disallowed characters.
  447. // The next() call is done to check for ASCII whitespace in the nick.
  448. if tokens.next().is_some() || nickname.starts_with(':') || nickname.starts_with('#') {
  449. self.penalty.fetch_add(1, SeqCst);
  450. return Ok(vec![ReplyType::Server((
  451. ERR_ERRONEOUSNICKNAME,
  452. format!("{} {} :Erroneous nickname", old_nick, nickname),
  453. ))])
  454. }
  455. // Disallow too long nicks
  456. if nickname.as_bytes().len() > MAX_NICK_LEN {
  457. self.penalty.fetch_add(1, SeqCst);
  458. return Ok(vec![ReplyType::Server((
  459. ERR_ERRONEOUSNICKNAME,
  460. format!("{} {} :Nickname too long", old_nick, nickname),
  461. ))])
  462. }
  463. // Set the new nickname
  464. *self.nickname.write().await = nickname.to_string();
  465. // If the username is set, we can complete the registration
  466. if *self.username.read().await != "*" &&
  467. !self.registered.load(SeqCst) &&
  468. self.is_pass_set.load(SeqCst)
  469. {
  470. self.registered.store(true, SeqCst);
  471. if self.reg_paused.load(SeqCst) {
  472. return Ok(vec![])
  473. } else {
  474. return Ok(self.welcome().await)
  475. }
  476. }
  477. // If we were registered, we send a client reply about it.
  478. if self.registered.load(SeqCst) {
  479. Ok(vec![ReplyType::Client((old_nick, format!("NICK :{}", nickname)))])
  480. } else {
  481. // Otherwise, we don't reply.
  482. Ok(vec![])
  483. }
  484. }
  485. /// `PART <channel>`
  486. ///
  487. /// Causes a user to leave the channel `<channel>`.
  488. pub async fn handle_cmd_part(&self, args: &str) -> Result<Vec<ReplyType>> {
  489. if !self.registered.load(SeqCst) {
  490. self.penalty.fetch_add(1, SeqCst);
  491. return Ok(vec![ReplyType::Server((
  492. ERR_NOTREGISTERED,
  493. format!("* :{}", NOT_REGISTERED),
  494. ))])
  495. }
  496. let nick = self.nickname.read().await.to_string();
  497. let mut tokens = args.split_ascii_whitespace();
  498. let Some(channel) = tokens.next() else {
  499. self.penalty.fetch_add(1, SeqCst);
  500. return Ok(vec![ReplyType::Server((
  501. ERR_NEEDMOREPARAMS,
  502. format!("{} PART :{}", nick, INVALID_SYNTAX),
  503. ))])
  504. };
  505. if !channel.starts_with('#') {
  506. self.penalty.fetch_add(1, SeqCst);
  507. return Ok(vec![ReplyType::Server((
  508. ERR_NEEDMOREPARAMS,
  509. format!("{} PART :{}", nick, INVALID_SYNTAX),
  510. ))])
  511. }
  512. let mut active_channels = self.channels.write().await;
  513. if !active_channels.contains(channel) {
  514. return Ok(vec![ReplyType::Server((
  515. ERR_NOSUCHCHANNEL,
  516. format!("{} {} :No such channel", nick, channel),
  517. ))])
  518. }
  519. // Remove the channel from the client's channel list
  520. active_channels.remove(channel);
  521. let replies = vec![ReplyType::Client((nick, format!("PART {} :Bye", channel)))];
  522. Ok(replies)
  523. }
  524. /// `PASS <password>`
  525. ///
  526. /// Used to set a ‘connection password’. If set, the password must
  527. /// be set before USER/NICK commands.
  528. pub async fn handle_cmd_pass(&self, args: &str) -> Result<Vec<ReplyType>> {
  529. let mut tokens = args.split_ascii_whitespace();
  530. let nick = self.nickname.read().await.to_string();
  531. let Some(password) = tokens.next() else {
  532. // self.penalty.fetch_add(1, SeqCst);
  533. return Ok(vec![ReplyType::Server((
  534. ERR_NEEDMOREPARAMS,
  535. format!("{} PASS :{}", nick, INVALID_SYNTAX),
  536. ))])
  537. };
  538. if self.server.password == bcrypt_hash_password(password) {
  539. self.is_pass_set.store(true, SeqCst);
  540. } else {
  541. error!("[IRC CLIENT] Password is not correct!");
  542. return Ok(vec![ReplyType::Server((
  543. ERR_PASSWDMISMATCH,
  544. format!("{} PASS :{}", nick, PASSWORD_MISMATCH),
  545. ))])
  546. }
  547. Ok(vec![])
  548. }
  549. /// `PING <server1>`
  550. ///
  551. /// Tests a connection. A PING message results in a PONG reply.
  552. pub async fn handle_cmd_ping(&self, args: &str) -> Result<Vec<ReplyType>> {
  553. if !self.registered.load(SeqCst) {
  554. self.penalty.fetch_add(1, SeqCst);
  555. return Ok(vec![ReplyType::Server((
  556. ERR_NOTREGISTERED,
  557. format!("* :{}", NOT_REGISTERED),
  558. ))])
  559. }
  560. let mut tokens = args.split_ascii_whitespace();
  561. let Some(origin) = tokens.next() else {
  562. self.penalty.fetch_add(1, SeqCst);
  563. return Ok(vec![ReplyType::Server((
  564. ERR_NOORIGIN,
  565. format!("{} :No origin specified", self.nickname.read().await),
  566. ))])
  567. };
  568. Ok(vec![ReplyType::Pong(origin.to_string())])
  569. }
  570. /// `PRIVMSG <msgtarget> <message>`
  571. ///
  572. /// Sends `<message>` to `<msgtarget>`. The target is usually a user or
  573. /// a channel.
  574. pub async fn handle_cmd_privmsg(&self, args: &str) -> Result<Vec<ReplyType>> {
  575. if !self.registered.load(SeqCst) {
  576. self.penalty.fetch_add(1, SeqCst);
  577. return Ok(vec![ReplyType::Server((
  578. ERR_NOTREGISTERED,
  579. format!("* :{}", NOT_REGISTERED),
  580. ))])
  581. }
  582. let nick = self.nickname.read().await.to_string();
  583. let mut tokens = args.split_ascii_whitespace();
  584. let Some(target) = tokens.next() else {
  585. return Ok(vec![ReplyType::Server((
  586. ERR_NORECIPIENT,
  587. format!("{} :No recipient given (PRIVMSG)", nick),
  588. ))])
  589. };
  590. let Some(message) = tokens.next() else {
  591. return Ok(vec![ReplyType::Server((
  592. ERR_NOTEXTTOSEND,
  593. format!("{} :No text to send", nick),
  594. ))])
  595. };
  596. if !message.starts_with(':') {
  597. return Ok(vec![ReplyType::Server((
  598. ERR_NOTEXTTOSEND,
  599. format!("{} :No text to send", nick),
  600. ))])
  601. }
  602. // We only send a client reply if the message is for ourself or if
  603. // we're trying to communicate with IRC services.
  604. // Anything else is rendered by the IRC client and not supposed
  605. // to be echoed by the IRC serer.
  606. if target == nick {
  607. return Ok(vec![ReplyType::Client((
  608. target.to_string(),
  609. format!("PRIVMSG {} {}", target, message),
  610. ))])
  611. }
  612. // Handle queries to NickServ
  613. if target.to_lowercase().as_str() == "nickserv" {
  614. return self.nickserv.handle_query(message.strip_prefix(':').unwrap()).await
  615. }
  616. // If it's a DM and we don't have an encryption key, we will
  617. // refuse to send it. Send ERR_NORECIPIENT to the client.
  618. if !target.starts_with('#') && !self.server.contacts.read().await.contains_key(target) {
  619. return Ok(vec![ReplyType::Server((ERR_NOSUCHNICK, format!("{} :{}", nick, target)))])
  620. }
  621. Ok(vec![])
  622. }
  623. /// `REHASH`
  624. ///
  625. /// Causes the server to re-read and re-process its configuration file(s).
  626. pub async fn handle_cmd_rehash(&self, _args: &str) -> Result<Vec<ReplyType>> {
  627. info!("Attempting to rehash server...");
  628. if let Err(e) = self.server.rehash().await {
  629. error!("Failed to rehash server: {}", e);
  630. }
  631. Ok(vec![])
  632. }
  633. /// `TOPIC <channel> [<topic>]`
  634. ///
  635. /// Used to get the channel topic on `<channel>`. If `<topic>` is given, it
  636. /// sets the channel topic to `<topic>`.
  637. pub async fn handle_cmd_topic(&self, args: &str) -> Result<Vec<ReplyType>> {
  638. if !self.registered.load(SeqCst) {
  639. self.penalty.fetch_add(1, SeqCst);
  640. return Ok(vec![ReplyType::Server((
  641. ERR_NOTREGISTERED,
  642. format!("* :{}", NOT_REGISTERED),
  643. ))])
  644. }
  645. let nick = self.nickname.read().await.to_string();
  646. let mut tokens = args.split_ascii_whitespace();
  647. let Some(channel) = tokens.next() else {
  648. self.penalty.fetch_add(1, SeqCst);
  649. return Ok(vec![ReplyType::Server((
  650. ERR_NEEDMOREPARAMS,
  651. format!("{} TOPIC :{}", nick, INVALID_SYNTAX),
  652. ))])
  653. };
  654. if !self.server.channels.read().await.contains_key(channel) {
  655. return Ok(vec![ReplyType::Server((
  656. ERR_NOSUCHCHANNEL,
  657. format!("{} {} :No such channel", nick, channel),
  658. ))])
  659. }
  660. // If there's a topic, we'll set it, otherwise return the set topic.
  661. let Some(topic) = tokens.next() else {
  662. let topic = self.server.channels.read().await.get(channel).unwrap().topic.clone();
  663. if topic.is_empty() {
  664. return Ok(vec![ReplyType::Server((
  665. RPL_NOTOPIC,
  666. format!("{} {} :No topic is set", nick, channel),
  667. ))])
  668. } else {
  669. return Ok(vec![ReplyType::Server((
  670. RPL_TOPIC,
  671. format!("{} {} :{}", nick, channel, topic),
  672. ))])
  673. }
  674. };
  675. // Set the new topic
  676. self.server.channels.write().await.get_mut(channel).unwrap().topic =
  677. topic.strip_prefix(':').unwrap().to_string();
  678. // Send reply
  679. let replies = vec![ReplyType::Client((nick, format!("TOPIC {} {}", channel, topic)))];
  680. Ok(replies)
  681. }
  682. /// `USER <user> <mode> <unused> <realname>`
  683. ///
  684. /// This command is used at the beginning of a connection to specify the
  685. /// username, hostname, real name, and the initial user modes of the
  686. /// connecting client. `<realname>` may contain spaces, and thus must be
  687. /// prefixed with a colon.
  688. pub async fn handle_cmd_user(&self, args: &str) -> Result<Vec<ReplyType>> {
  689. if self.registered.load(SeqCst) {
  690. self.penalty.fetch_add(1, SeqCst);
  691. return Ok(vec![ReplyType::Server((
  692. ERR_ALREADYREGISTERED,
  693. format!("{} :{}", self.nickname.read().await, ALREADY_REGISTERED),
  694. ))])
  695. }
  696. // If password is not set register user normally
  697. if self.server.password.is_empty() {
  698. self.is_pass_set.store(true, SeqCst);
  699. }
  700. // Parse the line
  701. let nick = self.nickname.read().await.to_string();
  702. let mut tokens = args.split_ascii_whitespace();
  703. let Some(username) = tokens.next() else {
  704. self.penalty.fetch_add(1, SeqCst);
  705. return Ok(vec![ReplyType::Server((
  706. ERR_NEEDMOREPARAMS,
  707. format!("{} USER :{}", nick, INVALID_SYNTAX),
  708. ))])
  709. };
  710. // Mode syntax is currently ignored, but should be part of the command
  711. let Some(_mode) = tokens.next() else {
  712. self.penalty.fetch_add(1, SeqCst);
  713. return Ok(vec![ReplyType::Server((
  714. ERR_NEEDMOREPARAMS,
  715. format!("{} USER :{}", nick, INVALID_SYNTAX),
  716. ))])
  717. };
  718. // Next token is unused per RFC, but should be part of the command
  719. let Some(_unused) = tokens.next() else {
  720. self.penalty.fetch_add(1, SeqCst);
  721. return Ok(vec![ReplyType::Server((
  722. ERR_NEEDMOREPARAMS,
  723. format!("{} USER :{}", nick, INVALID_SYNTAX),
  724. ))])
  725. };
  726. // The final token should be realname and should start with a colon
  727. let Some(realname) = tokens.next() else {
  728. self.penalty.fetch_add(1, SeqCst);
  729. return Ok(vec![ReplyType::Server((
  730. ERR_NEEDMOREPARAMS,
  731. format!("{} USER :{}", nick, INVALID_SYNTAX),
  732. ))])
  733. };
  734. if !realname.starts_with(':') {
  735. self.penalty.fetch_add(1, SeqCst);
  736. return Ok(vec![ReplyType::Server((
  737. ERR_NEEDMOREPARAMS,
  738. format!("{} USER :{}", nick, INVALID_SYNTAX),
  739. ))])
  740. }
  741. *self.username.write().await = username.to_string();
  742. *self.realname.write().await = realname.to_string();
  743. // If the nickname is set, we can complete the registration
  744. if nick != "*" {
  745. if !self.is_pass_set.load(SeqCst) {
  746. return Ok(vec![ReplyType::Server((
  747. ERR_PASSWDMISMATCH,
  748. format!("{} PASS :{}", nick, PASSWORD_MISMATCH),
  749. ))])
  750. }
  751. self.registered.store(true, SeqCst);
  752. if self.reg_paused.load(SeqCst) {
  753. return Ok(vec![])
  754. } else {
  755. return Ok(self.welcome().await)
  756. }
  757. }
  758. // Otherwise, we don't have to reply.
  759. Ok(vec![])
  760. }
  761. /// `VERSION`
  762. ///
  763. /// Returns the version of the server.
  764. pub async fn handle_cmd_version(&self, _args: &str) -> Result<Vec<ReplyType>> {
  765. if !self.registered.load(SeqCst) {
  766. self.penalty.fetch_add(1, SeqCst);
  767. return Ok(vec![ReplyType::Server((
  768. ERR_NOTREGISTERED,
  769. format!("* :{}", NOT_REGISTERED),
  770. ))])
  771. }
  772. let replies = vec![ReplyType::Server((
  773. RPL_VERSION,
  774. format!(
  775. "{} {} {} :Let there be dark!",
  776. self.nickname.read().await,
  777. env!("CARGO_PKG_VERSION"),
  778. SERVER_NAME
  779. ),
  780. ))];
  781. Ok(replies)
  782. }
  783. /// Internal function that constructs the welcome message.
  784. async fn welcome(&self) -> Vec<ReplyType> {
  785. let nick = self.nickname.read().await.to_string();
  786. let mut replies = vec![
  787. ReplyType::Server((RPL_WELCOME, format!("{} :{}", nick, WELCOME))),
  788. ReplyType::Server((
  789. RPL_YOURHOST,
  790. format!(
  791. "{} :Your host is irc.dark.fi, running version {}",
  792. nick,
  793. env!("CARGO_PKG_VERSION")
  794. ),
  795. )),
  796. ];
  797. // Append the MOTD
  798. replies.append(&mut self.handle_cmd_motd("").await.unwrap());
  799. let mut channels = HashSet::new();
  800. // If we have any configured autojoin channels, let's join the user
  801. // and set their topics, if any.
  802. if !*self.caps.read().await.get("no-autojoin").unwrap() {
  803. for channel in self.server.autojoin.read().await.iter() {
  804. replies.extend(self.handle_cmd_join(channel, false).await.unwrap());
  805. channels.insert(channel.to_string());
  806. }
  807. }
  808. // Potentially extend the replies with channel history
  809. replies.extend(self.get_history(&channels).await.unwrap());
  810. // And request NAMES list.
  811. if !*self.caps.read().await.get("no-autojoin").unwrap() {
  812. for channel in self.server.autojoin.read().await.iter() {
  813. if let Some(chan) = self.server.channels.read().await.get(channel) {
  814. let nicks: Vec<String> = chan.nicks.iter().cloned().collect();
  815. replies.push(ReplyType::Server((
  816. RPL_NAMREPLY,
  817. format!("{} = {} :{}", nick, channel, nicks.join(" ")),
  818. )));
  819. }
  820. replies.push(ReplyType::Server((
  821. RPL_ENDOFNAMES,
  822. format!("{} {} :End of NAMES list", nick, channel),
  823. )));
  824. }
  825. }
  826. replies
  827. }
  828. /// Internal function that scans the DAG and returns events for
  829. /// given channels. Will return empty if no_history CAP is requested.
  830. async fn get_history(&self, channels: &HashSet<String>) -> Result<Vec<ReplyType>> {
  831. if channels.is_empty() || *self.caps.read().await.get("no-history").unwrap() {
  832. return Ok(vec![])
  833. }
  834. // Fetch and order all the events from the DAG
  835. let dag_events = self.server.darkirc.event_graph.order_events().await;
  836. // Here we'll hold the events in order we'll push to the client
  837. let mut replies = vec![];
  838. for event_id in dag_events.iter() {
  839. // If it was seen, skip
  840. match self.is_seen(event_id).await {
  841. Ok(true) => continue,
  842. Ok(false) => {}
  843. Err(e) => {
  844. error!("[IRC CLIENT] (get_history) self.is_seen({}) failed: {}", event_id, e);
  845. return Err(e)
  846. }
  847. }
  848. // Get the event from the DAG
  849. let event = self.server.darkirc.event_graph.dag_get(event_id).await.unwrap().unwrap();
  850. // Try to deserialize it. (Here we skip errors)
  851. let Ok((mut privmsg, _)) = deserialize_async_partial(event.content()).await else {
  852. continue
  853. };
  854. // Potentially decrypt the privmsg
  855. self.server.try_decrypt(&mut privmsg).await;
  856. // If the privmsg is intented for any of the given
  857. // channels, contacts or oursleves, add it as a reply and
  858. // mark it as seen in the seen_events tree.
  859. let contacts = self.server.contacts.read().await;
  860. if !channels.contains(&privmsg.channel) &&
  861. !contacts.contains_key(&privmsg.channel) &&
  862. !contacts.contains_key(&privmsg.nick)
  863. {
  864. continue
  865. }
  866. // Insert nicks into channels
  867. if let Some(chan) = self.server.channels.write().await.get_mut(&privmsg.channel) {
  868. chan.nicks.insert(privmsg.nick.clone());
  869. }
  870. let msg = format!("PRIVMSG {} :{}", privmsg.channel, privmsg.msg);
  871. replies.push(ReplyType::Client((privmsg.nick, msg)));
  872. if let Err(e) = self.mark_seen(event_id).await {
  873. error!("[IRC CLIENT] (get_history) self.mark_seen({}) failed: {}", event_id, e);
  874. return Err(e)
  875. }
  876. }
  877. Ok(replies)
  878. }
  879. }