settings.rs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. use fxhash::FxHashMap;
  2. use log::info;
  3. use serde::Deserialize;
  4. use structopt::StructOpt;
  5. use structopt_toml::StructOptToml;
  6. use toml::Value;
  7. use url::Url;
  8. use darkfi::{net::settings::SettingsOpt, Result};
  9. pub const CONFIG_FILE: &str = "ircd_config.toml";
  10. pub const CONFIG_FILE_CONTENTS: &str = include_str!("../ircd_config.toml");
  11. /// ircd cli
  12. #[derive(Clone, Debug, Deserialize, StructOpt, StructOptToml)]
  13. #[serde(default)]
  14. #[structopt(name = "ircd")]
  15. pub struct Args {
  16. /// Sets a custom config file
  17. #[structopt(long)]
  18. pub config: Option<String>,
  19. /// JSON-RPC listen URL
  20. #[structopt(long = "rpc", default_value = "tcp://127.0.0.1:11055")]
  21. pub rpc_listen: Url,
  22. /// IRC listen URL
  23. #[structopt(long = "irc", default_value = "tcp://127.0.0.1:11066")]
  24. pub irc_listen: Url,
  25. /// Optional TLS certificate file path if `irc_listen` uses TLS
  26. pub irc_tls_cert: Option<String>,
  27. /// Optional TLS certificate key file path if `irc_listen` uses TLS
  28. pub irc_tls_secret: Option<String>,
  29. /// Generate a new NaCl secret and exit
  30. #[structopt(long)]
  31. pub gen_secret: bool,
  32. /// Autojoin channels
  33. #[structopt(long)]
  34. pub autojoin: Vec<String>,
  35. #[structopt(flatten)]
  36. pub net: SettingsOpt,
  37. /// Increase verbosity
  38. #[structopt(short, parse(from_occurrences))]
  39. pub verbose: u8,
  40. }
  41. /// This struct holds information about preconfigured channels.
  42. /// In the TOML configuration file, we can configure channels as such:
  43. /// ```toml
  44. /// [channel."#dev"]
  45. /// secret = "GvH4kno3kUu6dqPrZ8zjMhqxTUDZ2ev16EdprZiZJgj1"
  46. /// topic = "DarkFi Development Channel"
  47. /// ```
  48. /// Having a secret will enable a NaCl box that is able to encrypt and
  49. /// decrypt messages in this channel using this set shared secret.
  50. /// The secret should be shared OOB, via a secure channel.
  51. /// Having a topic set is useful if one wants to have a topic in the
  52. /// configured channel. It is not shared with others, but it is useful
  53. /// for personal reference.
  54. #[derive(Clone)]
  55. pub struct ChannelInfo {
  56. /// Optional topic for the channel
  57. pub topic: Option<String>,
  58. /// Optional NaCl box for the channel, used for {en,de}cryption.
  59. pub salt_box: Option<crypto_box::Box>,
  60. /// Flag indicates whether the user has joined the channel or not
  61. pub joined: bool,
  62. /// All nicknames which are visible on the channel
  63. pub names: Vec<String>,
  64. }
  65. impl ChannelInfo {
  66. pub fn new() -> Result<Self> {
  67. Ok(Self { topic: None, salt_box: None, joined: false, names: vec![] })
  68. }
  69. }
  70. fn salt_box_from_shared_secret(s: &str) -> Result<crypto_box::Box> {
  71. let bytes: [u8; 32] = bs58::decode(s).into_vec()?.try_into().unwrap();
  72. let secret = crypto_box::SecretKey::from(bytes);
  73. let public = secret.public_key();
  74. Ok(crypto_box::Box::new(&public, &secret))
  75. }
  76. /// Parse a TOML string for any configured contact list and return
  77. /// a map containing said configurations.
  78. ///
  79. /// ```toml
  80. /// [contact."7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"]
  81. /// nicks = ["sneed", "chuck"]
  82. /// ```
  83. pub fn parse_configured_contacts(data: &str) -> Result<FxHashMap<String, crypto_box::Box>> {
  84. let mut ret = FxHashMap::default();
  85. if let Value::Table(map) = toml::from_str(data)? {
  86. if map.contains_key("contact") && map["contact"].is_table() {
  87. for contact in map["contact"].as_table().unwrap() {
  88. // (secret, nicks = [nick0, nick1])
  89. if contact.1.as_table().unwrap().contains_key("nicks") {
  90. if let Some(nicks) = contact.1["nicks"].as_array() {
  91. let salt_box = salt_box_from_shared_secret(contact.0.as_str())?;
  92. for nick in nicks {
  93. if let Some(n) = nick.as_str() {
  94. info!("Instantiated salt box for {}", n);
  95. ret.insert(n.to_string(), salt_box.clone());
  96. }
  97. }
  98. }
  99. }
  100. }
  101. }
  102. }
  103. Ok(ret)
  104. }
  105. /// Parse a TOML string for any configured channels and return
  106. /// a map containing said configurations.
  107. ///
  108. /// ```toml
  109. /// [channel."#memes"]
  110. /// secret = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"
  111. /// topic = "Dank Memes"
  112. /// ```
  113. pub fn parse_configured_channels(data: &str) -> Result<FxHashMap<String, ChannelInfo>> {
  114. let mut ret = FxHashMap::default();
  115. if let Value::Table(map) = toml::from_str(data)? {
  116. if map.contains_key("channel") && map["channel"].is_table() {
  117. for chan in map["channel"].as_table().unwrap() {
  118. info!("Found configuration for channel {}", chan.0);
  119. let mut channel_info = ChannelInfo::new()?;
  120. if chan.1.as_table().unwrap().contains_key("topic") {
  121. let topic = chan.1["topic"].as_str().unwrap().to_string();
  122. info!("Found topic for channel {}: {}", chan.0, topic);
  123. channel_info.topic = Some(topic);
  124. }
  125. if chan.1.as_table().unwrap().contains_key("secret") {
  126. // Build the NaCl box
  127. if let Some(s) = chan.1["secret"].as_str() {
  128. let salt_box = salt_box_from_shared_secret(s)?;
  129. channel_info.salt_box = Some(salt_box);
  130. info!("Instantiated NaCl box for channel {}", chan.0);
  131. }
  132. }
  133. ret.insert(chan.0.to_string(), channel_info);
  134. }
  135. }
  136. };
  137. Ok(ret)
  138. }