mirror of
https://github.com/mailscope/kumomta.git
synced 2026-09-13 05:52:13 +00:00
http injection: fix auth_info regression for deferred_generation
This commit fixes a regression introduced as part of the updated AAA/ACL code. Since that code has not shipped in a stable release, this is not being entered into the changelog. The issue was that when processing the deferred payloads, we were trying to parse the `auth_info` key from the metadata as though it were a json-serialized-string, but it was in fact already parsed and was actually a json object. This resulted in a runtime error that caused the message to be logged as a Bounce like: ``` expected 'auth_info' to be a string value, got Ok(Object (..)) ``` This commit adds an explicit integration test for deferred generation so that we can catch this sort of thing more easily moving forwards, as well as resolves this issue.
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
use crate::kumod::DaemonWithMaildir;
|
||||
use anyhow::Context;
|
||||
use k9::assert_equal;
|
||||
use std::time::Duration;
|
||||
|
||||
/// Test HTTP injection with gzip compressed request body
|
||||
#[tokio::test]
|
||||
async fn http_inject_deferred() -> anyhow::Result<()> {
|
||||
let mut daemon = DaemonWithMaildir::start()
|
||||
.await
|
||||
.context("DaemonWithMaildir::start")?;
|
||||
|
||||
let payload = serde_json::json!({
|
||||
"envelope_sender": "sender@example.com",
|
||||
"recipients": [
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"name": "Test User"
|
||||
}
|
||||
],
|
||||
"deferred_generation": true,
|
||||
"content": {
|
||||
"text_body": "Hello {{ name }}! This is a message.",
|
||||
"subject": "Deferred Generation Test"
|
||||
}
|
||||
});
|
||||
|
||||
let json_data = serde_json::to_vec(&payload)?;
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let response = client
|
||||
.post(&format!(
|
||||
"http://{}/api/inject/v1",
|
||||
daemon.source.listener("http")
|
||||
))
|
||||
.header("Content-Type", "application/json")
|
||||
.body(json_data)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
anyhow::ensure!(
|
||||
response.status() == 200,
|
||||
"Response status: {}",
|
||||
response.status()
|
||||
);
|
||||
let response_json: serde_json::Value = response.json().await?;
|
||||
eprintln!("response: {response_json:?}");
|
||||
assert_equal!(
|
||||
response_json["success_count"],
|
||||
0,
|
||||
"deferred always shows zero"
|
||||
);
|
||||
assert_equal!(response_json["fail_count"], 0);
|
||||
|
||||
daemon
|
||||
.wait_for_maildir_count(1, Duration::from_secs(10))
|
||||
.await;
|
||||
|
||||
daemon.stop_both().await.context("stop_both")?;
|
||||
println!("Stopped!");
|
||||
|
||||
let delivery_summary = daemon.dump_logs().await.context("dump_logs")?;
|
||||
k9::snapshot!(
|
||||
delivery_summary,
|
||||
"
|
||||
DeliverySummary {
|
||||
source_counts: {
|
||||
Reception: 2,
|
||||
Delivery: 2,
|
||||
},
|
||||
sink_counts: {
|
||||
Reception: 1,
|
||||
Delivery: 1,
|
||||
},
|
||||
}
|
||||
"
|
||||
);
|
||||
|
||||
daemon.assert_no_acct_deny().await?;
|
||||
let mut messages = daemon.extract_maildir_messages()?;
|
||||
assert_equal!(messages.len(), 1);
|
||||
let parsed = messages[0].parsed()?;
|
||||
|
||||
// Verify the message content was properly expanded
|
||||
let body = parsed.body().unwrap();
|
||||
match body {
|
||||
mailparsing::DecodedBody::Text(text) => {
|
||||
assert!(text.contains("Hello Test User!"));
|
||||
assert!(text.contains("This is a message"));
|
||||
}
|
||||
_ => panic!("Expected text body"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -15,6 +15,7 @@ mod end_to_end_webhook_batch;
|
||||
mod expires;
|
||||
mod http_auth;
|
||||
mod http_inject_compression;
|
||||
mod http_inject_deferred;
|
||||
mod http_inject_size_limit;
|
||||
mod log_oob_arf;
|
||||
mod maildir_batch;
|
||||
|
||||
@@ -979,9 +979,10 @@ impl HttpInjectionGeneratorDispatcher {
|
||||
.ok_or_else(|| anyhow::anyhow!("received_from metadata is missing!?"))?
|
||||
.parse()?;
|
||||
|
||||
let auth_info: AuthInfo = match msg.get_meta_string("auth_info").await? {
|
||||
Some(info) => serde_json::from_str(&info)?,
|
||||
None => {
|
||||
let auth_info: AuthInfo = match msg.get_meta("auth_info").await? {
|
||||
obj @ serde_json::Value::Object(_) => serde_json::from_value(obj)
|
||||
.context("auth_info should be the json repr of AuthInfo")?,
|
||||
serde_json::Value::Null => {
|
||||
// We might not have auth_info serialized in the metadata
|
||||
// if we are upgrading from a prior version that did not
|
||||
// support AuthInfo, so default it to something approximating
|
||||
@@ -990,6 +991,9 @@ impl HttpInjectionGeneratorDispatcher {
|
||||
auth_info.set_peer_address(Some(peer_address));
|
||||
auth_info
|
||||
}
|
||||
other => {
|
||||
anyhow::bail!("expected optional `auth_info` object, but got {other:?}")
|
||||
}
|
||||
};
|
||||
|
||||
let via_address = match msg.get_meta_string("received_via").await {
|
||||
|
||||
Reference in New Issue
Block a user