Repository navigation
Payjoin Mailroom Tracking Issue #941
Copy link
Copy link
Open
Labels
trackingHigh-level tracking issuesHigh-level tracking issues
Milestone
Description
See #775 for discussion
Sub bullets indicate spinoffs of parent, which are directly dependent. Otherwise tasks mostly don't depend on each other.
Most of these do depend on #1232 however, as the ultimate goal here is to unify the directory and relay services.
blocking first release
- Add ACME certificate management to payjoin-service #1315
- Add standalone metrics service to Payjoin-service #1296
- @spacebear21 confirm if there's some issue exposing 80/443 on docker (I really don't think there is)
- refactor: introduce payjoin_directory::Service #914
- Introduce metrics Collection via prometheus for payjoin directory #848
- tower_http::metrics for simple in flight reqs metric, indicates ~ number of active sessions proxied by concurrent GET requests that are blocking on data
- Configure directory with config & clap #927
- Ensure key rotation is accounted for in server and client implementations #445
- config reloading? not sure how valuable this would be with acme and automatic key rotation
- Replace redis with file based mailbox storage #915
- DB should also be a tower::Service, using tower::{timeout,limit::rate} Half done. DbServiceAdapter exists (f2d07db), but no timeout or rate layer is
applied.
- DB should also be a tower::Service, using tower::{timeout,limit::rate} Half done. DbServiceAdapter exists (f2d07db), but no timeout or rate layer is
- tokio-rustls-acme
- configure rustls for PQ
- Fold ohttp-relay into rust-payjoin monorepo #1215
- merge ohttp-relay & payjoin-directory into a Unified payjoin service #1232
- deny access to own directory from the relay
payjoin-serviceshould use axum to simplify routes, split app into sub-apps that all implement the Service trait (e.g. the OHTTP target resources) (supersedes Remove hyper and migrate to axum. #1101)- backwards compatibility routes can be done using the tower_http::follow_redirect middleware instead of being aliased as they are today
- use tokio-listener, --listen-addr instead of --port or something like that
- that makes it more flexible if systemd does the listening for e.g. a nixos module. no more code complexity for us but more flexibility to override the nixos module... but equally systemd unit could just start it and it could bind on something
- Prometheus metrics with axum middleware in payjoin-service #1284
- handle HTTP 2
- maybe factor out a tower_http OHTTP gateway middleware Isolate OHTTP Gateway in payjoin-directory #1056
- Use tower-http corslayer for handling cors #1604
- remove boilerplate with tower middleware
- tower_http::trace, remove boilerplate tracing and only leave domain relevant logging
- Partly done. TraceLayer is applied in lib.rs:446. The manual tracing boilerplate hasn't been checked.
- tower_http::limit, remove our custom body size limiter
- Not done, and it's the RAM gap from earlier. The "custom limiter" is a req.len() > V1_MAX_BUFFER_SIZE check that runs only after body.collect() has buffered the whole body, so memory isn't bounded. This item is the fix.
- tower::limit::rate, POST reqs should be limited to 25/s to ensure all mailboxes have a TTL of minimum 24hrs given default capacity limit
- tokio_http::cors, removes tiny bit of boilerplate
- tower_http::trace, remove boilerplate tracing and only leave domain relevant logging
- Set up GitHub Actions for Docker image builds using flake.nix #1286
- Shift integration tests to payjoin-service once ready
- Deprecate payjoin-directory binary and library
- Deprecate ohttp-relay binary and library
- We also need to beef up our directory service docs. E.g what hardware resources you need to run one, instructions to run, explaining how to configure the directory. [edit: Inquire within for mailroom infosheet --Dan]
Far future:
- QUIC
- arti_client for Tor for bootstrapping #766 (hidden service for directories & tor bridge for relays), kinda tricky without https://gitlab.torproject.org/tpo/core/arti/-/issues/1932 see https://docs.rs/arti-client/0.33.0/arti_client/index.html#-warnings-
- multihop OHTTP Gateway opt-in makes onion routing over relays possible #582
-
- /{id} and /{authority} paths are distinguishable, ShortIDs are 13 bech32 chars, authorities must have
:or.
- /{id} and /{authority} paths are distinguishable, ShortIDs are 13 bech32 chars, authorities must have
-
Reacted by Dan Gould, spacebear, zealsham, Luis Schwab, Armin Sabouri and Oladapo Oyindamola
Metadata
Metadata
Assignees
Labels
trackingHigh-level tracking issuesHigh-level tracking issues
Activity
DanGould commentedon Aug 26, 2025
Now that
ohttp-relayis up to date with 1.85.0, it could be brought into this repository as a monorepo item. However, it depends onureqfor proxy which'd be nice to replace withreqwestif possible and it depends onnginxfor tls termination which would really be better to replace with whatever native ACME solution you cook up for the directory.In either case I don't think merging the repos affects
payjoincrate's 1.0 stability now so I'm just noting these things for when the time is right.zealsham commentedon Sep 25, 2025
@DanGould The ureq crate is only used for integration test in the ohttp-relay repo . i did a replacement with reqswest on my local branch and all test-cases pass .
benalleng commentedon Sep 25, 2025
Feel free to open a PR on the ohttp-relay so we can take a look
Harshdev098 commentedon Jan 30, 2026
Hey @spacebear21, Can I work on this refactor to move the existing OHTTP decrypt/encrypt + forwarding logic out of handlers and into a reusable Tower Layer / gateway. That keeps directory/relay logic OHTTP agnostic and easily portable to the unified payjoin-service.
spacebear21 commentedon Feb 4, 2026
Hey @Harshdev098 sorry for delayed response, that sounds like a good next step to follow up on #1296 ! I'd recommend rebasing and working on top of that PR to avoid conflicting work once it gets merged.
Implement Directory db as a tower-service
Implement db as a service
Implement db as a service
Implement db as a service
Implement db as a service
Implement db as a service
7 remaining items
Add db entry metrics
[-]Directory Service Tracking Issue[/-][+]Payjoin Mailroom Tracking Issue[/+]Add db entry metrics
Add db entry metrics
Add db entry metrics
Add db entry metrics
Request size limiter
V1 body limit
Use tower-http corslayer for handling cors
Use tower-http corslayer for handling cors
Delegate http tracing to tower middleware
Use tower-http corslayer for handling cors
Use tower-http corslayer for handling cors
Use tower-http corslayer for handling cors
codaMW commentedon Oct 30, 2026
I would like to take the "tower_http::limit, remove our custom body size limiter" item.
The gap, current as of #1983: every request body in
payjoin-mailroom/src/directory.rsis fully buffered before any size check, so memory is not bounded by the caps.post_mailbox:body.collect().await...to_bytes()thenif req.len() > MAX_MAILBOX_PAYLOAD_BYTES.put_payjoin_v1: same, then> V1_MAX_BUFFER_SIZE.post_fallback_v1: collects, then checks after building the v2-compat body.handle_ohttp_gateway: collects the encapsulated body with no size check at all, even though a valid encapsulated message is a fixedENCAPSULATED_MESSAGE_BYTES(8192).#1983's
MAX_MAILBOX_PAYLOAD_BYTES/BHTTP_REQ_BYTESbound what can be stored and returned, which is complementary, but none of them stop a client from making the server buffer an arbitrarily large body first. That is the RAM gap noted here.Proposed fix: a
tower_http::limit::RequestBodyLimitLayerat the service ingress so oversized bodies are rejected with 413 before being buffered, keeping the existing per-handler checks as semantic validation on the now-bounded body. tower-http is already a dependency (TraceLayer is in use); this enables itslimitfeature.Sizing, which #1983 mostly settles: the largest legitimate body is the direct V1 path at
V1_MAX_BUFFER_SIZE(64 KiB); a V2 OHTTP request is a fixedENCAPSULATED_MESSAGE_BYTES(8192). Two options:(a) one global ingress limit at 64 KiB: simplest, bounds per-request memory to 64 KiB everywhere, existing checks still enforce the tighter V2 cap.
(b) per-route limits: 8192 on the OHTTP gateway route (anything larger is definitionally invalid) and 64 KiB on the direct V1 routes: tighter, rejects an oversized V2 body at the first byte past the fixed size.
I lean (b) for the gateway since encapsulated messages are fixed size, but I will match your preference. Any reason to avoid a per-route limit?
Tests: a body one byte over the limit returns 413 at ingress without the handler buffering it; a body at or under the limit still succeeds for V1 PUT, the V1 fallback POST, and the V2 gateway; existing behavior otherwise unchanged. Mailroom tests with default and all features, plus fmt and clippy.
AI disclosure: I used an AI assistant to inspect the code and draft this comment. I will write and understand the implementation myself.