Skip to content

Commit

Permalink
add and use cookie_dir config, rpc client changes
Browse files Browse the repository at this point in the history
  • Loading branch information
oxarbitrage committed Oct 7, 2024
1 parent 212d517 commit e91b139
Show file tree
Hide file tree
Showing 21 changed files with 221 additions and 44 deletions.
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6151,6 +6151,7 @@ dependencies = [
name = "zebra-node-services"
version = "1.0.0-beta.39"
dependencies = [
"base64 0.22.1",
"color-eyre",
"jsonrpc-core",
"reqwest",
Expand Down
2 changes: 2 additions & 0 deletions zebra-node-services/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ getblocktemplate-rpcs = [
# Tool and test features

rpc-client = [
"base64",
"color-eyre",
"jsonrpc-core",
"reqwest",
Expand All @@ -42,6 +43,7 @@ zebra-chain = { path = "../zebra-chain" , version = "1.0.0-beta.39" }
# Optional dependencies

# Tool and test feature rpc-client
base64 = { version = "0.22.1", optional = true }
color-eyre = { version = "0.6.3", optional = true }
jsonrpc-core = { version = "18.0.0", optional = true }
# Security: avoid default dependency on openssl
Expand Down
12 changes: 11 additions & 1 deletion zebra-node-services/src/rpc_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use std::net::SocketAddr;

use base64::{engine::general_purpose::URL_SAFE, Engine as _};

Check failure on line 7 in zebra-node-services/src/rpc_client.rs

View workflow job for this annotation

GitHub Actions / Build zebra-node-services crate

failed to resolve: use of undeclared crate or module `base64`

Check failure on line 7 in zebra-node-services/src/rpc_client.rs

View workflow job for this annotation

GitHub Actions / Build zebra-node-services crate

unresolved import `base64`
use reqwest::Client;

use crate::BoxError;
Expand All @@ -13,14 +14,16 @@ use crate::BoxError;
pub struct RpcRequestClient {
client: Client,
rpc_address: SocketAddr,
auth_cookie: String,
}

impl RpcRequestClient {
/// Creates new RPCRequestSender
pub fn new(rpc_address: SocketAddr) -> Self {
pub fn new(rpc_address: SocketAddr, auth_cookie: String) -> Self {
Self {
client: Client::new(),
rpc_address,
auth_cookie,
}
}

Expand All @@ -39,6 +42,13 @@ impl RpcRequestClient {
r#"{{"jsonrpc": "2.0", "method": "{method}", "params": {params}, "id":123 }}"#
))
.header("Content-Type", "application/json")
.header(
"Authorization",
format!(
"Basic {}",
URL_SAFE.encode(format!("__cookie__:{}", &self.auth_cookie))
),
)
.send()
.await
}
Expand Down
10 changes: 9 additions & 1 deletion zebra-rpc/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
//! User-configurable RPC settings.

use std::net::SocketAddr;
use std::{net::SocketAddr, path::PathBuf};

use serde::{Deserialize, Serialize};

use zebra_chain::common::default_cache_dir;

pub mod mining;

/// RPC configuration section.
Expand Down Expand Up @@ -71,6 +73,9 @@ pub struct Config {
/// Test-only option that makes Zebra say it is at the chain tip,
/// no matter what the estimated height or local clock is.
pub debug_force_finished_sync: bool,

/// The directory where Zebra stores RPC cookies.
pub cookie_dir: PathBuf,
}

// This impl isn't derivable because it depends on features.
Expand All @@ -94,6 +99,9 @@ impl Default for Config {

// Debug options are always off by default.
debug_force_finished_sync: false,

//
cookie_dir: default_cache_dir(),
}
}
}
6 changes: 3 additions & 3 deletions zebra-rpc/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::{
#[cfg(feature = "getblocktemplate-rpcs")]
use crate::methods::{GetBlockTemplateRpc, GetBlockTemplateRpcImpl};

mod cookie;
pub mod cookie;
pub mod http_request_compatibility;
pub mod rpc_call_compatibility;

Expand Down Expand Up @@ -195,7 +195,7 @@ impl RpcServer {
}

// generate a cookie
cookie::generate();
cookie::generate(config.cookie_dir.clone());

// The server is a blocking task, which blocks on executor shutdown.
// So we need to start it in a std::thread.
Expand All @@ -209,7 +209,7 @@ impl RpcServer {
.threads(parallel_cpu_threads)
// TODO: disable this security check if we see errors from lightwalletd
//.allowed_hosts(DomainsValidation::Disabled)
.request_middleware(FixHttpRequestMiddleware)
.request_middleware(FixHttpRequestMiddleware(config.clone()))
.start_http(&listen_addr)
.expect("Unable to start RPC server");

Expand Down
11 changes: 6 additions & 5 deletions zebra-rpc/src/server/cookie.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,22 @@ use rand::RngCore;
use std::{
fs::{remove_file, File},
io::{Read, Write},
path::PathBuf,
};

/// The user field in the cookie (arbitrary, only for recognizability in debugging/logging purposes)
pub const COOKIEAUTH_USER: &str = "__cookie__";
/// Default name for auth cookie file */
const COOKIEAUTH_FILE: &str = ".cookie";
pub const COOKIEAUTH_FILE: &str = ".cookie";

/// Generate a new auth cookie and return the encoded password.
pub fn generate() -> Option<()> {
pub fn generate(cookie_dir: PathBuf) -> Option<()> {
let mut data = [0u8; 32];
rand::thread_rng().fill_bytes(&mut data);
let encoded_password = URL_SAFE.encode(data);
let cookie_content = format!("{}:{}", COOKIEAUTH_USER, encoded_password);

let mut file = File::create(COOKIEAUTH_FILE).ok()?;
let mut file = File::create(cookie_dir.join(COOKIEAUTH_FILE)).ok()?;
file.write_all(cookie_content.as_bytes()).ok()?;

tracing::info!("RPC auth cookie generated successfully");
Expand All @@ -29,8 +30,8 @@ pub fn generate() -> Option<()> {
}

/// Get the encoded password from the auth cookie.
pub fn get() -> Option<String> {
let mut file = File::open(COOKIEAUTH_FILE).ok()?;
pub fn get(cookie_dir: PathBuf) -> Option<String> {
let mut file = File::open(cookie_dir.join(COOKIEAUTH_FILE)).ok()?;
let mut contents = String::new();
file.read_to_string(&mut contents).ok()?;

Expand Down
8 changes: 4 additions & 4 deletions zebra-rpc/src/server/http_request_compatibility.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ use crate::server::cookie;
/// We assume lightwalletd validates data encodings before sending it on to Zebra.
/// So any fixes Zebra performs won't change user-specified data.
#[derive(Clone, Debug)]
pub struct FixHttpRequestMiddleware;
pub struct FixHttpRequestMiddleware(pub crate::config::Config);

impl RequestMiddleware for FixHttpRequestMiddleware {
fn on_request(&self, mut request: Request<Body>) -> RequestMiddlewareAction {
tracing::trace!(?request, "original HTTP request");

// Check if the request is authenticated
if !FixHttpRequestMiddleware::check_credentials(request.headers_mut()) {
if !self.check_credentials(request.headers_mut()) {
request = Self::unauthenticated(request);
}

Expand Down Expand Up @@ -175,7 +175,7 @@ impl FixHttpRequestMiddleware {
}

/// Check if the request is authenticated.
pub fn check_credentials(headers: &header::HeaderMap) -> bool {
pub fn check_credentials(&self, headers: &header::HeaderMap) -> bool {
headers
.get(header::AUTHORIZATION)
.and_then(|auth_header| auth_header.to_str().ok())
Expand All @@ -189,7 +189,7 @@ impl FixHttpRequestMiddleware {
.map(|password| password.to_string())
})
.map_or(false, |password| {
if let Some(cookie_password) = cookie::get() {
if let Some(cookie_password) = cookie::get(self.0.cookie_dir.clone()) {
cookie_password == password
} else {
false
Expand Down
4 changes: 4 additions & 0 deletions zebra-rpc/src/server/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ fn rpc_server_spawn(parallel_cpu_threads: bool) {
indexer_listen_addr: None,
parallel_cpu_threads: if parallel_cpu_threads { 2 } else { 1 },
debug_force_finished_sync: false,
cookie_dir: Default::default(),
};

let rt = tokio::runtime::Runtime::new().unwrap();
Expand Down Expand Up @@ -134,6 +135,7 @@ fn rpc_server_spawn_unallocated_port(parallel_cpu_threads: bool, do_shutdown: bo
indexer_listen_addr: None,
parallel_cpu_threads: if parallel_cpu_threads { 0 } else { 1 },
debug_force_finished_sync: false,
cookie_dir: Default::default(),
};

let rt = tokio::runtime::Runtime::new().unwrap();
Expand Down Expand Up @@ -215,6 +217,7 @@ fn rpc_server_spawn_port_conflict() {
indexer_listen_addr: None,
parallel_cpu_threads: 1,
debug_force_finished_sync: false,
cookie_dir: Default::default(),
};

let rt = tokio::runtime::Runtime::new().unwrap();
Expand Down Expand Up @@ -326,6 +329,7 @@ fn rpc_server_spawn_port_conflict_parallel_auto() {
indexer_listen_addr: None,
parallel_cpu_threads: 2,
debug_force_finished_sync: false,
cookie_dir: Default::default(),
};

let rt = tokio::runtime::Runtime::new().unwrap();
Expand Down
20 changes: 14 additions & 6 deletions zebra-rpc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ impl TrustedChainSync {
rpc_address: SocketAddr,
db: ZebraDb,
non_finalized_state_sender: tokio::sync::watch::Sender<NonFinalizedState>,
cookie_dir: std::path::PathBuf,
) -> (LatestChainTip, ChainTipChange, JoinHandle<()>) {
let rpc_client = RpcRequestClient::new(rpc_address);
let auth_cookie = crate::server::cookie::get(cookie_dir).expect("cookie should exist");
let rpc_client = RpcRequestClient::new(rpc_address, auth_cookie);
let non_finalized_state = NonFinalizedState::new(&db.network());
let (chain_tip_sender, latest_chain_tip, chain_tip_change) =
ChainTipSender::new(None, &db.network());
Expand Down Expand Up @@ -315,7 +317,8 @@ impl TrustedChainSync {
/// Returns a [`ReadStateService`], [`LatestChainTip`], [`ChainTipChange`], and
/// a [`JoinHandle`] for the sync task.
pub fn init_read_state_with_syncer(
config: zebra_state::Config,
state_config: zebra_state::Config,
rpc_config: crate::config::Config,
network: &Network,
rpc_address: SocketAddr,
) -> tokio::task::JoinHandle<
Expand All @@ -331,14 +334,19 @@ pub fn init_read_state_with_syncer(
> {
let network = network.clone();
tokio::spawn(async move {
if config.ephemeral {
if state_config.ephemeral {
return Err("standalone read state service cannot be used with ephemeral state".into());
}

let (read_state, db, non_finalized_state_sender) =
spawn_init_read_only(config, &network).await?;
let (latest_chain_tip, chain_tip_change, sync_task) =
TrustedChainSync::spawn(rpc_address, db, non_finalized_state_sender).await;
spawn_init_read_only(state_config, &network).await?;
let (latest_chain_tip, chain_tip_change, sync_task) = TrustedChainSync::spawn(
rpc_address,
db,
non_finalized_state_sender,
rpc_config.cookie_dir,
)
.await;
Ok((read_state, latest_chain_tip, chain_tip_change, sync_task))
})
}
Expand Down
4 changes: 4 additions & 0 deletions zebra-scan/src/bin/scanner/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use structopt::StructOpt;
use tracing::*;

use zebra_chain::{block::Height, parameters::Network};
use zebra_rpc::config::Config as RpcConfig;
use zebra_state::SaplingScanningKey;

use core::net::SocketAddr;
Expand Down Expand Up @@ -74,10 +75,13 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
db_config,
};

let rpc_config = RpcConfig::default();

// Get a read-only state and the database.
let (read_state, _latest_chain_tip, chain_tip_change, sync_task) =
zebra_rpc::sync::init_read_state_with_syncer(
state_config,
rpc_config,
&network,
args.zebra_rpc_listen_addr,
)
Expand Down
4 changes: 3 additions & 1 deletion zebra-utils/src/bin/zebra-checkpoints/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use zebra_node_services::{
constants::{MAX_CHECKPOINT_BYTE_COUNT, MAX_CHECKPOINT_HEIGHT_GAP},
rpc_client::RpcRequestClient,
};
use zebra_rpc::{config::Config as RpcConfig, server::cookie};
use zebra_utils::init_tracing;

pub mod args;
Expand Down Expand Up @@ -60,7 +61,8 @@ where
let addr = our_args
.addr
.unwrap_or_else(|| "127.0.0.1:8232".parse().expect("valid address"));
let client = RpcRequestClient::new(addr);
let auth_cookie = cookie::get(RpcConfig::default().cookie_dir).expect("cookie should exist");
let client = RpcRequestClient::new(addr, auth_cookie);

// Launch a request with the RPC method and arguments
//
Expand Down
Loading

0 comments on commit e91b139

Please sign in to comment.