1use std::future::Future;
6
7use std::pin::Pin;
8
9use futures::{future, FutureExt};
10use http_body_util::{BodyExt, Limited};
11use hyper::header;
12use jsonrpsee::{
13 core::BoxError,
14 server::{HttpBody, HttpRequest, HttpResponse},
15};
16use jsonrpsee_types::ErrorObject;
17use serde::{Deserialize, Serialize};
18use tower::Service;
19
20use super::cookie::Cookie;
21
22use base64::{engine::general_purpose::STANDARD, Engine as _};
23
24#[derive(Clone, Debug)]
56pub struct HttpRequestMiddleware<S> {
57 service: S,
58 cookie: Option<Cookie>,
59 max_request_body_size: usize,
60}
61
62impl<S> HttpRequestMiddleware<S> {
63 pub fn new(service: S, cookie: Option<Cookie>, max_request_body_size: usize) -> Self {
65 Self {
66 service,
67 cookie,
68 max_request_body_size,
69 }
70 }
71
72 pub fn check_credentials(&self, headers: &header::HeaderMap) -> bool {
74 self.cookie.as_ref().is_none_or(|internal_cookie| {
75 headers
76 .get(header::AUTHORIZATION)
77 .and_then(|auth_header| auth_header.to_str().ok())
78 .and_then(|auth_header| auth_header.split_whitespace().nth(1))
79 .and_then(|encoded| STANDARD.decode(encoded).ok())
80 .and_then(|decoded| String::from_utf8(decoded).ok())
81 .and_then(|request_cookie| request_cookie.split(':').nth(1).map(String::from))
82 .is_some_and(|passwd| internal_cookie.authenticate(passwd))
83 })
84 }
85
86 pub fn insert_or_replace_content_type_header(headers: &mut header::HeaderMap) {
108 if !headers.contains_key(header::CONTENT_TYPE)
109 || headers
110 .get(header::CONTENT_TYPE)
111 .filter(|value| {
112 value
113 .to_str()
114 .ok()
115 .unwrap_or_default()
116 .starts_with("text/plain")
117 })
118 .is_some()
119 {
120 headers.insert(
121 header::CONTENT_TYPE,
122 header::HeaderValue::from_static("application/json"),
123 );
124 }
125 }
126
127 async fn request_to_json_rpc_2(
129 request: HttpRequest<HttpBody>,
130 max_request_body_size: usize,
131 ) -> Result<(JsonRpcVersion, HttpRequest<HttpBody>), BoxError> {
132 let (parts, body) = request.into_parts();
133 let bytes = Limited::new(body, max_request_body_size)
134 .collect()
135 .await?
136 .to_bytes();
137 let (version, bytes) =
138 if let Ok(request) = serde_json::from_slice::<'_, JsonRpcRequest>(bytes.as_ref()) {
139 let version = request.version();
140 if matches!(version, JsonRpcVersion::Unknown) {
141 (version, bytes)
142 } else {
143 (
144 version,
145 serde_json::to_vec(&request.into_2()).expect("valid").into(),
146 )
147 }
148 } else {
149 (JsonRpcVersion::Unknown, bytes)
150 };
151 Ok((
152 version,
153 HttpRequest::from_parts(parts, HttpBody::from(Vec::from(bytes))),
155 ))
156 }
157 async fn response_from_json_rpc_2(
159 version: JsonRpcVersion,
160 response: HttpResponse<HttpBody>,
161 ) -> Result<HttpResponse<HttpBody>, BoxError> {
162 let (parts, body) = response.into_parts();
163 let bytes = body.collect().await?.to_bytes();
164 let bytes =
165 if let Ok(response) = serde_json::from_slice::<'_, JsonRpcResponse>(bytes.as_ref()) {
166 serde_json::to_vec(&response.into_version(version))
167 .expect("valid")
168 .into()
169 } else {
170 bytes
171 };
172 Ok(HttpResponse::from_parts(
173 parts,
174 HttpBody::from(bytes.as_ref().to_vec()),
175 ))
176 }
177}
178
179#[derive(Clone)]
181pub struct HttpRequestMiddlewareLayer {
182 cookie: Option<Cookie>,
183 max_request_body_size: usize,
184}
185
186impl HttpRequestMiddlewareLayer {
187 pub fn new(cookie: Option<Cookie>, max_request_body_size: usize) -> Self {
189 Self {
190 cookie,
191 max_request_body_size,
192 }
193 }
194}
195
196impl<S> tower::Layer<S> for HttpRequestMiddlewareLayer {
197 type Service = HttpRequestMiddleware<S>;
198
199 fn layer(&self, service: S) -> Self::Service {
200 HttpRequestMiddleware::new(service, self.cookie.clone(), self.max_request_body_size)
201 }
202}
203
204impl<S> Service<HttpRequest<HttpBody>> for HttpRequestMiddleware<S>
205where
206 S: Service<HttpRequest, Response = HttpResponse> + std::clone::Clone + Send + 'static,
207 S::Error: Into<BoxError> + 'static,
208 S::Future: Send + 'static,
209{
210 type Response = S::Response;
211 type Error = BoxError;
212 type Future =
213 Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send + 'static>>;
214
215 fn poll_ready(
216 &mut self,
217 cx: &mut std::task::Context<'_>,
218 ) -> std::task::Poll<Result<(), Self::Error>> {
219 self.service.poll_ready(cx).map_err(Into::into)
220 }
221
222 fn call(&mut self, mut request: HttpRequest<HttpBody>) -> Self::Future {
223 if !self.check_credentials(request.headers_mut()) {
225 let error = ErrorObject::borrowed(401, "unauthenticated method", None);
226 return future::err(BoxError::from(error)).boxed();
228 }
229
230 Self::insert_or_replace_content_type_header(request.headers_mut());
232
233 let mut service = self.service.clone();
234 let max_request_body_size = self.max_request_body_size;
235
236 async move {
237 let (version, request) =
238 Self::request_to_json_rpc_2(request, max_request_body_size).await?;
239 let response = service.call(request).await.map_err(Into::into)?;
240 Self::response_from_json_rpc_2(version, response).await
241 }
242 .boxed()
243 }
244}
245
246#[derive(Clone, Copy, Debug)]
247enum JsonRpcVersion {
248 Bitcoind,
250 Lightwalletd,
253 TwoPointZero,
255 Unknown,
257}
258
259#[derive(Debug, Deserialize, Serialize)]
261pub(super) struct JsonRpcRequest {
262 #[serde(skip_serializing_if = "Option::is_none")]
263 jsonrpc: Option<String>,
264 method: String,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 params: Option<serde_json::Value>,
267 #[serde(
268 default,
269 deserialize_with = "deserialize_present_id",
270 skip_serializing_if = "Option::is_none"
271 )]
272 id: Option<serde_json::Value>,
273}
274
275fn deserialize_present_id<'de, D: serde::Deserializer<'de>>(
276 deserializer: D,
277) -> Result<Option<serde_json::Value>, D::Error> {
278 serde_json::Value::deserialize(deserializer).map(Some)
279}
280
281impl JsonRpcRequest {
282 fn version(&self) -> JsonRpcVersion {
283 match (self.jsonrpc.as_deref(), &self.params, &self.id) {
284 (
285 Some("2.0"),
286 _,
287 None
288 | Some(
289 serde_json::Value::Null
290 | serde_json::Value::String(_)
291 | serde_json::Value::Number(_),
292 ),
293 ) => JsonRpcVersion::TwoPointZero,
294 (Some("1.0"), Some(_), Some(_)) => JsonRpcVersion::Lightwalletd,
295 (None, Some(_), Some(_)) => JsonRpcVersion::Bitcoind,
296 _ => JsonRpcVersion::Unknown,
297 }
298 }
299
300 pub(super) fn into_2(mut self) -> Self {
301 self.jsonrpc = Some("2.0".into());
302 self
303 }
304}
305#[derive(Debug, Deserialize, Serialize)]
307struct JsonRpcResponse {
308 #[serde(skip_serializing_if = "Option::is_none")]
309 jsonrpc: Option<String>,
310 id: serde_json::Value,
311 #[serde(skip_serializing_if = "Option::is_none")]
312 result: Option<Box<serde_json::value::RawValue>>,
313 #[serde(skip_serializing_if = "Option::is_none")]
314 error: Option<serde_json::Value>,
315}
316
317impl JsonRpcResponse {
318 fn into_version(mut self, version: JsonRpcVersion) -> Self {
319 match version {
320 JsonRpcVersion::Bitcoind => {
321 self.jsonrpc = None;
322 self.result = self
323 .result
324 .or_else(|| serde_json::value::to_raw_value(&()).ok());
325 self.error = self.error.or(Some(serde_json::Value::Null));
326 }
327 JsonRpcVersion::Lightwalletd => {
328 self.jsonrpc = Some("1.0".into());
329 self.result = self
330 .result
331 .or_else(|| serde_json::value::to_raw_value(&()).ok());
332 self.error = self.error.or(Some(serde_json::Value::Null));
333 }
334 JsonRpcVersion::TwoPointZero => {
335 assert_eq!(self.jsonrpc.as_deref(), Some("2.0"));
339 if self.error.is_none() {
340 self.result = self
341 .result
342 .or_else(|| serde_json::value::to_raw_value(&()).ok());
343 } else {
344 assert!(self.result.is_none());
345 }
346 }
347 JsonRpcVersion::Unknown => (),
348 }
349 self
350 }
351}