More CLI settings for IPFS API (#4608)
* TEMP: Bind to 0.0.0.0, don't check Origin * More CLI options for IPFS * CORS and Hosts filtering * Allow current interface as origin * Correctly handle CORS settings * fix grumbles
This commit is contained in:
@@ -76,6 +76,9 @@ path = "$HOME/.parity/secretstore"
|
||||
[ipfs]
|
||||
enable = false
|
||||
port = 5001
|
||||
interface = "local"
|
||||
cors = "null"
|
||||
hosts = ["none"]
|
||||
|
||||
[mining]
|
||||
author = "0xdeadbeefcafe0000000000000000000000000001"
|
||||
|
||||
@@ -96,7 +96,7 @@ usage! {
|
||||
|
||||
// -- Account Options
|
||||
flag_unlock: Option<String> = None,
|
||||
or |c: &Config| otry!(c.account).unlock.clone().map(|vec| Some(vec.join(","))),
|
||||
or |c: &Config| otry!(c.account).unlock.as_ref().map(|vec| Some(vec.join(","))),
|
||||
flag_password: Vec<String> = Vec::new(),
|
||||
or |c: &Config| otry!(c.account).password.clone(),
|
||||
flag_keys_iterations: u32 = 10240u32,
|
||||
@@ -138,7 +138,7 @@ usage! {
|
||||
flag_network_id: Option<u64> = None,
|
||||
or |c: &Config| otry!(c.network).id.clone().map(Some),
|
||||
flag_bootnodes: Option<String> = None,
|
||||
or |c: &Config| otry!(c.network).bootnodes.clone().map(|vec| Some(vec.join(","))),
|
||||
or |c: &Config| otry!(c.network).bootnodes.as_ref().map(|vec| Some(vec.join(","))),
|
||||
flag_no_discovery: bool = false,
|
||||
or |c: &Config| otry!(c.network).discovery.map(|d| !d).clone(),
|
||||
flag_node_key: Option<String> = None,
|
||||
@@ -160,9 +160,9 @@ usage! {
|
||||
flag_jsonrpc_cors: Option<String> = None,
|
||||
or |c: &Config| otry!(c.rpc).cors.clone().map(Some),
|
||||
flag_jsonrpc_apis: String = "web3,eth,net,parity,traces,rpc",
|
||||
or |c: &Config| otry!(c.rpc).apis.clone().map(|vec| vec.join(",")),
|
||||
or |c: &Config| otry!(c.rpc).apis.as_ref().map(|vec| vec.join(",")),
|
||||
flag_jsonrpc_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.rpc).hosts.clone().map(|vec| vec.join(",")),
|
||||
or |c: &Config| otry!(c.rpc).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
|
||||
// IPC
|
||||
flag_no_ipc: bool = false,
|
||||
@@ -170,7 +170,7 @@ usage! {
|
||||
flag_ipc_path: String = "$BASE/jsonrpc.ipc",
|
||||
or |c: &Config| otry!(c.ipc).path.clone(),
|
||||
flag_ipc_apis: String = "web3,eth,net,parity,parity_accounts,traces,rpc",
|
||||
or |c: &Config| otry!(c.ipc).apis.clone().map(|vec| vec.join(",")),
|
||||
or |c: &Config| otry!(c.ipc).apis.as_ref().map(|vec| vec.join(",")),
|
||||
|
||||
// DAPPS
|
||||
flag_no_dapps: bool = false,
|
||||
@@ -180,7 +180,7 @@ usage! {
|
||||
flag_dapps_interface: String = "local",
|
||||
or |c: &Config| otry!(c.dapps).interface.clone(),
|
||||
flag_dapps_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.dapps).hosts.clone().map(|vec| vec.join(",")),
|
||||
or |c: &Config| otry!(c.dapps).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
flag_dapps_path: String = "$BASE/dapps",
|
||||
or |c: &Config| otry!(c.dapps).path.clone(),
|
||||
flag_dapps_user: Option<String> = None,
|
||||
@@ -204,6 +204,12 @@ usage! {
|
||||
or |c: &Config| otry!(c.ipfs).enable.clone(),
|
||||
flag_ipfs_api_port: u16 = 5001u16,
|
||||
or |c: &Config| otry!(c.ipfs).port.clone(),
|
||||
flag_ipfs_api_interface: String = "local",
|
||||
or |c: &Config| otry!(c.ipfs).interface.clone(),
|
||||
flag_ipfs_api_cors: Option<String> = None,
|
||||
or |c: &Config| otry!(c.ipfs).cors.clone().map(Some),
|
||||
flag_ipfs_api_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.ipfs).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
|
||||
// -- Sealing/Mining Options
|
||||
flag_author: Option<String> = None,
|
||||
@@ -249,7 +255,7 @@ usage! {
|
||||
flag_remove_solved: bool = false,
|
||||
or |c: &Config| otry!(c.mining).remove_solved.clone(),
|
||||
flag_notify_work: Option<String> = None,
|
||||
or |c: &Config| otry!(c.mining).notify_work.clone().map(|vec| Some(vec.join(","))),
|
||||
or |c: &Config| otry!(c.mining).notify_work.as_ref().map(|vec| Some(vec.join(","))),
|
||||
flag_refuse_service_transactions: bool = false,
|
||||
or |c: &Config| otry!(c.mining).refuse_service_transactions.clone(),
|
||||
|
||||
@@ -439,6 +445,9 @@ struct SecretStore {
|
||||
struct Ipfs {
|
||||
enable: Option<bool>,
|
||||
port: Option<u16>,
|
||||
interface: Option<String>,
|
||||
cors: Option<String>,
|
||||
hosts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, PartialEq, RustcDecodable)]
|
||||
@@ -678,6 +687,9 @@ mod tests {
|
||||
// IPFS
|
||||
flag_ipfs_api: false,
|
||||
flag_ipfs_api_port: 5001u16,
|
||||
flag_ipfs_api_interface: "local".into(),
|
||||
flag_ipfs_api_cors: Some("null".into()),
|
||||
flag_ipfs_api_hosts: "none".into(),
|
||||
|
||||
// -- Sealing/Mining Options
|
||||
flag_author: Some("0xdeadbeefcafe0000000000000000000000000001".into()),
|
||||
@@ -872,7 +884,10 @@ mod tests {
|
||||
}),
|
||||
ipfs: Some(Ipfs {
|
||||
enable: Some(false),
|
||||
port: Some(5001)
|
||||
port: Some(5001),
|
||||
interface: None,
|
||||
cors: None,
|
||||
hosts: None,
|
||||
}),
|
||||
mining: Some(Mining {
|
||||
author: Some("0xdeadbeefcafe0000000000000000000000000001".into()),
|
||||
|
||||
@@ -178,6 +178,17 @@ API and Console Options:
|
||||
--ipfs-api Enable IPFS-compatible HTTP API. (default: {flag_ipfs_api})
|
||||
--ipfs-api-port PORT Configure on which port the IPFS HTTP API should listen.
|
||||
(default: {flag_ipfs_api_port})
|
||||
--ipfs-api-interface IP Specify the hostname portion of the IPFS API server,
|
||||
IP should be an interface's IP address or local.
|
||||
(default: {flag_ipfs_api_interface})
|
||||
--ipfs-api-cors URL Specify CORS header for IPFS API responses.
|
||||
(default: {flag_ipfs_api_cors:?})
|
||||
--ipfs-api-hosts HOSTS List of allowed Host header values. This option will
|
||||
validate the Host header sent by the browser, it
|
||||
is additional security against some attack
|
||||
vectors. Special options: "all", "none"
|
||||
(default: {flag_ipfs_api_hosts}).
|
||||
|
||||
|
||||
Secret Store Options:
|
||||
--no-secretstore Disable Secret Store functionality. (default: {flag_no_secretstore})
|
||||
|
||||
@@ -558,6 +558,9 @@ impl Configuration {
|
||||
IpfsConfiguration {
|
||||
enabled: self.args.flag_ipfs_api,
|
||||
port: self.args.flag_ipfs_api_port,
|
||||
interface: self.ipfs_interface(),
|
||||
cors: self.ipfs_cors(),
|
||||
hosts: self.ipfs_hosts(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -693,29 +696,39 @@ impl Configuration {
|
||||
apis
|
||||
}
|
||||
|
||||
fn cors(cors: Option<&String>) -> Option<Vec<String>> {
|
||||
cors.map(|ref c| c.split(',').map(Into::into).collect())
|
||||
}
|
||||
|
||||
fn rpc_cors(&self) -> Option<Vec<String>> {
|
||||
let cors = self.args.flag_jsonrpc_cors.clone().or(self.args.flag_rpccorsdomain.clone());
|
||||
cors.map(|c| c.split(',').map(|s| s.to_owned()).collect())
|
||||
let cors = self.args.flag_jsonrpc_cors.as_ref().or(self.args.flag_rpccorsdomain.as_ref());
|
||||
Self::cors(cors)
|
||||
}
|
||||
|
||||
fn ipfs_cors(&self) -> Option<Vec<String>> {
|
||||
Self::cors(self.args.flag_ipfs_api_cors.as_ref())
|
||||
}
|
||||
|
||||
fn hosts(hosts: &str) -> Option<Vec<String>> {
|
||||
match hosts {
|
||||
"none" => return Some(Vec::new()),
|
||||
"all" => return None,
|
||||
_ => {}
|
||||
}
|
||||
let hosts = hosts.split(',').map(Into::into).collect();
|
||||
Some(hosts)
|
||||
}
|
||||
|
||||
fn rpc_hosts(&self) -> Option<Vec<String>> {
|
||||
match self.args.flag_jsonrpc_hosts.as_ref() {
|
||||
"none" => return Some(Vec::new()),
|
||||
"all" => return None,
|
||||
_ => {}
|
||||
}
|
||||
let hosts = self.args.flag_jsonrpc_hosts.split(',').map(|h| h.into()).collect();
|
||||
Some(hosts)
|
||||
Self::hosts(&self.args.flag_jsonrpc_hosts)
|
||||
}
|
||||
|
||||
fn dapps_hosts(&self) -> Option<Vec<String>> {
|
||||
match self.args.flag_dapps_hosts.as_ref() {
|
||||
"none" => return Some(Vec::new()),
|
||||
"all" => return None,
|
||||
_ => {}
|
||||
}
|
||||
let hosts = self.args.flag_dapps_hosts.split(',').map(|h| h.into()).collect();
|
||||
Some(hosts)
|
||||
Self::hosts(&self.args.flag_dapps_hosts)
|
||||
}
|
||||
|
||||
fn ipfs_hosts(&self) -> Option<Vec<String>> {
|
||||
Self::hosts(&self.args.flag_ipfs_api_hosts)
|
||||
}
|
||||
|
||||
fn ipc_config(&self) -> Result<IpcConfiguration, String> {
|
||||
@@ -850,14 +863,18 @@ impl Configuration {
|
||||
}.into()
|
||||
}
|
||||
|
||||
fn rpc_interface(&self) -> String {
|
||||
match self.network_settings().rpc_interface.as_str() {
|
||||
fn interface(interface: &str) -> String {
|
||||
match interface {
|
||||
"all" => "0.0.0.0",
|
||||
"local" => "127.0.0.1",
|
||||
x => x,
|
||||
}.into()
|
||||
}
|
||||
|
||||
fn rpc_interface(&self) -> String {
|
||||
Self::interface(&self.network_settings().rpc_interface)
|
||||
}
|
||||
|
||||
fn dapps_interface(&self) -> String {
|
||||
match self.args.flag_dapps_interface.as_str() {
|
||||
"local" => "127.0.0.1",
|
||||
@@ -865,6 +882,10 @@ impl Configuration {
|
||||
}.into()
|
||||
}
|
||||
|
||||
fn ipfs_interface(&self) -> String {
|
||||
Self::interface(&self.args.flag_ipfs_api_interface)
|
||||
}
|
||||
|
||||
fn secretstore_interface(&self) -> String {
|
||||
match self.args.flag_secretstore_interface.as_str() {
|
||||
"local" => "127.0.0.1",
|
||||
@@ -873,11 +894,7 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn stratum_interface(&self) -> String {
|
||||
match self.args.flag_stratum_interface.as_str() {
|
||||
"local" => "127.0.0.1",
|
||||
"all" => "0.0.0.0",
|
||||
x => x,
|
||||
}.into()
|
||||
Self::interface(&self.args.flag_stratum_interface)
|
||||
}
|
||||
|
||||
fn dapps_enabled(&self) -> bool {
|
||||
@@ -1273,6 +1290,38 @@ mod tests {
|
||||
assert_eq!(conf3.dapps_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_ipfs_hosts() {
|
||||
// given
|
||||
|
||||
// when
|
||||
let conf0 = parse(&["parity"]);
|
||||
let conf1 = parse(&["parity", "--ipfs-api-hosts", "none"]);
|
||||
let conf2 = parse(&["parity", "--ipfs-api-hosts", "all"]);
|
||||
let conf3 = parse(&["parity", "--ipfs-api-hosts", "ethcore.io,something.io"]);
|
||||
|
||||
// then
|
||||
assert_eq!(conf0.ipfs_hosts(), Some(Vec::new()));
|
||||
assert_eq!(conf1.ipfs_hosts(), Some(Vec::new()));
|
||||
assert_eq!(conf2.ipfs_hosts(), None);
|
||||
assert_eq!(conf3.ipfs_hosts(), Some(vec!["ethcore.io".into(), "something.io".into()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_ipfs_cors() {
|
||||
// given
|
||||
|
||||
// when
|
||||
let conf0 = parse(&["parity"]);
|
||||
let conf1 = parse(&["parity", "--ipfs-api-cors", "*"]);
|
||||
let conf2 = parse(&["parity", "--ipfs-api-cors", "http://ethcore.io,http://something.io"]);
|
||||
|
||||
// then
|
||||
assert_eq!(conf0.ipfs_cors(), None);
|
||||
assert_eq!(conf1.ipfs_cors(), Some(vec!["*".into()]));
|
||||
assert_eq!(conf2.ipfs_cors(), Some(vec!["http://ethcore.io".into(),"http://something.io".into()]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_disable_signer_in_geth_compat() {
|
||||
// given
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
pub use parity_ipfs_api::start_server;
|
||||
use std::sync::Arc;
|
||||
use parity_ipfs_api;
|
||||
use parity_ipfs_api::error::ServerError;
|
||||
use ethcore::client::BlockChainClient;
|
||||
use hyper::server::Listening;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Configuration {
|
||||
pub enabled: bool,
|
||||
pub port: u16,
|
||||
pub interface: String,
|
||||
pub cors: Option<Vec<String>>,
|
||||
pub hosts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl Default for Configuration {
|
||||
@@ -11,6 +18,23 @@ impl Default for Configuration {
|
||||
Configuration {
|
||||
enabled: false,
|
||||
port: 5001,
|
||||
interface: "127.0.0.1".into(),
|
||||
cors: None,
|
||||
hosts: Some(Vec::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_server(conf: Configuration, client: Arc<BlockChainClient>) -> Result<Option<Listening>, ServerError> {
|
||||
if !conf.enabled {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
parity_ipfs_api::start_server(
|
||||
conf.port,
|
||||
conf.interface,
|
||||
conf.cors,
|
||||
conf.hosts,
|
||||
client
|
||||
).map(Some)
|
||||
}
|
||||
|
||||
@@ -471,10 +471,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps);
|
||||
|
||||
// the ipfs server
|
||||
let ipfs_server = match cmd.ipfs_conf.enabled {
|
||||
true => Some(ipfs::start_server(cmd.ipfs_conf.port, client.clone())?),
|
||||
false => None,
|
||||
};
|
||||
let ipfs_server = ipfs::start_server(cmd.ipfs_conf.clone(), client.clone())?;
|
||||
|
||||
// the informant
|
||||
let informant = Arc::new(Informant::new(
|
||||
|
||||
Reference in New Issue
Block a user