use crate::{
crypto::{CipherSuite, EncryptedSecret},
token::{Result, TokenMaterial},
};
#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub struct EncryptedToken<T: TokenMaterial> {
secret: EncryptedSecret,
_marker: std::marker::PhantomData<T>,
}
impl<T: TokenMaterial> EncryptedToken<T> {
pub fn from_secret(secret: EncryptedSecret) -> Self {
Self {
secret,
_marker: std::marker::PhantomData,
}
}
pub fn from_encrypted_bytes(input: &[u8]) -> Result<Self> {
let secret = EncryptedSecret::from_encrypted_bytes(input)?;
Ok(Self::from_secret(secret))
}
pub fn to_encrypted_bytes(&self) -> Vec<u8> {
self.secret.to_encrypted_bytes()
}
pub fn decrypt(&self, key: &[u8]) -> Result<T> {
let plaintext = self.secret.decrypt(key)?;
T::from_vec(plaintext)
}
pub fn algorithm(&self) -> CipherSuite {
self.secret.algorithm()
}
}
impl<T: TokenMaterial> std::fmt::Debug for EncryptedToken<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self.secret)
}
}
impl<T: TokenMaterial> std::fmt::Display for EncryptedToken<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.secret)
}
}
#[cfg(feature = "serde")]
impl<T: TokenMaterial> Serialize for EncryptedToken<T> {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
self.secret.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: TokenMaterial> Deserialize<'de> for EncryptedToken<T> {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let secret = EncryptedSecret::deserialize(deserializer)?;
Ok(Self::from_secret(secret))
}
}
#[cfg(feature = "sqlx")]
mod sqlx_impl {
use super::*;
use sqlx::{Database, Decode, Encode, Type, encode::IsNull, error::BoxDynError};
#[cfg(feature = "sqlx_postgres")]
impl<T: TokenMaterial> sqlx::postgres::PgHasArrayType for EncryptedToken<T> {
fn array_type_info() -> sqlx::postgres::PgTypeInfo {
<EncryptedSecret as sqlx::postgres::PgHasArrayType>::array_type_info()
}
}
impl<'a, T: TokenMaterial, DB: Database> Type<DB> for EncryptedToken<T>
where
&'a [u8]: Type<DB>,
{
fn type_info() -> <DB as Database>::TypeInfo {
<EncryptedSecret as Type<DB>>::type_info()
}
fn compatible(ty: &<DB as Database>::TypeInfo) -> bool {
<EncryptedSecret as Type<DB>>::compatible(ty)
}
}
impl<'a, T: TokenMaterial, DB: Database> Encode<'a, DB> for EncryptedToken<T>
where
Vec<u8>: Encode<'a, DB>,
{
fn encode_by_ref(
&self,
buf: &mut <DB as Database>::ArgumentBuffer<'a>,
) -> std::result::Result<IsNull, BoxDynError> {
<EncryptedSecret as Encode<'a, DB>>::encode_by_ref(&self.secret, buf)
}
fn produces(&self) -> Option<<DB as Database>::TypeInfo> {
<EncryptedSecret as Encode<'a, DB>>::produces(&self.secret)
}
fn size_hint(&self) -> usize {
<EncryptedSecret as Encode<'a, DB>>::size_hint(&self.secret)
}
}
impl<'a, T: TokenMaterial, DB: Database> Decode<'a, DB> for EncryptedToken<T>
where
Vec<u8>: Decode<'a, DB>,
{
fn decode(value: <DB as Database>::ValueRef<'a>) -> std::result::Result<Self, BoxDynError> {
let secret = <EncryptedSecret as Decode<'a, DB>>::decode(value)?;
Ok(Self::from_secret(secret))
}
}
}