UI server refactoring (#5580)
* Full API in Authenticated WS server. * Replacing UI server with Hyper. * Solving CLI, RPCs and tests. * Porting signer tests. * Fixing origin recognition for dapps/rpc. * Fixing tests. Adding parity-rpc-client to test. * Dapps exposed as RPC method. * JS code to support new connection scheme. * Fixing dapps tests. * Updating allowed origins/hosts to support web3.site. * Fixing tests, fixing UI. * Fixing tests. * Removing invalid tests. * Fixing merge. * 404 fallback for UI * Improve ContentFetcher constructor readability. * Naming. * Update .gitlab-ci.yml fix CI lint error * Fixing tests and linting issues. * Fixing new tests. * UI hosts. * Submodules fix.
This commit is contained in:
committed by
Arkadiy Paronyan
parent
7499efecf6
commit
cbcc369a2d
@@ -124,6 +124,8 @@ usage! {
|
||||
or |c: &Config| otry!(c.ui).port.clone(),
|
||||
flag_ui_interface: String = "local",
|
||||
or |c: &Config| otry!(c.ui).interface.clone(),
|
||||
flag_ui_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.ui).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
flag_ui_path: String = "$BASE/signer",
|
||||
or |c: &Config| otry!(c.ui).path.clone(),
|
||||
// NOTE [todr] For security reasons don't put this to config files
|
||||
@@ -188,7 +190,7 @@ usage! {
|
||||
or |c: &Config| otry!(c.websockets).interface.clone(),
|
||||
flag_ws_apis: String = "web3,eth,pubsub,net,parity,parity_pubsub,traces,rpc,secretstore",
|
||||
or |c: &Config| otry!(c.websockets).apis.as_ref().map(|vec| vec.join(",")),
|
||||
flag_ws_origins: String = "none",
|
||||
flag_ws_origins: String = "chrome-extension://*",
|
||||
or |c: &Config| otry!(c.websockets).origins.as_ref().map(|vec| vec.join(",")),
|
||||
flag_ws_hosts: String = "none",
|
||||
or |c: &Config| otry!(c.websockets).hosts.as_ref().map(|vec| vec.join(",")),
|
||||
@@ -430,6 +432,7 @@ struct Ui {
|
||||
disable: Option<bool>,
|
||||
port: Option<u16>,
|
||||
interface: Option<String>,
|
||||
hosts: Option<Vec<String>>,
|
||||
path: Option<String>,
|
||||
}
|
||||
|
||||
@@ -709,6 +712,7 @@ mod tests {
|
||||
flag_no_ui: false,
|
||||
flag_ui_port: 8180u16,
|
||||
flag_ui_interface: "127.0.0.1".into(),
|
||||
flag_ui_hosts: "none".into(),
|
||||
flag_ui_path: "$HOME/.parity/signer".into(),
|
||||
flag_ui_no_validation: false,
|
||||
|
||||
@@ -929,6 +933,7 @@ mod tests {
|
||||
disable: Some(true),
|
||||
port: None,
|
||||
interface: None,
|
||||
hosts: None,
|
||||
path: None,
|
||||
}),
|
||||
network: Some(Network {
|
||||
|
||||
@@ -110,6 +110,11 @@ UI Options:
|
||||
--ui-interface IP Specify the hostname portion of the Trusted UI
|
||||
server, IP should be an interface's IP address,
|
||||
or local (default: {flag_ui_interface}).
|
||||
--ui-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_ui_hosts}).
|
||||
--ui-path PATH Specify directory where Trusted UIs tokens should
|
||||
be stored. (default: {flag_ui_path})
|
||||
--ui-no-validation Disable Origin and Host headers validation for
|
||||
|
||||
@@ -30,7 +30,7 @@ use ethcore::client::{VMType};
|
||||
use ethcore::miner::{MinerOptions, Banning, StratumOptions};
|
||||
use ethcore::verification::queue::VerifierSettings;
|
||||
|
||||
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration};
|
||||
use rpc::{IpcConfiguration, HttpConfiguration, WsConfiguration, UiConfiguration};
|
||||
use rpc_apis::ApiSet;
|
||||
use parity_rpc::NetworkSettings;
|
||||
use cache::CacheConfig;
|
||||
@@ -41,7 +41,6 @@ use ethcore_logger::Config as LogConfig;
|
||||
use dir::{self, Directories, default_hypervisor_path, default_local_path, default_data_path};
|
||||
use dapps::Configuration as DappsConfiguration;
|
||||
use ipfs::Configuration as IpfsConfiguration;
|
||||
use signer::{Configuration as SignerConfiguration};
|
||||
use secretstore::Configuration as SecretStoreConfiguration;
|
||||
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
|
||||
use run::RunCmd;
|
||||
@@ -50,8 +49,6 @@ use presale::ImportWallet;
|
||||
use account::{AccountCmd, NewAccount, ListAccounts, ImportAccounts, ImportFromGethAccounts};
|
||||
use snapshot::{self, SnapshotCommand};
|
||||
|
||||
const AUTHCODE_FILENAME: &'static str = "authcodes";
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum Cmd {
|
||||
Run(RunCmd),
|
||||
@@ -59,7 +56,7 @@ pub enum Cmd {
|
||||
Account(AccountCmd),
|
||||
ImportPresaleWallet(ImportWallet),
|
||||
Blockchain(BlockchainCmd),
|
||||
SignerToken(SignerConfiguration),
|
||||
SignerToken(WsConfiguration, UiConfiguration),
|
||||
SignerSign {
|
||||
id: Option<usize>,
|
||||
pwfile: Option<PathBuf>,
|
||||
@@ -118,6 +115,7 @@ impl Configuration {
|
||||
let http_conf = self.http_config()?;
|
||||
let ipc_conf = self.ipc_config()?;
|
||||
let net_conf = self.net_config()?;
|
||||
let ui_conf = self.ui_config();
|
||||
let network_id = self.network_id();
|
||||
let cache_config = self.cache_config();
|
||||
let tracing = self.args.flag_tracing.parse()?;
|
||||
@@ -134,10 +132,8 @@ impl Configuration {
|
||||
let public_node = self.args.flag_public_node;
|
||||
let warp_sync = !self.args.flag_no_warp && fat_db != Switch::On && tracing != Switch::On && pruning != Pruning::Specific(Algorithm::Archive);
|
||||
let geth_compatibility = self.args.flag_geth;
|
||||
let ui_address = self.ui_port().map(|port| (self.ui_interface(), port));
|
||||
let mut dapps_conf = self.dapps_config();
|
||||
let ipfs_conf = self.ipfs_config();
|
||||
let signer_conf = self.signer_config();
|
||||
let secretstore_conf = self.secretstore_config()?;
|
||||
let format = self.format()?;
|
||||
|
||||
@@ -149,11 +145,10 @@ impl Configuration {
|
||||
let cmd = if self.args.flag_version {
|
||||
Cmd::Version
|
||||
} else if self.args.cmd_signer {
|
||||
let mut authfile = PathBuf::from(signer_conf.signer_path.clone());
|
||||
authfile.push(AUTHCODE_FILENAME);
|
||||
let authfile = ::signer::codes_path(&ws_conf.signer_path);
|
||||
|
||||
if self.args.cmd_new_token {
|
||||
Cmd::SignerToken(signer_conf)
|
||||
Cmd::SignerToken(ws_conf, ui_conf)
|
||||
} else if self.args.cmd_sign {
|
||||
let pwfile = self.args.flag_password.get(0).map(|pwfile| {
|
||||
PathBuf::from(pwfile)
|
||||
@@ -161,18 +156,18 @@ impl Configuration {
|
||||
Cmd::SignerSign {
|
||||
id: self.args.arg_id,
|
||||
pwfile: pwfile,
|
||||
port: signer_conf.port,
|
||||
port: ws_conf.port,
|
||||
authfile: authfile,
|
||||
}
|
||||
} else if self.args.cmd_reject {
|
||||
Cmd::SignerReject {
|
||||
id: self.args.arg_id,
|
||||
port: signer_conf.port,
|
||||
port: ws_conf.port,
|
||||
authfile: authfile,
|
||||
}
|
||||
} else if self.args.cmd_list {
|
||||
Cmd::SignerList {
|
||||
port: signer_conf.port,
|
||||
port: ws_conf.port,
|
||||
authfile: authfile,
|
||||
}
|
||||
} else {
|
||||
@@ -372,11 +367,10 @@ impl Configuration {
|
||||
warp_sync: warp_sync,
|
||||
public_node: public_node,
|
||||
geth_compatibility: geth_compatibility,
|
||||
ui_address: ui_address,
|
||||
net_settings: self.network_settings()?,
|
||||
dapps_conf: dapps_conf,
|
||||
ipfs_conf: ipfs_conf,
|
||||
signer_conf: signer_conf,
|
||||
ui_conf: ui_conf,
|
||||
secretstore_conf: secretstore_conf,
|
||||
dapp: self.dapp_to_open()?,
|
||||
ui: self.args.cmd_ui,
|
||||
@@ -553,13 +547,12 @@ impl Configuration {
|
||||
Ok(options)
|
||||
}
|
||||
|
||||
fn signer_config(&self) -> SignerConfiguration {
|
||||
SignerConfiguration {
|
||||
fn ui_config(&self) -> UiConfiguration {
|
||||
UiConfiguration {
|
||||
enabled: self.ui_enabled(),
|
||||
port: self.args.flag_ports_shift + self.args.flag_ui_port,
|
||||
interface: self.ui_interface(),
|
||||
signer_path: self.directories().signer,
|
||||
skip_origin_validation: self.args.flag_unsafe_expose || self.args.flag_ui_no_validation,
|
||||
port: self.args.flag_ports_shift + self.args.flag_ui_port,
|
||||
hosts: self.ui_hosts(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -768,6 +761,14 @@ impl Configuration {
|
||||
Some(hosts)
|
||||
}
|
||||
|
||||
fn ui_hosts(&self) -> Option<Vec<String>> {
|
||||
if self.args.flag_ui_no_validation {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.hosts(&self.args.flag_ui_hosts, &self.ui_interface())
|
||||
}
|
||||
|
||||
fn rpc_hosts(&self) -> Option<Vec<String>> {
|
||||
self.hosts(&self.args.flag_jsonrpc_hosts, &self.rpc_interface())
|
||||
}
|
||||
@@ -825,13 +826,17 @@ impl Configuration {
|
||||
}
|
||||
|
||||
fn ws_config(&self) -> Result<WsConfiguration, String> {
|
||||
let ui = self.ui_config();
|
||||
|
||||
let conf = WsConfiguration {
|
||||
enabled: self.ws_enabled(),
|
||||
interface: self.ws_interface(),
|
||||
port: self.args.flag_ports_shift + self.args.flag_ws_port,
|
||||
apis: self.args.flag_ws_apis.parse()?,
|
||||
hosts: self.ws_hosts(),
|
||||
origins: self.ws_origins()
|
||||
origins: self.ws_origins(),
|
||||
signer_path: self.directories().signer.into(),
|
||||
ui_address: ui.address(),
|
||||
};
|
||||
|
||||
Ok(conf)
|
||||
@@ -928,18 +933,6 @@ impl Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
fn ui_port(&self) -> Option<u16> {
|
||||
if !self.ui_enabled() {
|
||||
None
|
||||
} else {
|
||||
Some(self.args.flag_ui_port)
|
||||
}
|
||||
}
|
||||
|
||||
fn ui_interface(&self) -> String {
|
||||
self.interface(&self.args.flag_ui_interface)
|
||||
}
|
||||
|
||||
fn interface(&self, interface: &str) -> String {
|
||||
if self.args.flag_unsafe_expose {
|
||||
return "0.0.0.0".into();
|
||||
@@ -952,6 +945,11 @@ impl Configuration {
|
||||
}.into()
|
||||
}
|
||||
|
||||
|
||||
fn ui_interface(&self) -> String {
|
||||
self.interface(&self.args.flag_ui_interface)
|
||||
}
|
||||
|
||||
fn rpc_interface(&self) -> String {
|
||||
let rpc_interface = self.args.flag_rpcaddr.clone().unwrap_or(self.args.flag_jsonrpc_interface.clone());
|
||||
self.interface(&rpc_interface)
|
||||
@@ -1050,24 +1048,27 @@ impl Configuration {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use cli::Args;
|
||||
use parity_rpc::NetworkSettings;
|
||||
use ethcore::client::{VMType, BlockId};
|
||||
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
|
||||
use helpers::{default_network_config};
|
||||
use run::RunCmd;
|
||||
use dir::{Directories, default_hypervisor_path};
|
||||
use signer::{Configuration as SignerConfiguration};
|
||||
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat, ExportState};
|
||||
use presale::ImportWallet;
|
||||
use params::SpecType;
|
||||
use account::{AccountCmd, NewAccount, ImportAccounts, ListAccounts};
|
||||
use devtools::{RandomTempPath};
|
||||
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
|
||||
use std::io::Write;
|
||||
use std::fs::{File, create_dir};
|
||||
|
||||
use devtools::{RandomTempPath};
|
||||
use ethcore::client::{VMType, BlockId};
|
||||
use ethcore::miner::{MinerOptions, PrioritizationStrategy};
|
||||
use parity_rpc::NetworkSettings;
|
||||
use updater::{UpdatePolicy, UpdateFilter, ReleaseTrack};
|
||||
|
||||
use account::{AccountCmd, NewAccount, ImportAccounts, ListAccounts};
|
||||
use blockchain::{BlockchainCmd, ImportBlockchain, ExportBlockchain, DataFormat, ExportState};
|
||||
use cli::Args;
|
||||
use dir::{Directories, default_hypervisor_path};
|
||||
use helpers::{default_network_config};
|
||||
use params::SpecType;
|
||||
use presale::ImportWallet;
|
||||
use rpc::{WsConfiguration, UiConfiguration};
|
||||
use run::RunCmd;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
struct TestPasswordReader(&'static str);
|
||||
|
||||
@@ -1233,12 +1234,20 @@ mod tests {
|
||||
let args = vec!["parity", "signer", "new-token"];
|
||||
let conf = parse(&args);
|
||||
let expected = Directories::default().signer;
|
||||
assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(SignerConfiguration {
|
||||
assert_eq!(conf.into_command().unwrap().cmd, Cmd::SignerToken(WsConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8546,
|
||||
apis: ApiSet::UnsafeContext,
|
||||
origins: Some(vec!["chrome-extension://*".into()]),
|
||||
hosts: Some(vec![]),
|
||||
signer_path: expected.into(),
|
||||
ui_address: Some(("127.0.0.1".to_owned(), 8180)),
|
||||
}, UiConfiguration {
|
||||
enabled: true,
|
||||
signer_path: expected,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8180,
|
||||
skip_origin_validation: false,
|
||||
hosts: Some(vec![]),
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -1273,11 +1282,10 @@ mod tests {
|
||||
wal: true,
|
||||
vm_type: Default::default(),
|
||||
geth_compatibility: false,
|
||||
ui_address: Some(("127.0.0.1".into(), 8180)),
|
||||
net_settings: Default::default(),
|
||||
dapps_conf: Default::default(),
|
||||
ipfs_conf: Default::default(),
|
||||
signer_conf: Default::default(),
|
||||
ui_conf: Default::default(),
|
||||
secretstore_conf: Default::default(),
|
||||
ui: false,
|
||||
dapp: None,
|
||||
@@ -1457,7 +1465,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_parse_signer_configration() {
|
||||
fn should_parse_ui_configuration() {
|
||||
// given
|
||||
|
||||
// when
|
||||
@@ -1467,33 +1475,33 @@ mod tests {
|
||||
let conf3 = parse(&["parity", "--ui-path", "signer", "--ui-interface", "test"]);
|
||||
|
||||
// then
|
||||
assert_eq!(conf0.signer_config(), SignerConfiguration {
|
||||
assert_eq!(conf0.directories().signer, "signer".to_owned());
|
||||
assert_eq!(conf0.ui_config(), UiConfiguration {
|
||||
enabled: true,
|
||||
port: 8180,
|
||||
interface: "127.0.0.1".into(),
|
||||
signer_path: "signer".into(),
|
||||
skip_origin_validation: false,
|
||||
});
|
||||
assert_eq!(conf1.signer_config(), SignerConfiguration {
|
||||
enabled: true,
|
||||
port: 8180,
|
||||
interface: "127.0.0.1".into(),
|
||||
signer_path: "signer".into(),
|
||||
skip_origin_validation: true,
|
||||
hosts: Some(vec![]),
|
||||
});
|
||||
assert_eq!(conf2.signer_config(), SignerConfiguration {
|
||||
assert_eq!(conf1.directories().signer, "signer".to_owned());
|
||||
assert_eq!(conf1.ui_config(), UiConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8180,
|
||||
hosts: None,
|
||||
});
|
||||
assert_eq!(conf2.directories().signer, "signer".to_owned());
|
||||
assert_eq!(conf2.ui_config(), UiConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 3123,
|
||||
interface: "127.0.0.1".into(),
|
||||
signer_path: "signer".into(),
|
||||
skip_origin_validation: false,
|
||||
hosts: Some(vec![]),
|
||||
});
|
||||
assert_eq!(conf3.signer_config(), SignerConfiguration {
|
||||
assert_eq!(conf3.directories().signer, "signer".to_owned());
|
||||
assert_eq!(conf3.ui_config(), UiConfiguration {
|
||||
enabled: true,
|
||||
port: 8180,
|
||||
interface: "test".into(),
|
||||
signer_path: "signer".into(),
|
||||
skip_origin_validation: false,
|
||||
port: 8180,
|
||||
hosts: Some(vec![]),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1551,7 +1559,7 @@ mod tests {
|
||||
assert_eq!(conf0.network_settings().unwrap().rpc_port, 8546);
|
||||
assert_eq!(conf0.http_config().unwrap().port, 8546);
|
||||
assert_eq!(conf0.ws_config().unwrap().port, 8547);
|
||||
assert_eq!(conf0.signer_config().port, 8181);
|
||||
assert_eq!(conf0.ui_config().port, 8181);
|
||||
assert_eq!(conf0.secretstore_config().unwrap().port, 8084);
|
||||
assert_eq!(conf0.secretstore_config().unwrap().http_port, 8083);
|
||||
assert_eq!(conf0.ipfs_config().port, 5002);
|
||||
@@ -1563,7 +1571,7 @@ mod tests {
|
||||
assert_eq!(conf1.network_settings().unwrap().rpc_port, 8545);
|
||||
assert_eq!(conf1.http_config().unwrap().port, 8545);
|
||||
assert_eq!(conf1.ws_config().unwrap().port, 8547);
|
||||
assert_eq!(conf1.signer_config().port, 8181);
|
||||
assert_eq!(conf1.ui_config().port, 8181);
|
||||
assert_eq!(conf1.secretstore_config().unwrap().port, 8084);
|
||||
assert_eq!(conf1.secretstore_config().unwrap().http_port, 8083);
|
||||
assert_eq!(conf1.ipfs_config().port, 5002);
|
||||
@@ -1582,8 +1590,8 @@ mod tests {
|
||||
assert_eq!(conf0.http_config().unwrap().hosts, None);
|
||||
assert_eq!(&conf0.ws_config().unwrap().interface, "0.0.0.0");
|
||||
assert_eq!(conf0.ws_config().unwrap().hosts, None);
|
||||
assert_eq!(&conf0.signer_config().interface, "0.0.0.0");
|
||||
assert_eq!(conf0.signer_config().skip_origin_validation, true);
|
||||
assert_eq!(&conf0.ui_config().interface, "0.0.0.0");
|
||||
assert_eq!(conf0.ui_config().hosts, None);
|
||||
assert_eq!(&conf0.secretstore_config().unwrap().interface, "0.0.0.0");
|
||||
assert_eq!(&conf0.secretstore_config().unwrap().http_interface, "0.0.0.0");
|
||||
assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0");
|
||||
|
||||
@@ -27,6 +27,7 @@ use hash_fetch::urlhint::ContractClient;
|
||||
use helpers::replace_home;
|
||||
use light::client::Client as LightClient;
|
||||
use light::on_demand::{self, OnDemand};
|
||||
use rpc;
|
||||
use rpc_apis::SignerService;
|
||||
use parity_reactor;
|
||||
use util::{Bytes, Address};
|
||||
@@ -49,6 +50,15 @@ impl Default for Configuration {
|
||||
}
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
pub fn address(&self, address: Option<(String, u16)>) -> Option<(String, u16)> {
|
||||
match self.enabled {
|
||||
true => address,
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Registrar implementation of the full client.
|
||||
pub struct FullRegistrar {
|
||||
/// Handle to the full client.
|
||||
@@ -125,35 +135,49 @@ impl ContractClient for LightRegistrar {
|
||||
|
||||
// TODO: light client implementation forwarding to OnDemand and waiting for future
|
||||
// to resolve.
|
||||
#[derive(Clone)]
|
||||
pub struct Dependencies {
|
||||
pub sync_status: Arc<SyncStatus>,
|
||||
pub contract_client: Arc<ContractClient>,
|
||||
pub remote: parity_reactor::TokioRemote,
|
||||
pub fetch: FetchClient,
|
||||
pub signer: Arc<SignerService>,
|
||||
pub ui_address: Option<(String, u16)>,
|
||||
}
|
||||
|
||||
pub fn new(configuration: Configuration, deps: Dependencies)
|
||||
-> Result<Option<Middleware>, String>
|
||||
{
|
||||
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<Middleware>, String> {
|
||||
if !configuration.enabled {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
dapps_middleware(
|
||||
server::dapps_middleware(
|
||||
deps,
|
||||
configuration.dapps_path,
|
||||
configuration.extra_dapps,
|
||||
rpc::DAPPS_DOMAIN.into(),
|
||||
).map(Some)
|
||||
}
|
||||
|
||||
pub use self::server::{SyncStatus, Middleware, dapps_middleware};
|
||||
pub fn new_ui(enabled: bool, deps: Dependencies) -> Result<Option<Middleware>, String> {
|
||||
if !enabled {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
server::ui_middleware(
|
||||
deps,
|
||||
rpc::DAPPS_DOMAIN.into(),
|
||||
).map(Some)
|
||||
}
|
||||
|
||||
pub use self::server::{SyncStatus, Middleware, service};
|
||||
|
||||
#[cfg(not(feature = "dapps"))]
|
||||
mod server {
|
||||
use super::Dependencies;
|
||||
use std::sync::Arc;
|
||||
use std::path::PathBuf;
|
||||
use parity_rpc::{hyper, RequestMiddleware, RequestMiddlewareAction};
|
||||
use rpc_apis;
|
||||
|
||||
pub type SyncStatus = Fn() -> bool;
|
||||
|
||||
@@ -170,9 +194,21 @@ mod server {
|
||||
_deps: Dependencies,
|
||||
_dapps_path: PathBuf,
|
||||
_extra_dapps: Vec<PathBuf>,
|
||||
_dapps_domain: String,
|
||||
) -> Result<Middleware, String> {
|
||||
Err("Your Parity version has been compiled without WebApps support.".into())
|
||||
}
|
||||
|
||||
pub fn ui_middleware(
|
||||
_deps: Dependencies,
|
||||
_dapps_domain: String,
|
||||
) -> Result<Middleware, String> {
|
||||
Err("Your Parity version has been compiled without UI support.".into())
|
||||
}
|
||||
|
||||
pub fn service(_: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "dapps")]
|
||||
@@ -180,6 +216,7 @@ mod server {
|
||||
use super::Dependencies;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use rpc_apis;
|
||||
|
||||
use parity_dapps;
|
||||
use parity_reactor;
|
||||
@@ -191,20 +228,62 @@ mod server {
|
||||
deps: Dependencies,
|
||||
dapps_path: PathBuf,
|
||||
extra_dapps: Vec<PathBuf>,
|
||||
dapps_domain: String,
|
||||
) -> Result<Middleware, String> {
|
||||
let signer = deps.signer.clone();
|
||||
let signer = deps.signer;
|
||||
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
|
||||
let web_proxy_tokens = Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token));
|
||||
|
||||
Ok(parity_dapps::Middleware::new(
|
||||
Ok(parity_dapps::Middleware::dapps(
|
||||
parity_remote,
|
||||
deps.signer.address(),
|
||||
deps.ui_address,
|
||||
dapps_path,
|
||||
extra_dapps,
|
||||
dapps_domain,
|
||||
deps.contract_client,
|
||||
deps.sync_status,
|
||||
web_proxy_tokens,
|
||||
deps.fetch.clone(),
|
||||
deps.fetch,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn ui_middleware(
|
||||
deps: Dependencies,
|
||||
dapps_domain: String,
|
||||
) -> Result<Middleware, String> {
|
||||
let parity_remote = parity_reactor::Remote::new(deps.remote.clone());
|
||||
Ok(parity_dapps::Middleware::ui(
|
||||
parity_remote,
|
||||
deps.contract_client,
|
||||
deps.sync_status,
|
||||
deps.fetch,
|
||||
dapps_domain,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn service(middleware: &Option<Middleware>) -> Option<Arc<rpc_apis::DappsService>> {
|
||||
middleware.as_ref().map(|m| Arc::new(DappsServiceWrapper {
|
||||
endpoints: m.endpoints()
|
||||
}) as Arc<rpc_apis::DappsService>)
|
||||
}
|
||||
|
||||
pub struct DappsServiceWrapper {
|
||||
endpoints: parity_dapps::Endpoints,
|
||||
}
|
||||
|
||||
impl rpc_apis::DappsService for DappsServiceWrapper {
|
||||
fn list_dapps(&self) -> Vec<rpc_apis::LocalDapp> {
|
||||
self.endpoints.list()
|
||||
.into_iter()
|
||||
.map(|app| rpc_apis::LocalDapp {
|
||||
id: app.id,
|
||||
name: app.name,
|
||||
description: app.description,
|
||||
version: app.version,
|
||||
author: app.author,
|
||||
icon_url: app.icon_url,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ extern crate ethcore_ipc_hypervisor as hypervisor;
|
||||
extern crate ethcore_ipc_nano as nanoipc;
|
||||
extern crate ethcore_light as light;
|
||||
extern crate ethcore_logger;
|
||||
extern crate ethcore_signer;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethkey;
|
||||
extern crate ethsync;
|
||||
@@ -114,9 +113,9 @@ mod presale;
|
||||
mod rpc;
|
||||
mod rpc_apis;
|
||||
mod run;
|
||||
mod secretstore;
|
||||
mod signer;
|
||||
mod snapshot;
|
||||
mod secretstore;
|
||||
mod upgrade;
|
||||
mod url;
|
||||
mod user_defaults;
|
||||
@@ -170,7 +169,7 @@ fn execute(command: Execute, can_restart: bool) -> Result<PostExecutionAction, S
|
||||
Cmd::Account(account_cmd) => account::execute(account_cmd).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::ImportPresaleWallet(presale_cmd) => presale::execute(presale_cmd).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::Blockchain(blockchain_cmd) => blockchain::execute(blockchain_cmd).map(|_| PostExecutionAction::Quit),
|
||||
Cmd::SignerToken(signer_cmd) => signer::execute(signer_cmd).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::SignerToken(ws_conf, ui_conf) => signer::execute(ws_conf, ui_conf).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::SignerSign { id, pwfile, port, authfile } => rpc_cli::signer_sign(id, pwfile, port, authfile).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::SignerList { port, authfile } => rpc_cli::signer_list(port, authfile).map(|s| PostExecutionAction::Print(s)),
|
||||
Cmd::SignerReject { id, port, authfile } => rpc_cli::signer_reject(id, port, authfile).map(|s| PostExecutionAction::Print(s)),
|
||||
|
||||
267
parity/rpc.rs
267
parity/rpc.rs
@@ -16,18 +16,24 @@
|
||||
|
||||
use std::io;
|
||||
use std::sync::Arc;
|
||||
use std::path::PathBuf;
|
||||
use std::collections::HashSet;
|
||||
|
||||
use dapps;
|
||||
use parity_rpc::informant::{RpcStats, Middleware};
|
||||
use parity_rpc::{self as rpc, HttpServerError, Metadata, Origin, DomainsValidation};
|
||||
use helpers::parity_ipc_path;
|
||||
use dir::default_data_path;
|
||||
use helpers::{parity_ipc_path, replace_home};
|
||||
use jsonrpc_core::MetaIoHandler;
|
||||
use parity_reactor::TokioRemote;
|
||||
use parity_rpc::informant::{RpcStats, Middleware};
|
||||
use parity_rpc::{self as rpc, Metadata, DomainsValidation};
|
||||
use rpc_apis::{self, ApiSet};
|
||||
|
||||
pub use parity_rpc::{IpcServer, HttpServer, RequestMiddleware};
|
||||
pub use parity_rpc::ws::Server as WsServer;
|
||||
|
||||
|
||||
pub const DAPPS_DOMAIN: &'static str = "web3.site";
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct HttpConfiguration {
|
||||
pub enabled: bool,
|
||||
@@ -39,6 +45,15 @@ pub struct HttpConfiguration {
|
||||
pub threads: Option<usize>,
|
||||
}
|
||||
|
||||
impl HttpConfiguration {
|
||||
pub fn address(&self) -> Option<(String, u16)> {
|
||||
match self.enabled {
|
||||
true => Some((self.interface.clone(), self.port)),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HttpConfiguration {
|
||||
fn default() -> Self {
|
||||
HttpConfiguration {
|
||||
@@ -53,6 +68,48 @@ impl Default for HttpConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct UiConfiguration {
|
||||
pub enabled: bool,
|
||||
pub interface: String,
|
||||
pub port: u16,
|
||||
pub hosts: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
impl UiConfiguration {
|
||||
pub fn address(&self) -> Option<(String, u16)> {
|
||||
match self.enabled {
|
||||
true => Some((self.interface.clone(), self.port)),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<UiConfiguration> for HttpConfiguration {
|
||||
fn from(conf: UiConfiguration) -> Self {
|
||||
HttpConfiguration {
|
||||
enabled: conf.enabled,
|
||||
interface: conf.interface,
|
||||
port: conf.port,
|
||||
apis: rpc_apis::ApiSet::SafeContext,
|
||||
cors: None,
|
||||
hosts: conf.hosts,
|
||||
threads: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for UiConfiguration {
|
||||
fn default() -> Self {
|
||||
UiConfiguration {
|
||||
enabled: true,
|
||||
port: 8180,
|
||||
interface: "127.0.0.1".into(),
|
||||
hosts: Some(vec![]),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct IpcConfiguration {
|
||||
pub enabled: bool,
|
||||
@@ -75,7 +132,7 @@ impl Default for IpcConfiguration {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct WsConfiguration {
|
||||
pub enabled: bool,
|
||||
pub interface: String,
|
||||
@@ -83,17 +140,32 @@ pub struct WsConfiguration {
|
||||
pub apis: ApiSet,
|
||||
pub origins: Option<Vec<String>>,
|
||||
pub hosts: Option<Vec<String>>,
|
||||
pub signer_path: PathBuf,
|
||||
pub ui_address: Option<(String, u16)>,
|
||||
}
|
||||
|
||||
impl Default for WsConfiguration {
|
||||
fn default() -> Self {
|
||||
let data_dir = default_data_path();
|
||||
WsConfiguration {
|
||||
enabled: true,
|
||||
interface: "127.0.0.1".into(),
|
||||
port: 8546,
|
||||
apis: ApiSet::UnsafeContext,
|
||||
origins: Some(Vec::new()),
|
||||
origins: Some(vec!["chrome-extension://*".into()]),
|
||||
hosts: Some(Vec::new()),
|
||||
signer_path: replace_home(&data_dir, "$BASE/signer").into(),
|
||||
ui_address: Some(("127.0.0.1".to_owned(), 8180)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl WsConfiguration {
|
||||
pub fn address(&self) -> Option<(String, u16)> {
|
||||
match self.enabled {
|
||||
true => Some((self.interface.clone(), self.port)),
|
||||
false => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,62 +176,6 @@ pub struct Dependencies<D: rpc_apis::Dependencies> {
|
||||
pub stats: Arc<RpcStats>,
|
||||
}
|
||||
|
||||
pub struct RpcExtractor;
|
||||
impl rpc::HttpMetaExtractor for RpcExtractor {
|
||||
type Metadata = Metadata;
|
||||
|
||||
fn read_metadata(&self, origin: String, dapps_origin: Option<String>) -> Metadata {
|
||||
let mut metadata = Metadata::default();
|
||||
|
||||
metadata.origin = match (origin.as_str(), dapps_origin) {
|
||||
("null", Some(dapp)) => Origin::Dapps(dapp.into()),
|
||||
_ => Origin::Rpc(origin),
|
||||
};
|
||||
|
||||
metadata
|
||||
}
|
||||
}
|
||||
|
||||
impl rpc::IpcMetaExtractor<Metadata> for RpcExtractor {
|
||||
fn extract(&self, _req: &rpc::IpcRequestContext) -> Metadata {
|
||||
let mut metadata = Metadata::default();
|
||||
// TODO [ToDr] Extract proper session id when it's available in context.
|
||||
metadata.origin = Origin::Ipc(1.into());
|
||||
metadata
|
||||
}
|
||||
}
|
||||
|
||||
struct WsRpcExtractor;
|
||||
impl rpc::ws::MetaExtractor<Metadata> for WsRpcExtractor {
|
||||
fn extract(&self, req: &rpc::ws::RequestContext) -> Metadata {
|
||||
let mut metadata = Metadata::default();
|
||||
let id = req.session_id as u64;
|
||||
metadata.origin = Origin::Ws(id.into());
|
||||
metadata.session = Some(Arc::new(rpc::PubSubSession::new(req.sender())));
|
||||
metadata
|
||||
}
|
||||
}
|
||||
|
||||
struct WsStats {
|
||||
stats: Arc<RpcStats>,
|
||||
}
|
||||
|
||||
impl rpc::ws::SessionStats for WsStats {
|
||||
fn open_session(&self, _id: rpc::ws::SessionId) {
|
||||
self.stats.open_session()
|
||||
}
|
||||
|
||||
fn close_session(&self, _id: rpc::ws::SessionId) {
|
||||
self.stats.close_session()
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_apis<D>(apis: ApiSet, deps: &Dependencies<D>) -> MetaIoHandler<Metadata, Middleware<D::Notifier>>
|
||||
where D: rpc_apis::Dependencies
|
||||
{
|
||||
rpc_apis::setup_rpc(deps.stats.clone(), &*deps.apis, apis)
|
||||
}
|
||||
|
||||
pub fn new_ws<D: rpc_apis::Dependencies>(
|
||||
conf: WsConfiguration,
|
||||
deps: &Dependencies<D>,
|
||||
@@ -168,23 +184,41 @@ pub fn new_ws<D: rpc_apis::Dependencies>(
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let url = format!("{}:{}", conf.interface, conf.port);
|
||||
let domain = DAPPS_DOMAIN;
|
||||
let ws_address = (conf.interface, conf.port);
|
||||
let url = format!("{}:{}", ws_address.0, ws_address.1);
|
||||
let addr = url.parse().map_err(|_| format!("Invalid WebSockets listen host/port given: {}", url))?;
|
||||
let handler = setup_apis(conf.apis, deps);
|
||||
let remote = deps.remote.clone();
|
||||
let allowed_origins = into_domains(conf.origins);
|
||||
let allowed_hosts = into_domains(conf.hosts);
|
||||
|
||||
|
||||
let full_handler = setup_apis(rpc_apis::ApiSet::SafeContext, deps);
|
||||
let handler = {
|
||||
let mut handler = MetaIoHandler::with_middleware((
|
||||
rpc::WsDispatcher::new(full_handler),
|
||||
Middleware::new(deps.stats.clone(), deps.apis.activity_notifier())
|
||||
));
|
||||
let apis = conf.apis.list_apis().into_iter().collect::<Vec<_>>();
|
||||
deps.apis.extend_with_set(&mut handler, &apis);
|
||||
|
||||
handler
|
||||
};
|
||||
|
||||
let remote = deps.remote.clone();
|
||||
let ui_address = conf.ui_address.clone();
|
||||
let allowed_origins = into_domains(with_domain(conf.origins, domain, &[ui_address]));
|
||||
let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &[Some(ws_address)]));
|
||||
|
||||
let signer_path = conf.signer_path;
|
||||
let signer_path = conf.ui_address.map(move |_| ::signer::codes_path(&signer_path));
|
||||
let path = signer_path.as_ref().map(|p| p.as_path());
|
||||
let start_result = rpc::start_ws(
|
||||
&addr,
|
||||
handler,
|
||||
remote.clone(),
|
||||
allowed_origins,
|
||||
allowed_hosts,
|
||||
WsRpcExtractor,
|
||||
WsStats {
|
||||
stats: deps.stats.clone(),
|
||||
},
|
||||
rpc::WsExtractor::new(path.clone()),
|
||||
rpc::WsExtractor::new(path.clone()),
|
||||
rpc::WsStats::new(deps.stats.clone()),
|
||||
);
|
||||
|
||||
match start_result {
|
||||
@@ -197,21 +231,25 @@ pub fn new_ws<D: rpc_apis::Dependencies>(
|
||||
}
|
||||
|
||||
pub fn new_http<D: rpc_apis::Dependencies>(
|
||||
id: &str,
|
||||
options: &str,
|
||||
conf: HttpConfiguration,
|
||||
deps: &Dependencies<D>,
|
||||
middleware: Option<dapps::Middleware>
|
||||
middleware: Option<dapps::Middleware>,
|
||||
) -> Result<Option<HttpServer>, String> {
|
||||
if !conf.enabled {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
let url = format!("{}:{}", conf.interface, conf.port);
|
||||
let addr = url.parse().map_err(|_| format!("Invalid HTTP JSON-RPC listen host/port given: {}", url))?;
|
||||
let domain = DAPPS_DOMAIN;
|
||||
let http_address = (conf.interface, conf.port);
|
||||
let url = format!("{}:{}", http_address.0, http_address.1);
|
||||
let addr = url.parse().map_err(|_| format!("Invalid {} listen host/port given: {}", id, url))?;
|
||||
let handler = setup_apis(conf.apis, deps);
|
||||
let remote = deps.remote.clone();
|
||||
|
||||
let cors_domains = into_domains(conf.cors);
|
||||
let allowed_hosts = into_domains(conf.hosts);
|
||||
let allowed_hosts = into_domains(with_domain(conf.hosts, domain, &[Some(http_address)]));
|
||||
|
||||
let start_result = rpc::start_http(
|
||||
&addr,
|
||||
@@ -219,7 +257,7 @@ pub fn new_http<D: rpc_apis::Dependencies>(
|
||||
allowed_hosts,
|
||||
handler,
|
||||
remote,
|
||||
RpcExtractor,
|
||||
rpc::RpcExtractor,
|
||||
match (conf.threads, middleware) {
|
||||
(Some(threads), None) => rpc::HttpSettings::Threads(threads),
|
||||
(None, middleware) => rpc::HttpSettings::Dapps(middleware),
|
||||
@@ -231,17 +269,13 @@ pub fn new_http<D: rpc_apis::Dependencies>(
|
||||
|
||||
match start_result {
|
||||
Ok(server) => Ok(Some(server)),
|
||||
Err(HttpServerError::Io(ref err)) if err.kind() == io::ErrorKind::AddrInUse => Err(
|
||||
format!("HTTP address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --jsonrpc-port and --jsonrpc-interface options.", url)
|
||||
Err(rpc::HttpServerError::Io(ref err)) if err.kind() == io::ErrorKind::AddrInUse => Err(
|
||||
format!("{} address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --{}-port and --{}-interface options.", id, url, options, options)
|
||||
),
|
||||
Err(e) => Err(format!("HTTP error: {:?}", e)),
|
||||
Err(e) => Err(format!("{} error: {:?}", id, e)),
|
||||
}
|
||||
}
|
||||
|
||||
fn into_domains<T: From<String>>(items: Option<Vec<String>>) -> DomainsValidation<T> {
|
||||
items.map(|vals| vals.into_iter().map(T::from).collect()).into()
|
||||
}
|
||||
|
||||
pub fn new_ipc<D: rpc_apis::Dependencies>(
|
||||
conf: IpcConfiguration,
|
||||
dependencies: &Dependencies<D>
|
||||
@@ -252,48 +286,39 @@ pub fn new_ipc<D: rpc_apis::Dependencies>(
|
||||
|
||||
let handler = setup_apis(conf.apis, dependencies);
|
||||
let remote = dependencies.remote.clone();
|
||||
let ipc = rpc::start_ipc(
|
||||
&conf.socket_addr,
|
||||
handler,
|
||||
remote,
|
||||
RpcExtractor,
|
||||
);
|
||||
|
||||
match ipc {
|
||||
match rpc::start_ipc(&conf.socket_addr, handler, remote, rpc::RpcExtractor) {
|
||||
Ok(server) => Ok(Some(server)),
|
||||
Err(io_error) => Err(format!("IPC error: {}", io_error)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::RpcExtractor;
|
||||
use parity_rpc::{HttpMetaExtractor, Origin};
|
||||
|
||||
#[test]
|
||||
fn should_extract_rpc_origin() {
|
||||
// given
|
||||
let extractor = RpcExtractor;
|
||||
|
||||
// when
|
||||
let meta = extractor.read_metadata("http://parity.io".into(), None);
|
||||
let meta1 = extractor.read_metadata("http://parity.io".into(), Some("ignored".into()));
|
||||
|
||||
// then
|
||||
assert_eq!(meta.origin, Origin::Rpc("http://parity.io".into()));
|
||||
assert_eq!(meta1.origin, Origin::Rpc("http://parity.io".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_dapps_origin() {
|
||||
// given
|
||||
let extractor = RpcExtractor;
|
||||
let dapp = "https://wallet.ethereum.org".to_owned();
|
||||
|
||||
// when
|
||||
let meta = extractor.read_metadata("null".into(), Some(dapp.clone()));
|
||||
|
||||
// then
|
||||
assert_eq!(meta.origin, Origin::Dapps(dapp.into()));
|
||||
}
|
||||
fn into_domains<T: From<String>>(items: Option<Vec<String>>) -> DomainsValidation<T> {
|
||||
items.map(|vals| vals.into_iter().map(T::from).collect()).into()
|
||||
}
|
||||
|
||||
fn with_domain(items: Option<Vec<String>>, domain: &str, addresses: &[Option<(String, u16)>]) -> Option<Vec<String>> {
|
||||
items.map(move |items| {
|
||||
let mut items = items.into_iter().collect::<HashSet<_>>();
|
||||
for address in addresses {
|
||||
if let Some((host, port)) = address.clone() {
|
||||
items.insert(format!("{}:{}", host, port));
|
||||
items.insert(format!("{}:{}", host.replace("127.0.0.1", "localhost"), port));
|
||||
items.insert(format!("http://*.{}:{}", domain, port));
|
||||
items.insert(format!("http://*.{}", domain)); //proxypac
|
||||
}
|
||||
}
|
||||
items.into_iter().collect()
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_apis<D>(apis: ApiSet, deps: &Dependencies<D>) -> MetaIoHandler<Metadata, Middleware<D::Notifier>>
|
||||
where D: rpc_apis::Dependencies
|
||||
{
|
||||
let mut handler = MetaIoHandler::with_middleware(
|
||||
Middleware::new(deps.stats.clone(), deps.apis.activity_notifier())
|
||||
);
|
||||
let apis = apis.list_apis().into_iter().collect::<Vec<_>>();
|
||||
deps.apis.extend_with_set(&mut handler, &apis);
|
||||
|
||||
handler
|
||||
}
|
||||
|
||||
@@ -20,14 +20,15 @@ use std::collections::HashSet;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Weak};
|
||||
|
||||
pub use parity_rpc::SignerService;
|
||||
pub use parity_rpc::signer::SignerService;
|
||||
pub use parity_rpc::dapps::{DappsService, LocalDapp};
|
||||
|
||||
use ethcore::account_provider::AccountProvider;
|
||||
use ethcore::client::Client;
|
||||
use ethcore::miner::{Miner, ExternalMiner};
|
||||
use ethcore::snapshot::SnapshotService;
|
||||
use parity_rpc::{Metadata, NetworkSettings};
|
||||
use parity_rpc::informant::{ActivityNotifier, Middleware, RpcStats, ClientNotifier};
|
||||
use parity_rpc::informant::{ActivityNotifier, ClientNotifier};
|
||||
use parity_rpc::dispatch::{FullDispatcher, LightDispatcher};
|
||||
use ethsync::{ManageNetwork, SyncProvider, LightSync};
|
||||
use hash_fetch::fetch::Client as FetchClient;
|
||||
@@ -183,7 +184,11 @@ pub trait Dependencies {
|
||||
fn activity_notifier(&self) -> Self::Notifier;
|
||||
|
||||
/// Extend the given I/O handler with endpoints for each API.
|
||||
fn extend_with_set(&self, handler: &mut MetaIoHandler<Metadata, Middleware<Self::Notifier>>, apis: &[Api]);
|
||||
fn extend_with_set<S>(
|
||||
&self,
|
||||
handler: &mut MetaIoHandler<Metadata, S>,
|
||||
apis: &[Api],
|
||||
) where S: core::Middleware<Metadata>;
|
||||
}
|
||||
|
||||
/// RPC dependencies for a full node.
|
||||
@@ -201,19 +206,20 @@ pub struct FullDependencies {
|
||||
pub net_service: Arc<ManageNetwork>,
|
||||
pub updater: Arc<Updater>,
|
||||
pub geth_compatibility: bool,
|
||||
pub dapps_interface: Option<String>,
|
||||
pub dapps_port: Option<u16>,
|
||||
pub dapps_service: Option<Arc<DappsService>>,
|
||||
pub dapps_address: Option<(String, u16)>,
|
||||
pub ws_address: Option<(String, u16)>,
|
||||
pub fetch: FetchClient,
|
||||
pub remote: parity_reactor::Remote,
|
||||
}
|
||||
|
||||
impl FullDependencies {
|
||||
fn extend_api<T: core::Middleware<Metadata>>(
|
||||
fn extend_api<S>(
|
||||
&self,
|
||||
handler: &mut MetaIoHandler<Metadata, T>,
|
||||
handler: &mut MetaIoHandler<Metadata, S>,
|
||||
apis: &[Api],
|
||||
for_generic_pubsub: bool,
|
||||
) {
|
||||
) where S: core::Middleware<Metadata> {
|
||||
use parity_rpc::v1::*;
|
||||
|
||||
macro_rules! add_signing_methods {
|
||||
@@ -288,8 +294,8 @@ impl FullDependencies {
|
||||
self.logger.clone(),
|
||||
self.settings.clone(),
|
||||
signer,
|
||||
self.dapps_interface.clone(),
|
||||
self.dapps_port,
|
||||
self.dapps_address.clone(),
|
||||
self.ws_address.clone(),
|
||||
).to_delegate());
|
||||
|
||||
if !for_generic_pubsub {
|
||||
@@ -312,6 +318,7 @@ impl FullDependencies {
|
||||
&self.miner,
|
||||
&self.updater,
|
||||
&self.net_service,
|
||||
self.dapps_service.clone(),
|
||||
self.fetch.clone(),
|
||||
).to_delegate())
|
||||
},
|
||||
@@ -339,7 +346,11 @@ impl Dependencies for FullDependencies {
|
||||
}
|
||||
}
|
||||
|
||||
fn extend_with_set(&self, handler: &mut MetaIoHandler<Metadata, Middleware<Self::Notifier>>, apis: &[Api]) {
|
||||
fn extend_with_set<S>(
|
||||
&self,
|
||||
handler: &mut MetaIoHandler<Metadata, S>,
|
||||
apis: &[Api],
|
||||
) where S: core::Middleware<Metadata> {
|
||||
self.extend_api(handler, apis, false)
|
||||
}
|
||||
}
|
||||
@@ -363,8 +374,9 @@ pub struct LightDependencies {
|
||||
pub on_demand: Arc<::light::on_demand::OnDemand>,
|
||||
pub cache: Arc<Mutex<LightDataCache>>,
|
||||
pub transaction_queue: Arc<RwLock<LightTransactionQueue>>,
|
||||
pub dapps_interface: Option<String>,
|
||||
pub dapps_port: Option<u16>,
|
||||
pub dapps_service: Option<Arc<DappsService>>,
|
||||
pub dapps_address: Option<(String, u16)>,
|
||||
pub ws_address: Option<(String, u16)>,
|
||||
pub fetch: FetchClient,
|
||||
pub geth_compatibility: bool,
|
||||
pub remote: parity_reactor::Remote,
|
||||
@@ -457,8 +469,8 @@ impl LightDependencies {
|
||||
self.logger.clone(),
|
||||
self.settings.clone(),
|
||||
signer,
|
||||
self.dapps_interface.clone(),
|
||||
self.dapps_port,
|
||||
self.dapps_address.clone(),
|
||||
self.ws_address.clone(),
|
||||
).to_delegate());
|
||||
|
||||
if !for_generic_pubsub {
|
||||
@@ -479,6 +491,7 @@ impl LightDependencies {
|
||||
Api::ParitySet => {
|
||||
handler.extend_with(light::ParitySetClient::new(
|
||||
self.sync.clone(),
|
||||
self.dapps_service.clone(),
|
||||
self.fetch.clone(),
|
||||
).to_delegate())
|
||||
},
|
||||
@@ -502,7 +515,12 @@ impl Dependencies for LightDependencies {
|
||||
type Notifier = LightClientNotifier;
|
||||
|
||||
fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier }
|
||||
fn extend_with_set(&self, handler: &mut MetaIoHandler<Metadata, Middleware<Self::Notifier>>, apis: &[Api]) {
|
||||
|
||||
fn extend_with_set<S>(
|
||||
&self,
|
||||
handler: &mut MetaIoHandler<Metadata, S>,
|
||||
apis: &[Api],
|
||||
) where S: core::Middleware<Metadata> {
|
||||
self.extend_api(handler, apis, false)
|
||||
}
|
||||
}
|
||||
@@ -552,15 +570,6 @@ impl ApiSet {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn setup_rpc<D: Dependencies>(stats: Arc<RpcStats>, deps: &D, apis: ApiSet) -> MetaIoHandler<Metadata, Middleware<D::Notifier>> {
|
||||
let mut handler = MetaIoHandler::with_middleware(Middleware::new(stats, deps.activity_notifier()));
|
||||
// it's turned into vector, cause ont of the cases requires &[]
|
||||
let apis = apis.list_apis().into_iter().collect::<Vec<_>>();
|
||||
deps.extend_with_set(&mut handler, &apis[..]);
|
||||
|
||||
handler
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{Api, ApiSet};
|
||||
|
||||
173
parity/run.rs
173
parity/run.rs
@@ -49,11 +49,11 @@ use cache::CacheConfig;
|
||||
use user_defaults::UserDefaults;
|
||||
use dapps;
|
||||
use ipfs;
|
||||
use signer;
|
||||
use secretstore;
|
||||
use modules;
|
||||
use rpc_apis;
|
||||
use rpc;
|
||||
use rpc_apis;
|
||||
use secretstore;
|
||||
use signer;
|
||||
use url;
|
||||
|
||||
// how often to take periodic snapshots.
|
||||
@@ -99,11 +99,10 @@ pub struct RunCmd {
|
||||
pub wal: bool,
|
||||
pub vm_type: VMType,
|
||||
pub geth_compatibility: bool,
|
||||
pub ui_address: Option<(String, u16)>,
|
||||
pub net_settings: NetworkSettings,
|
||||
pub dapps_conf: dapps::Configuration,
|
||||
pub ipfs_conf: ipfs::Configuration,
|
||||
pub signer_conf: signer::Configuration,
|
||||
pub ui_conf: rpc::UiConfiguration,
|
||||
pub secretstore_conf: secretstore::Configuration,
|
||||
pub dapp: Option<String>,
|
||||
pub ui: bool,
|
||||
@@ -119,12 +118,12 @@ pub struct RunCmd {
|
||||
pub no_persistent_txqueue: bool,
|
||||
}
|
||||
|
||||
pub fn open_ui(signer_conf: &signer::Configuration) -> Result<(), String> {
|
||||
if !signer_conf.enabled {
|
||||
pub fn open_ui(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration) -> Result<(), String> {
|
||||
if !ui_conf.enabled {
|
||||
return Err("Cannot use UI command with UI turned off.".into())
|
||||
}
|
||||
|
||||
let token = signer::generate_token_and_url(signer_conf)?;
|
||||
let token = signer::generate_token_and_url(ws_conf, ui_conf)?;
|
||||
// Open a browser
|
||||
url::open(&token.url);
|
||||
// Print a message
|
||||
@@ -195,7 +194,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
||||
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, compaction.clone())?;
|
||||
|
||||
// create dirs used by parity
|
||||
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.signer_conf.enabled, cmd.secretstore_conf.enabled)?;
|
||||
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?;
|
||||
|
||||
info!("Starting {}", Colour::White.bold().paint(version()));
|
||||
info!("Running in experimental {} mode.", Colour::Blue.bold().paint("Light Client"));
|
||||
@@ -267,31 +266,47 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
||||
// prepare account provider
|
||||
let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
|
||||
let rpc_stats = Arc::new(informant::RpcStats::default());
|
||||
let signer_path = cmd.signer_conf.signer_path.clone();
|
||||
|
||||
// the dapps server
|
||||
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf));
|
||||
let dapps_deps = {
|
||||
let contract_client = Arc::new(::dapps::LightRegistrar {
|
||||
client: service.client().clone(),
|
||||
sync: light_sync.clone(),
|
||||
on_demand: on_demand.clone(),
|
||||
});
|
||||
|
||||
let sync = light_sync.clone();
|
||||
dapps::Dependencies {
|
||||
sync_status: Arc::new(move || sync.is_major_importing()),
|
||||
contract_client: contract_client,
|
||||
remote: event_loop.raw_remote(),
|
||||
fetch: fetch.clone(),
|
||||
signer: signer_service.clone(),
|
||||
ui_address: cmd.ui_conf.address(),
|
||||
}
|
||||
};
|
||||
|
||||
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
|
||||
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
|
||||
|
||||
// start RPCs
|
||||
let dapps_service = dapps::service(&dapps_middleware);
|
||||
let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies {
|
||||
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
|
||||
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
|
||||
}, cmd.ui_address)),
|
||||
signer_service: signer_service,
|
||||
client: service.client().clone(),
|
||||
sync: light_sync.clone(),
|
||||
net: light_sync.clone(),
|
||||
secret_store: account_provider,
|
||||
logger: logger,
|
||||
settings: Arc::new(cmd.net_settings),
|
||||
on_demand: on_demand.clone(),
|
||||
on_demand: on_demand,
|
||||
cache: cache,
|
||||
transaction_queue: txq,
|
||||
dapps_interface: match cmd.dapps_conf.enabled {
|
||||
true => Some(cmd.http_conf.interface.clone()),
|
||||
false => None,
|
||||
},
|
||||
dapps_port: match cmd.dapps_conf.enabled {
|
||||
true => Some(cmd.http_conf.port),
|
||||
false => None,
|
||||
},
|
||||
fetch: fetch.clone(),
|
||||
dapps_service: dapps_service,
|
||||
dapps_address: cmd.dapps_conf.address(cmd.http_conf.address()),
|
||||
ws_address: cmd.ws_conf.address(),
|
||||
fetch: fetch,
|
||||
geth_compatibility: cmd.geth_compatibility,
|
||||
remote: event_loop.remote(),
|
||||
});
|
||||
@@ -302,39 +317,11 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
||||
stats: rpc_stats.clone(),
|
||||
};
|
||||
|
||||
// the dapps server
|
||||
let dapps_deps = {
|
||||
let contract_client = Arc::new(::dapps::LightRegistrar {
|
||||
client: service.client().clone(),
|
||||
sync: light_sync.clone(),
|
||||
on_demand: on_demand,
|
||||
});
|
||||
|
||||
let sync = light_sync.clone();
|
||||
dapps::Dependencies {
|
||||
sync_status: Arc::new(move || sync.is_major_importing()),
|
||||
contract_client: contract_client,
|
||||
remote: event_loop.raw_remote(),
|
||||
fetch: fetch,
|
||||
signer: deps_for_rpc_apis.signer_service.clone(),
|
||||
}
|
||||
};
|
||||
|
||||
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
|
||||
|
||||
// start rpc servers
|
||||
let _ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?;
|
||||
let _http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||
let _http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||
let _ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
||||
|
||||
// the signer server
|
||||
let signer_deps = signer::Dependencies {
|
||||
apis: deps_for_rpc_apis.clone(),
|
||||
remote: event_loop.raw_remote(),
|
||||
rpc_stats: rpc_stats.clone(),
|
||||
};
|
||||
let signing_queue = deps_for_rpc_apis.signer_service.queue();
|
||||
let _signer_server = signer::start(cmd.signer_conf.clone(), signing_queue, signer_deps)?;
|
||||
let _ui_server = rpc::new_http("Parity Wallet (UI)", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
|
||||
|
||||
// minimal informant thread. Just prints block number every 5 seconds.
|
||||
// TODO: integrate with informant.rs
|
||||
@@ -351,9 +338,9 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
|
||||
pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
|
||||
if cmd.ui && cmd.dapps_conf.enabled {
|
||||
// Check if Parity is already running
|
||||
let addr = format!("{}:{}", cmd.signer_conf.interface, cmd.signer_conf.port);
|
||||
let addr = format!("{}:{}", cmd.ui_conf.interface, cmd.ui_conf.port);
|
||||
if !TcpListener::bind(&addr as &str).is_ok() {
|
||||
return open_ui(&cmd.signer_conf).map(|_| (false, None));
|
||||
return open_ui(&cmd.ws_conf, &cmd.ui_conf).map(|_| (false, None));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +395,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.db_root_path().as_path()))?;
|
||||
|
||||
// create dirs used by parity
|
||||
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.signer_conf.enabled, cmd.secretstore_conf.enabled)?;
|
||||
cmd.dirs.create_dirs(cmd.dapps_conf.enabled, cmd.ui_conf.enabled, cmd.secretstore_conf.enabled)?;
|
||||
|
||||
// run in daemon mode
|
||||
if let Some(pid_file) = cmd.daemon {
|
||||
@@ -620,16 +607,33 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
|
||||
// set up dependencies for rpc servers
|
||||
let rpc_stats = Arc::new(informant::RpcStats::default());
|
||||
let signer_path = cmd.signer_conf.signer_path.clone();
|
||||
let secret_store = match cmd.public_node {
|
||||
true => None,
|
||||
false => Some(account_provider.clone())
|
||||
};
|
||||
|
||||
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.ui_conf));
|
||||
|
||||
// the dapps server
|
||||
let dapps_deps = {
|
||||
let (sync, client) = (sync_provider.clone(), client.clone());
|
||||
let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() });
|
||||
|
||||
dapps::Dependencies {
|
||||
sync_status: Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())),
|
||||
contract_client: contract_client,
|
||||
remote: event_loop.raw_remote(),
|
||||
fetch: fetch.clone(),
|
||||
signer: signer_service.clone(),
|
||||
ui_address: cmd.ui_conf.address(),
|
||||
}
|
||||
};
|
||||
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?;
|
||||
let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, dapps_deps)?;
|
||||
|
||||
let dapps_service = dapps::service(&dapps_middleware);
|
||||
let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies {
|
||||
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
|
||||
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
|
||||
}, cmd.ui_address)),
|
||||
signer_service: signer_service,
|
||||
snapshot: snapshot_service.clone(),
|
||||
client: client.clone(),
|
||||
sync: sync_provider.clone(),
|
||||
@@ -642,14 +646,9 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
net_service: manage_network.clone(),
|
||||
updater: updater.clone(),
|
||||
geth_compatibility: cmd.geth_compatibility,
|
||||
dapps_interface: match cmd.dapps_conf.enabled {
|
||||
true => Some(cmd.http_conf.interface.clone()),
|
||||
false => None,
|
||||
},
|
||||
dapps_port: match cmd.dapps_conf.enabled {
|
||||
true => Some(cmd.http_conf.port),
|
||||
false => None,
|
||||
},
|
||||
dapps_service: dapps_service,
|
||||
dapps_address: cmd.dapps_conf.address(cmd.http_conf.address()),
|
||||
ws_address: cmd.ws_conf.address(),
|
||||
fetch: fetch.clone(),
|
||||
remote: event_loop.remote(),
|
||||
});
|
||||
@@ -660,34 +659,12 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
stats: rpc_stats.clone(),
|
||||
};
|
||||
|
||||
// the dapps server
|
||||
let dapps_deps = {
|
||||
let (sync, client) = (sync_provider.clone(), client.clone());
|
||||
let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() });
|
||||
|
||||
dapps::Dependencies {
|
||||
sync_status: Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())),
|
||||
contract_client: contract_client,
|
||||
remote: event_loop.raw_remote(),
|
||||
fetch: fetch.clone(),
|
||||
signer: deps_for_rpc_apis.signer_service.clone(),
|
||||
}
|
||||
};
|
||||
let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
|
||||
|
||||
// start rpc servers
|
||||
let ws_server = rpc::new_ws(cmd.ws_conf, &dependencies)?;
|
||||
let http_server = rpc::new_http(cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||
let ws_server = rpc::new_ws(cmd.ws_conf.clone(), &dependencies)?;
|
||||
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
|
||||
|
||||
// the signer server
|
||||
let signer_deps = signer::Dependencies {
|
||||
apis: deps_for_rpc_apis.clone(),
|
||||
remote: event_loop.raw_remote(),
|
||||
rpc_stats: rpc_stats.clone(),
|
||||
};
|
||||
let signing_queue = deps_for_rpc_apis.signer_service.queue();
|
||||
let signer_server = signer::start(cmd.signer_conf.clone(), signing_queue, signer_deps)?;
|
||||
let http_server = rpc::new_http("HTTP JSON-RPC", "jsonrpc", cmd.http_conf.clone(), &dependencies, dapps_middleware)?;
|
||||
// the ui server
|
||||
let ui_server = rpc::new_http("UI WALLET", "ui", cmd.ui_conf.clone().into(), &dependencies, ui_middleware)?;
|
||||
|
||||
// secret store key server
|
||||
let secretstore_deps = secretstore::Dependencies {
|
||||
@@ -746,7 +723,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
|
||||
// start ui
|
||||
if cmd.ui {
|
||||
open_ui(&cmd.signer_conf)?;
|
||||
open_ui(&cmd.ws_conf, &cmd.ui_conf)?;
|
||||
}
|
||||
|
||||
if let Some(dapp) = cmd.dapp {
|
||||
@@ -756,11 +733,11 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
// Handle exit
|
||||
let restart = wait_for_exit(panic_handler, Some(updater), Some(client), can_restart);
|
||||
|
||||
// drop this stuff as soon as exit detected.
|
||||
drop((ws_server, http_server, ipc_server, signer_server, secretstore_key_server, ipfs_server, event_loop));
|
||||
|
||||
info!("Finishing work, please wait...");
|
||||
|
||||
// drop this stuff as soon as exit detected.
|
||||
drop((ws_server, http_server, ipc_server, ui_server, secretstore_key_server, ipfs_server, event_loop));
|
||||
|
||||
// to make sure timer does not spawn requests while shutdown is in progress
|
||||
informant.shutdown();
|
||||
// just Arc is dropping here, to allow other reference release in its default time
|
||||
|
||||
125
parity/signer.rs
125
parity/signer.rs
@@ -15,51 +15,16 @@
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::io;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use ethcore_signer::Server as SignerServer;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use ansi_term::Colour;
|
||||
use dir::default_data_path;
|
||||
use parity_rpc::informant::RpcStats;
|
||||
use parity_rpc::{self, ConfirmationsQueue};
|
||||
use ethcore_signer as signer;
|
||||
use helpers::replace_home;
|
||||
use parity_reactor::TokioRemote;
|
||||
use rpc;
|
||||
use rpc_apis;
|
||||
use parity_rpc;
|
||||
use path::restrict_permissions_owner;
|
||||
use util::H256;
|
||||
|
||||
const CODES_FILENAME: &'static str = "authcodes";
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct Configuration {
|
||||
pub enabled: bool,
|
||||
pub port: u16,
|
||||
pub interface: String,
|
||||
pub signer_path: String,
|
||||
pub skip_origin_validation: bool,
|
||||
}
|
||||
|
||||
impl Default for Configuration {
|
||||
fn default() -> Self {
|
||||
let data_dir = default_data_path();
|
||||
Configuration {
|
||||
enabled: true,
|
||||
port: 8180,
|
||||
interface: "127.0.0.1".into(),
|
||||
signer_path: replace_home(&data_dir, "$BASE/signer"),
|
||||
skip_origin_validation: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dependencies<D: rpc_apis::Dependencies> {
|
||||
pub apis: Arc<D>,
|
||||
pub remote: TokioRemote,
|
||||
pub rpc_stats: Arc<RpcStats>,
|
||||
}
|
||||
pub const CODES_FILENAME: &'static str = "authcodes";
|
||||
|
||||
pub struct NewToken {
|
||||
pub token: String,
|
||||
@@ -67,42 +32,29 @@ pub struct NewToken {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct StandardExtractor;
|
||||
impl signer::MetaExtractor<parity_rpc::Metadata> for StandardExtractor {
|
||||
fn extract_metadata(&self, session: &H256) -> parity_rpc::Metadata {
|
||||
let mut metadata = parity_rpc::Metadata::default();
|
||||
metadata.origin = parity_rpc::Origin::Signer((*session).into());
|
||||
metadata
|
||||
}
|
||||
pub fn new_service(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration) -> rpc_apis::SignerService {
|
||||
let signer_path = ws_conf.signer_path.clone();
|
||||
let signer_enabled = ui_conf.enabled;
|
||||
|
||||
rpc_apis::SignerService::new(move || {
|
||||
generate_new_token(&signer_path).map_err(|e| format!("{:?}", e))
|
||||
}, signer_enabled)
|
||||
}
|
||||
|
||||
pub fn start<D: rpc_apis::Dependencies>(
|
||||
conf: Configuration,
|
||||
queue: Arc<ConfirmationsQueue>,
|
||||
deps: Dependencies<D>,
|
||||
) -> Result<Option<SignerServer>, String> {
|
||||
if !conf.enabled {
|
||||
Ok(None)
|
||||
} else {
|
||||
Ok(Some(do_start(conf, queue, deps)?))
|
||||
}
|
||||
}
|
||||
|
||||
fn codes_path(path: String) -> PathBuf {
|
||||
let mut p = PathBuf::from(path);
|
||||
pub fn codes_path(path: &Path) -> PathBuf {
|
||||
let mut p = path.to_owned();
|
||||
p.push(CODES_FILENAME);
|
||||
let _ = restrict_permissions_owner(&p, true, false);
|
||||
p
|
||||
}
|
||||
|
||||
pub fn execute(cmd: Configuration) -> Result<String, String> {
|
||||
Ok(generate_token_and_url(&cmd)?.message)
|
||||
pub fn execute(ws_conf: rpc::WsConfiguration, ui_conf: rpc::UiConfiguration) -> Result<String, String> {
|
||||
Ok(generate_token_and_url(&ws_conf, &ui_conf)?.message)
|
||||
}
|
||||
|
||||
pub fn generate_token_and_url(conf: &Configuration) -> Result<NewToken, String> {
|
||||
let code = generate_new_token(conf.signer_path.clone()).map_err(|err| format!("Error generating token: {}", err))?;
|
||||
let auth_url = format!("http://{}:{}/#/auth?token={}", conf.interface, conf.port, code);
|
||||
pub fn generate_token_and_url(ws_conf: &rpc::WsConfiguration, ui_conf: &rpc::UiConfiguration) -> Result<NewToken, String> {
|
||||
let code = generate_new_token(&ws_conf.signer_path).map_err(|err| format!("Error generating token: {:?}", err))?;
|
||||
let auth_url = format!("http://{}:{}/#/auth?token={}", ui_conf.interface, ui_conf.port, code);
|
||||
// And print in to the console
|
||||
Ok(NewToken {
|
||||
token: code.clone(),
|
||||
@@ -119,49 +71,12 @@ Or use the generated token:
|
||||
})
|
||||
}
|
||||
|
||||
pub fn generate_new_token(path: String) -> io::Result<String> {
|
||||
fn generate_new_token(path: &Path) -> io::Result<String> {
|
||||
let path = codes_path(path);
|
||||
let mut codes = signer::AuthCodes::from_file(&path)?;
|
||||
let mut codes = parity_rpc::AuthCodes::from_file(&path)?;
|
||||
codes.clear_garbage();
|
||||
let code = codes.generate_new()?;
|
||||
codes.to_file(&path)?;
|
||||
trace!("New key code created: {}", Colour::White.bold().paint(&code[..]));
|
||||
Ok(code)
|
||||
}
|
||||
|
||||
fn do_start<D: rpc_apis::Dependencies>(
|
||||
conf: Configuration,
|
||||
queue: Arc<ConfirmationsQueue>,
|
||||
deps: Dependencies<D>
|
||||
) -> Result<SignerServer, String> {
|
||||
let addr = format!("{}:{}", conf.interface, conf.port)
|
||||
.parse()
|
||||
.map_err(|_| format!("Invalid port specified: {}", conf.port))?;
|
||||
|
||||
let start_result = {
|
||||
let server = signer::ServerBuilder::new(
|
||||
queue,
|
||||
codes_path(conf.signer_path),
|
||||
);
|
||||
if conf.skip_origin_validation {
|
||||
warn!("{}", Colour::Red.bold().paint("*** INSECURE *** Running Trusted Signer with no origin validation."));
|
||||
info!("If you do not intend this, exit now.");
|
||||
}
|
||||
let server = server.skip_origin_validation(conf.skip_origin_validation);
|
||||
let server = server.stats(deps.rpc_stats.clone());
|
||||
let handler = rpc_apis::setup_rpc(deps.rpc_stats, &*deps.apis, rpc_apis::ApiSet::SafeContext);
|
||||
let remote = deps.remote.clone();
|
||||
server.start_with_extractor(addr, handler, remote, StandardExtractor)
|
||||
};
|
||||
|
||||
match start_result {
|
||||
Err(signer::ServerError::IoError(err)) => match err.kind() {
|
||||
io::ErrorKind::AddrInUse => Err(format!("Trusted UI address {} is already in use, make sure that another instance of an Ethereum client is not running or change the address using the --ui-port and --ui-interface options.", addr)),
|
||||
_ => Err(format!("Trusted Signer io error: {}", err)),
|
||||
},
|
||||
Err(e) => Err(format!("Trusted Signer Error: {:?}", e)),
|
||||
Ok(server) => Ok(server),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user