1use crate::error::{RpcError, ServerKind};
2use http::header::AUTHORIZATION;
3use jsonrpsee::{
4 core::{client::SubscriptionClientT, RegisterMethodError},
5 http_client::HeaderMap,
6 server::{AlreadyStoppedError, RpcModule},
7 Methods,
8};
9use reth_rpc_api::servers::*;
10use reth_rpc_eth_types::EthSubscriptionIdProvider;
11use reth_rpc_layer::{
12 secret_to_bearer_header, AuthClientLayer, AuthLayer, JwtAuthValidator, JwtSecret,
13};
14use reth_rpc_server_types::constants;
15use std::net::{IpAddr, Ipv4Addr, SocketAddr};
16use tower::layer::util::Identity;
17
18pub use jsonrpsee::server::ServerBuilder;
19use jsonrpsee::server::{ServerConfig, ServerConfigBuilder};
20pub use reth_ipc::server::Builder as IpcServerBuilder;
21
22#[derive(Debug)]
24pub struct AuthServerConfig {
25 pub(crate) socket_addr: SocketAddr,
27 pub(crate) secret: JwtSecret,
29 pub(crate) server_config: ServerConfigBuilder,
31 pub(crate) ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
33 pub(crate) ipc_endpoint: Option<String>,
35}
36
37impl AuthServerConfig {
40 pub const fn builder(secret: JwtSecret) -> AuthServerConfigBuilder {
42 AuthServerConfigBuilder::new(secret)
43 }
44
45 pub const fn address(&self) -> SocketAddr {
47 self.socket_addr
48 }
49
50 pub async fn start(self, module: AuthRpcModule) -> Result<AuthServerHandle, RpcError> {
52 let Self { socket_addr, secret, server_config, ipc_server_config, ipc_endpoint } = self;
53
54 let middleware =
56 tower::ServiceBuilder::new().layer(AuthLayer::new(JwtAuthValidator::new(secret)));
57
58 let server = ServerBuilder::new()
60 .set_config(server_config.build())
61 .set_http_middleware(middleware)
62 .build(socket_addr)
63 .await
64 .map_err(|err| RpcError::server_error(err, ServerKind::Auth(socket_addr)))?;
65
66 let local_addr = server
67 .local_addr()
68 .map_err(|err| RpcError::server_error(err, ServerKind::Auth(socket_addr)))?;
69
70 let handle = server.start(module.inner.clone());
71 let mut ipc_handle: Option<jsonrpsee::server::ServerHandle> = None;
72
73 if let Some(ipc_server_config) = ipc_server_config {
74 let ipc_endpoint_str = ipc_endpoint
75 .clone()
76 .unwrap_or_else(|| constants::DEFAULT_ENGINE_API_IPC_ENDPOINT.to_string());
77 let ipc_server = ipc_server_config.build(ipc_endpoint_str);
78 let res = ipc_server.start(module.inner).await?;
79 ipc_handle = Some(res);
80 }
81
82 Ok(AuthServerHandle { handle: Some(handle), local_addr, secret, ipc_endpoint, ipc_handle })
83 }
84}
85
86#[derive(Debug)]
88pub struct AuthServerConfigBuilder {
89 socket_addr: Option<SocketAddr>,
90 secret: JwtSecret,
91 server_config: Option<ServerConfigBuilder>,
92 ipc_server_config: Option<IpcServerBuilder<Identity, Identity>>,
93 ipc_endpoint: Option<String>,
94}
95
96impl AuthServerConfigBuilder {
99 pub const fn new(secret: JwtSecret) -> Self {
101 Self {
102 socket_addr: None,
103 secret,
104 server_config: None,
105 ipc_server_config: None,
106 ipc_endpoint: None,
107 }
108 }
109
110 pub const fn socket_addr(mut self, socket_addr: SocketAddr) -> Self {
112 self.socket_addr = Some(socket_addr);
113 self
114 }
115
116 pub const fn maybe_socket_addr(mut self, socket_addr: Option<SocketAddr>) -> Self {
118 self.socket_addr = socket_addr;
119 self
120 }
121
122 pub const fn secret(mut self, secret: JwtSecret) -> Self {
124 self.secret = secret;
125 self
126 }
127
128 pub fn with_server_config(mut self, config: ServerConfigBuilder) -> Self {
133 self.server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
134 self
135 }
136
137 pub fn ipc_endpoint(mut self, ipc_endpoint: String) -> Self {
139 self.ipc_endpoint = Some(ipc_endpoint);
140 self
141 }
142
143 pub fn with_ipc_config(mut self, config: IpcServerBuilder<Identity, Identity>) -> Self {
147 self.ipc_server_config = Some(config.set_id_provider(EthSubscriptionIdProvider::default()));
148 self
149 }
150
151 pub fn build(self) -> AuthServerConfig {
153 AuthServerConfig {
154 socket_addr: self.socket_addr.unwrap_or_else(|| {
155 SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), constants::DEFAULT_AUTH_PORT)
156 }),
157 secret: self.secret,
158 server_config: self.server_config.unwrap_or_else(|| {
159 ServerConfig::builder()
160 .max_response_body_size(750 * 1024 * 1024)
165 .max_connections(500)
171 .max_request_body_size(128 * 1024 * 1024)
174 .set_id_provider(EthSubscriptionIdProvider::default())
175 }),
176 ipc_server_config: self.ipc_server_config.map(|ipc_server_config| {
177 ipc_server_config
178 .max_response_body_size(750 * 1024 * 1024)
179 .max_connections(500)
180 .max_request_body_size(128 * 1024 * 1024)
181 .set_id_provider(EthSubscriptionIdProvider::default())
182 }),
183 ipc_endpoint: self.ipc_endpoint,
184 }
185 }
186}
187
188#[derive(Debug, Clone)]
190pub struct AuthRpcModule {
191 pub(crate) inner: RpcModule<()>,
192}
193
194impl AuthRpcModule {
195 pub fn new(engine: impl IntoEngineApiRpcModule) -> Self {
197 Self { inner: engine.into_rpc_module() }
198 }
199
200 pub const fn module_mut(&mut self) -> &mut RpcModule<()> {
202 &mut self.inner
203 }
204
205 pub fn merge_auth_methods(
209 &mut self,
210 other: impl Into<Methods>,
211 ) -> Result<bool, RegisterMethodError> {
212 self.module_mut().merge(other.into()).map(|_| true)
213 }
214
215 pub fn remove_auth_method(&mut self, method_name: &'static str) -> bool {
219 self.module_mut().remove_method(method_name).is_some()
220 }
221
222 pub fn remove_auth_methods(&mut self, methods: impl IntoIterator<Item = &'static str>) {
224 for name in methods {
225 self.remove_auth_method(name);
226 }
227 }
228
229 pub fn replace_auth_methods(
231 &mut self,
232 other: impl Into<Methods>,
233 ) -> Result<bool, RegisterMethodError> {
234 let other = other.into();
235 self.remove_auth_methods(other.method_names());
236 self.merge_auth_methods(other)
237 }
238
239 pub async fn start_server(
241 self,
242 config: AuthServerConfig,
243 ) -> Result<AuthServerHandle, RpcError> {
244 config.start(self).await
245 }
246}
247
248#[derive(Clone, Debug)]
253#[must_use = "Server stops if dropped"]
254pub struct AuthServerHandle {
255 local_addr: SocketAddr,
256 handle: Option<jsonrpsee::server::ServerHandle>,
257 secret: JwtSecret,
258 ipc_endpoint: Option<String>,
259 ipc_handle: Option<jsonrpsee::server::ServerHandle>,
260}
261
262impl AuthServerHandle {
265 pub fn noop() -> Self {
269 Self {
270 local_addr: SocketAddr::new(
271 IpAddr::V4(Ipv4Addr::LOCALHOST),
272 constants::DEFAULT_AUTH_PORT,
273 ),
274 handle: None,
275 secret: JwtSecret::random(),
276 ipc_endpoint: None,
277 ipc_handle: None,
278 }
279 }
280
281 pub const fn local_addr(&self) -> SocketAddr {
283 self.local_addr
284 }
285
286 pub fn stop(self) -> Result<(), AlreadyStoppedError> {
288 let Some(handle) = self.handle else { return Ok(()) };
289 handle.stop()
290 }
291
292 pub fn http_url(&self) -> String {
294 format!("http://{}", self.local_addr)
295 }
296
297 pub fn ws_url(&self) -> String {
299 format!("ws://{}", self.local_addr)
300 }
301
302 pub fn http_client(&self) -> impl SubscriptionClientT + Clone + Send + Sync + Unpin + 'static {
306 let secret_layer = AuthClientLayer::new(self.secret);
308 let middleware = tower::ServiceBuilder::default().layer(secret_layer);
309 jsonrpsee::http_client::HttpClientBuilder::default()
310 .set_http_middleware(middleware)
311 .build(self.http_url())
312 .expect("Failed to create http client")
313 }
314
315 pub async fn ws_client(&self) -> jsonrpsee::ws_client::WsClient {
318 jsonrpsee::ws_client::WsClientBuilder::default()
319 .set_headers(HeaderMap::from_iter([(
320 AUTHORIZATION,
321 secret_to_bearer_header(&self.secret),
322 )]))
323 .build(self.ws_url())
324 .await
325 .expect("Failed to create ws client")
326 }
327
328 #[cfg(unix)]
330 pub async fn ipc_client(&self) -> Option<jsonrpsee::async_client::Client> {
331 use reth_ipc::client::IpcClientBuilder;
332
333 if let Some(ipc_endpoint) = &self.ipc_endpoint {
334 return Some(
335 IpcClientBuilder::default()
336 .build(ipc_endpoint)
337 .await
338 .expect("Failed to create ipc client"),
339 )
340 }
341 None
342 }
343
344 pub fn ipc_handle(&self) -> Option<jsonrpsee::server::ServerHandle> {
346 self.ipc_handle.clone()
347 }
348
349 pub fn ipc_endpoint(&self) -> Option<String> {
351 self.ipc_endpoint.clone()
352 }
353}