//! Verify HTTP signatures
use std::collections::HashMap;

use chrono::{DateTime, TimeDelta, TimeZone, Utc};
use http::{HeaderMap, Method, Uri};
use indexmap::IndexMap;
use regex::Regex;
use sfv::{
    BareItem,
    Item,
    ListEntry,
    Parser,
    SerializeValue,
};
use thiserror::Error;

use crate::{
    base64,
    crypto::{
        common::PublicKey,
        eddsa::verify_eddsa_signature,
        rsa::verify_rsa_sha256_signature,
    },
    http_digest::{
        parse_digest_header,
        parse_content_digest_header,
        ContentDigest,
    },
    http_utils::remove_quotes,
};

pub use crate::json_signatures::verify::VerificationMethod;

const SIGNATURE_PARAMETER_RE: &str = r#"^(?P<key>[a-zA-Z]+)=(?P<value>.+)$"#;

const SIGNATURE_EXPIRES_IN: i64 = 12; // 12 hours

const REQUIRED_COMPONENTS_CAVAGE: [&str; 2] = ["(request-target)", "host"];
const REQUIRED_COMPONENTS_RFC9421: [&str; 2] = ["@method", "@target-uri"];

// Component IDs are lower case
const HEADER_DIGEST: &str = "digest";
const HEADER_CONTENT_DIGEST: &str = "content-digest";

/// Errors that may occur during signature verification
#[derive(Debug, Error)]
pub enum HttpSignatureVerificationError {
    #[error("missing signature header")]
    NoSignature,

    #[error("missing header '{0}'")]
    MissingHeader(String),

