uselesskey-webhook 0.9.1

Deterministic webhook fixtures for GitHub, Stripe, and Slack signature tests.
Documentation
use crate::{WebhookPayloadSpec, WebhookProfile};

pub(crate) fn stable_spec_bytes(
    profile: WebhookProfile,
    payload_spec: &WebhookPayloadSpec,
) -> Vec<u8> {
    let mut out = profile.stable_tag().as_bytes().to_vec();
    out.push(0);
    out.extend_from_slice(&payload_spec.stable_bytes());
    out
}

pub(crate) fn canonical_payload(
    profile: WebhookProfile,
    label: &str,
    payload_spec: WebhookPayloadSpec,
    nonce: u32,
) -> String {
    match payload_spec {
        WebhookPayloadSpec::Raw(payload) => payload,
        WebhookPayloadSpec::Canonical => provider_canonical_payload(profile, label, nonce),
    }
}

fn provider_canonical_payload(profile: WebhookProfile, label: &str, nonce: u32) -> String {
    match profile {
        WebhookProfile::GitHub => github_payload(label, nonce),
        WebhookProfile::Stripe => stripe_payload(label, nonce),
        WebhookProfile::Slack => slack_payload(label, nonce),
    }
}

fn github_payload(label: &str, nonce: u32) -> String {
    let repository = json_string(&format!("acme/{label}"));
    format!(
        "{{\"action\":\"opened\",\"repository\":{{\"full_name\":{repository}}},\"number\":{}}}",
        (nonce % 9000) + 1000
    )
}

fn stripe_payload(label: &str, nonce: u32) -> String {
    let label = json_string(label);
    let mut payload = format!(
        "{{\"id\":\"evt_{nonce:08x}\",\"type\":\"checkout.session.completed\",\"data\":{{\"object\":{{\"metadata\":{{\"label\":"
    );
    payload.push_str(&label);
    payload.push_str("}}}}");
    payload
}

fn slack_payload(label: &str, nonce: u32) -> String {
    let text = json_string(&format!("ping {label}"));
    format!(
        "{{\"type\":\"event_callback\",\"team_id\":\"T{nonce:08x}\",\"event\":{{\"type\":\"app_mention\",\"text\":{text}}}}}"
    )
}

fn json_string(value: &str) -> String {
    serde_json::Value::String(value.to_string()).to_string()
}