From e6da3253381ef93a104a2450470775ce0a244423 Mon Sep 17 00:00:00 2001 From: magine Date: Sat, 15 Jul 2023 12:24:50 +0800 Subject: [PATCH] Sign rpc request by session_manager --- Cargo.lock | 1 + node/bin/rings.rs | 5 ++-- node/src/browser/jsonrpc_client.rs | 2 +- node/src/jsonrpc/server.rs | 2 ++ node/src/native/cli.rs | 7 +++--- node/src/native/endpoint/mod.rs | 21 ++++++++++++++--- node/src/processor.rs | 2 +- rpc/Cargo.toml | 3 ++- rpc/src/client.rs | 26 +++++--------------- rpc/src/jsonrpc_client/client.rs | 38 ++++++++++++++++-------------- 10 files changed, 57 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 658f19a5a..4dda50d90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3319,6 +3319,7 @@ dependencies = [ name = "rings-rpc" version = "0.2.6" dependencies = [ + "base64 0.13.1", "http", "jsonrpc-core", "jsonrpc-pubsub", diff --git a/node/bin/rings.rs b/node/bin/rings.rs index a3b605128..0eee1ee96 100644 --- a/node/bin/rings.rs +++ b/node/bin/rings.rs @@ -22,6 +22,7 @@ use rings_node::native::endpoint::run_http_api; use rings_node::prelude::http; use rings_node::prelude::rings_core::ecc::SecretKey; use rings_node::prelude::PersistenceStorage; +use rings_node::prelude::SessionManager; use rings_node::processor::Processor; use rings_node::processor::ProcessorBuilder; use rings_node::processor::ProcessorConfig; @@ -174,8 +175,8 @@ impl ClientArgs { let c = config::Config::read_fs(self.config_args.config.as_str())?; let endpoint_url = self.endpoint_url.as_ref().unwrap_or(&c.endpoint_url); - - Client::new(endpoint_url.as_str(), "") + let session_manager = SessionManager::from_str(&c.session_manager)?; + Client::new(endpoint_url.as_str(), session_manager) } } diff --git a/node/src/browser/jsonrpc_client.rs b/node/src/browser/jsonrpc_client.rs index c55264420..e47a28add 100644 --- a/node/src/browser/jsonrpc_client.rs +++ b/node/src/browser/jsonrpc_client.rs @@ -17,7 +17,7 @@ impl JsonRpcClient { /// Create a new `JsonRpcClient` #[wasm_bindgen(constructor)] pub fn new(node: String) -> JsonRpcClient { - let client = Arc::new(jsonrpc_client::SimpleClient::new_with_url(node.as_str())); + let client = Arc::new(jsonrpc_client::SimpleClient::new(node.as_str(), None)); JsonRpcClient { client } } diff --git a/node/src/jsonrpc/server.rs b/node/src/jsonrpc/server.rs index 65b586bd8..68f3f8243 100644 --- a/node/src/jsonrpc/server.rs +++ b/node/src/jsonrpc/server.rs @@ -111,6 +111,7 @@ pub(crate) async fn node_info(_: Params, meta: RpcMeta) -> Result { /// Connect Peer VIA http pub(crate) async fn connect_peer_via_http(params: Params, meta: RpcMeta) -> Result { + meta.require_authed()?; let p: Vec = params.parse()?; let peer_url = p .first() @@ -125,6 +126,7 @@ pub(crate) async fn connect_peer_via_http(params: Params, meta: RpcMeta) -> Resu /// Connect Peer with seed pub(crate) async fn connect_with_seed(params: Params, meta: RpcMeta) -> Result { + meta.require_authed()?; let p: Vec = params.parse()?; let seed = p .first() diff --git a/node/src/native/cli.rs b/node/src/native/cli.rs index e94ae9b4b..14219933b 100644 --- a/node/src/native/cli.rs +++ b/node/src/native/cli.rs @@ -28,6 +28,7 @@ use serde_json::json; use crate::prelude::http; use crate::prelude::rings_core::inspect::SwarmInspect; +use crate::prelude::rings_core::session::SessionManager; use crate::prelude::rings_rpc::client::Client as RpcClient; use crate::prelude::rings_rpc::types::Timeout; use crate::seed::Seed; @@ -37,7 +38,6 @@ use crate::util::loader::ResourceLoader; type Output = anyhow::Result>; /// Wrap json_client send request between nodes or browsers. -#[derive(Clone)] pub struct Client { client: RpcClient, } @@ -51,9 +51,8 @@ pub struct ClientOutput { impl Client { /// Creates a new Client instance with the specified endpoint URL and signature. - pub fn new(endpoint_url: &str, signature: &str) -> anyhow::Result { - let rpc_client = - RpcClient::new(endpoint_url, signature).map_err(|e| anyhow::anyhow!("{}", e))?; + pub fn new(endpoint_url: &str, session_manager: SessionManager) -> anyhow::Result { + let rpc_client = RpcClient::new(endpoint_url, Some(session_manager)); Ok(Self { client: rpc_client }) } diff --git a/node/src/native/endpoint/mod.rs b/node/src/native/endpoint/mod.rs index c9e0c2fb9..c2df7db75 100644 --- a/node/src/native/endpoint/mod.rs +++ b/node/src/native/endpoint/mod.rs @@ -101,9 +101,24 @@ async fn jsonrpc_io_handler( body: String, ) -> Result { let is_auth = if let Some(signature) = headermap.get("X-SIGNATURE") { - // TODO: check signature - tracing::debug!("signature: {:?}", signature); - true + let sig = base64::decode(signature).map_err(|e| { + tracing::debug!("signature: {:?}", signature); + tracing::error!("signature decode failed: {:?}", e); + HttpError::BadRequest + })?; + state + .processor + .swarm + .session_manager() + .session() + .verify(&body, sig) + .map_err(|e| { + tracing::debug!("body: {:?}", body); + tracing::debug!("signature: {:?}", signature); + tracing::error!("signature verify failed: {:?}", e); + e + }) + .is_ok() } else { false }; diff --git a/node/src/processor.rs b/node/src/processor.rs index f3dc67dd2..aed4e7200 100644 --- a/node/src/processor.rs +++ b/node/src/processor.rs @@ -187,7 +187,7 @@ impl Processor { // request remote offer and sand answer to remote tracing::debug!("connect_peer_via_http: {}", peer_url); - let client = SimpleClient::new_with_url(peer_url); + let client = SimpleClient::new(peer_url, None); let (_, offer) = self .swarm .create_offer() diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index cb1dfdee4..694fd812f 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -27,12 +27,13 @@ wasm = [ ] [dependencies] +base64 = { version = "0.13.0" } http = { version = "0.2.6" } jsonrpc-core = { version = "18.0.0" } jsonrpc-pubsub = { version = "18.0.0" } reqwest = { version = "0.11", features = ["json", "rustls-tls"], optional = true, default-features = false } reqwest-wasm = { version = "0.11", features = ["json", "rustls-tls"], optional = true, default-features = false } -rings-core = { package = "rings-core", path = "../core", optional = true, default-features = false, version = "0.2.5" } +rings-core = { workspace = true, optional = true } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.70" thiserror = "1" diff --git a/rpc/src/client.rs b/rpc/src/client.rs index c39d9a1e8..5c2a86c3d 100644 --- a/rpc/src/client.rs +++ b/rpc/src/client.rs @@ -1,7 +1,6 @@ //! rings-rpc client -use std::sync::Arc; - +use rings_core::session::SessionManager; use serde_json::json; use serde_json::Value; @@ -17,29 +16,16 @@ use crate::types; use crate::types::Timeout; /// Wrap json_client send request between nodes or browsers. -#[derive(Clone)] pub struct Client { client: SimpleClient, } impl Client { - /// Creates a new Client instance with the specified endpoint URL and signature. - pub fn new(endpoint_url: &str, signature: &str) -> Result { - let mut default_headers = reqwest::header::HeaderMap::default(); - default_headers.insert( - "X-SIGNATURE", - http::header::HeaderValue::from_str(signature).map_err(|_| Error::InvalidSignature)?, - ); - let client = SimpleClient::new( - Arc::new( - reqwest::Client::builder() - .default_headers(default_headers) - .build() - .map_err(|_| Error::InvalidHeaders)?, - ), - endpoint_url, - ); - Ok(Self { client }) + /// Creates a new Client instance with the specified endpoint URL + pub fn new(endpoint_url: &str, session_manager: Option) -> Self { + Self { + client: SimpleClient::new(endpoint_url, session_manager), + } } /// Establishes a WebRTC connection with a remote peer using HTTP as the signaling channel. diff --git a/rpc/src/jsonrpc_client/client.rs b/rpc/src/jsonrpc_client/client.rs index 1e7049b14..53535c63b 100644 --- a/rpc/src/jsonrpc_client/client.rs +++ b/rpc/src/jsonrpc_client/client.rs @@ -2,13 +2,12 @@ //! SimpleClient for jsonrpc request use reqwest::Client. /// /// Sample: -/// let client = Simpleclient::new(reqwest::Client::default(), "http://localhost:5000"); +/// let client = Simpleclient::new("http://localhost:5000", session_manager); /// client.call_method("test", params); -use std::sync::Arc; - use jsonrpc_core::Error; use jsonrpc_core::Params; use jsonrpc_core::Value; +use rings_core::session::SessionManager; use super::request::parse_response; use super::request::RequestBuilder; @@ -17,28 +16,21 @@ use crate::prelude::reqwest::Client as HttpClient; /// Create a new SimpleClient /// * client: a instance of reqwest::Client /// * url: remote jsonrpc_server url -#[derive(Clone)] pub struct SimpleClient { - client: Arc, + client: HttpClient, url: String, + session_manager: Option, } impl SimpleClient { /// * client: reqwest::Client handle http request. /// * url: remote json_server url. - pub fn new(client: Arc, url: &str) -> Self { + /// * session_key: session_key for sign request. + pub fn new(url: &str, session_manager: Option) -> Self { Self { - client, - url: url.to_owned(), - } - } - - /// Create a new SimpleClient, - /// * url: remote jsonrpc_server url - pub fn new_with_url(url: &str) -> Self { - Self { - client: Arc::new(HttpClient::default()), + client: HttpClient::default(), url: url.to_string(), + session_manager, } } @@ -73,7 +65,7 @@ impl SimpleClient { } }; - let resp = self + let mut req = self .client .post(self.url.as_str()) .header( @@ -84,7 +76,17 @@ impl SimpleClient { http::header::ACCEPT, http::header::HeaderValue::from_static("application/json"), ) - .body(request) + .body(request.clone()); + + if let Some(session_manager) = &self.session_manager { + let sig = session_manager + .sign(&request.clone()) + .map_err(|e| RpcError::Client(format!("Failed to sign request: {}", e)))?; + let encoded_sig = base64::encode(sig); + req = req.header("X-SIGNATURE", encoded_sig); + } + + let resp = req .send() .await .map_err(|e| RpcError::Client(e.to_string()))?;