Allow to expose a subset of unsafe RPCs (#5233)

* sc-cli: Use type-safe constructors for RPC/Prometheus interfaces

* service: Simplify rpc handler creation

Could probably be further simplifies once [this][commit] lands.

[commit]: https://github.com/paritytech/jsonrpc/commit/20485387ed06a48f1a70bf4d609a7cde6cf0accf

* service: Streamline some HTTP & WS server start logic

* client: Introduce a simple RPC policy mechanism

* rpc/system: Check unsafe RPCs

* rpc/offchain: Check unsafe RPCs

* rpc/author: Check unsafe RPCs
This commit is contained in:
Igor Matuszewski
2020-04-20 11:03:58 +02:00
committed by GitHub
parent d05dc090a8
commit 4b1f7d187f
20 changed files with 281 additions and 95 deletions
+23 -23
View File
@@ -46,6 +46,7 @@ use sp_runtime::traits::{
use sp_api::ProvideRuntimeApi;
use sc_executor::{NativeExecutor, NativeExecutionDispatch};
use std::{
collections::HashMap,
io::{Read, Write, Seek},
marker::PhantomData, sync::Arc, pin::Pin
};
@@ -1001,7 +1002,7 @@ ServiceBuilder<
// RPC
let (system_rpc_tx, system_rpc_rx) = tracing_unbounded("mpsc_system_rpc");
let gen_handler = || {
let gen_handler = |deny_unsafe: sc_rpc::DenyUnsafe| {
use sc_rpc::{chain, state, author, system, offchain};
let system_info = sc_rpc::system::SystemInfo {
@@ -1043,32 +1044,31 @@ ServiceBuilder<
transaction_pool.clone(),
subscriptions,
keystore.clone(),
deny_unsafe,
);
let system = system::System::new(system_info, system_rpc_tx.clone());
let system = system::System::new(system_info, system_rpc_tx.clone(), deny_unsafe);
match offchain_storage.clone() {
Some(storage) => {
let offchain = sc_rpc::offchain::Offchain::new(storage);
sc_rpc_server::rpc_handler((
state::StateApi::to_delegate(state),
chain::ChainApi::to_delegate(chain),
offchain::OffchainApi::to_delegate(offchain),
author::AuthorApi::to_delegate(author),
system::SystemApi::to_delegate(system),
rpc_extensions.clone(),
))
},
None => sc_rpc_server::rpc_handler((
state::StateApi::to_delegate(state),
chain::ChainApi::to_delegate(chain),
author::AuthorApi::to_delegate(author),
system::SystemApi::to_delegate(system),
rpc_extensions.clone(),
))
}
let maybe_offchain_rpc = offchain_storage.clone()
.map(|storage| {
let offchain = sc_rpc::offchain::Offchain::new(storage, deny_unsafe);
// FIXME: Use plain Option (don't collect into HashMap) when we upgrade to jsonrpc 14.1
// https://github.com/paritytech/jsonrpc/commit/20485387ed06a48f1a70bf4d609a7cde6cf0accf
let delegate = offchain::OffchainApi::to_delegate(offchain);
delegate.into_iter().collect::<HashMap<_, _>>()
}).unwrap_or_default();
sc_rpc_server::rpc_handler((
state::StateApi::to_delegate(state),
chain::ChainApi::to_delegate(chain),
maybe_offchain_rpc,
author::AuthorApi::to_delegate(author),
system::SystemApi::to_delegate(system),
rpc_extensions.clone(),
))
};
let rpc_handlers = gen_handler();
let rpc = start_rpc_servers(&config, gen_handler)?;
// This is used internally, so don't restrict access to unsafe RPC
let rpc_handlers = gen_handler(sc_rpc::DenyUnsafe::No);
spawn_handle.spawn(
"network-worker",
+2
View File
@@ -59,6 +59,8 @@ pub struct Configuration {
pub wasm_method: WasmExecutionMethod,
/// Execution strategies.
pub execution_strategies: ExecutionStrategies,
/// Whether potentially unsafe RPC is considered safe to be exposed.
pub unsafe_rpc_expose: bool,
/// RPC over HTTP binding address. `None` if disabled.
pub rpc_http: Option<SocketAddr>,
/// RPC over Websockets binding address. `None` if disabled.
+18 -5
View File
@@ -511,7 +511,7 @@ mod waiting {
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(not(target_os = "unknown"))]
fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
fn start_rpc_servers<H: FnMut(sc_rpc::DenyUnsafe) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
config: &Configuration,
mut gen_handler: H
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {
@@ -533,10 +533,23 @@ fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
})
}
fn deny_unsafe(addr: &Option<SocketAddr>, unsafe_rpc_expose: bool) -> sc_rpc::DenyUnsafe {
let is_exposed_addr = addr.map(|x| x.ip().is_loopback()).unwrap_or(false);
if is_exposed_addr && !unsafe_rpc_expose {
sc_rpc::DenyUnsafe::Yes
} else {
sc_rpc::DenyUnsafe::No
}
}
Ok(Box::new((
maybe_start_server(
config.rpc_http,
|address| sc_rpc_server::start_http(address, config.rpc_cors.as_ref(), gen_handler()),
|address| sc_rpc_server::start_http(
address,
config.rpc_cors.as_ref(),
gen_handler(deny_unsafe(&config.rpc_http, config.unsafe_rpc_expose)),
),
)?.map(|s| waiting::HttpServer(Some(s))),
maybe_start_server(
config.rpc_ws,
@@ -544,15 +557,15 @@ fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
address,
config.rpc_ws_max_connections,
config.rpc_cors.as_ref(),
gen_handler(),
gen_handler(deny_unsafe(&config.rpc_ws, config.unsafe_rpc_expose)),
),
)?.map(|s| waiting::WsServer(Some(s))).map(Mutex::new),
)?.map(|s| waiting::WsServer(Some(s))),
)))
}
/// Starts RPC servers that run in their own thread, and returns an opaque object that keeps them alive.
#[cfg(target_os = "unknown")]
fn start_rpc_servers<H: FnMut() -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
fn start_rpc_servers<H: FnMut(sc_rpc::DenyUnsafe) -> sc_rpc_server::RpcHandler<sc_rpc::Metadata>>(
_: &Configuration,
_: H
) -> Result<Box<dyn std::any::Any + Send + Sync>, error::Error> {