From a0cb104c8df1a42f0516bf366af52b7b3879270a Mon Sep 17 00:00:00 2001 From: Jamie Ford Date: Tue, 12 Sep 2023 15:57:41 +1000 Subject: [PATCH] feat: use SecretUrl type for endpoints --- api/bin/chainflip-cli/src/settings.rs | 10 +- engine/src/btc/rpc.rs | 7 +- engine/src/dot/http_rpc.rs | 9 +- engine/src/dot/retry_rpc.rs | 6 +- engine/src/dot/rpc.rs | 11 +- engine/src/eth/rpc.rs | 28 ++-- engine/src/settings.rs | 89 +++++------ engine/src/witness/eth/key_manager.rs | 4 +- .../src/with_std/redact_endpoint_secret.rs | 143 ++++++++++++++---- 9 files changed, 194 insertions(+), 113 deletions(-) diff --git a/api/bin/chainflip-cli/src/settings.rs b/api/bin/chainflip-cli/src/settings.rs index 5279e1fa0f6..c7edd9185e1 100644 --- a/api/bin/chainflip-cli/src/settings.rs +++ b/api/bin/chainflip-cli/src/settings.rs @@ -252,7 +252,7 @@ mod tests { .unwrap(); assert_eq!(settings.state_chain.ws_endpoint, "ws://localhost:9944"); - assert_eq!(settings.eth.nodes.primary.ws_node_endpoint, "ws://localhost:8545"); + assert_eq!(settings.eth.nodes.primary.ws_node_endpoint.as_ref(), "ws://localhost:8545"); } #[test] @@ -294,21 +294,21 @@ mod tests { ); assert_eq!( opts.eth_opts.eth_ws_node_endpoint.unwrap(), - settings.eth.nodes.primary.ws_node_endpoint + settings.eth.nodes.primary.ws_node_endpoint.as_ref() ); assert_eq!( opts.eth_opts.eth_http_node_endpoint.unwrap(), - settings.eth.nodes.primary.http_node_endpoint + settings.eth.nodes.primary.http_node_endpoint.as_ref() ); let eth_backup_node = settings.eth.nodes.backup.unwrap(); assert_eq!( opts.eth_opts.eth_backup_ws_node_endpoint.unwrap(), - eth_backup_node.ws_node_endpoint + eth_backup_node.ws_node_endpoint.as_ref() ); assert_eq!( opts.eth_opts.eth_backup_http_node_endpoint.unwrap(), - eth_backup_node.http_node_endpoint + eth_backup_node.http_node_endpoint.as_ref() ); assert_eq!(opts.eth_opts.eth_private_key_file.unwrap(), settings.eth.private_key_file); diff --git a/engine/src/btc/rpc.rs b/engine/src/btc/rpc.rs index bc992fb17fc..824b0c79ae3 100644 --- a/engine/src/btc/rpc.rs +++ b/engine/src/btc/rpc.rs @@ -7,6 +7,7 @@ use serde; use serde_json::json; use bitcoin::{block::Version, Amount, Block, BlockHash, Txid}; +use utilities::redact_endpoint_secret::SecretUrl; use crate::settings::HttpBasicAuthEndpoint; @@ -59,7 +60,7 @@ struct FeeRateResponse { pub struct BtcRpcClient { // internally the Client is Arc'd client: Client, - url: String, + url: SecretUrl, user: String, password: String, } @@ -88,7 +89,7 @@ impl BtcRpcClient { let response = &self .client - .post(&self.url) + .post(self.url.as_ref()) .basic_auth(&self.user, Some(&self.password)) .json(&request_body) .send() @@ -223,7 +224,7 @@ mod tests { #[ignore = "requires local node, useful for manual testing"] async fn test_btc_async() { let client = BtcRpcClient::new(HttpBasicAuthEndpoint { - http_node_endpoint: "http://localhost:8332".to_string(), + http_node_endpoint: "http://localhost:8332".into(), rpc_user: "flip".to_string(), rpc_password: "flip".to_string(), }) diff --git a/engine/src/dot/http_rpc.rs b/engine/src/dot/http_rpc.rs index 3fb5a0cc677..6dafa758dd6 100644 --- a/engine/src/dot/http_rpc.rs +++ b/engine/src/dot/http_rpc.rs @@ -21,7 +21,7 @@ use subxt::{ }; use anyhow::Result; -use utilities::make_periodic_tick; +use utilities::{make_periodic_tick, redact_endpoint_secret::SecretUrl}; use crate::constants::DOT_AVERAGE_BLOCK_TIME; @@ -30,7 +30,7 @@ use super::rpc::DotRpcApi; pub struct PolkadotHttpClient(HttpClient); impl PolkadotHttpClient { - pub fn new(url: &str) -> Result { + pub fn new(url: &SecretUrl) -> Result { let token = format!("Bearer {}", "TOKEN"); let mut headers = HeaderMap::new(); headers.insert(AUTHORIZATION, token.parse().unwrap()); @@ -80,7 +80,7 @@ pub struct DotHttpRpcClient { } impl DotHttpRpcClient { - pub fn new(url: String) -> Result> { + pub fn new(url: SecretUrl) -> Result> { let polkadot_http_client = Arc::new(PolkadotHttpClient::new(&url)?); Ok(async move { @@ -201,8 +201,7 @@ mod tests { #[ignore = "requires local node"] #[tokio::test] async fn test_http_rpc() { - let url = "http://localhost:9945"; - let dot_http_rpc = DotHttpRpcClient::new(url.to_string()).unwrap().await; + let dot_http_rpc = DotHttpRpcClient::new("http://localhost:9945".into()).unwrap().await; let block_hash = dot_http_rpc.block_hash(1).await.unwrap(); println!("block_hash: {:?}", block_hash); } diff --git a/engine/src/dot/retry_rpc.rs b/engine/src/dot/retry_rpc.rs index d54ff066122..47f5bb097f6 100644 --- a/engine/src/dot/retry_rpc.rs +++ b/engine/src/dot/retry_rpc.rs @@ -48,7 +48,7 @@ impl DotRetryRpcClient { let f_create_clients = |endpoints: WsHttpEndpoints| { Result::<_, anyhow::Error>::Ok(( DotHttpRpcClient::new(endpoints.http_node_endpoint)?, - DotSubClient::new(&endpoints.ws_node_endpoint), + DotSubClient::new(endpoints.ws_node_endpoint), )) }; @@ -310,8 +310,8 @@ mod tests { scope, NodeContainer { primary: WsHttpEndpoints { - http_node_endpoint: "http://127.0.0.1:9945".to_string(), - ws_node_endpoint: "ws://127.0.0.1:9945".to_string(), + http_node_endpoint: "http://127.0.0.1:9945".into(), + ws_node_endpoint: "ws://127.0.0.1:9945".into(), }, backup: None, }, diff --git a/engine/src/dot/rpc.rs b/engine/src/dot/rpc.rs index 3b18ad0c7fa..1d55829889f 100644 --- a/engine/src/dot/rpc.rs +++ b/engine/src/dot/rpc.rs @@ -12,6 +12,7 @@ use subxt::{ Config, OnlineClient, PolkadotConfig, }; use tokio::sync::RwLock; +use utilities::redact_endpoint_secret::SecretUrl; use anyhow::{anyhow, Result}; @@ -134,12 +135,12 @@ impl DotRpcApi for DotRpcClient { #[derive(Clone)] pub struct DotSubClient { - pub ws_endpoint: String, + pub ws_endpoint: SecretUrl, } impl DotSubClient { - pub fn new(ws_endpoint: &str) -> Self { - Self { ws_endpoint: ws_endpoint.to_string() } + pub fn new(ws_endpoint: SecretUrl) -> Self { + Self { ws_endpoint } } } @@ -148,7 +149,7 @@ impl DotSubscribeApi for DotSubClient { async fn subscribe_best_heads( &self, ) -> Result> + Send>>> { - let client = OnlineClient::::from_url(self.ws_endpoint.clone()).await?; + let client = OnlineClient::::from_url(&self.ws_endpoint).await?; Ok(Box::pin( client .blocks() @@ -162,7 +163,7 @@ impl DotSubscribeApi for DotSubClient { async fn subscribe_finalized_heads( &self, ) -> Result> + Send>>> { - let client = OnlineClient::::from_url(self.ws_endpoint.clone()).await?; + let client = OnlineClient::::from_url(&self.ws_endpoint).await?; Ok(Box::pin( client .blocks() diff --git a/engine/src/eth/rpc.rs b/engine/src/eth/rpc.rs index c7550d7401e..0a7399ec900 100644 --- a/engine/src/eth/rpc.rs +++ b/engine/src/eth/rpc.rs @@ -2,6 +2,7 @@ pub mod address_checker; use ethers::{prelude::*, signers::Signer, types::transaction::eip2718::TypedTransaction}; use futures_core::Future; +use utilities::redact_endpoint_secret::SecretUrl; use crate::constants::{ETH_AVERAGE_BLOCK_TIME, SYNC_POLL_INTERVAL}; use anyhow::{anyhow, Context, Result}; @@ -25,10 +26,10 @@ pub struct EthRpcClient { impl EthRpcClient { pub fn new( private_key_file: PathBuf, - http_node_endpoint: String, + http_node_endpoint: SecretUrl, expected_chain_id: u64, ) -> Result> { - let provider = Arc::new(Provider::::try_from(http_node_endpoint.clone())?); + let provider = Arc::new(Provider::::try_from(http_node_endpoint.as_ref())?); let wallet = read_clean_and_decode_hex_str_file(&private_key_file, "Ethereum Private Key", |key| { ethers::signers::Wallet::from_str(key).map_err(anyhow::Error::new) @@ -49,17 +50,14 @@ impl EthRpcClient { Ok(chain_id) if chain_id == expected_chain_id.into() => break client, Ok(chain_id) => { tracing::warn!( - "Connected to Ethereum node but with chain_id {}, expected {}. Please check your CFE - configuration file...", - chain_id, - expected_chain_id - ); + "Connected to Ethereum node but with chain_id {chain_id}, expected {expected_chain_id}. Please check your CFE + configuration file...", + ); }, Err(e) => tracing::error!( - "Cannot connect to an Ethereum node at {} with error: {e}. Please check your CFE - configuration file. Retrying...", - http_node_endpoint - ), + "Cannot connect to an Ethereum node at {http_node_endpoint} with error: {e}. Please check your CFE + configuration file. Retrying...", + ), } } }) @@ -191,13 +189,13 @@ impl EthRpcApi for EthRpcClient { /// On each subscription this will create a new WS connection. #[derive(Clone)] pub struct ReconnectSubscriptionClient { - ws_node_endpoint: String, + ws_node_endpoint: SecretUrl, // This value comes from the SC. chain_id: web3::types::U256, } impl ReconnectSubscriptionClient { - pub fn new(ws_node_endpoint: String, chain_id: web3::types::U256) -> Self { + pub fn new(ws_node_endpoint: SecretUrl, chain_id: web3::types::U256) -> Self { Self { ws_node_endpoint, chain_id } } } @@ -212,7 +210,9 @@ use crate::eth::ConscientiousEthWebsocketBlockHeaderStream; #[async_trait::async_trait] impl ReconnectSubscribeApi for ReconnectSubscriptionClient { async fn subscribe_blocks(&self) -> Result { - let web3 = web3::Web3::new(web3::transports::WebSocket::new(&self.ws_node_endpoint).await?); + let web3 = web3::Web3::new( + web3::transports::WebSocket::new((&self.ws_node_endpoint).into()).await?, + ); let mut poll_interval = make_periodic_tick(SYNC_POLL_INTERVAL, false); diff --git a/engine/src/settings.rs b/engine/src/settings.rs index 877b0d1b11c..46e00ee3b09 100644 --- a/engine/src/settings.rs +++ b/engine/src/settings.rs @@ -6,7 +6,7 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::bail; +use anyhow::{bail, Context}; use config::{Config, ConfigBuilder, ConfigError, Environment, File, Map, Source, Value}; use serde::{de, Deserialize, Deserializer}; @@ -15,7 +15,7 @@ use sp_runtime::DeserializeOwned; use url::Url; use clap::Parser; -use utilities::Port; +use utilities::{redact_endpoint_secret::SecretUrl, Port}; use crate::constants::{CONFIG_ROOT, DEFAULT_CONFIG_ROOT}; @@ -37,7 +37,7 @@ pub struct StateChain { impl StateChain { pub fn validate_settings(&self) -> Result<(), ConfigError> { - validate_websocket_endpoint(&self.ws_endpoint) + validate_websocket_endpoint(self.ws_endpoint.clone().into()) .map_err(|e| ConfigError::Message(e.to_string()))?; Ok(()) } @@ -45,8 +45,8 @@ impl StateChain { #[derive(Debug, Deserialize, Clone, Default, PartialEq, Eq)] pub struct WsHttpEndpoints { - pub ws_node_endpoint: String, - pub http_node_endpoint: String, + pub ws_node_endpoint: SecretUrl, + pub http_node_endpoint: SecretUrl, } pub trait ValidateSettings { @@ -56,9 +56,9 @@ pub trait ValidateSettings { impl ValidateSettings for WsHttpEndpoints { /// Ensure the endpoints are valid HTTP and WS endpoints. fn validate(&self) -> Result<(), ConfigError> { - validate_websocket_endpoint(&self.ws_node_endpoint) + validate_websocket_endpoint(self.ws_node_endpoint.clone()) .map_err(|e| ConfigError::Message(e.to_string()))?; - validate_http_endpoint(&self.http_node_endpoint) + validate_http_endpoint(self.http_node_endpoint.clone()) .map_err(|e| ConfigError::Message(e.to_string()))?; Ok(()) } @@ -110,7 +110,7 @@ impl Dot { #[derive(Debug, Deserialize, Clone, Default, PartialEq, Eq)] pub struct HttpBasicAuthEndpoint { - pub http_node_endpoint: String, + pub http_node_endpoint: SecretUrl, pub rpc_user: String, pub rpc_password: String, } @@ -118,7 +118,7 @@ pub struct HttpBasicAuthEndpoint { impl ValidateSettings for HttpBasicAuthEndpoint { /// Ensure the endpoint is a valid HTTP endpoint. fn validate(&self) -> Result<(), ConfigError> { - validate_http_endpoint(&self.http_node_endpoint) + validate_http_endpoint(self.http_node_endpoint.clone().into()) .map_err(|e| ConfigError::Message(e.to_string()))?; Ok(()) } @@ -642,21 +642,21 @@ impl Settings { } /// Validate a websocket endpoint URL -pub fn validate_websocket_endpoint(url: &str) -> Result<()> { +pub fn validate_websocket_endpoint(url: SecretUrl) -> Result<()> { validate_endpoint(vec!["ws", "wss"], url) } /// Validate a http endpoint URL -pub fn validate_http_endpoint(url: &str) -> Result<()> { +pub fn validate_http_endpoint(url: SecretUrl) -> Result<()> { validate_endpoint(vec!["http", "https"], url) } /// Parse the URL to check that it is the correct scheme and a valid endpoint URL -fn validate_endpoint(valid_schemes: Vec<&str>, url: &str) -> Result<()> { - let parsed_url = Url::parse(url)?; +fn validate_endpoint(valid_schemes: Vec<&str>, url: SecretUrl) -> Result<()> { + let parsed_url = Url::parse(url.as_ref()).context(format!("Error parsing url: {url}"))?; let scheme = parsed_url.scheme(); if !valid_schemes.contains(&scheme) { - bail!("Invalid scheme: `{scheme}`"); + bail!("Invalid scheme: `{scheme}` in endpoint: {url}"); } if parsed_url.host().is_none() || parsed_url.username() != "" || @@ -664,7 +664,7 @@ fn validate_endpoint(valid_schemes: Vec<&str>, url: &str) -> Result<()> { parsed_url.fragment().is_some() || parsed_url.cannot_be_a_base() { - bail!("Invalid URL data."); + bail!("Invalid URL data in endpoint: {url}"); } Ok(()) @@ -746,17 +746,17 @@ pub mod tests { let settings = Settings::new(CommandLineOptions::default()) .expect("Check that the test environment is set correctly"); assert_eq!(settings.state_chain.ws_endpoint, "ws://localhost:9944"); - assert_eq!(settings.eth.nodes.primary.http_node_endpoint, "http://localhost:8545"); + assert_eq!(settings.eth.nodes.primary.http_node_endpoint.as_ref(), "http://localhost:8545"); assert_eq!( - settings.dot.nodes.primary.ws_node_endpoint, + settings.dot.nodes.primary.ws_node_endpoint.as_ref(), "wss://my_fake_polkadot_rpc:443/" ); assert_eq!( - settings.eth.nodes.backup.unwrap().http_node_endpoint, + settings.eth.nodes.backup.unwrap().http_node_endpoint.as_ref(), "http://second.localhost:8545" ); assert_eq!( - settings.dot.nodes.backup.unwrap().ws_node_endpoint, + settings.dot.nodes.backup.unwrap().ws_node_endpoint.as_ref(), "wss://second.my_fake_polkadot_rpc:443/" ); } @@ -774,28 +774,31 @@ pub mod tests { #[test] fn test_websocket_endpoint_url_parsing() { assert_ok!(validate_websocket_endpoint( - "wss://network.my_eth_node:80/d2er2easdfasdfasdf2e" + "wss://network.my_eth_node:80/d2er2easdfasdfasdf2e".into() )); - assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node:80/")); - assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node/")); - assert_ok!(validate_websocket_endpoint("ws://network.my_eth_node/")); - assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node")); + assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node:80/".into())); + assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node/".into())); + assert_ok!(validate_websocket_endpoint("ws://network.my_eth_node/".into())); + assert_ok!(validate_websocket_endpoint("wss://network.my_eth_node".into())); assert_ok!(validate_websocket_endpoint( "wss://polkadot.api.onfinality.io:443/ws?apikey=00000000-0000-0000-0000-000000000000" + .into() )); - assert!(validate_websocket_endpoint("https://wrong_scheme.com").is_err()); - assert!(validate_websocket_endpoint("").is_err()); + assert!(validate_websocket_endpoint("https://wrong_scheme.com".into()).is_err()); + assert!(validate_websocket_endpoint("".into()).is_err()); } #[test] fn test_http_endpoint_url_parsing() { - assert_ok!(validate_http_endpoint("http://network.my_eth_node:80/d2er2easdfasdfasdf2e")); - assert_ok!(validate_http_endpoint("http://network.my_eth_node:80/")); - assert_ok!(validate_http_endpoint("http://network.my_eth_node/")); - assert_ok!(validate_http_endpoint("https://network.my_eth_node/")); - assert_ok!(validate_http_endpoint("http://network.my_eth_node")); - assert!(validate_http_endpoint("wss://wrong_scheme.com").is_err()); - assert!(validate_http_endpoint("").is_err()); + assert_ok!(validate_http_endpoint( + "http://network.my_eth_node:80/d2er2easdfasdfasdf2e".into() + )); + assert_ok!(validate_http_endpoint("http://network.my_eth_node:80/".into())); + assert_ok!(validate_http_endpoint("http://network.my_eth_node/".into())); + assert_ok!(validate_http_endpoint("https://network.my_eth_node/".into())); + assert_ok!(validate_http_endpoint("http://network.my_eth_node".into())); + assert!(validate_http_endpoint("wss://wrong_scheme.com".into()).is_err()); + assert!(validate_http_endpoint("".into()).is_err()); } #[test] @@ -839,7 +842,7 @@ pub mod tests { assert_eq!( custom_base_path_settings.btc.nodes.primary.http_node_endpoint, - "http://localhost:18443" + "http://localhost:18443".into() ); assert!(custom_base_path_settings.btc.nodes.backup.is_none()); } @@ -914,47 +917,47 @@ pub mod tests { assert_eq!( opts.eth_opts.eth_ws_node_endpoint.unwrap(), - settings.eth.nodes.primary.ws_node_endpoint + settings.eth.nodes.primary.ws_node_endpoint.as_ref() ); assert_eq!( opts.eth_opts.eth_http_node_endpoint.unwrap(), - settings.eth.nodes.primary.http_node_endpoint + settings.eth.nodes.primary.http_node_endpoint.as_ref() ); let eth_backup_node = settings.eth.nodes.backup.unwrap(); assert_eq!( opts.eth_opts.eth_backup_ws_node_endpoint.unwrap(), - eth_backup_node.ws_node_endpoint + eth_backup_node.ws_node_endpoint.as_ref() ); assert_eq!( opts.eth_opts.eth_backup_http_node_endpoint.unwrap(), - eth_backup_node.http_node_endpoint + eth_backup_node.http_node_endpoint.as_ref() ); assert_eq!(opts.eth_opts.eth_private_key_file.unwrap(), settings.eth.private_key_file); assert_eq!( opts.dot_opts.dot_ws_node_endpoint.unwrap(), - settings.dot.nodes.primary.ws_node_endpoint + settings.dot.nodes.primary.ws_node_endpoint.as_ref() ); assert_eq!( opts.dot_opts.dot_http_node_endpoint.unwrap(), - settings.dot.nodes.primary.http_node_endpoint + settings.dot.nodes.primary.http_node_endpoint.as_ref() ); let dot_backup_node = settings.dot.nodes.backup.unwrap(); assert_eq!( opts.dot_opts.dot_backup_ws_node_endpoint.unwrap(), - dot_backup_node.ws_node_endpoint + dot_backup_node.ws_node_endpoint.as_ref() ); assert_eq!( opts.dot_opts.dot_backup_http_node_endpoint.unwrap(), - dot_backup_node.http_node_endpoint + dot_backup_node.http_node_endpoint.as_ref() ); assert_eq!( opts.btc_opts.btc_http_node_endpoint.unwrap(), - settings.btc.nodes.primary.http_node_endpoint + settings.btc.nodes.primary.http_node_endpoint.as_ref() ); assert_eq!(opts.btc_opts.btc_rpc_user.unwrap(), settings.btc.nodes.primary.rpc_user); assert_eq!( diff --git a/engine/src/witness/eth/key_manager.rs b/engine/src/witness/eth/key_manager.rs index d2b39927fc2..97f340f6cb1 100644 --- a/engine/src/witness/eth/key_manager.rs +++ b/engine/src/witness/eth/key_manager.rs @@ -228,8 +228,8 @@ mod tests { let eth_settings = settings::Eth { nodes: NodeContainer { primary: WsHttpEndpoints { - ws_node_endpoint: "ws://localhost:8546".to_string(), - http_node_endpoint: "http://localhost:8545".to_string(), + ws_node_endpoint: "ws://localhost:8546".into(), + http_node_endpoint: "http://localhost:8545".into(), }, backup: None, }, diff --git a/utilities/src/with_std/redact_endpoint_secret.rs b/utilities/src/with_std/redact_endpoint_secret.rs index f0c2e980cfa..ddb56a5d133 100644 --- a/utilities/src/with_std/redact_endpoint_secret.rs +++ b/utilities/src/with_std/redact_endpoint_secret.rs @@ -1,15 +1,71 @@ -use anyhow::Context; use regex::Regex; +use serde::Deserialize; +use std::fmt::{Debug, Display}; use url::Url; const MAX_SECRET_CHARACTERS_REVEALED: usize = 3; const SCHEMA_PADDING_LEN: usize = 3; +/// A wrapper around a `String` that redacts a secret in the url when displayed. Used for node +/// endpoints. +#[derive(Clone, PartialEq, Eq, Deserialize, Default)] +pub struct SecretUrl(String); + +impl Display for SecretUrl { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", redact_secret_node_endpoint(&self.0)) + } +} + +// Only debug print the secret in debug mode +#[cfg(debug_assertions)] +impl Debug for SecretUrl { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.0) + } +} +#[cfg(not(debug_assertions))] +impl Debug for SecretUrl { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", redact_secret_node_endpoint(&self.0)) + } +} + +impl From for SecretUrl { + fn from(s: String) -> Self { + SecretUrl(s) + } +} + +impl<'a> From<&'a str> for SecretUrl { + fn from(s: &'a str) -> Self { + SecretUrl(s.to_string()) + } +} + +impl From for String { + fn from(s: SecretUrl) -> Self { + s.0 + } +} + +impl<'a> From<&'a SecretUrl> for &'a str { + fn from(s: &'a SecretUrl) -> Self { + &s.0 + } +} + +impl AsRef for SecretUrl { + fn as_ref(&self) -> &str { + &self.0 + } +} + /// Partially redacts the secret in the url of the node endpoint. /// eg: `wss://cdcd639308194d3f977a1a5a7ff0d545.rinkeby.ws.rivet.cloud/` -> /// `wss://cdc****.rinkeby.ws.rivet.cloud/` #[allow(unused)] -pub fn redact_secret_eth_node_endpoint(endpoint: &str) -> Result { +pub fn redact_secret_node_endpoint(endpoint: &str) -> String { let re = Regex::new(r"[0-9a-fA-F]{32}").unwrap(); if re.is_match(endpoint) { // A 32 character hex string was found, redact it @@ -23,19 +79,26 @@ pub fn redact_secret_eth_node_endpoint(endpoint: &str) -> Result