Skip to content

Commit

Permalink
Merge pull request #86 from yrashk/force-tls
Browse files Browse the repository at this point in the history
Problem: insecure RPCs are subject to MITM attacks
  • Loading branch information
yrashk authored Jun 4, 2018
2 parents 036e83e + 18802df commit 0968c6f
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 16 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ bridge --config config.toml --database db.toml
- `--config` - location of the configuration file. configuration file must exist
- `--database` - location of the database file.

Bridge forces TLS for RPC connections by default. However, in some limited scenarios (like local testing),
this might be undesirable. In this case, you can use `--allow-insecure-rpc-endpoints` option to allow non-TLS
endpoints to be used. Ensure, however, that this option is not going to be used in production.


#### Exit Status Codes

| Code | Meaning |
Expand Down
34 changes: 22 additions & 12 deletions bridge/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rustc_hex::FromHex;
use web3::types::Address;
#[cfg(feature = "deploy")]
use web3::types::Bytes;
use error::{ResultExt, Error};
use error::{ResultExt, Error, ErrorKind};
use {toml};

const DEFAULT_POLL_INTERVAL: u64 = 1;
Expand All @@ -33,22 +33,22 @@ pub struct Config {
}

impl Config {
pub fn load<P: AsRef<Path>>(path: P) -> Result<Config, Error> {
pub fn load<P: AsRef<Path>>(path: P, allow_insecure_rpc_endpoints: bool) -> Result<Config, Error> {
let mut file = fs::File::open(path).chain_err(|| "Cannot open config")?;
let mut buffer = String::new();
file.read_to_string(&mut buffer).expect("TODO");
Self::load_from_str(&buffer)
Self::load_from_str(&buffer, allow_insecure_rpc_endpoints)
}

fn load_from_str(s: &str) -> Result<Config, Error> {
fn load_from_str(s: &str, allow_insecure_rpc_endpoints: bool) -> Result<Config, Error> {
let config: load::Config = toml::from_str(s).chain_err(|| "Cannot parse config")?;
Config::from_load_struct(config)
Config::from_load_struct(config, allow_insecure_rpc_endpoints)
}

fn from_load_struct(config: load::Config) -> Result<Config, Error> {
fn from_load_struct(config: load::Config, allow_insecure_rpc_endpoints: bool) -> Result<Config, Error> {
let result = Config {
home: Node::from_load_struct(config.home)?,
foreign: Node::from_load_struct(config.foreign)?,
home: Node::from_load_struct(config.home, allow_insecure_rpc_endpoints)?,
foreign: Node::from_load_struct(config.foreign, allow_insecure_rpc_endpoints)?,
authorities: Authorities {
#[cfg(feature = "deploy")]
accounts: config.authorities.accounts,
Expand Down Expand Up @@ -106,7 +106,7 @@ impl PartialEq for NodeInfo {
}

impl Node {
fn from_load_struct(node: load::Node) -> Result<Node, Error> {
fn from_load_struct(node: load::Node, allow_insecure_rpc_endpoints: bool) -> Result<Node, Error> {
let gas_price_oracle_url = node.gas_price_oracle_url.clone();

let gas_price_speed = match node.gas_price_speed {
Expand All @@ -122,6 +122,16 @@ impl Node {
let default_gas_price = node.default_gas_price.unwrap_or(DEFAULT_GAS_PRICE_WEI);
let concurrent_http_requests = node.concurrent_http_requests.unwrap_or(DEFAULT_CONCURRENCY);

let rpc_host = node.rpc_host.unwrap();

if !rpc_host.starts_with("https://") {
if !allow_insecure_rpc_endpoints {
return Err(ErrorKind::ConfigError(format!("RPC endpoints must use TLS, {} doesn't", rpc_host)).into());
} else {
warn!("RPC endpoints must use TLS, {} doesn't", rpc_host);
}
}

let result = Node {
account: node.account,
#[cfg(feature = "deploy")]
Expand All @@ -136,7 +146,7 @@ impl Node {
request_timeout: Duration::from_secs(node.request_timeout.unwrap_or(DEFAULT_TIMEOUT)),
poll_interval: Duration::from_secs(node.poll_interval.unwrap_or(DEFAULT_POLL_INTERVAL)),
required_confirmations: node.required_confirmations.unwrap_or(DEFAULT_CONFIRMATIONS),
rpc_host: node.rpc_host.unwrap(),
rpc_host,
rpc_port: node.rpc_port.unwrap_or(DEFAULT_RPC_PORT),
password: node.password,
info: Default::default(),
Expand Down Expand Up @@ -398,7 +408,7 @@ required_signatures = 2
keystore: "/keys/".into(),
};

let config = Config::load_from_str(toml).unwrap();
let config = Config::load_from_str(toml, true).unwrap();
assert_eq!(expected, config);
}

Expand Down Expand Up @@ -461,7 +471,7 @@ required_signatures = 2
keystore: "/keys/".into(),
};

let config = Config::load_from_str(toml).unwrap();
let config = Config::load_from_str(toml, true).unwrap();
assert_eq!(expected, config);
}
}
4 changes: 4 additions & 0 deletions bridge/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ error_chain! {
OtherError(error: String) {
description("other error")
display("{}", error)
}
ConfigError(err: String) {
description("config error")
display("{}", err)
}
}
}
Expand Down
10 changes: 6 additions & 4 deletions cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,22 @@ POA-Ethereum bridge.
Copyright 2018 POA Networks Ltd.
Usage:
bridge --config <config> --database <database>
bridge [options] --config <config> --database <database>
bridge -h | --help
bridge -v | --version
Options:
-h, --help Display help message and exit.
-v, --version Print version and exit.
-h, --help Display help message and exit.
-v, --version Print version and exit.
--allow-insecure-rpc-endpoints Allow non-HTTPS endpoints
"#;

#[derive(Debug, Deserialize)]
pub struct Args {
arg_config: PathBuf,
arg_database: PathBuf,
flag_version: bool,
flag_allow_insecure_rpc_endpoints: bool,
}

use std::sync::atomic::{AtomicBool, Ordering};
Expand Down Expand Up @@ -128,7 +130,7 @@ fn execute<S, I>(command: I, running: Arc<AtomicBool>) -> Result<String, UserFac
}

info!(target: "bridge", "Loading config");
let config = Config::load(args.arg_config)?;
let config = Config::load(args.arg_config, args.flag_allow_insecure_rpc_endpoints)?;

info!(target: "bridge", "Starting event loop");
let mut event_loop = Core::new().unwrap();
Expand Down
1 change: 1 addition & 0 deletions integration-tests/tests/basic_deposit_then_withdraw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ fn test_basic_deposit_then_withdraw() {
.env("RUST_LOG", "info")
.arg("--config").arg("bridge_config.toml")
.arg("--database").arg("tmp/bridge1_db.txt")
.arg("--allow-insecure-rpc-endpoints")
.spawn()
.expect("failed to spawn bridge process");

Expand Down
1 change: 1 addition & 0 deletions integration-tests/tests/insufficient_funds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ fn test_insufficient_funds() {
.env("RUST_LOG", "info")
.arg("--config").arg("bridge_config_gas_price.toml")
.arg("--database").arg("tmp/bridge1_db.txt")
.arg("--allow-insecure-rpc-endpoints")
.spawn()
.expect("failed to spawn bridge process");

Expand Down

0 comments on commit 0968c6f

Please sign in to comment.