diff --git a/Cargo.lock b/Cargo.lock index 10ad848..e6ac763 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1809,6 +1809,16 @@ dependencies = [ "untrusted", ] +[[package]] +name = "secrecy" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e" +dependencies = [ + "serde", + "zeroize", +] + [[package]] name = "security-framework" version = "2.4.2" @@ -2841,6 +2851,7 @@ dependencies = [ "quickcheck", "quickcheck_macros", "reqwest", + "secrecy", "serde", "serde-aux", "serde_json", @@ -2857,6 +2868,12 @@ dependencies = [ "wiremock", ] +[[package]] +name = "zeroize" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" + [[package]] name = "zstd" version = "0.9.1+zstd.1.5.1" diff --git a/Cargo.toml b/Cargo.toml index 9bdcb6b..e1fe561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ serde-aux = "1.0.1" unicode-segmentation = "1.7.1" tracing-actix-web = "0.5.0-beta.6" validator = "0.12.0" +secrecy = { version = "0.8", features = ["serde"] } [dev-dependencies] once_cell = "1.7.2" diff --git a/src/configuration.rs b/src/configuration.rs index ae5e38c..54b4700 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -1,4 +1,5 @@ use crate::domain::SubscriberEmail; +use secrecy::{ExposeSecret, Secret}; use serde_aux::field_attributes::deserialize_number_from_string; use sqlx::postgres::{PgConnectOptions, PgSslMode}; use sqlx::ConnectOptions; @@ -21,7 +22,7 @@ pub struct ApplicationSettings { #[derive(serde::Deserialize, Clone)] pub struct DatabaseSettings { pub username: String, - pub password: String, + pub password: Secret, #[serde(deserialize_with = "deserialize_number_from_string")] pub port: u16, pub host: String, @@ -39,7 +40,7 @@ impl DatabaseSettings { PgConnectOptions::new() .host(&self.host) .username(&self.username) - .password(&self.password) + .password(&self.password.expose_secret()) .port(self.port) .ssl_mode(ssl_mode) } @@ -55,7 +56,7 @@ impl DatabaseSettings { pub struct EmailClientSettings { pub base_url: String, pub sender_email: String, - pub authorization_token: String, + pub authorization_token: Secret, pub timeout_milliseconds: u64, } diff --git a/src/email_client.rs b/src/email_client.rs index cad139a..947bb7b 100644 --- a/src/email_client.rs +++ b/src/email_client.rs @@ -1,18 +1,19 @@ use crate::domain::SubscriberEmail; use reqwest::Client; +use secrecy::{ExposeSecret, Secret}; pub struct EmailClient { http_client: Client, base_url: String, sender: SubscriberEmail, - authorization_token: String, + authorization_token: Secret, } impl EmailClient { pub fn new( base_url: String, sender: SubscriberEmail, - authorization_token: String, + authorization_token: Secret, timeout: std::time::Duration, ) -> Self { let http_client = Client::builder().timeout(timeout).build().unwrap(); @@ -41,7 +42,10 @@ impl EmailClient { }; self.http_client .post(&url) - .header("X-Postmark-Server-Token", &self.authorization_token) + .header( + "X-Postmark-Server-Token", + self.authorization_token.expose_secret(), + ) .json(&request_body) .send() .await? @@ -68,6 +72,7 @@ mod tests { use fake::faker::internet::en::SafeEmail; use fake::faker::lorem::en::{Paragraph, Sentence}; use fake::{Fake, Faker}; + use secrecy::Secret; use wiremock::matchers::{any, header, header_exists, method, path}; use wiremock::{Mock, MockServer, Request, ResponseTemplate}; @@ -108,7 +113,7 @@ mod tests { EmailClient::new( base_url, email(), - Faker.fake(), + Secret::new(Faker.fake()), std::time::Duration::from_millis(200), ) }