use std::{borrow::Cow, str::FromStr};
use bh_jws_utils::{
jwt, HasJwkKid, HasX5Chain, JwkPublic, SignatureVerifier, Signer, SigningAlgorithm,
};
use bhx5chain::X5Chain;
use serde::{Deserialize, Serialize};
use crate::{json_object, JsonObject};
pub(crate) struct StubSigner {
pub(crate) public_jwk: JwkPublic,
pub(crate) x5chain: X5Chain,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
pub(crate) struct StubSignature<'m, 'k>(Cow<'m, [u8]>, Cow<'k, JwkPublic>);
impl StubSignature<'_, '_> {
pub(crate) fn verify(&self, message: &[u8], public_key: &JwkPublic) -> bool {
self == &StubSignature(message.into(), Cow::Borrowed(public_key))
}
}
impl Signer for StubSigner {
fn algorithm(&self) -> SigningAlgorithm {
SigningAlgorithm::from_str(self.public_jwk.get("alg").unwrap().as_str().unwrap()).unwrap()
}
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
Ok(serde_json::to_string(&StubSignature(
message.into(),
Cow::Borrowed(&self.public_jwk),
))?
.into_bytes())
}
fn public_jwk(&self) -> Result<JwkPublic, Box<dyn std::error::Error + Send + Sync>> {
Ok(self.public_jwk.clone())
}
}
impl HasJwkKid for StubSigner {
fn jwk_kid(&self) -> &str {
self.public_jwk.get("kid").unwrap().as_str().unwrap()
}
}
impl HasX5Chain for StubSigner {
fn x5chain(&self) -> X5Chain {
self.x5chain.clone()
}
}
impl Default for StubSigner {
fn default() -> Self {
Self {
public_jwk: dummy_public_jwk(),
x5chain: X5Chain::dummy(),
}
}
}
impl StubSigner {
pub fn new(public_jwk: JwkPublic, x5chain: X5Chain) -> Self {
Self {
public_jwk,
x5chain,
}
}
}
#[derive(Clone)]
pub(crate) struct StubVerifier {
pub(crate) public_jwk: JwkPublic,
}
impl Default for StubVerifier {
fn default() -> Self {
Self {
public_jwk: dummy_public_jwk(),
}
}
}
impl StubVerifier {
pub fn new(public_jwk: JwkPublic) -> Self {
Self { public_jwk }
}
}
impl jwt::VerifyingAlgorithm for StubVerifier {
fn algorithm_type(&self) -> jwt::AlgorithmType {
self.algorithm().into()
}
fn verify_bytes(
&self,
header: &str,
claims: &str,
signature: &[u8],
) -> std::result::Result<bool, jwt::Error> {
let message = bh_jws_utils::construct_jws_payload(header, claims);
let success = <Self as SignatureVerifier>::verify(
self,
message.as_bytes(),
signature,
&self.public_jwk,
)
.expect("StubVerifier::verify should never error");
Ok(success)
}
}
impl SignatureVerifier for StubVerifier {
fn algorithm(&self) -> SigningAlgorithm {
SigningAlgorithm::from_str(self.public_jwk.get("alg").unwrap().as_str().unwrap()).unwrap()
}
fn verify(
&self,
message: &[u8],
signature: &[u8],
public_key: &JwkPublic,
) -> Result<bool, Box<dyn std::error::Error + Send + Sync>> {
let Ok(symbolic_signature) = serde_json::from_slice::<StubSignature>(signature) else {
return Ok(false);
};
Ok(symbolic_signature.verify(message, public_key))
}
}
pub(crate) fn dummy_public_jwk() -> JsonObject {
json_object!({
"kid": Option::<String>::None,
"alg": "ES256",
})
}