Skip to content

Commit 89d951a

Browse files
committed
chore: removed ohttp handling from directory
Signed-off-by: Harsh Dev Pathak <hiddenHaze@proton.me>
1 parent 43b12a9 commit 89d951a

File tree

3 files changed

+63
-168
lines changed

3 files changed

+63
-168
lines changed

ohttp-relay/src/gateway_helpers.rs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ use std::io::Cursor;
22

33
pub const CHACHA20_POLY1305_NONCE_LEN: usize = 32;
44
pub const POLY1305_TAG_SIZE: usize = 16;
5-
pub const ENCAPSULATED_MESSAGE_BYTES: usize = 65536;
6-
pub const BHTTP_REQ_BYTES: usize =
7-
ENCAPSULATED_MESSAGE_BYTES - (CHACHA20_POLY1305_NONCE_LEN + POLY1305_TAG_SIZE);
5+
pub const OHTTP_OVERHEAD: usize = CHACHA20_POLY1305_NONCE_LEN + POLY1305_TAG_SIZE;
6+
pub const ENCAPSULATED_MESSAGE_BYTES: usize = 8192;
7+
pub const BHTTP_REQ_BYTES: usize = ENCAPSULATED_MESSAGE_BYTES - OHTTP_OVERHEAD;
88

99
#[derive(Debug)]
1010
pub enum GatewayError {
@@ -25,7 +25,6 @@ impl std::fmt::Display for GatewayError {
2525

2626
impl std::error::Error for GatewayError {}
2727

28-
/// Represents the decapsulated HTTP request extracted from OHTTP
2928
pub struct DecapsulatedRequest {
3029
pub method: String,
3130
pub uri: String,
@@ -90,18 +89,27 @@ pub fn encapsulate_ohttp_response(
9089
GatewayError::InternalServerError(format!("BHTTP serialization failed: {}", e))
9190
})?;
9291

92+
if bhttp_bytes.len() > BHTTP_REQ_BYTES {
93+
return Err(GatewayError::InternalServerError(format!(
94+
"BHTTP response too large: {} > {}",
95+
bhttp_bytes.len(),
96+
BHTTP_REQ_BYTES
97+
)));
98+
}
99+
93100
bhttp_bytes.resize(BHTTP_REQ_BYTES, 0);
94101

95102
let ohttp_res = res_ctx.encapsulate(&bhttp_bytes).map_err(|e| {
96103
GatewayError::InternalServerError(format!("OHTTP encapsulation failed: {}", e))
97104
})?;
98105

99-
assert!(
100-
ohttp_res.len() == ENCAPSULATED_MESSAGE_BYTES,
101-
"Unexpected OHTTP response size: {} != {}",
102-
ohttp_res.len(),
103-
ENCAPSULATED_MESSAGE_BYTES
104-
);
106+
if ohttp_res.len() != ENCAPSULATED_MESSAGE_BYTES {
107+
return Err(GatewayError::InternalServerError(format!(
108+
"Unexpected OHTTP response size: {} != {}",
109+
ohttp_res.len(),
110+
ENCAPSULATED_MESSAGE_BYTES
111+
)));
112+
}
105113

106114
Ok(ohttp_res)
107115
}

ohttp-relay/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,7 @@ pub mod sentinel;
3838
pub use sentinel::SentinelTag;
3939
pub mod gateway_helpers;
4040

41-
pub use gateway_helpers::{
42-
decapsulate_ohttp_request, encapsulate_ohttp_response, BHTTP_REQ_BYTES,
43-
ENCAPSULATED_MESSAGE_BYTES,
44-
};
41+
pub use gateway_helpers::{decapsulate_ohttp_request, encapsulate_ohttp_response};
4542

4643
use crate::error::{BoxError, Error};
4744

payjoin-directory/src/lib.rs

Lines changed: 44 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ use http_body_util::{BodyExt, Empty, Full};
1010
use hyper::body::{Body, Bytes};
1111
use hyper::header::{HeaderValue, ACCESS_CONTROL_ALLOW_ORIGIN, CONTENT_TYPE};
1212
use hyper::server::conn::http1;
13-
use hyper::{Method, Request, Response, StatusCode, Uri};
13+
use hyper::{Method, Request, Response, StatusCode};
1414
use hyper_util::rt::TokioIo;
1515
use hyper_util::service::TowerToHyperService;
16-
use payjoin::directory::{ShortId, ShortIdError, ENCAPSULATED_MESSAGE_BYTES};
16+
use payjoin::directory::{ShortId, ShortIdError};
1717
use tokio::net::TcpListener;
1818
#[cfg(feature = "acme")]
1919
use tokio_rustls_acme::AcmeConfig;
2020
use tokio_stream::wrappers::TcpListenerStream;
2121
use tokio_stream::Stream;
22-
use tracing::{debug, error, trace, warn};
22+
use tracing::{debug, error, warn};
2323

2424
pub use crate::db::files::Db as FilesDb;
2525
use crate::db::Db;
@@ -28,14 +28,8 @@ use ohttp_relay::SentinelTag;
2828

2929
pub use crate::key_config::*;
3030

31-
const CHACHA20_POLY1305_NONCE_LEN: usize = 32; // chacha20poly1305 n_k
32-
const POLY1305_TAG_SIZE: usize = 16;
33-
pub const BHTTP_REQ_BYTES: usize =
34-
ENCAPSULATED_MESSAGE_BYTES - (CHACHA20_POLY1305_NONCE_LEN + POLY1305_TAG_SIZE);
3531
const V1_MAX_BUFFER_SIZE: usize = 65536;
3632

37-
const V1_REJECT_RES_JSON: &str =
38-
r#"{{"errorCode": "original-psbt-rejected ", "message": "Body is not a string"}}"#;
3933
const V1_UNAVAILABLE_RES_JSON: &str = r#"{{"errorCode": "unavailable", "message": "V2 receiver offline. V1 sends require synchronous communications."}}"#;
4034

4135
pub(crate) mod db;
@@ -208,15 +202,14 @@ impl<D: Db> Service<D> {
208202
}
209203

210204
let mut response = match (parts.method, path_segments.as_slice()) {
211-
(Method::POST, ["", ".well-known", "ohttp-gateway"]) =>
212-
self.handle_ohttp_gateway(body).await,
213205
(Method::GET, ["", ".well-known", "ohttp-gateway"]) =>
214206
self.handle_ohttp_gateway_get(&query).await,
215-
(Method::POST, ["", ""]) => self.handle_ohttp_gateway(body).await,
216207
(Method::GET, ["", "ohttp-keys"]) => self.get_ohttp_keys().await,
217-
(Method::POST, ["", id]) => self.post_fallback_v1(id, query, body).await,
218208
(Method::GET, ["", "health"]) => health_check().await,
219209
(Method::GET, ["", ""]) => handle_directory_home_path().await,
210+
(Method::POST, ["", id]) => self.post_mailbox_or_v1(id, query, body).await,
211+
(Method::GET, ["", id]) => self.get_mailbox(id).await,
212+
(Method::PUT, ["", id]) => self.put_payjoin_v1(id, body).await,
220213
_ => Ok(not_found()),
221214
}
222215
.unwrap_or_else(|e| e.to_response());
@@ -227,132 +220,76 @@ impl<D: Db> Service<D> {
227220
Ok(response)
228221
}
229222

230-
async fn handle_ohttp_gateway<B>(
223+
async fn post_mailbox_or_v1<B>(
231224
&self,
225+
id: &str,
226+
query: String,
232227
body: B,
233228
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError>
234229
where
235230
B: Body<Data = Bytes> + Send + 'static,
236231
B::Error: Into<BoxError>,
237232
{
238-
let ohttp_body = body
233+
let body_bytes = body
239234
.collect()
240235
.await
241236
.map_err(|e| HandlerError::BadRequest(anyhow::anyhow!(e.into())))?
242237
.to_bytes();
243238

244-
let (bhttp_req, res_ctx) = self
245-
.ohttp
246-
.decapsulate(&ohttp_body)
247-
.map_err(|e| HandlerError::OhttpKeyRejection(e.into()))?;
248-
let mut cursor = std::io::Cursor::new(bhttp_req);
249-
let req = bhttp::Message::read_bhttp(&mut cursor)
250-
.map_err(|e| HandlerError::BadRequest(e.into()))?;
251-
let uri = Uri::builder()
252-
.scheme(req.control().scheme().unwrap_or_default())
253-
.authority(req.control().authority().unwrap_or_default())
254-
.path_and_query(req.control().path().unwrap_or_default())
255-
.build()?;
256-
let body = req.content().to_vec();
257-
let mut http_req =
258-
Request::builder().uri(uri).method(req.control().method().unwrap_or_default());
259-
for header in req.header().fields() {
260-
http_req = http_req.header(header.name(), header.value())
261-
}
262-
let request = http_req.body(full(body))?;
263-
264-
let response = self.handle_v2(request).await?;
265-
266-
let (parts, body) = response.into_parts();
267-
let mut bhttp_res = bhttp::Message::response(
268-
bhttp::StatusCode::try_from(parts.status.as_u16())
269-
.map_err(|e| HandlerError::InternalServerError(e.into()))?,
270-
);
271-
for (name, value) in parts.headers.iter() {
272-
bhttp_res.put_header(name.as_str(), value.to_str().unwrap_or_default());
273-
}
274-
let full_body = body
275-
.collect()
276-
.await
277-
.map_err(|e| HandlerError::InternalServerError(e.into()))?
278-
.to_bytes();
279-
bhttp_res.write_content(&full_body);
280-
let mut bhttp_bytes = Vec::new();
281-
bhttp_res
282-
.write_bhttp(bhttp::Mode::KnownLength, &mut bhttp_bytes)
283-
.map_err(|e| HandlerError::InternalServerError(e.into()))?;
284-
bhttp_bytes.resize(BHTTP_REQ_BYTES, 0);
285-
let ohttp_res = res_ctx
286-
.encapsulate(&bhttp_bytes)
287-
.map_err(|e| HandlerError::InternalServerError(e.into()))?;
288-
assert!(ohttp_res.len() == ENCAPSULATED_MESSAGE_BYTES, "Unexpected OHTTP response size");
289-
Ok(Response::new(full(ohttp_res)))
290-
}
291-
292-
async fn handle_v2(
293-
&self,
294-
req: Request<BoxBody<Bytes, hyper::Error>>,
295-
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
296-
let path = req.uri().path().to_string();
297-
let (parts, body) = req.into_parts();
298-
299-
let path_segments: Vec<&str> = path.split('/').collect();
300-
debug!("handle_v2: {:?}", &path_segments);
301-
match (parts.method, path_segments.as_slice()) {
302-
(Method::POST, &["", id]) => self.post_mailbox(id, body).await,
303-
(Method::GET, &["", id]) => self.get_mailbox(id).await,
304-
(Method::PUT, &["", id]) => self.put_payjoin_v1(id, body).await,
305-
_ => Ok(not_found()),
239+
if body_bytes.len() > V1_MAX_BUFFER_SIZE {
240+
return Err(HandlerError::PayloadTooLarge);
306241
}
307-
}
308-
309-
async fn post_mailbox(
310-
&self,
311-
id: &str,
312-
body: BoxBody<Bytes, hyper::Error>,
313-
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
314-
let none_response = Response::builder().status(StatusCode::OK).body(empty())?;
315-
trace!("post_mailbox");
316242

317243
let id = ShortId::from_str(id)?;
318244

319-
let req = body
320-
.collect()
321-
.await
322-
.map_err(|e| HandlerError::InternalServerError(e.into()))?
323-
.to_bytes();
324-
if req.len() > V1_MAX_BUFFER_SIZE {
325-
return Err(HandlerError::PayloadTooLarge);
326-
}
327-
328-
match self.db.post_v2_payload(&id, req.into()).await {
329-
Ok(_) => Ok(none_response),
330-
Err(e) => Err(HandlerError::InternalServerError(e.into())),
245+
if let Ok(body_str) = String::from_utf8(body_bytes.to_vec()) {
246+
let v2_compat_body = format!("{body_str}\n{query}");
247+
let none_response = Response::builder()
248+
.status(StatusCode::SERVICE_UNAVAILABLE)
249+
.body(full(V1_UNAVAILABLE_RES_JSON))?;
250+
handle_peek(
251+
self.db.post_v1_request_and_wait_for_response(&id, v2_compat_body.into()).await,
252+
none_response,
253+
)
254+
} else {
255+
let none_response = Response::builder().status(StatusCode::OK).body(empty())?;
256+
match self.db.post_v2_payload(&id, body_bytes.into()).await {
257+
Ok(_) => Ok(none_response),
258+
Err(e) => Err(HandlerError::InternalServerError(e.into())),
259+
}
331260
}
332261
}
333262

334263
async fn get_mailbox(
335264
&self,
336265
id: &str,
337266
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
338-
trace!("get_mailbox");
339267
let id = ShortId::from_str(id)?;
340268
let timeout_response = Response::builder().status(StatusCode::ACCEPTED).body(empty())?;
341269
handle_peek(self.db.wait_for_v2_payload(&id).await, timeout_response)
342270
}
343-
async fn put_payjoin_v1(
271+
272+
async fn put_payjoin_v1<B>(
344273
&self,
345274
id: &str,
346-
body: BoxBody<Bytes, hyper::Error>,
347-
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError> {
348-
trace!("Put_payjoin_v1");
275+
body: B,
276+
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError>
277+
where
278+
B: Body<Data = Bytes> + Send + 'static,
279+
B::Error: Into<BoxError>,
280+
{
349281
let ok_response = Response::builder().status(StatusCode::OK).body(empty())?;
350282

351283
let id = ShortId::from_str(id)?;
352284
let req = body
353285
.collect()
354286
.await
355-
.map_err(|e| HandlerError::InternalServerError(e.into()))?
287+
.map_err(|e| {
288+
HandlerError::InternalServerError(anyhow::anyhow!(
289+
"Failed to read body: {}",
290+
e.into()
291+
))
292+
})?
356293
.to_bytes();
357294
if req.len() > V1_MAX_BUFFER_SIZE {
358295
return Err(HandlerError::PayloadTooLarge);
@@ -364,41 +301,6 @@ impl<D: Db> Service<D> {
364301
}
365302
}
366303

367-
async fn post_fallback_v1<B>(
368-
&self,
369-
id: &str,
370-
query: String,
371-
body: B,
372-
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError>
373-
where
374-
B: Body<Data = Bytes> + Send + 'static,
375-
B::Error: Into<BoxError>,
376-
{
377-
trace!("Post fallback v1");
378-
let none_response = Response::builder()
379-
.status(StatusCode::SERVICE_UNAVAILABLE)
380-
.body(full(V1_UNAVAILABLE_RES_JSON))?;
381-
let bad_request_body_res =
382-
Response::builder().status(StatusCode::BAD_REQUEST).body(full(V1_REJECT_RES_JSON))?;
383-
384-
let body_bytes = match body.collect().await {
385-
Ok(bytes) => bytes.to_bytes(),
386-
Err(_) => return Ok(bad_request_body_res),
387-
};
388-
389-
let body_str = match String::from_utf8(body_bytes.to_vec()) {
390-
Ok(body_str) => body_str,
391-
Err(_) => return Ok(bad_request_body_res),
392-
};
393-
394-
let v2_compat_body = format!("{body_str}\n{query}");
395-
let id = ShortId::from_str(id)?;
396-
handle_peek(
397-
self.db.post_v1_request_and_wait_for_response(&id, v2_compat_body.into()).await,
398-
none_response,
399-
)
400-
}
401-
402304
async fn handle_ohttp_gateway_get(
403305
&self,
404306
query: &str,
@@ -466,10 +368,6 @@ async fn health_check() -> Result<Response<BoxBody<Bytes, hyper::Error>>, Handle
466368

467369
async fn handle_directory_home_path() -> Result<Response<BoxBody<Bytes, hyper::Error>>, HandlerError>
468370
{
469-
let mut res = Response::new(empty());
470-
*res.status_mut() = StatusCode::OK;
471-
res.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static("text/html"));
472-
473371
let html = r#"
474372
<!DOCTYPE html>
475373
<html lang="en">
@@ -521,7 +419,9 @@ async fn handle_directory_home_path() -> Result<Response<BoxBody<Bytes, hyper::E
521419
</html>
522420
"#;
523421

524-
*res.body_mut() = full(html);
422+
let mut res = Response::new(full(html));
423+
*res.status_mut() = StatusCode::OK;
424+
res.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static("text/html"));
525425
Ok(res)
526426
}
527427

@@ -531,7 +431,6 @@ enum HandlerError {
531431
InternalServerError(anyhow::Error),
532432
ServiceUnavailable(anyhow::Error),
533433
SenderGone(anyhow::Error),
534-
OhttpKeyRejection(anyhow::Error),
535434
BadRequest(anyhow::Error),
536435
Forbidden(anyhow::Error),
537436
}
@@ -553,15 +452,6 @@ impl HandlerError {
553452
error!("Sender gone: {}", e);
554453
*res.status_mut() = StatusCode::GONE
555454
}
556-
HandlerError::OhttpKeyRejection(e) => {
557-
const OHTTP_KEY_REJECTION_RES_JSON: &str = r#"{"type":"https://iana.org/assignments/http-problem-types#ohttp-key", "title": "key identifier unknown"}"#;
558-
559-
warn!("Bad request: Key configuration rejected: {}", e);
560-
*res.status_mut() = StatusCode::BAD_REQUEST;
561-
res.headers_mut()
562-
.insert(CONTENT_TYPE, HeaderValue::from_static("application/problem+json"));
563-
*res.body_mut() = full(OHTTP_KEY_REJECTION_RES_JSON);
564-
}
565455
HandlerError::BadRequest(e) => {
566456
warn!("Bad request: {}", e);
567457
*res.status_mut() = StatusCode::BAD_REQUEST

0 commit comments

Comments
 (0)