arlyon / async-stripe

Async (and blocking!) Rust bindings for the Stripe API
https://payments.rs
Apache License 2.0
464 stars 131 forks source link

http_types panics on CheckoutSession call in production #566

Open kraemahz opened 4 months ago

kraemahz commented 4 months ago

Describe the bug

I have code that works in stripe test mode but causes a panic when switching to live mode. This is a basic implementation of a checkout session largely transcribed from stripe's other examples for embedded checkout code.

Update: I discovered the problem to be a newline character getting into my API key from the environment due to the way my production server loads its secrets.

thread 'tokio-runtime-worker' panicked at /usr/local/cargo/registry/src/index.crates.io-6f17d22bba15001f/http-types-2.12.0/src/hyperium_http.rs:162:71:
called `Result::unwrap()` on an `Err` value: InvalidHeaderValue
stack backtrace:
   0: rust_begin_unwind
   1: core::panicking::panic_fmt
   2: core::result::unwrap_failed
   3: http_types::hyperium_http::headers_to_hyperium_headers
   4: http_types::hyperium_http::<impl core::convert::From<http_types::request::Request> for http::request::Request<http_types::body::Body>>::from
   5: stripe::client::base::tokio::send_inner::{{closure}}
   6: stripe::client::base::tokio::TokioClient::execute::{{closure}}

I looked into http_types and it seems to be blindly doing an unwrap in this function, likely invoked by an into within send_inner

To Reproduce

  1. Create a checkout session using the provided code
  2. Include a newline character in the stripe API key

Expected behavior

Should not panic

Code snippets

let client = stripe::Client::new(stripe_key);
    let mut params = CreateCheckoutSession::new();
    let auto_tax = CreateCheckoutSessionAutomaticTax {
        enabled: true,
        liability: None,
    };
    let client_reference_id = org.add_checkout_reference(&mut conn).ok();
    params.client_reference_id = client_reference_id.as_deref();

    params.automatic_tax = Some(auto_tax);
    params.ui_mode = Some(stripe::CheckoutSessionUiMode::Embedded);
    params.mode = Some(stripe::CheckoutSessionMode::Subscription);
    params.line_items = Some(vec![stripe::CreateCheckoutSessionLineItems {
        price: Some(plan.price_id),
        quantity: Some(n_users as u64),
        ..Default::default()
    }]);
    let return_url = format!(
        "{}{}?session_id={{CHECKOUT_SESSION_ID}}",
        base_url, STRIPE_RETURN_URI
    );
    params.return_url = Some(&return_url);
    let stripe_session = stripe::CheckoutSession::create(&client, params)
        .await
        .map_err(|_| warp::reject::custom(ParseError {}))?;
    let secret = stripe_session
        .client_secret
        .ok_or_else(|| warp::reject::custom(ParseError {}))?;

OS

linux

Rust version

1.79

Library version

0.37.1

API version

2024-04-10

Additional context

This is happening before I get a tick in the 'api calls' section of Stripe.

kraemahz commented 4 months ago

I figured out my issue, it was related to the configuration of my prod environment. A new line character was sneaking in to the environment variable holding my API key and that's what caused the panic.

I think this is still worth fixing with some checks or coercion, but feel free to close if you don't agree after you see this.

arlyon commented 3 months ago

I think a trim and a warning is probably reasonable. Will open a PR against the next branch