use std::{convert::Infallible, ffi::OsString};
use snafu::prelude::*;
use crate::{
platform::MaybeSendSync,
secrets::{
DecodingError, Secret, SecretDecoder, SecretOutput, SecretString, encodings::StringEncoding,
},
};
#[derive(Debug, Clone)]
pub struct EnvVarSecret<Output = SecretString> {
value: Output,
}
impl<O> EnvVarSecret<O> {
pub fn new<E: SecretDecoder<Output = O>>(
var_name: impl Into<OsString>,
encoding: &E,
) -> Result<Self, EnvVarSecretError> {
let var_name = var_name.into();
let encoded_value = std::env::var(var_name.clone()).context(EnvAccessSnafu { var_name })?;
let value = encoding
.decode(encoded_value.as_bytes())
.context(DecodeSnafu)?;
Ok(Self { value })
}
}
impl EnvVarSecret<SecretString> {
pub fn string(var_name: impl Into<OsString>) -> Result<Self, EnvVarSecretError> {
Self::new(var_name, &StringEncoding)
}
}
impl<O: Clone + MaybeSendSync> Secret for EnvVarSecret<O> {
type Output = O;
type Error = Infallible;
async fn get_secret_value(&self) -> Result<SecretOutput<Self::Output>, Self::Error> {
Ok(SecretOutput {
value: self.value.clone(),
identity: None,
})
}
}
#[derive(Debug, Snafu)]
pub enum EnvVarSecretError {
#[snafu(display("Failed to read env variable '{}'", var_name.to_string_lossy()))]
EnvAccess {
var_name: OsString,
source: std::env::VarError,
},
#[snafu(display("Failed to decode secret"))]
Decode {
source: DecodingError,
},
}
impl crate::Error for EnvVarSecretError {
fn is_retryable(&self) -> bool {
false
}
}