Skip to content

Commit

Permalink
Merge pull request #38 from mycognosist/add_hmac_env_var
Browse files Browse the repository at this point in the history
Add ability to set network key HMAC via env var
  • Loading branch information
mycognosist authored Dec 23, 2022
2 parents 1dad14c + e479d09 commit 14df991
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 42 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
60 changes: 38 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,42 @@ 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 [email protected]: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.

`solar --help`

```shell
🌞 Solar 0.3.1-6266b38
🌞 Solar 0.3.1-1dad14c
Sunbathing scuttlecrabs in kuskaland

USAGE:
Expand All @@ -42,33 +70,21 @@ USAGE:
--resync <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 [email protected]: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

Expand Down
9 changes: 6 additions & 3 deletions src/actors/peer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -27,6 +26,7 @@ use crate::{
WhoAmIHandler,
},
broker::*,
config::NETWORK_KEY,
Result,
};

Expand Down Expand Up @@ -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.
Expand All @@ -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());

Expand All @@ -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.
Expand Down
49 changes: 36 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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<NetworkKey> = OnceCell::new();
// Write once store for the list of Scuttlebutt peers to replicate.
pub static REPLICATION_CONFIG: OnceCell<ReplicationConfig> = OnceCell::new();
// Write once store for the database resync configuration.
Expand All @@ -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<String>,

/// 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,
}

Expand All @@ -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(),
Expand All @@ -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.
Expand All @@ -125,6 +145,7 @@ impl ApplicationConfig {
lan_discov,
muxrpc_port,
muxrpc_addr,
network_key,
replicate: cli_args.replicate,
resync,
};
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 10 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 14df991

Please sign in to comment.