mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-09 14:48:08 -05:00
bin/darkirc: added support for private channels and DMs
This commit is contained in:
@@ -80,40 +80,48 @@ pub fn encrypt(salt_box: &SalsaBox, plaintext: &str) -> String {
|
||||
bs58::encode(concat).into_string()
|
||||
}
|
||||
|
||||
/// Decrypt PrivMsg target
|
||||
pub fn decrypt_target(
|
||||
contact: &mut String,
|
||||
privmsg: &mut PrivMsgEvent,
|
||||
configured_chans: &HashMap<String, ChannelInfo>,
|
||||
configured_contacts: &HashMap<String, ContactInfo>,
|
||||
private_key: &Option<String>,
|
||||
configured_chans: HashMap<String, ChannelInfo>,
|
||||
configured_contacts: HashMap<String, ContactInfo>,
|
||||
) {
|
||||
for (name, chan_info) in configured_chans {
|
||||
for chan_name in configured_chans.keys() {
|
||||
let chan_info = configured_chans.get(chan_name).unwrap();
|
||||
if !chan_info.joined {
|
||||
continue
|
||||
}
|
||||
|
||||
let salt_box = chan_info.salt_box(name).clone();
|
||||
let salt_box = chan_info.salt_box.clone();
|
||||
|
||||
if let Some(salt_box) = salt_box {
|
||||
if try_decrypt(&salt_box, &privmsg.target).is_some() {
|
||||
privmsg.target = name.clone();
|
||||
let decrypted_target = try_decrypt(&salt_box, &privmsg.target);
|
||||
if decrypted_target.is_none() {
|
||||
continue
|
||||
}
|
||||
|
||||
let target = decrypted_target.unwrap();
|
||||
if *chan_name == target {
|
||||
privmsg.target = target;
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if private_key.is_none() {
|
||||
return
|
||||
}
|
||||
|
||||
for (name, contact_info) in configured_contacts {
|
||||
let salt_box = contact_info.salt_box(private_key.as_ref().unwrap(), name).clone();
|
||||
for cnt_name in configured_contacts.keys() {
|
||||
let cnt_info = configured_contacts.get(cnt_name).unwrap();
|
||||
|
||||
let salt_box = cnt_info.salt_box.clone();
|
||||
if let Some(salt_box) = salt_box {
|
||||
if try_decrypt(&salt_box, &privmsg.target).is_some() {
|
||||
privmsg.target = name.clone();
|
||||
return
|
||||
let decrypted_target = try_decrypt(&salt_box, &privmsg.target);
|
||||
if decrypted_target.is_none() {
|
||||
continue
|
||||
}
|
||||
|
||||
let target = decrypted_target.unwrap();
|
||||
privmsg.target = target;
|
||||
*contact = cnt_name.into();
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +26,11 @@ use futures::{
|
||||
|
||||
use log::{debug, error, info, warn};
|
||||
|
||||
use darkfi::{event_graph::model::Event, system::Subscription, Error, Result};
|
||||
use darkfi::{
|
||||
event_graph::{model::Event, EventMsg},
|
||||
system::Subscription,
|
||||
Error, Result,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
crypto::{decrypt_privmsg, decrypt_target, encrypt_privmsg},
|
||||
@@ -115,23 +119,27 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
|
||||
self.irc_config.channels.extend(new_config.channels);
|
||||
self.irc_config.contacts.extend(new_config.contacts);
|
||||
self.irc_config.nickname = new_config.nickname;
|
||||
self.irc_config.private_key = new_config.private_key;
|
||||
// self.irc_config.private_key = new_config.private_key;
|
||||
self.irc_config.password = new_config.password;
|
||||
|
||||
if self.on_receive_join(self.irc_config.channels.keys().cloned().collect()).await.is_err() {
|
||||
warn!("Error to join updated channels");
|
||||
} else {
|
||||
info!("[CLIENT {}] Config updated", self.address);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn process_msg(&mut self, msg: &mut PrivMsgEvent) -> Result<()> {
|
||||
info!("[CLIENT {}] msg from View: {:?}", self.address, msg.to_string());
|
||||
|
||||
let mut msg = msg.clone();
|
||||
let mut contact = String::new();
|
||||
|
||||
decrypt_target(
|
||||
msg,
|
||||
&self.irc_config.channels,
|
||||
&self.irc_config.contacts,
|
||||
&self.irc_config.private_key,
|
||||
&mut contact,
|
||||
&mut msg,
|
||||
self.irc_config.channels.clone(),
|
||||
self.irc_config.contacts.clone(),
|
||||
);
|
||||
|
||||
if msg.target.starts_with('#') {
|
||||
@@ -145,13 +153,9 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if let Some(salt_box) = &chan_info.salt_box(&msg.target) {
|
||||
decrypt_privmsg(salt_box, msg);
|
||||
info!(
|
||||
"[CLIENT {}] Decrypted received message: {:?}",
|
||||
self.address,
|
||||
msg.to_string()
|
||||
);
|
||||
if let Some(salt_box) = &chan_info.salt_box {
|
||||
decrypt_privmsg(salt_box, &mut msg);
|
||||
info!("Decrypted received message: {:?}", msg);
|
||||
}
|
||||
|
||||
// add the nickname to the channel's names
|
||||
@@ -160,25 +164,20 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
}
|
||||
|
||||
self.reply(&msg.to_string()).await?;
|
||||
} else if self.irc_config.private_key.is_some() {
|
||||
if let Some(contact_info) = self.irc_config.contacts.get(&msg.target) {
|
||||
let salt_box = &contact_info
|
||||
.salt_box(self.irc_config.private_key.as_ref().unwrap(), &msg.target);
|
||||
|
||||
if salt_box.is_none() {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
decrypt_privmsg(salt_box.as_ref().unwrap(), msg);
|
||||
|
||||
info!(
|
||||
"[CLIENT {}] Decrypted received message: {:?}",
|
||||
self.address,
|
||||
msg.to_string()
|
||||
);
|
||||
|
||||
self.reply(&msg.to_string()).await?;
|
||||
} else if self.irc_config.is_cap_end && self.irc_config.is_nick_init {
|
||||
if !self.irc_config.contacts.contains_key(&contact) {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let contact_info = self.irc_config.contacts.get(&contact).unwrap();
|
||||
if let Some(salt_box) = &contact_info.salt_box {
|
||||
decrypt_privmsg(salt_box, &mut msg);
|
||||
// This is for /query
|
||||
msg.nick = contact;
|
||||
info!("[P2P] Decrypted received message: {:?}", msg);
|
||||
}
|
||||
|
||||
self.reply(&msg.to_string()).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -246,6 +245,7 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
self.irc_config.is_registered = true;
|
||||
|
||||
// join all channels
|
||||
self.on_receive_join(self.irc_config.auto_channels.clone()).await?;
|
||||
self.on_receive_join(self.irc_config.channels.keys().cloned().collect()).await?;
|
||||
|
||||
if *self.irc_config.capabilities.get("no-history").unwrap() {
|
||||
@@ -487,11 +487,11 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
|
||||
info!("[CLIENT {}] (Plain) PRIVMSG {} :{}", self.address, target, message,);
|
||||
|
||||
let mut privmsg = PrivMsgEvent {
|
||||
nick: self.irc_config.nickname.clone(),
|
||||
target: target.to_string(),
|
||||
msg: message,
|
||||
};
|
||||
let mut privmsg = PrivMsgEvent::new();
|
||||
|
||||
privmsg.nick = self.irc_config.nickname.clone();
|
||||
privmsg.target = target.to_string();
|
||||
privmsg.msg = message.clone();
|
||||
|
||||
if target.starts_with('#') {
|
||||
if !self.irc_config.channels.contains_key(target) {
|
||||
@@ -504,22 +504,19 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
if let Some(salt_box) = &channel_info.salt_box(target) {
|
||||
if let Some(salt_box) = &channel_info.salt_box {
|
||||
encrypt_privmsg(salt_box, &mut privmsg);
|
||||
info!("[CLIENT {}] (Encrypted) PRIVMSG: {:?}", self.address, privmsg.to_string());
|
||||
info!("[CLIENT {}] (Encrypted) PRIVMSG: {:?}", self.address, privmsg);
|
||||
}
|
||||
} else if self.irc_config.private_key.is_some() {
|
||||
if let Some(contact_info) = self.irc_config.contacts.get(target) {
|
||||
if let Some(salt_box) =
|
||||
&contact_info.salt_box(self.irc_config.private_key.as_ref().unwrap(), target)
|
||||
{
|
||||
encrypt_privmsg(salt_box, &mut privmsg);
|
||||
info!(
|
||||
"[CLIENT {}] (Encrypted) PRIVMSG: {:?}",
|
||||
self.address,
|
||||
privmsg.to_string()
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if !self.irc_config.contacts.contains_key(target) {
|
||||
return Ok(())
|
||||
}
|
||||
|
||||
let contact_info = self.irc_config.contacts.get(target).unwrap();
|
||||
if let Some(salt_box) = &contact_info.salt_box {
|
||||
encrypt_privmsg(salt_box, &mut privmsg);
|
||||
info!("[CLIENT {}] (Encrypted) PRIVMSG: {:?}", self.address, privmsg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,7 +533,7 @@ impl<C: AsyncRead + AsyncWrite + Send + Unpin + 'static> IrcClient<C> {
|
||||
continue
|
||||
}
|
||||
if !self.irc_config.channels.contains_key(chan) {
|
||||
let mut chan_info = ChannelInfo::new();
|
||||
let mut chan_info = ChannelInfo::new()?;
|
||||
chan_info.topic = Some("n/a".to_string());
|
||||
self.irc_config.channels.insert(chan.to_string(), chan_info);
|
||||
}
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use darkfi::Result;
|
||||
use darkfi::{util::path::get_config_path, Result};
|
||||
|
||||
use crate::{
|
||||
settings::{Args, ChannelInfo, ContactInfo},
|
||||
settings::{
|
||||
parse_configured_channels, parse_configured_contacts, Args, ChannelInfo, ContactInfo,
|
||||
CONFIG_FILE,
|
||||
},
|
||||
PrivMsgEvent,
|
||||
};
|
||||
|
||||
@@ -43,10 +46,11 @@ pub struct IrcConfig {
|
||||
// user config
|
||||
pub nickname: String,
|
||||
pub password: String,
|
||||
pub private_key: Option<String>,
|
||||
// pub private_key: Option<String>,
|
||||
pub capabilities: HashMap<String, bool>,
|
||||
|
||||
// channels and contacts
|
||||
pub auto_channels: Vec<String>,
|
||||
pub channels: HashMap<String, ChannelInfo>,
|
||||
pub contacts: HashMap<String, ContactInfo>,
|
||||
}
|
||||
@@ -54,17 +58,15 @@ pub struct IrcConfig {
|
||||
impl IrcConfig {
|
||||
pub fn new(settings: &Args) -> Result<Self> {
|
||||
let password = settings.password.as_ref().unwrap_or(&String::new()).clone();
|
||||
let private_key = settings.private_key.clone();
|
||||
// let private_key = settings.private_key.clone();
|
||||
|
||||
let mut channels = settings.channels.clone();
|
||||
let auto_channels = settings.autojoin.clone();
|
||||
|
||||
for chan in settings.autojoin.iter() {
|
||||
if !channels.contains_key(chan) {
|
||||
channels.insert(chan.clone(), ChannelInfo::new());
|
||||
}
|
||||
}
|
||||
|
||||
let contacts = settings.contacts.clone();
|
||||
// Pick up channel settings from the TOML configuration
|
||||
let cfg_path = get_config_path(settings.config.clone(), CONFIG_FILE)?;
|
||||
let toml_contents = std::fs::read_to_string(cfg_path)?;
|
||||
let channels = parse_configured_channels(&toml_contents)?;
|
||||
let contacts = parse_configured_contacts(&toml_contents)?;
|
||||
|
||||
let mut capabilities = HashMap::new();
|
||||
capabilities.insert("no-history".to_string(), false);
|
||||
@@ -77,9 +79,9 @@ impl IrcConfig {
|
||||
is_pass_init: false,
|
||||
nickname: "anon".to_string(),
|
||||
password,
|
||||
auto_channels,
|
||||
channels,
|
||||
contacts,
|
||||
private_key,
|
||||
capabilities,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -96,6 +96,7 @@ impl IrcServer {
|
||||
))
|
||||
.detach();
|
||||
|
||||
// Listen to msgs from View
|
||||
executor
|
||||
.clone()
|
||||
.spawn(Self::listen_to_view(
|
||||
|
||||
@@ -17,18 +17,19 @@
|
||||
*/
|
||||
|
||||
use crypto_box::SalsaBox;
|
||||
use log::error;
|
||||
use serde::{self, Deserialize, Serialize};
|
||||
use log::{info, warn};
|
||||
use serde::{self, Deserialize};
|
||||
use std::collections::HashMap;
|
||||
use structopt::StructOpt;
|
||||
use structopt_toml::StructOptToml;
|
||||
use toml::Value;
|
||||
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");
|
||||
pub const CONFIG_FILE: &str = "darkirc_config.toml";
|
||||
pub const CONFIG_FILE_CONTENTS: &str = include_str!("../darkirc_config.toml");
|
||||
|
||||
// Msg config
|
||||
pub const MAXIMUM_LENGTH_OF_MESSAGE: usize = 1024;
|
||||
@@ -45,7 +46,7 @@ pub enum RPL {
|
||||
/// ircd cli
|
||||
#[derive(Clone, Deserialize, StructOpt, StructOptToml)]
|
||||
#[serde(default)]
|
||||
#[structopt(name = "ircd")]
|
||||
#[structopt(name = "darkirc")]
|
||||
pub struct Args {
|
||||
/// Sets a custom config file
|
||||
#[structopt(long)]
|
||||
@@ -56,7 +57,7 @@ pub struct Args {
|
||||
pub rpc_listen: Url,
|
||||
|
||||
/// IRC listen URL
|
||||
#[structopt(long = "irc", default_value = "tcp://127.0.0.1:7776")]
|
||||
#[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
|
||||
@@ -81,18 +82,10 @@ pub struct Args {
|
||||
#[structopt(long)]
|
||||
pub password: Option<String>,
|
||||
|
||||
/// Channels
|
||||
#[structopt(skip)]
|
||||
pub channels: HashMap<String, ChannelInfo>,
|
||||
|
||||
/// Channels
|
||||
#[structopt(skip)]
|
||||
pub contacts: HashMap<String, ContactInfo>,
|
||||
|
||||
/// Private key
|
||||
#[structopt(skip)]
|
||||
pub private_key: Option<String>,
|
||||
|
||||
// /// Private key
|
||||
// #[structopt(skip)]
|
||||
// pub private_key: Option<String>,
|
||||
/// Network settings
|
||||
#[structopt(flatten)]
|
||||
pub net: SettingsOpt,
|
||||
|
||||
@@ -108,30 +101,15 @@ pub struct Args {
|
||||
/// [contact."nick"]
|
||||
/// pubkey = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"
|
||||
/// ```
|
||||
#[derive(Default, Clone, Debug, Deserialize, Serialize)]
|
||||
#[derive(Clone)]
|
||||
pub struct ContactInfo {
|
||||
pub pubkey: Option<String>,
|
||||
/// Optional NaCl box for the channel, used for {en,de}cryption.
|
||||
pub salt_box: Option<SalsaBox>,
|
||||
}
|
||||
|
||||
impl ContactInfo {
|
||||
pub fn new() -> Self {
|
||||
Self { pubkey: None }
|
||||
}
|
||||
|
||||
pub fn salt_box(&self, private_key: &str, contact_name: &str) -> Option<SalsaBox> {
|
||||
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
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self { salt_box: None })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,48 +126,214 @@ impl ContactInfo {
|
||||
/// 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)]
|
||||
#[derive(Default, Clone)]
|
||||
pub struct ChannelInfo {
|
||||
/// Optional topic for the channel
|
||||
pub topic: Option<String>,
|
||||
/// Optional NaCl box for the channel, used for {en,de}cryption.
|
||||
pub secret: Option<String>,
|
||||
pub salt_box: Option<SalsaBox>,
|
||||
/// 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<String>,
|
||||
}
|
||||
|
||||
impl ChannelInfo {
|
||||
pub fn new() -> Self {
|
||||
Self { topic: None, secret: None, joined: false, names: vec![] }
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self { topic: None, salt_box: None, joined: false, names: vec![] })
|
||||
}
|
||||
}
|
||||
|
||||
/// Parse a TOML string for any configured channels and return
|
||||
/// a map containing said configurations.
|
||||
///
|
||||
/// ```toml
|
||||
/// [channel."#memes"]
|
||||
/// secret = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"
|
||||
/// topic = "Dank Memes"
|
||||
/// ```
|
||||
pub fn parse_configured_channels(data: &str) -> Result<HashMap<String, ChannelInfo>> {
|
||||
let mut ret = HashMap::new();
|
||||
|
||||
let map = match toml::from_str(data)? {
|
||||
Value::Table(m) => m,
|
||||
_ => return Ok(ret),
|
||||
};
|
||||
|
||||
if !map.contains_key("channel") {
|
||||
return Ok(ret)
|
||||
}
|
||||
|
||||
pub fn salt_box(&self, channel_name: &str) -> Option<SalsaBox> {
|
||||
if let Some(s) = &self.secret {
|
||||
let secret = parse_priv(s);
|
||||
if !map["channel"].is_table() {
|
||||
return Ok(ret)
|
||||
}
|
||||
|
||||
if secret.is_err() {
|
||||
error!("Uncorrect secret key for the channel {}", channel_name);
|
||||
return None
|
||||
}
|
||||
for chan in map["channel"].as_table().unwrap() {
|
||||
info!("Found configuration for channel {}", chan.0);
|
||||
let mut channel_info = ChannelInfo::new()?;
|
||||
|
||||
let secret = secret.unwrap();
|
||||
let public = secret.public_key();
|
||||
return Some(SalsaBox::new(&public, &secret))
|
||||
if chan.1.as_table().unwrap().contains_key("topic") {
|
||||
let topic = chan.1["topic"].as_str().unwrap().to_string();
|
||||
info!("Found topic for channel {}: {}", chan.0, topic);
|
||||
channel_info.topic = Some(topic);
|
||||
}
|
||||
None
|
||||
|
||||
if chan.1.as_table().unwrap().contains_key("secret") {
|
||||
// Build the NaCl box
|
||||
if let Some(s) = chan.1["secret"].as_str() {
|
||||
let salt_box = salt_box_from_shared_secret(s)?;
|
||||
channel_info.salt_box = Some(salt_box);
|
||||
info!("Instantiated NaCl box for channel {}", chan.0);
|
||||
}
|
||||
}
|
||||
|
||||
ret.insert(chan.0.to_string(), channel_info);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn parse_priv(key: &str) -> Result<crypto_box::SecretKey> {
|
||||
let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap();
|
||||
Ok(crypto_box::SecretKey::from(bytes))
|
||||
/// Parse a TOML string for any configured contact list and return
|
||||
/// a map containing said configurations.
|
||||
///
|
||||
/// ```toml
|
||||
/// [contact."nick"]
|
||||
/// contact_pubkey = "7CkVuFgwTUpJn5Sv67Q3fyEDpa28yrSeL5Hg2GqQ4jfM"
|
||||
/// ```
|
||||
pub fn parse_configured_contacts(data: &str) -> Result<HashMap<String, ContactInfo>> {
|
||||
let mut ret = HashMap::new();
|
||||
|
||||
let map = match toml::from_str(data) {
|
||||
Ok(Value::Table(m)) => m,
|
||||
_ => {
|
||||
warn!("Invalid TOML string passed as argument to parse_configured_contacts()");
|
||||
return Ok(ret)
|
||||
}
|
||||
};
|
||||
|
||||
if !map.contains_key("contact") {
|
||||
return Ok(ret)
|
||||
}
|
||||
|
||||
if !map["contact"].is_table() {
|
||||
warn!("TOML configuration contains a \"contact\" field, but it is not a table.");
|
||||
return Ok(ret)
|
||||
}
|
||||
|
||||
let contacts = map["contact"].as_table().unwrap();
|
||||
|
||||
// Our secret key for NaCl boxes.
|
||||
let found_priv = match parse_priv_key(data) {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
info!("Did not find private key in config, skipping contact configuration.");
|
||||
return Ok(ret)
|
||||
}
|
||||
};
|
||||
|
||||
let bytes: [u8; 32] = match bs58::decode(found_priv).into_vec() {
|
||||
Ok(v) => {
|
||||
if v.len() != 32 {
|
||||
warn!("Decoded base58 secret key string is not 32 bytes");
|
||||
warn!("Skipping private contact configuration");
|
||||
return Ok(ret)
|
||||
}
|
||||
v.try_into().unwrap()
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to decode base58 secret key from string: {}", e);
|
||||
warn!("Skipping private contact configuration");
|
||||
return Ok(ret)
|
||||
}
|
||||
};
|
||||
|
||||
let secret = crypto_box::SecretKey::from(bytes);
|
||||
|
||||
for cnt in contacts {
|
||||
info!("Found configuration for contact {}", cnt.0);
|
||||
let mut contact_info = ContactInfo::new()?;
|
||||
|
||||
if !cnt.1.is_table() {
|
||||
warn!("Config for contact {} isn't a TOML table", cnt.0);
|
||||
continue
|
||||
}
|
||||
|
||||
let table = cnt.1.as_table().unwrap();
|
||||
if table.is_empty() {
|
||||
warn!("Configuration for contact {} is empty.", cnt.0);
|
||||
continue
|
||||
}
|
||||
|
||||
// Build the NaCl box
|
||||
if !table.contains_key("contact_pubkey") || !table["contact_pubkey"].is_str() {
|
||||
warn!("Contact {} doesn't have `contact_pubkey` set or is not a string.", cnt.0);
|
||||
continue
|
||||
}
|
||||
|
||||
let pub_str = table["contact_pubkey"].as_str().unwrap();
|
||||
let bytes: [u8; 32] = match bs58::decode(pub_str).into_vec() {
|
||||
Ok(v) => {
|
||||
if v.len() != 32 {
|
||||
warn!("Decoded base58 string is not 32 bytes");
|
||||
continue
|
||||
}
|
||||
|
||||
v.try_into().unwrap()
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to decode base58 pubkey from string: {}", e);
|
||||
continue
|
||||
}
|
||||
};
|
||||
|
||||
let public = crypto_box::PublicKey::from(bytes);
|
||||
contact_info.salt_box = Some(SalsaBox::new(&public, &secret));
|
||||
ret.insert(cnt.0.to_string(), contact_info);
|
||||
info!("Instantiated NaCl box for contact {}", cnt.0);
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn parse_pub(key: &str) -> Result<crypto_box::PublicKey> {
|
||||
let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap();
|
||||
Ok(crypto_box::PublicKey::from(bytes))
|
||||
fn salt_box_from_shared_secret(s: &str) -> Result<SalsaBox> {
|
||||
let bytes: [u8; 32] = bs58::decode(s).into_vec()?.try_into().unwrap();
|
||||
let secret = crypto_box::SecretKey::from(bytes);
|
||||
let public = secret.public_key();
|
||||
Ok(SalsaBox::new(&public, &secret))
|
||||
}
|
||||
|
||||
fn parse_priv_key(data: &str) -> Result<String> {
|
||||
let mut pk = String::new();
|
||||
|
||||
let map = match toml::from_str(data)? {
|
||||
Value::Table(m) => m,
|
||||
_ => return Ok(pk),
|
||||
};
|
||||
|
||||
if !map.contains_key("private_key") {
|
||||
return Ok(pk)
|
||||
}
|
||||
|
||||
if !map["private_key"].is_table() {
|
||||
return Ok(pk)
|
||||
}
|
||||
|
||||
let private_keys = map["private_key"].as_table().unwrap();
|
||||
|
||||
for prv_key in private_keys {
|
||||
pk = prv_key.0.into();
|
||||
}
|
||||
|
||||
info!("Found secret key in config, noted it down.");
|
||||
Ok(pk)
|
||||
}
|
||||
|
||||
// fn parse_priv(key: &str) -> Result<crypto_box::SecretKey> {
|
||||
// let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap();
|
||||
// Ok(crypto_box::SecretKey::from(bytes))
|
||||
// }
|
||||
|
||||
// fn parse_pub(key: &str) -> Result<crypto_box::PublicKey> {
|
||||
// let bytes: [u8; 32] = bs58::decode(key).into_vec()?.try_into().unwrap();
|
||||
// Ok(crypto_box::PublicKey::from(bytes))
|
||||
// }
|
||||
|
||||
Reference in New Issue
Block a user