From fdc9952808013e232cc9aa3a132976bc7dd27e15 Mon Sep 17 00:00:00 2001 From: mycognosist Date: Fri, 23 Dec 2022 14:22:36 +0200 Subject: [PATCH 1/3] add support for alt net key via env var --- src/actors/peer.rs | 9 ++++++--- src/config.rs | 49 ++++++++++++++++++++++++++++++++++------------ src/main.rs | 14 +++++++++---- 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/src/actors/peer.rs b/src/actors/peer.rs index f7800cd..bcced6d 100644 --- a/src/actors/peer.rs +++ b/src/actors/peer.rs @@ -10,7 +10,6 @@ use futures::{pin_mut, select_biased, stream::StreamExt, FutureExt, SinkExt}; use kuska_ssb::{ api::ApiCaller, crypto::{ed25519, ToSsbId}, - discovery::ssb_net_id, handshake::{ async_std::{handshake_client, handshake_server, BoxStream}, HandshakeComplete, @@ -27,6 +26,7 @@ use crate::{ WhoAmIHandler, }, broker::*, + config::NETWORK_KEY, Result, }; @@ -60,6 +60,9 @@ pub async fn actor_inner(id: OwnedIdentity, connect: Connect) -> Result<()> { // Parse the public key and secret key from the identity. let OwnedIdentity { pk, sk, .. } = id; + // Define the network key to be used for the secret handshake. + let network_key = NETWORK_KEY.get().unwrap().to_owned(); + // Handle a TCP connection event (inbound or outbound). let (stream, handshake) = match connect { // Handle an outgoing TCP connection event. @@ -80,7 +83,7 @@ pub async fn actor_inner(id: OwnedIdentity, connect: Connect) -> Result<()> { // Attempt a TCP connection. let mut stream = TcpStream::connect(server_port).await?; // Attempt a secret handshake. - let handshake = handshake_client(&mut stream, ssb_net_id(), pk, sk, peer_pk).await?; + let handshake = handshake_client(&mut stream, network_key, pk, sk, peer_pk).await?; info!("💃 connected to peer {}", handshake.peer_pk.to_ssb_id()); @@ -89,7 +92,7 @@ pub async fn actor_inner(id: OwnedIdentity, connect: Connect) -> Result<()> { // Handle an incoming TCP connection event. Connect::ClientStream { mut stream } => { // Attempt a secret handshake. - let handshake = handshake_server(&mut stream, ssb_net_id(), pk, sk).await?; + let handshake = handshake_server(&mut stream, network_key, pk, sk).await?; // Check if we are already connected to the selected peer. // If yes, return immediately. // If no, return the stream and handshake. diff --git a/src/config.rs b/src/config.rs index 366e785..2dce2cf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -4,8 +4,10 @@ use async_std::{ fs::File, io::{ReadExt, WriteExt}, }; +use kuska_sodiumoxide::crypto::auth::Key as NetworkKey; use kuska_ssb::{ crypto::{ed25519, ToSodiumObject, ToSsbId}, + discovery, keystore::OwnedIdentity, }; use log::{debug, info}; @@ -16,15 +18,17 @@ use structopt::StructOpt; use crate::{cli::Cli, Result}; -// Define the IP used for TCP connections (boxstream and MUXRPC). +// Define the default IP used for TCP connections (boxstream and MUXRPC). const MUXRPC_IP: &str = "0.0.0.0"; -// Define the port used for TCP connections (boxstream and MUXRPC). +// Define the default port used for TCP connections (boxstream and MUXRPC). const MUXRPC_PORT: u16 = 8008; -// Define the IP used for the JSON-RPC server. +// Define the default IP used for the JSON-RPC server. const JSONRPC_IP: &str = "127.0.0.1"; -// Define the port used for the JSON-RPC server. +// Define the default port used for the JSON-RPC server. const JSONRPC_PORT: u16 = 3030; +// Write once store for the network key (aka. SHS key or caps key). +pub static NETWORK_KEY: OnceCell = OnceCell::new(); // Write once store for the list of Scuttlebutt peers to replicate. pub static REPLICATION_CONFIG: OnceCell = OnceCell::new(); // Write once store for the database resync configuration. @@ -47,29 +51,32 @@ pub struct ApplicationConfig { /// Path to the feed store. pub feeds_folder: PathBuf, - /// Run the JSON-RPC server (default: true) + /// Run the JSON-RPC server (default: true). pub jsonrpc: bool, - /// JSON-RPC IP and port to bind (default: 127.0.0.1:3030) + /// JSON-RPC IP and port to bind (default: 127.0.0.1:3030). pub jsonrpc_addr: String, /// Sled key-value cache capacity. pub kv_cache_capacity: u64, - /// Run LAN discovery (default: false) + /// Run LAN discovery (default: false). pub lan_discov: bool, - /// MUXRPC IP and port to bind (default: 0.0.0.0:8008) + /// MUXRPC IP and port to bind (default: 0.0.0.0:8008). pub muxrpc_addr: String, - /// MUXRPC port to bind (default: 8008) + /// MUXRPC port to bind (default: 8008). pub muxrpc_port: u16, + /// Secret handshake HMAC key (aka. network key, caps key, SHS key). + pub network_key: NetworkKey, + /// List of peers to replicate; "connect" magic word means that peers - /// specified with --connect are added to the replication list + /// specified with --connect are added to the replication list. pub replicate: Option, - /// Resync the local database by requesting the local feed from peers + /// Resync the local database by requesting the local feed from peers. pub resync: bool, } @@ -88,10 +95,14 @@ impl ApplicationConfig { let jsonrpc = cli_args.jsonrpc.unwrap_or(true); let resync = cli_args.resync.unwrap_or(false); + // Set the JSON-RPC server IP address. + // First check for an env var before falling back to the default. let jsonrpc_ip = match env::var("SOLAR_JSONRPC_IP") { Ok(ip) => ip, Err(_) => JSONRPC_IP.to_string(), }; + // Set the JSON-RPC server port number. + // First check for an env var before falling back to the default. let jsonrpc_port = match env::var("SOLAR_JSONRPC_PORT") { Ok(port) => port, Err(_) => JSONRPC_PORT.to_string(), @@ -105,6 +116,15 @@ impl ApplicationConfig { Err(_) => 1000 * 1000 * 1000, }; + // Define the default HMAC-SHA-512-256 key for secret handshakes. + // This is also sometimes known as the SHS key, caps key or network key. + let network_key = match env::var("SOLAR_NETWORK_KEY") { + Ok(key) => NetworkKey::from_slice(&hex::decode(key) + .expect("shs key supplied via SOLAR_NETWORK_KEY env var is not valid hex")) + .expect("failed to instantiate an authentication key from the supplied shs key; check byte length"), + Err(_) => discovery::ssb_net_id(), + }; + // Create the root data directory for solar. // This is the path at which application data is stored, including the // public-private keypair, key-value database and blob store. @@ -125,6 +145,7 @@ impl ApplicationConfig { lan_discov, muxrpc_port, muxrpc_addr, + network_key, replicate: cli_args.replicate, resync, }; @@ -203,12 +224,14 @@ impl ApplicationConfig { let secret_config = SecretConfig::configure(secret_key_file).await?; let owned_identity = secret_config.owned_identity()?; - // Set the value of the secret configuration cell. - let _err = SECRET_CONFIG.set(secret_config); + // Set the value of the network key (aka. secret handshake key or caps key). + let _err = NETWORK_KEY.set(application_config.network_key.to_owned()); // Set the value of the replication configuration cell. let _err = REPLICATION_CONFIG.set(replication_config); // Set the value of the resync configuration cell. let _err = RESYNC_CONFIG.set(application_config.resync); + // Set the value of the secret configuration cell. + let _err = SECRET_CONFIG.set(secret_config); Ok(( application_config, diff --git a/src/main.rs b/src/main.rs index 9df4f98..d634fe8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,17 +51,23 @@ async fn main() -> Result<()> { // Spawn the ctrlc actor. Listens for SIGINT termination signal. Broker::spawn(actors::ctrlc::actor()); + // Print 'starting server' announcement. + println!( + "Starting TCP server on {}:{}", + &app_config.muxrpc_addr, + base64::encode(&secret_config.pk[..]), + ); + // Spawn the TCP server. Facilitates peer connections. Broker::spawn(actors::tcp_server::actor( secret_config.clone(), app_config.muxrpc_addr, )); - // Print 'server started' announcement. + // Print the network key. println!( - "Server started on {}:{}", - app_config.muxrpc_port, - base64::encode(&secret_config.pk[..]) + "Node deploy on network: {}", + hex::encode(app_config.network_key) ); // Spawn the JSON-RPC server if the option has been set to true in the From 8147bea0107c4cdba667f36c7b617487f4069408 Mon Sep 17 00:00:00 2001 From: mycognosist Date: Fri, 23 Dec 2022 14:23:29 +0200 Subject: [PATCH 2/3] add sodiumoxide and hex dependencies --- Cargo.lock | 2 ++ Cargo.toml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index c6a0912..197c774 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1700,7 +1700,9 @@ dependencies = [ "base64 0.13.1", "env_logger", "futures", + "hex", "jsonrpc-http-server", + "kuska-sodiumoxide", "kuska-ssb", "log", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index a311e27..c4368fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,9 @@ async-trait = "0.1" base64 = "0.13" env_logger = "0.10" futures = "0.3" +hex = "0.4.0" jsonrpc-http-server = "18" +kuska-sodiumoxide = "0.2.5-0" kuska-ssb = { git = "https://github.com/Kuska-ssb/ssb", branch = "master" } log = "0.4" once_cell = "1.16" From e479d093b92f99ee275b5d5264137b95b4b935a5 Mon Sep 17 00:00:00 2001 From: mycognosist Date: Fri, 23 Dec 2022 14:24:15 +0200 Subject: [PATCH 3/3] update readme with env var config options --- README.md | 60 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 42221a8..d10d419 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,34 @@ message publishing and replication. Indexing of database messages will be offloaded to client applications (ie. piping feeds from solar into a SQLite database). +## Quick Start + +Clone the source and build the binary (see [RPi build instructions](https://mycelial.technology/computers/rust-compilation.html) if required): + +``` +git clone git@github.com:mycognosist/solar.git +cd solar +cargo build --release +``` + +Add peer(s) to `replication.toml` (public key(s) of feeds you wish to replicate): + +``` +vim ~/.local/share/solar/replication.toml + +peers = ["@...=.ed25519"] +``` + +Run solar with LAN discovery enabled: + +``` +./target/release/solar --lan true +``` + +_Note: a new public-private keypair will be generated and saved to +`~/.local/share/solar/secret.toml` (or in the equivalent directory on your +operating system)._ + ## CLI Solar can be configured and launched using the CLI interface. @@ -21,7 +49,7 @@ Solar can be configured and launched using the CLI interface. `solar --help` ```shell -🌞 Solar 0.3.1-6266b38 +🌞 Solar 0.3.1-1dad14c Sunbathing scuttlecrabs in kuskaland USAGE: @@ -42,33 +70,21 @@ USAGE: --resync Resync the local database by requesting the local feed from peers ``` -## Quick Start - -Clone the source and build the binary (see [RPi build instructions](https://mycelial.technology/computers/rust-compilation.html) if required): - -``` -git clone git@github.com:mycognosist/solar.git -cd solar -cargo build --release -``` +## Environment Variables -Add peer(s) to `replication.toml` (public key(s) of feeds you wish to replicate): +Additional configuration parameters can be supplied via environment variables. ``` -vim ~/.local/share/solar/replication.toml - -peers = ["@...=.ed25519"] +RUST_LOG +SLED_CACHE_CAPACITY +SOLAR_JSONRPC_IP +SOLAR_JSONRPC_PORT +SOLAR_NETWORK_KEY ``` -Run solar with LAN discovery enabled: - -``` -./target/release/solar --lan true -``` +For example, run `solar` with a log-level of `debug` and an alternative network key: -_Note: a new public-private keypair will be generated and saved to -`~/.local/share/solar/secret.toml` (or in the equivalent directory on your -operating system)._ +`RUST_LOG=solar=debug SOLAR_NETWORK_KEY=3c42fff79381c451fcafd73cec3c9f897bb2232949dcdd35936d64d67c47a374 solar` ## Core Features