use chacha20poly1305::{
aead::{Aead, AeadCore, KeyInit, OsRng},
ChaCha20Poly1305,
};
use proc_macro::TokenStream;
use proc_macro2::Literal;
use quote::quote;
pub(crate) fn encrypt<V: Into<UnencryptedVariable>>(v: V) -> TokenStream {
let unencrypted_variable: UnencryptedVariable = v.into();
if let Some(variable) = unencrypted_variable.inner() {
let key = ChaCha20Poly1305::generate_key(&mut OsRng);
let nonce = ChaCha20Poly1305::generate_nonce(&mut OsRng);
let cipher = ChaCha20Poly1305::new(&key);
let encrypted_variable = cipher.encrypt(&nonce, variable.as_bytes()).unwrap();
let data = key
.into_iter()
.chain(nonce.into_iter())
.chain(encrypted_variable.into_iter())
.collect::<Vec<_>>();
let bytestring = Literal::byte_string(&data);
if unencrypted_variable.is_optional() {
quote!(::core::option::Option::Some(::envcrypt::__internal::decrypt(#bytestring)))
} else {
quote!(::envcrypt::__internal::decrypt(#bytestring))
}
} else {
quote!(::core::option::Option::<&'static str>::None)
}
.into()
}
pub(crate) enum UnencryptedVariable {
Required(String),
Optional(Option<String>),
}
impl From<String> for UnencryptedVariable {
fn from(unencrypted_variable: String) -> Self {
UnencryptedVariable::Required(unencrypted_variable)
}
}
impl From<Option<String>> for UnencryptedVariable {
fn from(option_unencrypted_variable: Option<String>) -> Self {
UnencryptedVariable::Optional(option_unencrypted_variable)
}
}
impl UnencryptedVariable {
fn inner(&self) -> Option<&String> {
match self {
UnencryptedVariable::Optional(ref option) => option.as_ref(),
UnencryptedVariable::Required(ref v) => Some(v),
}
}
fn is_optional(&self) -> bool {
matches!(self, UnencryptedVariable::Optional(_))
}
}