rust-payjoin icon indicating copy to clipboard operation
rust-payjoin copied to clipboard

Enforce content-length validation on sender and size limits on payjoin-cli

Open GideonBature opened this issue 6 months ago • 9 comments

This PR follows up on #770 and addresses the remaining improvements in comment. It implements stricter content-length validation and removes MAX_CONTENT_LENGTH from the sender side, moving it to payjoin-cli.

Summary of changes

  1. Sender-side validation

    • Mirrors the receiver-side logic by removing MAX_CONTENT_LENGTH and validating that the actual body length matches the Content-Length header.
  2. payjoin-cli receiver

    • Adds a size limit when collecting the body using .collect(), to avoid unbounded memory allocations from a potentially malicious counterparty.
  3. payjoin-cli sender

    • Enforces a similar limit when handling response bodies using response.bytes() from reqwest.

Ref: #770 Closes: #756

GideonBature avatar Jun 25 '25 16:06 GideonBature

Pull Request Test Coverage Report for Build 17460319220

Details

  • 72 of 81 (88.89%) changed or added relevant lines in 5 files are covered.
  • 2 unchanged lines in 2 files lost coverage.
  • Overall coverage increased (+0.09%) to 86.033%

Changes Missing Coverage Covered Lines Changed/Added Lines %
payjoin-cli/src/app/mod.rs 13 14 92.86%
payjoin-cli/src/app/v1.rs 12 20 60.0%
<!-- Total: 72 81
Files with Coverage Reduction New Missed Lines %
payjoin/src/core/send/error.rs 1 33.14%
payjoin/src/core/send/v1.rs 1 92.31%
<!-- Total: 2
Totals Coverage Status
Change from base Build 17446213698: 0.09%
Covered Lines: 8248
Relevant Lines: 9587

💛 - Coveralls

coveralls avatar Jun 25 '25 16:06 coveralls

I have implemented the changes suggested. However, I had to introduce about two dependencies, which are:

  • futures
  • bytes

as a result of that I attempted to update the lock files using the update-lock-files.sh script. However, I kept getting can't find crate for serde`` for bitcoin-0.32.5 and for rustls-0.22.4.

I want you to review what I have thus far, let me know if I am going in the right direction, as I find a solution to the error I am having.

GideonBature avatar Jul 01 '25 18:07 GideonBature

I implemented the suggestions you gave, however, for the utility function, putting it in mod.rs of app, I am encountering a challenge where I am unable to access the hyper dependencies, I really don't know why. And I will be needing it, since I will need to make use of Bytes from it for the utility function.

GideonBature avatar Jul 07 '25 17:07 GideonBature

I didn't quite understand your last comment about hyper & bytes, but i think the read_limited_body function is in the right place?

similar limiting for app/v2.rs can be added in a separate PR, with a fixed response size, and reusing this function, but moving it to the top level mod.rs should be straightforward (just making it pub(crate) and bringing in the necessary imports, namely hyper::body::Bytes)

anyway this is getting close, i only have some fairly small cleanup suggestions

Moving the function to mod.rs, I always have issue bringing in the hyper dependency. This is the error I always get, despite hyper being present in the Cargo.toml file.

error[E0433]: failed to resolve: use of unresolved module or unlinked crate `hyper`
 --> payjoin-cli/src/app/mod.rs:5:5
  |
5 | use hyper::body::Bytes;
  |     ^^^^^ use of unresolved module or unlinked crate `hyper`
  |
  = help: if you wanted to use a crate named `hyper`, use `cargo add hyper` to add it to your `Cargo.toml`

I have been trying to figure out where the problem is, but till now nothing.

GideonBature avatar Jul 20 '25 02:07 GideonBature

This PR addresses the hyper crate issue and also all the suggestions given. Thank you.

GideonBature avatar Aug 05 '25 08:08 GideonBature

Resolved merge conflicts.

GideonBature avatar Aug 17 '25 15:08 GideonBature

Whenever this gets merged I suggest it get squashed rather than have all $n$ commits used.

DanGould avatar Aug 17 '25 23:08 DanGould

Lint is failing with this:

error[E0599]: no variant or associated item named `Parse` found for enum `core::send::error::InternalValidationError` in the current scope
   --> payjoin/src/core/send/mod.rs:699:90
    |
699 |         let res_str = std::str::from_utf8(response).map_err(|_| InternalValidationError::Parse)?;
    |                                                                                          ^^^^^ variant or associated item not found in `core::send::error::InternalValidationError`
    |
   ::: payjoin/src/core/send/error.rs:94:1
    |
 94 | pub(crate) enum InternalValidationError {
    | --------------------------------------- variant or associated item `Parse` not found for this enum

error[E0599]: no variant or associated item named `parse` found for enum `core::send::error::ResponseError` in the current scope
   --> payjoin/src/core/send/mod.rs:700:75
    |
700 |         let proposal = Psbt::from_str(res_str).map_err(|_| ResponseError::parse(res_str))?;
    |                                                                           ^^^^^ variant or associated item not found in `core::send::error::ResponseError`
    |
   ::: payjoin/src/core/send/error.rs:250:1
    |
250 | pub enum ResponseError {
    | ---------------------- variant or associated item `parse` not found for this enum

I don't really know, I observed that the Parse is actually present, but it was feature gated to v1, I don't know if that is what is causing the lint to fail here? Same thing with the parse too in the ResponseError.

GideonBature avatar Sep 02 '25 16:09 GideonBature

Resolved merge conflict.

GideonBature avatar Sep 04 '25 09:09 GideonBature