119 lines
3.3 KiB
Rust
119 lines
3.3 KiB
Rust
//! Common webhook handler utilities
|
|
|
|
use crate::webhook::types::{WebhookConfig, WebhookError};
|
|
use actix_web::http::header::HeaderMap;
|
|
|
|
/// Application state for webhook handling
|
|
#[derive(Clone)]
|
|
pub struct WebhookAppState {
|
|
pub config: WebhookConfig,
|
|
pub redis_url: String,
|
|
pub caller_id: String,
|
|
pub worker_id: String,
|
|
}
|
|
|
|
/// Create webhook application state
|
|
pub fn create_webhook_app_state(
|
|
config: WebhookConfig,
|
|
redis_url: String,
|
|
worker_id: String,
|
|
) -> WebhookAppState {
|
|
// For now, we'll use the worker_id as the caller_id for webhooks.
|
|
// This can be changed if a more specific caller_id is needed.
|
|
let caller_id = worker_id.clone();
|
|
|
|
WebhookAppState {
|
|
config,
|
|
redis_url,
|
|
caller_id,
|
|
worker_id,
|
|
}
|
|
}
|
|
|
|
/// Extract signature from request headers with the given header name
|
|
pub fn extract_signature_header(
|
|
headers: &HeaderMap,
|
|
header_name: &str,
|
|
) -> Result<String, WebhookError> {
|
|
match headers.get(header_name) {
|
|
Some(sig) => match sig.to_str() {
|
|
Ok(s) => Ok(s.to_string()),
|
|
Err(_) => Err(WebhookError::InvalidSignature(format!(
|
|
"Invalid {} header format", header_name
|
|
))),
|
|
},
|
|
None => Err(WebhookError::InvalidSignature(format!(
|
|
"Missing {} header", header_name
|
|
))),
|
|
}
|
|
}
|
|
|
|
/// Create a standard error response for webhook failures
|
|
pub fn create_error_response(error: &str, details: Option<String>) -> serde_json::Value {
|
|
let mut response = serde_json::json!({
|
|
"error": error
|
|
});
|
|
|
|
if let Some(details) = details {
|
|
response["details"] = serde_json::Value::String(details);
|
|
}
|
|
|
|
response
|
|
}
|
|
|
|
/// Create a standard success response for webhook processing
|
|
pub fn create_success_response(
|
|
message: &str,
|
|
additional_fields: Option<serde_json::Map<String, serde_json::Value>>,
|
|
) -> serde_json::Value {
|
|
let mut response = serde_json::json!({
|
|
"success": true,
|
|
"message": message
|
|
});
|
|
|
|
if let Some(fields) = additional_fields {
|
|
for (key, value) in fields {
|
|
response[key] = value;
|
|
}
|
|
}
|
|
|
|
response
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use actix_web::http::header::HeaderName;
|
|
|
|
#[test]
|
|
fn test_extract_signature_header_success() {
|
|
let mut headers = HeaderMap::new();
|
|
headers.insert(HeaderName::from_static("test-signature"), "test_value".parse().unwrap());
|
|
|
|
let result = extract_signature_header(&headers, "test-signature");
|
|
assert!(result.is_ok());
|
|
assert_eq!(result.unwrap(), "test_value");
|
|
}
|
|
|
|
#[test]
|
|
fn test_extract_signature_header_missing() {
|
|
let headers = HeaderMap::new();
|
|
|
|
let result = extract_signature_header(&headers, "missing-header");
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_create_error_response() {
|
|
let response = create_error_response("Test error", Some("Test details".to_string()));
|
|
assert_eq!(response["error"], "Test error");
|
|
assert_eq!(response["details"], "Test details");
|
|
}
|
|
|
|
#[test]
|
|
fn test_create_success_response() {
|
|
let response = create_success_response("Test success", None);
|
|
assert_eq!(response["success"], true);
|
|
assert_eq!(response["message"], "Test success");
|
|
}
|
|
} |