use crate::error::{Error, Result};
use base64::Engine;
use serde::{Deserialize, Serialize};
pub mod base64_bytes {
use base64::{engine::general_purpose::STANDARD, Engine};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&STANDARD.encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
STANDARD.decode(s).map_err(serde::de::Error::custom)
}
}
pub mod base64_bytes_option {
use base64::{engine::general_purpose::STANDARD, Engine};
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(bytes: &Option<Vec<u8>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match bytes {
Some(b) => serializer.serialize_some(&STANDARD.encode(b)),
None => serializer.serialize_none(),
}
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Option<Vec<u8>>, D::Error>
where
D: Deserializer<'de>,
{
let opt: Option<String> = Option::deserialize(deserializer)?;
match opt {
Some(s) => STANDARD
.decode(s)
.map(Some)
.map_err(serde::de::Error::custom),
None => Ok(None),
}
}
}
pub mod hex_bytes {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(bytes))
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
hex::decode(s).map_err(serde::de::Error::custom)
}
}
macro_rules! base64_newtype {
($(#[$meta:meta])* $name:ident) => {
$(#[$meta])*
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct $name(Vec<u8>);
impl $name {
pub fn new(bytes: Vec<u8>) -> Self {
Self(bytes)
}
pub fn from_bytes(bytes: &[u8]) -> Self {
Self(bytes.to_vec())
}
pub fn from_base64(s: &str) -> Result<Self> {
let bytes = base64::engine::general_purpose::STANDARD
.decode(s)
.map_err(|e| Error::InvalidEncoding(format!("invalid base64: {}", e)))?;
Ok(Self(bytes))
}
pub fn to_base64(&self) -> String {
base64::engine::general_purpose::STANDARD.encode(&self.0)
}
pub fn as_bytes(&self) -> &[u8] {
&self.0
}
pub fn into_bytes(self) -> Vec<u8> {
self.0
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl From<Vec<u8>> for $name {
fn from(bytes: Vec<u8>) -> Self {
Self(bytes)
}
}
impl From<&[u8]> for $name {
fn from(bytes: &[u8]) -> Self {
Self(bytes.to_vec())
}
}
impl std::fmt::Display for $name {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.to_base64())
}
}
impl serde::Serialize for $name {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_base64())
}
}
impl<'de> serde::Deserialize<'de> for $name {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Self::from_base64(&s).map_err(serde::de::Error::custom)
}
}
};
}
base64_newtype!(
DerCertificate
);
base64_newtype!(
DerPublicKey
);
base64_newtype!(
SignatureBytes
);
base64_newtype!(
PayloadBytes
);
base64_newtype!(
CanonicalizedBody
);
base64_newtype!(
SignedTimestamp
);
base64_newtype!(
TimestampToken
);
base64_newtype!(
PemContent
);
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct EntryUuid(String);
impl EntryUuid {
pub fn new(s: String) -> Self {
EntryUuid(s)
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl From<String> for EntryUuid {
fn from(s: String) -> Self {
EntryUuid::new(s)
}
}
impl AsRef<str> for EntryUuid {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for EntryUuid {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LogIndex(String);
impl LogIndex {
pub fn new(s: String) -> Self {
LogIndex(s)
}
pub fn from_u64(index: u64) -> Self {
LogIndex(index.to_string())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
pub fn as_u64(&self) -> Result<u64> {
self.0
.parse()
.map_err(|e| Error::InvalidEncoding(format!("invalid log index '{}': {}", self.0, e)))
}
}
impl From<String> for LogIndex {
fn from(s: String) -> Self {
LogIndex::new(s)
}
}
impl From<u64> for LogIndex {
fn from(index: u64) -> Self {
LogIndex::from_u64(index)
}
}
impl AsRef<str> for LogIndex {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for LogIndex {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct LogKeyId(String);
impl LogKeyId {
pub fn new(s: String) -> Self {
LogKeyId(s)
}
pub fn from_bytes(bytes: &[u8]) -> Self {
LogKeyId(base64::engine::general_purpose::STANDARD.encode(bytes))
}
pub fn decode(&self) -> Result<Vec<u8>> {
base64::engine::general_purpose::STANDARD
.decode(&self.0)
.map_err(|e| Error::InvalidEncoding(format!("invalid base64 in log key id: {}", e)))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
impl From<String> for LogKeyId {
fn from(s: String) -> Self {
LogKeyId::new(s)
}
}
impl AsRef<str> for LogKeyId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for LogKeyId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct KeyId(String);
impl KeyId {
pub fn new(s: String) -> Self {
KeyId(s)
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl From<String> for KeyId {
fn from(s: String) -> Self {
KeyId::new(s)
}
}
impl AsRef<str> for KeyId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for KeyId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct Sha256Hash([u8; 32]);
impl Sha256Hash {
pub fn from_bytes(bytes: [u8; 32]) -> Self {
Sha256Hash(bytes)
}
pub fn try_from_slice(bytes: &[u8]) -> Result<Self> {
if bytes.len() != 32 {
return Err(Error::InvalidEncoding(format!(
"SHA-256 hash must be 32 bytes, got {}",
bytes.len()
)));
}
let mut arr = [0u8; 32];
arr.copy_from_slice(bytes);
Ok(Sha256Hash(arr))
}
pub fn from_hex(hex_str: &str) -> Result<Self> {
let bytes = hex::decode(hex_str)
.map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))?;
Self::try_from_slice(&bytes)
}
pub fn from_base64(s: &str) -> Result<Self> {
let bytes = base64::engine::general_purpose::STANDARD
.decode(s)
.map_err(|e| Error::InvalidEncoding(format!("invalid base64: {}", e)))?;
Self::try_from_slice(&bytes)
}
pub fn from_hex_or_base64(s: &str) -> Result<Self> {
if s.len() == 64 && s.chars().all(|c| c.is_ascii_hexdigit()) {
return Self::from_hex(s);
}
Self::from_base64(s)
}
pub fn to_hex(&self) -> String {
hex::encode(self.0)
}
pub fn to_base64(&self) -> String {
base64::engine::general_purpose::STANDARD.encode(self.0)
}
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
pub fn as_slice(&self) -> &[u8] {
&self.0
}
}
impl AsRef<[u8]> for Sha256Hash {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl From<[u8; 32]> for Sha256Hash {
fn from(bytes: [u8; 32]) -> Self {
Sha256Hash(bytes)
}
}
impl serde::Serialize for Sha256Hash {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_base64())
}
}
impl<'de> serde::Deserialize<'de> for Sha256Hash {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
Sha256Hash::from_hex_or_base64(&s).map_err(serde::de::Error::custom)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HexLogId(String);
impl HexLogId {
pub fn new(s: String) -> Self {
HexLogId(s)
}
pub fn from_bytes(bytes: &[u8]) -> Self {
HexLogId(hex::encode(bytes))
}
pub fn decode(&self) -> Result<Vec<u8>> {
hex::decode(&self.0).map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))
}
pub fn to_base64(&self) -> Result<String> {
let bytes = self.decode()?;
Ok(base64::engine::general_purpose::STANDARD.encode(&bytes))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
impl From<String> for HexLogId {
fn from(s: String) -> Self {
HexLogId::new(s)
}
}
impl AsRef<str> for HexLogId {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for HexLogId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HexHash(String);
impl HexHash {
pub fn new(s: String) -> Self {
HexHash(s)
}
pub fn from_bytes(bytes: &[u8]) -> Self {
HexHash(hex::encode(bytes))
}
pub fn decode(&self) -> Result<Vec<u8>> {
hex::decode(&self.0).map_err(|e| Error::InvalidEncoding(format!("invalid hex: {}", e)))
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
pub fn to_sha256(&self) -> Result<Sha256Hash> {
Sha256Hash::from_hex(&self.0)
}
}
impl From<String> for HexHash {
fn from(s: String) -> Self {
HexHash::new(s)
}
}
impl AsRef<str> for HexHash {
fn as_ref(&self) -> &str {
&self.0
}
}
impl std::fmt::Display for HexHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_der_certificate_roundtrip() {
let cert = DerCertificate::from_bytes(b"fake cert data");
let json = serde_json::to_string(&cert).unwrap();
let decoded: DerCertificate = serde_json::from_str(&json).unwrap();
assert_eq!(cert, decoded);
}
#[test]
fn test_signature_bytes_roundtrip() {
let sig = SignatureBytes::from_bytes(b"fake signature");
let json = serde_json::to_string(&sig).unwrap();
let decoded: SignatureBytes = serde_json::from_str(&json).unwrap();
assert_eq!(sig, decoded);
}
#[test]
fn test_sha256_hash() {
let hash_hex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
let hash = Sha256Hash::from_hex(hash_hex).unwrap();
assert_eq!(hash.to_hex(), hash_hex);
let json_hex = format!("\"{}\"", hash_hex);
let from_hex: Sha256Hash = serde_json::from_str(&json_hex).unwrap();
assert_eq!(hash, from_hex);
}
#[test]
fn test_hex_log_id() {
let bytes = vec![1, 2, 3, 4];
let log_id = HexLogId::from_bytes(&bytes);
assert_eq!(log_id.as_str(), "01020304");
assert_eq!(log_id.decode().unwrap(), bytes);
assert_eq!(log_id.to_base64().unwrap(), "AQIDBA==");
}
#[test]
fn test_log_key_id() {
let bytes = vec![1, 2, 3, 4];
let key_id = LogKeyId::from_bytes(&bytes);
assert_eq!(key_id.decode().unwrap(), bytes);
}
}