use std::fmt::Display;
use chrono::TimeZone;
use jsonwebtoken::{Algorithm, Header, encode};
use serde::Serialize;
use crate::{box_err::BoxResult, open_badge::{BadgeAssertion, Type}};
pub fn sign<S: AsRef<str> + Display + Serialize>(
badge_assertion: &BadgeAssertion<S>,
secret_key: &[u8],
) -> BoxResult<String> {
let secret_key_parsed = jsonwebtoken::EncodingKey::from_rsa_pem(secret_key)?;
let mut header = Header::new(Algorithm::RS256);
header.typ = Some("JOSE+JSON".to_string());
Ok(encode(&header, badge_assertion, &secret_key_parsed)?)
}
#[cfg(test)]
mod tests {
use std::fs;
use super::*;
use crate::{box_err::BoxResult, constants, hash, open_badge};
use chrono::DateTime;
use jsonwebtoken::{DecodingKey, Validation, decode};
use serde::de::DeserializeOwned;
fn sign_and_verify<S: AsRef<str> + Display + Serialize + DeserializeOwned + PartialEq>(
badge_assertion: &BadgeAssertion<S>,
secret_key: &[u8],
public_key: &[u8],
) -> BoxResult<()> {
let encoded = sign(badge_assertion, secret_key)?;
let decoded = decode::<BadgeAssertion<S>>(&encoded, &DecodingKey::from_rsa_pem(public_key)?, &Validation::new(Algorithm::RS256))?;
assert!(&decoded.claims.eq(badge_assertion));
Ok(())
}
#[test]
fn test_sign() -> BoxResult<()> {
let email_hash = hash::sha256(constants::BADGE_ASSERTION_RECIPIENT_EMAIL);
let badge_asser = open_badge::BadgeAssertion {
id: constants::BADGE_ASSERTION_WITH_KEY_ID.to_string(),
badge_id: constants::BADGE_DEFINITION_WITH_KEY_ID.to_string(),
recipient_salt: Some(constants::EMAIL_SALT.to_string()),
recipient_hashed_email: email_hash,
verification_public_key: Some(constants::KEY_ID.to_string()),
issued_on: DateTime::parse_from_rfc3339(constants::DT_PAST)?.into(),
expires: DateTime::parse_from_rfc3339(constants::DT_FAR_FUTURE)?.into(),
};
let key_priv = fs::read_to_string("example.com.key")?;
let key_pub = fs::read_to_string("example.com.pem")?;
sign_and_verify(&badge_asser, key_priv.as_bytes(), key_pub.as_bytes())?;
Ok(())
}
}