huskies: merge 807

This commit is contained in:
dave
2026-04-28 20:56:17 +00:00
parent 2a77f73ba4
commit 97b9eaa39d
8 changed files with 175 additions and 9 deletions
+26 -1
View File
@@ -12,6 +12,7 @@ pub mod format;
pub mod history;
pub mod meta;
pub mod twilio;
pub mod verify;
pub use history::{MessagingWindowTracker, WhatsAppConversationHistory, load_whatsapp_history};
pub use meta::WhatsAppTransport;
@@ -121,6 +122,10 @@ pub struct WhatsAppWebhookContext {
/// Phone numbers allowed to send messages to the bot.
/// When empty, all numbers are allowed (backwards compatible).
pub allowed_phones: Vec<String>,
/// Meta app secret for `X-Hub-Signature-256` HMAC verification.
/// When non-empty, every inbound POST is verified against this secret.
/// When empty, signature verification is skipped.
pub app_secret: String,
}
/// GET /webhook/whatsapp — webhook verification.
@@ -158,13 +163,16 @@ pub async fn webhook_verify(
/// - `"twilio"`: parses Twilio's `application/x-www-form-urlencoded` body.
///
/// Both providers expect a `200 OK` response, even on parse errors.
///
/// For the `"meta"` provider, the `X-Hub-Signature-256` header is verified
/// against the configured app secret (HMAC-SHA256). Requests with a missing
/// or invalid signature are rejected with `401`/`403` respectively.
#[handler]
pub async fn webhook_receive(
req: &Request,
body: poem::Body,
ctx: poem::web::Data<&Arc<WhatsAppWebhookContext>>,
) -> Response {
let _ = req;
let bytes = match body.into_bytes().await {
Ok(b) => b,
Err(e) => {
@@ -175,6 +183,23 @@ pub async fn webhook_receive(
}
};
// Verify HMAC-SHA256 signature for Meta webhooks when an app secret is configured.
if ctx.provider != "twilio" && !ctx.app_secret.is_empty() {
let signature = req.header("X-Hub-Signature-256").unwrap_or("");
if signature.is_empty() {
slog!("[whatsapp] Missing X-Hub-Signature-256 header; rejecting request");
return Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body("Missing signature");
}
if !verify::verify_meta_signature(&ctx.app_secret, &bytes, signature) {
slog!("[whatsapp] X-Hub-Signature-256 verification failed; rejecting request");
return Response::builder()
.status(StatusCode::FORBIDDEN)
.body("Invalid signature");
}
}
let messages = if ctx.provider == "twilio" {
let msgs = extract_twilio_text_messages(&bytes);
if msgs.is_empty() {