/* This file is part of DarkFi (https://dark.fi) * * Copyright (C) 2020-2022 Dyne.org foundation * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ use crypto_box::SalsaBox; use log::error; use serde::{self, Deserialize, Serialize}; use std::collections::HashMap; use structopt::StructOpt; use structopt_toml::StructOptToml; use url::Url; use darkfi::{net::settings::SettingsOpt, Result}; // Location for config file pub const CONFIG_FILE: &str = "ircd_config.toml"; pub const CONFIG_FILE_CONTENTS: &str = include_str!("../ircd_config.toml"); // Msg config pub const MAXIMUM_LENGTH_OF_MESSAGE: usize = 1024; pub const MAXIMUM_LENGTH_OF_NICKNAME: usize = 32; // IRC Client pub enum RPL { NoTopic = 331, Topic = 332, NameReply = 353, EndOfNames = 366, } /// ircd cli #[derive(Clone, Deserialize, StructOpt, StructOptToml)] #[serde(default)] #[structopt(name = "ircd")] pub struct Args { /// Sets a custom config file #[structopt(long)] pub config: Option, /// JSON-RPC listen URL #[structopt(long = "rpc", default_value = "tcp://127.0.0.1:25550")] pub rpc_listen: Url, /// IRC listen URL #[structopt(long = "irc", default_value = "tcp://127.0.0.1:6667")] pub irc_listen: Url, /// Optional TLS certificate file path if `irc_listen` uses TLS pub irc_tls_cert: Option, /// Optional TLS certificate key file path if `irc_listen` uses TLS pub irc_tls_secret: Option, /// Generate a new NaCl keypair and exit #[structopt(long)] pub gen_keypair: bool, /// Path to save keypair in #[structopt(short)] pub output: Option, /// Autojoin channels #[structopt(long)] pub autojoin: Vec, /// Password #[structopt(long)] pub password: Option, /// Channels #[structopt(skip)] pub channels: HashMap, /// Channels #[structopt(skip)] pub contacts: HashMap, /// Private key #[structopt(skip)] pub private_key: Option, #[structopt(flatten)] pub net: SettingsOpt, /// Increase verbosity #[structopt(short, parse(from_occurrences))] pub verbose: u8, } /// This struct holds information about preconfigured contacts. /// In the TOML configuration file, we can configure contacts as such: /// /// ```toml /// [contact."nick"] /// pubkey = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM" /// ``` #[derive(Default, Clone, Debug, Deserialize, Serialize)] pub struct ContactInfo { pub pubkey: Option, } impl ContactInfo { pub fn new() -> Self { Self { pubkey: None } } pub fn salt_box(&self, private_key: &str, contact_name: &str) -> Option { if let Ok(private) = parse_priv(private_key) { if let Some(p) = &self.pubkey { if let Ok(public) = parse_pub(p) { return Some(SalsaBox::new(&public, &private)) } else { error!("Uncorrect public key in for contact {}", contact_name); } } } else { error!("Uncorrect Private key in config",); } None } } /// This struct holds information about preconfigured channels. /// In the TOML configuration file, we can configure channels as such: /// ```toml /// [channel."#dev"] /// secret = "GvH4kno3kUu6dqPrZ8zjMhqxTUDZ2ev16EdprZiZJgj1" /// topic = "DarkFi Development Channel" /// ``` /// Having a secret will enable a NaCl box that is able to encrypt and /// decrypt messages in this channel using this set shared secret. /// The secret should be shared OOB, via a secure channel. /// Having a topic set is useful if one wants to have a topic in the /// configured channel. It is not shared with others, but it is useful /// for personal reference. #[derive(Default, Clone, Debug, Serialize, Deserialize)] pub struct ChannelInfo { /// Optional topic for the channel pub topic: Option, /// Optional NaCl box for the channel, used for {en,de}cryption. pub secret: Option, /// Flag indicates whether the user has joined the channel or not #[serde(default, skip_serializing)] pub joined: bool, /// All nicknames which are visible on the channel #[serde(default, skip_serializing)] pub names: Vec, } impl ChannelInfo { pub fn new() -> Self { Self { topic: None, secret: None, joined: false, names: vec![] } } pub fn salt_box(&self, channel_name: &str) -> Option { if let Some(s) = &self.secret { let secret = parse_priv(s); if secret.is_err() { error!("Uncorrect secret key for the channel {}", channel_name); return None } let secret = secret.unwrap(); let public = secret.public_key(); return Some(SalsaBox::new(&public, &secret)) } None } } pub fn get_current_time() -> u64 { let start = std::time::SystemTime::now(); start .duration_since(std::time::UNIX_EPOCH) .expect("Time went backwards") .as_millis() .try_into() .unwrap() } fn parse_priv(key: &str) -> Result { let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap(); Ok(crypto_box::SecretKey::from(bytes)) } fn parse_pub(key: &str) -> Result { let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap(); Ok(crypto_box::PublicKey::from(bytes)) }