(general) refactor

This commit is contained in:
adria0 2020-02-26 19:18:07 +01:00
parent d6edfc681b
commit 26d7e8cfd8
19 changed files with 169 additions and 97 deletions

View File

@ -10,9 +10,13 @@ use async_std::io::{Read, Write};
use async_std::net::TcpStream;
use kuska_handshake::async_std::{handshake_client, BoxStream};
use kuska_ssb::api::{
ApiHelper, CreateHistoryStreamArgs, CreateStreamArgs, LatestUserMessage, WhoAmI,
};
use kuska_ssb::discovery::ssb_net_id;
use kuska_ssb::feed::{is_privatebox, privatebox_decipher, Feed, Message};
use kuska_ssb::patchwork::*;
use kuska_ssb::patchwork::{ApiHelper, LatestUserMessage, WhoAmI};
use kuska_ssb::keystore::from_patchwork_local;
use kuska_ssb::keystore::OwnedIdentity;
use kuska_ssb::rpc::{RecvMsg, RequestNo, RpcStream};
type AnyResult<T> = std::result::Result<T, Box<dyn std::error::Error>>;
@ -116,8 +120,7 @@ async fn main() -> AnyResult<()> {
env_logger::init();
log::set_max_level(log::LevelFilter::max());
let IdentitySecret { pk, sk, .. } =
IdentitySecret::from_local_config().expect("read local secret");
let OwnedIdentity { pk, sk, .. } = from_patchwork_local().expect("read local secret");
let mut socket = TcpStream::connect("127.0.0.1:8080").await?;
let handshake = handshake_client(&mut socket, ssb_net_id(), pk, sk.clone(), pk).await?;

View File

@ -1,11 +1,8 @@
mod api;
mod config;
mod error;
mod helper;
pub mod msgs;
pub mod pubs;
pub use api::{
pub use error::{Error, Result};
pub use helper::{
ApiHelper, ApiMethod, CreateHistoryStreamArgs, CreateStreamArgs, LatestUserMessage, WhoAmI,
};
pub use config::{ssb_net_id, IdentitySecret};
pub use error::{Error, Result};

View File

@ -2,4 +2,6 @@ mod error;
mod sodium;
pub use error::{Error, Result};
pub use sodium::{ToSodiumObject, ToSsbId};
pub use sodium::{
ToSodiumObject, ToSsbId, CURVE_ED25519_SUFFIX, ED25519_SIGNATURE_SUFFIX, SHA256_SUFFIX,
};

View File

@ -4,9 +4,9 @@ use sodiumoxide::crypto::sign::ed25519;
use super::error::{Error, Result};
const CURVE_ED25519_SUFFIX: &str = ".ed25519";
const ED25519_SIGNATURE_SUFFIX: &str = ".sig.ed25519";
const SHA256_SUFFIX: &str = ".sha256";
pub const CURVE_ED25519_SUFFIX: &str = ".ed25519";
pub const ED25519_SIGNATURE_SUFFIX: &str = ".sig.ed25519";
pub const SHA256_SUFFIX: &str = ".sha256";
pub trait ToSodiumObject {
fn to_ed25519_pk(&self) -> Result<ed25519::PublicKey>;

27
src/discovery/error.rs Normal file
View File

@ -0,0 +1,27 @@
#[derive(Debug)]
pub enum Error {
ParseInt(std::num::ParseIntError),
InvalidInviteCode,
CryptoFormat(crate::crypto::Error),
}
impl From<crate::crypto::Error> for Error {
fn from(err: crate::crypto::Error) -> Self {
Error::CryptoFormat(err)
}
}
impl From<std::num::ParseIntError> for Error {
fn from(err: std::num::ParseIntError) -> Self {
Error::ParseInt(err)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;

6
src/discovery/mod.rs Normal file
View File

@ -0,0 +1,6 @@
mod error;
mod network;
mod pubs;
pub use network::ssb_net_id;
pub use pubs::Invite;

6
src/discovery/network.rs Normal file
View File

@ -0,0 +1,6 @@
use sodiumoxide::crypto::auth;
pub const SSB_NET_ID: &str = "d4a1cb88a66f02f8db635ce26441cc5dac1b08420ceaac230839b755845a9ffb";
pub fn ssb_net_id() -> auth::Key {
auth::Key::from_slice(&hex::decode(SSB_NET_ID).unwrap()).unwrap()
}

View File

@ -7,7 +7,7 @@ use sodiumoxide::crypto::sign::ed25519;
use super::error::{Error, Result};
use super::{ssb_sha256, stringify_json};
use crate::crypto::ToSodiumObject;
use crate::patchwork::IdentitySecret;
use crate::keystore::OwnedIdentity;
use sodiumoxide::crypto::hash::sha256;
const MSG_PREVIOUS: &str = "previous";
@ -58,7 +58,7 @@ pub struct Message {
}
impl Message {
pub fn sign(prev: Option<&Message>, identity: &IdentitySecret, content: Value) -> Result<Self> {
pub fn sign(prev: Option<&Message>, identity: &OwnedIdentity, content: Value) -> Result<Self> {
let mut value: serde_json::Map<String, Value> = serde_json::Map::new();
if let Some(prev) = prev {
value.insert(
@ -206,7 +206,7 @@ mod test {
#[test]
fn test_sign_verify() -> Result<()> {
let content = Value::String("thistest".to_string());
let id = IdentitySecret::new();
let id = OwnedIdentity::new();
let msg1 = Message::sign(None, &id, content.clone())?.to_string();
let msg1 = Message::from_str(&msg1)?;
let msg2 = Message::sign(Some(&msg1), &id, content)?.to_string();

View File

@ -125,7 +125,7 @@ fn decipher(ciphertext: &[u8], sk: &SecretKey) -> Result<Option<Vec<u8>>> {
#[cfg(test)]
mod test {
use super::*;
use crate::patchwork::IdentitySecret;
use crate::keystore::OwnedIdentity;
#[test]
fn test_msg_cipher_to_one() -> Result<()> {
@ -139,7 +139,7 @@ mod test {
#[test]
fn test_msg_cipher_to_one_helper() -> Result<()> {
let id = IdentitySecret::new();
let id = OwnedIdentity::new();
let plaintext = "holar";
let ciphertext = privatebox_cipher(plaintext, &[&id.id])?;
assert_eq!(is_privatebox(&ciphertext), true);

27
src/keystore/error.rs Normal file
View File

@ -0,0 +1,27 @@
#[derive(Debug)]
pub enum Error {
HomeNotFound,
InvalidConfig,
CryptoFormat(crate::crypto::Error),
Io(std::io::Error),
}
impl From<crate::crypto::Error> for Error {
fn from(err: crate::crypto::Error) -> Self {
Error::CryptoFormat(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::Io(err)
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;

20
src/keystore/identity.rs Normal file
View File

@ -0,0 +1,20 @@
use crate::crypto::CURVE_ED25519_SUFFIX;
use sodiumoxide::crypto::sign::ed25519;
#[derive(Debug, Clone)]
pub struct OwnedIdentity {
pub id: String,
pub pk: ed25519::PublicKey,
pub sk: ed25519::SecretKey,
}
impl OwnedIdentity {
pub fn new() -> OwnedIdentity {
let (pk, sk) = ed25519::gen_keypair();
OwnedIdentity {
pk,
sk,
id: format!("@{}{}", base64::encode(&pk), CURVE_ED25519_SUFFIX),
}
}
}

6
src/keystore/mod.rs Normal file
View File

@ -0,0 +1,6 @@
mod error;
mod identity;
pub mod patchwork;
pub use identity::OwnedIdentity;
pub use patchwork::{from_patchwork_config, from_patchwork_local};

53
src/keystore/patchwork.rs Normal file
View File

@ -0,0 +1,53 @@
use std::io;
use std::string::ToString;
use crate::crypto::ToSodiumObject;
use super::error::{Error, Result};
use super::OwnedIdentity;
pub const CURVE_ED25519: &str = "ed25519";
#[derive(Deserialize)]
struct JsonSSBSecret {
id: String,
curve: String,
public: String,
private: String,
}
fn to_ioerr<T: ToString>(err: T) -> io::Error {
io::Error::new(io::ErrorKind::Other, err.to_string())
}
#[allow(clippy::new_without_default)]
pub fn from_patchwork_local() -> Result<OwnedIdentity> {
let home_dir = dirs::home_dir().ok_or(Error::HomeNotFound)?;
let local_key_file = format!("{}/.ssb/secret", home_dir.to_string_lossy());
let content = std::fs::read_to_string(local_key_file)?;
Ok(from_patchwork_config(content)?)
}
pub fn from_patchwork_config<T: AsRef<str>>(config: T) -> Result<OwnedIdentity> {
// strip all comments
let json = config
.as_ref()
.lines()
.filter(|line| !line.starts_with('#'))
.collect::<Vec<_>>()
.join("");
// parse json
let secret: JsonSSBSecret = serde_json::from_str(json.as_ref()).map_err(to_ioerr)?;
if secret.curve != CURVE_ED25519 {
return Err(Error::InvalidConfig);
}
Ok(OwnedIdentity {
id: secret.id,
pk: secret.public.to_ed25519_pk()?,
sk: secret.private.to_ed25519_sk()?,
})
}

View File

@ -5,7 +5,9 @@ extern crate serde;
extern crate async_std;
extern crate serde_json;
pub mod api;
pub mod crypto;
pub mod discovery;
pub mod feed;
pub mod patchwork;
pub mod keystore;
pub mod rpc;

View File

@ -1,77 +0,0 @@
use std::io;
use std::string::ToString;
use sodiumoxide::crypto::auth;
use sodiumoxide::crypto::sign::ed25519;
use crate::crypto::ToSodiumObject;
use super::error::{Error, Result};
const CURVE_ED25519: &str = "ed25519";
pub const SSB_NET_ID: &str = "d4a1cb88a66f02f8db635ce26441cc5dac1b08420ceaac230839b755845a9ffb";
#[derive(Debug, Clone)]
pub struct IdentitySecret {
pub id: String,
pub pk: ed25519::PublicKey,
pub sk: ed25519::SecretKey,
}
#[derive(Deserialize)]
struct JsonSSBSecret {
id: String,
curve: String,
public: String,
private: String,
}
pub fn ssb_net_id() -> auth::Key {
auth::Key::from_slice(&hex::decode(SSB_NET_ID).unwrap()).unwrap()
}
fn to_ioerr<T: ToString>(err: T) -> io::Error {
io::Error::new(io::ErrorKind::Other, err.to_string())
}
#[allow(clippy::new_without_default)]
impl IdentitySecret {
pub fn new() -> IdentitySecret {
let (pk, sk) = ed25519::gen_keypair();
IdentitySecret {
pk,
sk,
id: format!("@{}.{}", base64::encode(&pk), CURVE_ED25519),
}
}
pub fn from_local_config() -> Result<IdentitySecret> {
let home_dir = dirs::home_dir().ok_or(Error::HomeNotFound)?;
let local_key_file = format!("{}/.ssb/secret", home_dir.to_string_lossy());
let content = std::fs::read_to_string(local_key_file)?;
Ok(IdentitySecret::from_config(content)?)
}
pub fn from_config<T: AsRef<str>>(config: T) -> Result<IdentitySecret> {
// strip all comments
let json = config
.as_ref()
.lines()
.filter(|line| !line.starts_with('#'))
.collect::<Vec<_>>()
.join("");
// parse json
let secret: JsonSSBSecret = serde_json::from_str(json.as_ref()).map_err(to_ioerr)?;
if secret.curve != CURVE_ED25519 {
return Err(Error::InvalidConfig);
}
Ok(IdentitySecret {
id: secret.id,
pk: secret.public.to_ed25519_pk()?,
sk: secret.private.to_ed25519_sk()?,
})
}
}