use std::{fmt::Display, time::Duration};
use base64::{prelude::BASE64_STANDARD, Engine};
use p256::ecdsa::{self, signature::Verifier, Signature, VerifyingKey};
use serde::Deserialize;
#[derive(Debug)]
pub enum Error {
RequestError(reqwest::Error),
InvalidSignature(Box<dyn std::error::Error + Send + Sync>),
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::RequestError(error) => write!(f, "Request error: {}", error),
Error::InvalidSignature(error) => write!(f, "Invalid signature: {}", error),
}
}
}
impl From<reqwest::Error> for Error {
fn from(value: reqwest::Error) -> Self {
Self::RequestError(value)
}
}
impl From<ecdsa::Error> for Error {
fn from(value: ecdsa::Error) -> Self {
Self::InvalidSignature(Box::new(value))
}
}
impl From<base64::DecodeError> for Error {
fn from(value: base64::DecodeError) -> Self {
Self::InvalidSignature(Box::new(value))
}
}
impl std::error::Error for Error {}
#[derive(Deserialize)]
pub(crate) struct RawTime {
timestamp: u64,
signature: String,
}
impl RawTime {
pub(crate) fn digest(&self, nonce: &str, verifying_key: &VerifyingKey) -> Result<Duration, Error> {
let msg = self.timestamp.to_string() + nonce;
verifying_key.verify(
msg.as_bytes(),
&Signature::from_slice(
&BASE64_STANDARD.decode(&self.signature)?
)?
)?;
Ok(Duration::from_secs(self.timestamp))
}
}