From 2aa1cec907b069afc727a486fa9da7bf0588b551 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin Date: Thu, 22 Jun 2023 15:50:16 +0100 Subject: [PATCH] feat(rpc): report JWT path in case of an IO read error (#3324) --- Cargo.lock | 2 ++ crates/rpc/rpc/Cargo.toml | 2 ++ crates/rpc/rpc/src/layers/jwt_secret.rs | 23 +++++++++++++++++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39b95fa1a0..b474f25091 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5634,6 +5634,7 @@ dependencies = [ name = "reth-rpc" version = "0.1.0-alpha.1" dependencies = [ + "assert_matches", "async-trait", "bytes", "ethers-core", @@ -5663,6 +5664,7 @@ dependencies = [ "secp256k1", "serde", "serde_json", + "tempfile", "thiserror", "tokio", "tokio-stream", diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index 30b94277f7..9fdf2c913f 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -61,3 +61,5 @@ futures = { workspace = true } [dev-dependencies] jsonrpsee = { version = "0.18", features = ["client"] } +assert_matches = "1.5.0" +tempfile = "3.5.0" \ No newline at end of file diff --git a/crates/rpc/rpc/src/layers/jwt_secret.rs b/crates/rpc/rpc/src/layers/jwt_secret.rs index abca0ff50a..589308e9d3 100644 --- a/crates/rpc/rpc/src/layers/jwt_secret.rs +++ b/crates/rpc/rpc/src/layers/jwt_secret.rs @@ -3,7 +3,7 @@ use jsonwebtoken::{decode, errors::ErrorKind, Algorithm, DecodingKey, Validation use rand::Rng; use serde::{Deserialize, Serialize}; use std::{ - path::Path, + path::{Path, PathBuf}, time::{Duration, SystemTime, UNIX_EPOCH}, }; use thiserror::Error; @@ -26,6 +26,10 @@ pub enum JwtError { MissingOrInvalidAuthorizationHeader, #[error("JWT decoding error {0}")] JwtDecodingError(String), + #[error("IO error occurred while reading {path}: {err}")] + IORead { err: std::io::Error, path: PathBuf }, + #[error("IO error occurred while writing {path}: {err}")] + IOWrite { err: std::io::Error, path: PathBuf }, #[error("An I/O error occurred: {0}")] IOError(#[from] std::io::Error), } @@ -76,7 +80,8 @@ impl JwtSecret { /// I/O or secret validation errors might occur during read operations in the form of /// a [`JwtError`]. pub fn from_file(fpath: &Path) -> Result { - let hex = std::fs::read_to_string(fpath)?; + let hex = std::fs::read_to_string(fpath) + .map_err(|err| JwtError::IORead { err, path: fpath.to_path_buf() })?; let secret = JwtSecret::from_hex(hex)?; Ok(secret) } @@ -92,7 +97,8 @@ impl JwtSecret { let secret = JwtSecret::random(); let bytes = &secret.0; let hex = hex::encode(bytes); - std::fs::write(fpath, hex)?; + std::fs::write(fpath, hex) + .map_err(|err| JwtError::IOWrite { err, path: fpath.to_path_buf() })?; Ok(secret) } } @@ -195,12 +201,14 @@ impl Claims { mod tests { use super::{Claims, JwtError, JwtSecret}; use crate::layers::jwt_secret::JWT_MAX_IAT_DIFF; + use assert_matches::assert_matches; use hex::encode as hex_encode; use jsonwebtoken::{encode, Algorithm, EncodingKey, Header}; use std::{ path::Path, time::{Duration, SystemTime, UNIX_EPOCH}, }; + use tempfile::tempdir; #[test] fn from_hex() { @@ -367,10 +375,17 @@ mod tests { fn provided_file_not_exists() { let fpath = Path::new("secret3.hex"); let result = JwtSecret::from_file(fpath); - assert!(result.is_err()); + assert_matches!(result, Err(JwtError::IORead {err: _, path}) if path == fpath.to_path_buf()); assert!(!exists(fpath)); } + #[test] + fn provided_file_is_a_directory() { + let dir = tempdir().unwrap(); + let result = JwtSecret::from_file(dir.path()); + assert_matches!(result, Err(JwtError::IORead {err: _, path}) if path == dir.into_path()); + } + fn hex(secret: &JwtSecret) -> String { hex::encode(secret.0) }