#![allow(non_camel_case_types)]
mod jwe;
use std::fmt;
use crate::Result;
use azure_core::{
base64,
json::{from_json, to_json},
};
use clap::ValueEnum;
pub use jwe::{Jwe, JweEncryptor, WrapKeyResult};
use serde::{de::DeserializeOwned, Deserialize, Serialize};
pub trait Encode
where
Self: Sized,
{
fn decode(value: &str) -> Result<Self>;
fn encode(&self) -> Result<String>;
}
impl<T: DeserializeOwned + Serialize> Encode for T {
fn decode(value: &str) -> Result<Self> {
let buf = base64::decode_url_safe(value)?;
Ok(from_json(buf)?)
}
fn encode(&self) -> Result<String> {
let buf = to_json(self)?;
Ok(base64::encode_url_safe(buf))
}
}
#[derive(Debug, Serialize, Deserialize)]
pub struct Header {
#[serde(rename = "alg")]
pub alg: Algorithm,
#[serde(rename = "enc", skip_serializing_if = "Option::is_none")]
pub enc: Option<EncryptionAlgorithm>,
#[serde(rename = "kid", skip_serializing_if = "Option::is_none")]
pub kid: Option<String>,
#[serde(rename = "typ")]
pub typ: Type,
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "UPPERCASE")]
pub enum Type {
JWE,
#[serde(untagged)]
Other(String),
}
impl fmt::Display for Type {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::JWE => f.write_str("JWE"),
Self::Other(s) => f.write_str(s),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, ValueEnum)]
#[serde(rename_all = "UPPERCASE")]
pub enum Algorithm {
#[serde(rename = "RSA1_5")]
RSA1_5,
#[serde(rename = "RSA-OAEP")]
RSA_OAEP,
#[serde(rename = "RSA-OAEP-256")]
RSA_OAEP_256,
#[serde(untagged)]
#[value(skip)]
Other(String),
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, ValueEnum)]
#[serde(rename_all = "UPPERCASE")]
pub enum EncryptionAlgorithm {
A128GCM,
A192GCM,
A256GCM,
#[serde(untagged)]
#[value(skip)]
Other(String),
}
impl fmt::Display for EncryptionAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::A128GCM => f.write_str("A128GCM"),
Self::A192GCM => f.write_str("A192GCM"),
Self::A256GCM => f.write_str("A256GCM"),
Self::Other(s) => f.write_str(s),
}
}
}
#[derive(Debug)]
#[doc(hidden)]
pub enum Set {}
#[derive(Debug)]
#[doc(hidden)]
pub enum Unset {}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn header_encode_decode() {
let header = Header {
alg: Algorithm::RSA_OAEP_256,
enc: Some(EncryptionAlgorithm::A256GCM),
kid: Some("https://myvault.vault.azure.net/keys/mykey/1234567890abcdef".into()),
typ: Type::JWE,
};
let expected_json = json!({
"alg": "RSA-OAEP-256",
"enc": "A256GCM",
"kid": "https://myvault.vault.azure.net/keys/mykey/1234567890abcdef",
"typ": "JWE"
});
let expected_bytes = serde_json::to_vec(&expected_json).unwrap();
let expected_b64 = azure_core::base64::encode_url_safe(expected_bytes);
let encoded = header.encode().unwrap();
assert_eq!(encoded, expected_b64);
let decoded = Header::decode(&encoded).unwrap();
assert_eq!(decoded.alg, Algorithm::RSA_OAEP_256);
assert_eq!(decoded.enc, Some(EncryptionAlgorithm::A256GCM));
assert_eq!(
decoded.kid,
Some("https://myvault.vault.azure.net/keys/mykey/1234567890abcdef".into()),
);
assert_eq!(decoded.typ, Type::JWE);
}
}