    #[error("invalid header '{0}': {1}")]
    InvalidHeader(String, &'static str),

    #[error("{0}")]
    ParseError(&'static str),

    #[error("missing component {0}")]
    MissingComponent(&'static str),

    #[error("unsupported component {0}")]
    UnsupportedComponent(String),

    #[error("invalid encoding")]
    InvalidEncoding(#[from] base64::DecodeError),

    #[error("signature has expired")]
    Expired,

    #[error("missing content digest")]
    NoDigest,

    #[error("digest mismatch")]
    DigestMismatch,

    #[error("invalid signature")]
    InvalidSignature,
}

impl HttpSignatureVerificationError {
    fn header_missing(header_name: &str) -> Self {
        Self::MissingHeader(header_name.to_owned())
    }

    fn header_value(header_name: &str) -> Self {
        Self::InvalidHeader(header_name.to_owned(), "invalid value")
    }
}

type VerificationError = HttpSignatureVerificationError;

/// Parsed HTTP signature
pub struct HttpSignatureData {
    pub is_rfc9421: bool,
    pub key_id: VerificationMethod,
    pub base: String, // recreated signature base
    pub signature: Vec<u8>,
    pub expires_at: DateTime<Utc>,
    /// The authority of the target URI
    pub authority: String,
    pub content_digest: Option<ContentDigest>,
}

// Returns header name and its parsed value.
// The header name should be added to the list of required components.
fn get_content_digest(
    method: &Method,
    headers: &HeaderMap,
    components: &[&str],
) -> Result<Option<(&'static str, ContentDigest)>, VerificationError> {
    let (Method::POST | Method::PUT | Method::PATCH) = *method else {
        return Ok(None);
    };
    // Prefer signed header over unsigned.
    // Prefer Content-Digest over Digest.
    let header_name = if components.contains(&HEADER_CONTENT_DIGEST) {
        HEADER_CONTENT_DIGEST
    } else if components.contains(&HEADER_DIGEST) {
        HEADER_DIGEST
    } else if headers.contains_key(HEADER_CONTENT_DIGEST) {
        HEADER_CONTENT_DIGEST
    } else {
        HEADER_DIGEST
    };
    let Some(header_value) = headers.get(header_name) else {
        return Err(VerificationError::NoDigest);
    };
    let header_value = header_value
        .to_str()
        .map_err(|_| VerificationError::header_value(header_name))?;
    let parse_header = match header_name {
        HEADER_DIGEST => parse_digest_header,
        HEADER_CONTENT_DIGEST => parse_content_digest_header,
        _ => unreachable!(),
    };
    let content_digest = parse_header(header_value)
        .map_err(|error| VerificationError::InvalidHeader(
            header_name.to_owned(),
            error,
        ))?;
    Ok(Some((header_name, content_digest)))
}

fn check_required_components(
    components: &[&str],
    required: &[&'static str],
) -> Result<(), VerificationError> {
    for component_id in required {
        if !components.contains(component_id) {
            return Err(VerificationError::MissingComponent(component_id));
        };
    };
    Ok(())
}

/// Parses Draft-Cavage HTTP signature  
/// <https://datatracker.ietf.org/doc/html/draft-cavage-http-signatures>
pub fn parse_http_signature_cavage(
    request_method: &Method,
    request_uri: &Uri,
    request_headers: &HeaderMap,
) -> Result<HttpSignatureData, VerificationError> {
    // Parse Signature header
    let signature_header = request_headers.get("signature")
        .ok_or(VerificationError::NoSignature)?
        .to_str()
        .map_err(|_| VerificationError::header_value("Signature"))?;

    let signature_parameter_re = Regex::new(SIGNATURE_PARAMETER_RE)
        .expect("regexp should be valid");
    let mut signature_parameters = HashMap::new();
    for item in signature_header.split(',') {
        let caps = signature_parameter_re.captures(item)
            .ok_or(VerificationError::header_value("Signature"))?;
        let key = caps["key"].to_string();
        let value = remove_quotes(&caps["value"]);
        signature_parameters.insert(key, value);
    };

    let key_id_str = signature_parameters.get("keyId")
        .ok_or(VerificationError::ParseError("keyId parameter is missing"))?;
    let key_id = VerificationMethod::parse(key_id_str)
        .map_err(|_| VerificationError::ParseError("invalid key ID"))?;
    let headers_parameter = signature_parameters.get("headers")
        .ok_or(VerificationError::ParseError("headers parameter is missing"))?
        .to_owned();
    let signature_b64 = signature_parameters.get("signature")
        .ok_or(VerificationError::ParseError("signature is missing"))?;
    let signature = base64::decode(signature_b64)?;
    let target_authority = request_headers.get("Host")
        .ok_or(VerificationError::header_missing("Host"))?
        .to_str()
        .map_err(|_| VerificationError::header_value("Host"))?
        .to_string();
    let created_at = if let Some(created_at) = signature_parameters.get("created") {
        let create_at_timestamp = created_at.parse()
            .map_err(|_| VerificationError::ParseError("invalid timestamp"))?;
        Utc.timestamp_opt(create_at_timestamp, 0).single()
            .ok_or(VerificationError::ParseError("invalid timestamp"))?
    } else {
        let date_str = request_headers.get("date")
            .ok_or(VerificationError::header_missing("Date"))?
            .to_str()
            .map_err(|_| VerificationError::header_value("Date"))?;
        let date = DateTime::parse_from_rfc2822(date_str)
            .map_err(|_| VerificationError::header_value("Date"))?;
        date.with_timezone(&Utc)
    };
    let expires_at = if let Some(expires_at) = signature_parameters.get("expires") {
        let expires_at_timestamp = expires_at.parse()
            .map_err(|_| VerificationError::ParseError("invalid timestamp"))?;
        Utc.timestamp_opt(expires_at_timestamp, 0).single()
            .ok_or(VerificationError::ParseError("invalid timestamp"))?
    } else {
        created_at + TimeDelta::hours(SIGNATURE_EXPIRES_IN)
    };

    let signed_headers: Vec<_> = headers_parameter.split(' ').collect();
    let mut required_components = REQUIRED_COMPONENTS_CAVAGE.to_vec();
    let maybe_digest = get_content_digest(
        request_method,
        request_headers,
        &signed_headers,
    )?
        .map(|(header_name, content_digest)| {
            required_components.push(header_name);
            content_digest
        });
    check_required_components(
        &signed_headers,
        &required_components,
    )?;

    // Recreate signature base
    let mut signature_base_entries = IndexMap::new();
    for header in signed_headers {
        let header_value = if header == "(request-target)" {
            format!(
                "{} {}",
                request_method.as_str().to_lowercase(),
                request_uri.path(),
            )
        } else if header == "(created)" {
            signature_parameters.get("created")
                .ok_or(VerificationError::ParseError("created parameter is missing"))?
                .clone()
        } else if header == "(expires)" {
            signature_parameters.get("expires")
                .ok_or(VerificationError::ParseError("expires parameter is missing"))?
                .clone()
        } else {
            request_headers.get(header)
                .ok_or(VerificationError::header_missing(header))?
                .to_str()
                .map_err(|_| VerificationError::header_value(header))?
                .to_owned()
        };
        signature_base_entries.insert(header, header_value);
    };
    let signature_base = signature_base_entries
        .into_iter()
        .map(|(id, value)| format!("{id}: {value}"))
        .collect::<Vec<_>>()
        .join("\n");

    let signature_data = HttpSignatureData {
        key_id,
        base: signature_base,
        signature,
        expires_at,
        authority: target_authority,
        content_digest: maybe_digest,
        is_rfc9421: false,
    };
    Ok(signature_data)
}

/// Parses RFC-9421 HTTP message signature  
/// <https://www.rfc-editor.org/rfc/rfc9421>
pub fn parse_http_signature_rfc9421(
    request_method: &Method,
    request_uri: &Uri,
    request_headers: &HeaderMap,
    ignore_required_components: bool,
) -> Result<HttpSignatureData, VerificationError> {
    // Parse Signature header
    let signature_header = request_headers.get("Signature")
        .ok_or(VerificationError::NoSignature)?
        .to_str()
        .map_err(|_| VerificationError::header_value("Signature"))?;
    let signature_dict = Parser::new(signature_header.as_bytes())
        .parse_dictionary()
        .map_err(|_| VerificationError::ParseError("invalid 'signature' dictionary"))?;
    let (signature_label, signature_value_item) = signature_dict.first()
        .ok_or(VerificationError::ParseError("invalid 'signature' dictionary"))?;
    let signature_value = match signature_value_item {
        ListEntry::Item(Item { bare_item: BareItem::ByteSequence(value), .. }) => {
            value.clone()
        },
        _ => return Err(VerificationError::ParseError("invalid signature value")),
    };

    // Parse Signature-Input header
    let signature_input_header = request_headers.get("Signature-Input")
        .ok_or(VerificationError::NoSignature)?
        .to_str()
        .map_err(|_| VerificationError::header_value("Signature-Input"))?;
    let signature_input_dict = Parser::new(signature_input_header.as_bytes())
        .parse_dictionary()
        .map_err(|_| VerificationError::ParseError("invalid 'signature-input' dictionary"))?;
    let signature_param_list = signature_input_dict.get(signature_label)
        .ok_or(VerificationError::ParseError("signature parameters not found"))?;
    let signature_params = vec![signature_param_list.clone()]
        .serialize_value()
        .map_err(|_| VerificationError::ParseError("serialization error"))?;
    let ListEntry::InnerList(signature_param_list) = signature_param_list else {
        return Err(VerificationError::ParseError("invalid encoding of signature parameters"));
    };
    let key_id = signature_param_list.params.get("keyid")
        .ok_or(VerificationError::ParseError("parameter 'keyid' not found"))?
        .as_string()
        .ok_or(VerificationError::ParseError("invalid encoding of 'keyid'"))?;
    let key_id = VerificationMethod::parse(key_id.as_str())
        .map_err(|_| VerificationError::ParseError("invalid key ID"))?;
    let expires_at = if let Some(expires_item) = signature_param_list.params.get("expires") {
        let expires = expires_item.as_integer()
            .ok_or(VerificationError::ParseError("invalid encoding of 'expires'"))?
            .into();
        Utc.timestamp_opt(expires, 0).single()
            .ok_or(VerificationError::ParseError("invalid timestamp"))?
    } else {
        let created = signature_param_list.params.get("created")
            .ok_or(VerificationError::ParseError("parameter 'created' not found"))?
            .as_integer()
            .ok_or(VerificationError::ParseError("invalid encoding of 'created'"))?
            .into();
        let created_at = Utc.timestamp_opt(created, 0).single()
            .ok_or(VerificationError::ParseError("invalid timestamp"))?;
        created_at + TimeDelta::hours(SIGNATURE_EXPIRES_IN)
    };
    let mut components = vec![];
    for list_item in &signature_param_list.items {
        let component_id = list_item.bare_item.as_string()
            .ok_or(VerificationError::ParseError("invalid encoding of signature parameter"))?
            .as_str();
        components.push(component_id);
    };
    let target_authority = request_uri.authority()
        .ok_or(VerificationError::ParseError("incomplete request URI"))?
        .to_string();

    let mut required_components = REQUIRED_COMPONENTS_RFC9421.to_vec();
    let maybe_digest = get_content_digest(
        request_method,
        request_headers,
        &components,
    )?
        .map(|(header_name, content_digest)| {
            required_components.push(header_name);
            content_digest
        });
    if !ignore_required_components {
        check_required_components(&components, &required_components)?;
    };

    // Recreate signature base
    let mut signature_base_entries = IndexMap::new();
    for component_id in components {
        if signature_base_entries.contains_key(component_id) {
            return Err(VerificationError::ParseError("duplicate component"));
        };
        let component_value = match component_id {
            "@method" => {
                request_method.to_string()
            },
            "@target-uri" => {
                request_uri.to_string()
            },
            "@request-target" => {
                // https://datatracker.ietf.org/doc/html/rfc9421#name-request-target
                let mut request_target = request_uri.path().to_owned();
                if let Some(query) = request_uri.query() {
                    request_target += &format!("?{query}");
                };
                request_target
            },
            "@path" => {
                request_uri.path().to_owned()
            },
            "@query" => {
                // https://www.rfc-editor.org/rfc/rfc9421#name-query
                let query = request_uri.query().unwrap_or_default();
                format!("?{query}")
            },
            "@authority" => {
                // https://www.rfc-editor.org/rfc/rfc9421#name-authority
                target_authority.clone()
            },
            id if id.starts_with('@') => {
                return Err(VerificationError::UnsupportedComponent(id.to_owned()));
            },
            _ => {
                request_headers.get(component_id)
                    .ok_or(VerificationError::header_missing(component_id))?
                    .to_str()
                    .map_err(|_| VerificationError::header_value(component_id))?
                    .to_owned()
            },
        };
        signature_base_entries.insert(component_id, component_value);
    };
    signature_base_entries.insert("@signature-params", signature_params);
    let signature_base = signature_base_entries
        .into_iter()
        .map(|(id, value)| format!(r#""{id}": {value}"#))
        .collect::<Vec<_>>()
        .join("\n");

    let signature_data = HttpSignatureData {
        key_id,
        base: signature_base,
        signature: signature_value,
        expires_at,
        authority: target_authority,
        content_digest: maybe_digest,
        is_rfc9421: true,
    };
    Ok(signature_data)
}

/// Parses Draft-Cavage HTTP signature or RFC-9421 HTTP message signature
pub fn parse_http_signature(
    method: &Method,
    uri: &Uri,
    headers: &HeaderMap,
) -> Result<HttpSignatureData, VerificationError> {
    if headers.get("Signature-Input").is_some() {
        parse_http_signature_rfc9421(
            method, uri, headers,
            false, // check required components
        )
    } else {
        parse_http_signature_cavage(method, uri, headers)
    }
}

/// Verifies HTTP signature
pub fn verify_http_signature(
    signature_data: &HttpSignatureData,
    signer_key: &PublicKey,
    content_digest: Option<ContentDigest>,
) -> Result<(), VerificationError> {
    if signature_data.expires_at < Utc::now() {
        return Err(VerificationError::Expired);
    };
    if signature_data.content_digest != content_digest {
        return Err(VerificationError::DigestMismatch);
    };
    let is_valid_signature = match signer_key {
        PublicKey::Ed25519(ed25519_key) => {
            verify_eddsa_signature(
                ed25519_key,
                signature_data.base.as_bytes(),
                &signature_data.signature,
            ).is_ok()
        },
        PublicKey::Rsa(rsa_key) => {
            verify_rsa_sha256_signature(
                rsa_key,
                signature_data.base.as_bytes(),
                &signature_data.signature,
            ).is_ok()
        },
    };
    if !is_valid_signature {
        return Err(VerificationError::InvalidSignature);
    };
    Ok(())
}

#[cfg(test)]
mod tests {
    use http::{HeaderName, HeaderValue};
    use crate::{
        crypto::{
            eddsa::generate_weak_ed25519_key,
            rsa::generate_weak_rsa_key,
        },
        http_signatures::create::{
            create_http_signature_cavage,
            create_http_signature_rfc9421,
            HttpSigner,
        },
    };
    use super::*;

    #[test]
    fn test_error_missing_header() {
        let error = HttpSignatureVerificationError::header_missing("Date");
        assert_eq!(error.to_string(), "missing header 'Date'");
    }

    #[test]
    fn test_error_invalid_header() {
        let error = HttpSignatureVerificationError::header_value("Date");
        assert_eq!(error.to_string(), "invalid header 'Date': invalid value");
    }

    #[test]
    fn test_parse_http_signature_cavage() {
        let request_method = Method::GET;
        let request_uri = "/user/123/inbox".parse::<Uri>().unwrap();
        let date = "20 Oct 2022 20:00:00 GMT";
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("host"),
            HeaderValue::from_static("verifier.example"),
        );
        request_headers.insert(
            HeaderName::from_static("date"),
            HeaderValue::from_str(date).unwrap(),
        );
        let signature_header = concat!(
            r#"keyId="https://signer.example/actor#main-key","#,
            r#"algorithm=hs2019,"#,
            r#"headers="(request-target) host date","#,
            r#"signature="test""#,
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_static(signature_header),
        );

        let signature_data = parse_http_signature_cavage(
            &request_method,
            &request_uri,
            &request_headers,
        ).unwrap();
        assert_eq!(signature_data.is_rfc9421, false);
        assert_eq!(
            signature_data.key_id.to_string(),
            "https://signer.example/actor#main-key",
        );
        assert_eq!(
            signature_data.base,
            "(request-target): get /user/123/inbox\nhost: verifier.example\ndate: 20 Oct 2022 20:00:00 GMT",
        );
        assert_eq!(signature_data.signature, [181, 235, 45]);
        assert!(signature_data.expires_at < Utc::now());
        assert!(signature_data.content_digest.is_none());
    }

    #[test]
    fn test_parse_http_signature_rfc9421() {
        // https://www.rfc-editor.org/rfc/rfc9421#name-signing-a-request-using-ed2
        let request_method = Method::POST;
        let request_uri = "https://example.com/foo?param=Value&Pet=dog".parse::<Uri>().unwrap();
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("date"),
            HeaderValue::from_static("Tue, 20 Apr 2021 02:07:55 GMT"),
        );
        request_headers.insert(
            HeaderName::from_static("content-type"),
            HeaderValue::from_static("application/json"),
        );
        request_headers.insert(
            HeaderName::from_static("content-digest"),
            HeaderValue::from_static("sha-512=:WZDPaVn/7XgHaAy8pmojAkGWoRx2UFChF41A2svX+TaPm+AbwAgBWnrIiYllu7BNNyealdVLvRwEmTHWXvJwew==:"),
        );
        request_headers.insert(
            HeaderName::from_static("content-length"),
            HeaderValue::from_static("18"),
        );
        // Key ID is different from the RFC test vector
        request_headers.insert(
            HeaderName::from_static("signature-input"),
            HeaderValue::from_static(r#"sig-b26=("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="https://example.com/actor#test-key-ed25519""#),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_static("sig-b26=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:"),
        );
        let signature_data = parse_http_signature_rfc9421(
            &request_method,
            &request_uri,
            &request_headers,
            true, // ignore required components
        ).unwrap();

        let expected_signature_base =
r#""date": Tue, 20 Apr 2021 02:07:55 GMT
"@method": POST
"@path": /foo
"@authority": example.com
"content-type": application/json
"content-length": 18
"@signature-params": ("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="https://example.com/actor#test-key-ed25519""#;
        assert_eq!(signature_data.is_rfc9421, true);
        assert_eq!(signature_data.base, expected_signature_base);
        assert_eq!(signature_data.content_digest.is_some(), true);
    }

    #[test]
    fn test_parse_http_signature_rfc9421_missing_content_digest_header() {
        let request_method = Method::POST;
        let request_uri = Uri::from_static("https://verifier.example/inbox");
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("signature-input"),
            HeaderValue::from_static(r#"sig-b26=("@method" "@target-uri" "content-digest");created=1618884473;keyid="https://signer.example/key""#),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_static("sig-b26=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:"),
        );
        let error = parse_http_signature_rfc9421(
            &request_method,
            &request_uri,
            &request_headers,
            false,
        ).err().unwrap();
        assert_eq!(error.to_string(), "missing content digest");
    }

    #[test]
    fn test_create_and_verify_signature_cavage_get() {
        let request_method = Method::GET;
        let request_url = "https://verifier.example/private/object";
        let signer_key = generate_weak_rsa_key().unwrap();
        let signer_key_id = "https://signer.example/actor#main-key".to_string();
        let signer = HttpSigner::new_rsa(signer_key, signer_key_id);
        let signed_headers = create_http_signature_cavage(
            request_method.clone(),
            request_url,
            None,
            &signer,
        ).unwrap();

        let request_uri = request_url.parse::<Uri>().unwrap();
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("host"),
            HeaderValue::from_str(&signed_headers.host).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_str(&signed_headers.signature).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("date"),
            HeaderValue::from_str(&signed_headers.date).unwrap(),
        );
        let signature_data = parse_http_signature_cavage(
            &request_method,
            &request_uri,
            &request_headers,
        ).unwrap();
        assert_eq!(signature_data.content_digest.is_some(), false);

        let signer_public_key = signer.key.public_key();
        let result = verify_http_signature(
            &signature_data,
            &signer_public_key,
            None,
        );
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_create_and_verify_signature_cavage_post() {
        let request_method = Method::POST;
        let request_url = "https://verifier.example/inbox";
        let request_body = "{}";
        let signer_key = generate_weak_rsa_key().unwrap();
        let signer_key_id = "https://signer.example/actor#main-key".to_string();
        let signer = HttpSigner::new_rsa(signer_key, signer_key_id);
        let signed_headers = create_http_signature_cavage(
            request_method.clone(),
            request_url,
            Some(request_body.as_bytes()),
            &signer,
        ).unwrap();

        let request_uri = request_url.parse::<Uri>().unwrap();
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("host"),
            HeaderValue::from_str(&signed_headers.host).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_str(&signed_headers.signature).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("date"),
            HeaderValue::from_str(&signed_headers.date).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("digest"),
            HeaderValue::from_str(&signed_headers.digest.unwrap()).unwrap(),
        );
        let signature_data = parse_http_signature_cavage(
            &request_method,
            &request_uri,
            &request_headers,
        ).unwrap();
        assert_eq!(signature_data.content_digest.is_some(), true);

        let signer_public_key = signer.key.public_key();
        let content_digest = ContentDigest::new(request_body.as_bytes());
        let result = verify_http_signature(
            &signature_data,
            &signer_public_key,
            Some(content_digest),
        );
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_create_and_verify_signature_cavage_post_eddsa() {
        let request_method = Method::POST;
        let request_url = "https://verifier.example/inbox";
        let request_body = "{}";
        let signer_key = generate_weak_ed25519_key();
        let signer_key_id = "https://signer.example/actor#ed25519-key".to_string();
        let signer = HttpSigner::new_ed25519(signer_key, signer_key_id);
        let signed_headers = create_http_signature_cavage(
            request_method.clone(),
            request_url,
            Some(request_body.as_bytes()),
            &signer,
        ).unwrap();

        let request_url = request_url.parse::<Uri>().unwrap();
        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("host"),
            HeaderValue::from_str(&signed_headers.host).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_str(&signed_headers.signature).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("date"),
            HeaderValue::from_str(&signed_headers.date).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("digest"),
            HeaderValue::from_str(&signed_headers.digest.unwrap()).unwrap(),
        );
        let signature_data = parse_http_signature_cavage(
            &request_method,
            &request_url,
            &request_headers,
        ).unwrap();
        assert_eq!(signature_data.content_digest.is_some(), true);

        let signer_public_key = signer.key.public_key();
        let content_digest = ContentDigest::new(request_body.as_bytes());
        let result = verify_http_signature(
            &signature_data,
            &signer_public_key,
            Some(content_digest),
        );
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_create_and_verify_signature_rfc9421_post() {
        let request_method = Method::POST;
        let request_uri = Uri::from_static("https://verifier.example/inbox");
        let request_body = "{}";
        let signer_key = generate_weak_ed25519_key();
        let signer_key_id = "https://signer.example/actor#main-key".to_string();
        let signer = HttpSigner::new_ed25519(signer_key, signer_key_id);
        let signed_headers = create_http_signature_rfc9421(
            request_method.clone(),
            &request_uri.to_string(),
            Some(request_body.as_bytes()),
            &signer,
        ).unwrap();

        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("content-digest"),
            HeaderValue::from_str(&signed_headers.content_digest.unwrap()).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature-input"),
            HeaderValue::from_str(&signed_headers.signature_input).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_str(&signed_headers.signature).unwrap(),
        );
        let signature_data = parse_http_signature_rfc9421(
            &request_method,
            &request_uri,
            &request_headers,
            false,
        ).unwrap();
        assert_eq!(signature_data.content_digest.is_some(), true);

        let signer_public_key = signer.key.public_key();
        let content_digest = ContentDigest::new(request_body.as_bytes());
        let result = verify_http_signature(
            &signature_data,
            &signer_public_key,
            Some(content_digest),
        );
        assert_eq!(result.is_ok(), true);
    }

    #[test]
    fn test_create_and_verify_signature_rfc9421_delete() {
        let request_method = Method::DELETE;
        let request_uri = Uri::from_static("https://verifier.example/endpoint");
        let signer_key = generate_weak_ed25519_key();
        let signer_key_id = "https://signer.example/actor#main-key".to_string();
        let signer = HttpSigner::new_ed25519(signer_key, signer_key_id);
        let signed_headers = create_http_signature_rfc9421(
            request_method.clone(),
            &request_uri.to_string(),
            None,
            &signer,
        ).unwrap();

        let mut request_headers = HeaderMap::new();
        request_headers.insert(
            HeaderName::from_static("signature-input"),
            HeaderValue::from_str(&signed_headers.signature_input).unwrap(),
        );
        request_headers.insert(
            HeaderName::from_static("signature"),
            HeaderValue::from_str(&signed_headers.signature).unwrap(),
        );
        let signature_data = parse_http_signature_rfc9421(
            &request_method,
            &request_uri,
            &request_headers,
            false,
        ).unwrap();
        assert_eq!(signature_data.content_digest.is_none(), true);

        let signer_public_key = signer.key.public_key();
        let result = verify_http_signature(
            &signature_data,
            &signer_public_key,
            None,
        );
        assert_eq!(result.is_ok(), true);
    }
}
