Support for .pem files
Closed this issue · 3 comments
In my current project, it was decided to use a .pem file to save a private RSA key. I would like to know it it is possible to assign the content of such file as a source to be defined as the value of access_token_private_key field.
Here is my settings struct:
/// Global settings for the exposing all preconfigured variables
#[derive(serde::Deserialize, Clone)]
pub struct Settings {
pub application: ApplicationSettings,
pub debug: bool,
pub redis: RedisSettings,
pub secret: Secret,
pub email: EmailSettings,
pub frontend_url: String
}
I wanna setup access_token_private_key field
#[derive(serde::Deserialize, Clone)]
pub struct Secret {
pub secret_key: String,
pub token_expiration: i64,
pub hmac_secret: String,
pub access_token_private_key: String,
pub access_token_public_key: String,
pub access_token_expired_in: String,
pub access_token_maxage: i64
}
Here is a function that I call to retrieve my settings
pub fn get_settings() -> Result<Settings, config::ConfigError> {
let base_path = std::env::current_dir().expect("Failed to determine the current directory");
let settings_directory = base_path.join("settings");
//Cert Path
let cert_directory = base_path.join("settings");
// Detect the running environment.
// Default to `development` if unspecified.
let environment: Environment = std::env::var("APP_ENVIRONMENT")
.unwrap_or_else(|_| "development".into())
.try_into()
.expect("Failed to parse APP_ENVIRONMENT.");
let environment_filename = format!("{}.yaml", environment.as_str());
let settings = config::Config::builder()
.add_source(config::File::from(settings_directory.join("base.yaml")))
.add_source(config::File::from(
settings_directory.join(environment_filename),
))
// Add in settings from environment variables (with a prefix of APP and '__' as separator)
// E.g. `APP_APPLICATION__PORT=5001 would set `Settings.application.port`
.add_source(
config::Environment::with_prefix("APP")
.prefix_separator("_")
.separator("__"),
)
// Add private/public key value
.add_source(????)
.build()?;
settings.try_deserialize::<Settings>()
}
Hi! So this should be possible with the config crate, yes. Have a look at the Format
trait, you probably need to implement this for a custom type of yours representing your pem file format. You should then be able to populate a Source
with your format and pass this into the builder for loading your pem file.
I hope I didn't overlook anything in your example, but that's as far as I can see right now your path.
Thanks for answer! I have taken the approach that you have mention in your previous response. I just took a while to figure it out but ended up with this:
#[derive(Debug, Clone)]
pub struct PemFile;
impl Format for PemFile {
fn parse(
&self,
uri: Option<&String>,
text: &str,
) -> Result<Map<String, config::Value>, Box<dyn std::error::Error + Send + Sync>> {
let mut result = Map::new();
let key = match text.contains("PRIVATE") {
true => String::from("secret.access_token_private_key"),
false => String::from("secret.access_token_public_key"),
};
let encoded_key = base64::engine::general_purpose::STANDARD.encode::<String>(text.into());
result.insert(key.clone(), Value::new(uri, ValueKind::String(encoded_key)));
result.insert(format!("{}_raw", key), Value::new(uri, ValueKind::String(text.into())));
Ok(result)
}
}
static PEM_EXT: Vec<&'static str> = vec![];
impl FileStoredFormat for PemFile {
fn file_extensions(&self) -> &'static [&'static str] {
&PEM_EXT
}
}
Then in inside get_settings function I did this:
let settings = config::Config::builder()
.add_source(config::File::from(settings_directory.join("base.yaml")))
//Load Keys from PEM files in cert folder
.add_source(
config::File::new(
cert_directory
.join("private.pem")
.to_str()
.expect("unable to convert into string"),
PemFile,
)
.required(false),
)
.add_source(
config::File::new(
cert_directory
.join("public.pem")
.to_str()
.expect("unable to convert into string"),
PemFile,
)
.required(false),
)
This is working just fine! I think that documentation regarding custom formats should be improved. If it is of your interest, I can provide previous code as an example of a custom format for .pem files.
Please do, I would love to see more examples and documentation for this crate!