use ed25519_dalek::{Signature, Verifier, VerifyingKey};
use crate::error::{Error, Result};
pub const SIGNATURE_HEADER: &str = "x-signature-ed25519";
pub const TIMESTAMP_HEADER: &str = "x-signature-timestamp";
pub fn public_key_from_hex(hex_key: &str) -> Result<VerifyingKey> {
let bytes = hex::decode(hex_key.trim())
.map_err(|_| Error::Signature("public key is not valid hex".to_owned()))?;
let array: [u8; 32] = bytes
.try_into()
.map_err(|_| Error::Signature("public key must decode to 32 bytes".to_owned()))?;
VerifyingKey::from_bytes(&array)
.map_err(|_| Error::Signature("public key is not a valid Ed25519 key".to_owned()))
}
pub fn verify_interaction(
public_key: &VerifyingKey,
signature_hex: Option<&str>,
timestamp: Option<&str>,
body: &[u8],
) -> Result<()> {
let signature_hex = signature_hex
.ok_or_else(|| Error::Signature(format!("missing {SIGNATURE_HEADER} header")))?;
let timestamp =
timestamp.ok_or_else(|| Error::Signature(format!("missing {TIMESTAMP_HEADER} header")))?;
let signature_bytes = hex::decode(signature_hex.trim())
.map_err(|_| Error::Signature("signature header is not valid hex".to_owned()))?;
let signature_array: [u8; 64] = signature_bytes
.try_into()
.map_err(|_| Error::Signature("signature must decode to 64 bytes".to_owned()))?;
let signature = Signature::from_bytes(&signature_array);
let mut message = Vec::with_capacity(timestamp.len() + body.len());
message.extend_from_slice(timestamp.as_bytes());
message.extend_from_slice(body);
public_key
.verify(&message, &signature)
.map_err(|_| Error::Signature("signature verification failed".to_owned()))
}
#[cfg(test)]
mod tests;