Add secrecy

This commit is contained in:
Luca Palmieri 2021-12-27 13:24:24 +01:00
parent 40b67c7160
commit f7f25b93d6
6 changed files with 51 additions and 12 deletions

17
Cargo.lock generated
View file

@ -1818,6 +1818,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"
@ -2853,6 +2863,7 @@ dependencies = [
"quickcheck_macros",
"rand 0.8.4",
"reqwest",
"secrecy",
"serde",
"serde-aux",
"serde_json",
@ -2871,6 +2882,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"

View file

@ -34,6 +34,7 @@ validator = "0.12.0"
rand = { version = "0.8", features=["std_rng"] }
sha2 = { version = "0.9" }
anyhow = "1.0.40"
secrecy = { version = "0.8", features = ["serde"] }
[dev-dependencies]
once_cell = "1.7.2"

View file

@ -11,4 +11,5 @@ database:
email_client:
base_url: "localhost"
sender_email: "test@gmail.com"
authorization_token: "my-secret-token"
authorization_token: "my-secret-token"
timeout_milliseconds: 10000

View file

@ -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;
@ -22,7 +23,7 @@ pub struct ApplicationSettings {
#[derive(serde::Deserialize, Clone)]
pub struct DatabaseSettings {
pub username: String,
pub password: String,
pub password: Secret<String>,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub port: u16,
pub host: String,
@ -40,7 +41,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)
}
@ -56,13 +57,18 @@ impl DatabaseSettings {
pub struct EmailClientSettings {
pub base_url: String,
pub sender_email: String,
pub authorization_token: String,
pub authorization_token: Secret<String>,
pub timeout_milliseconds: u64,
}
impl EmailClientSettings {
pub fn sender(&self) -> Result<SubscriberEmail, String> {
SubscriberEmail::parse(self.sender_email.clone())
}
pub fn timeout(&self) -> std::time::Duration {
std::time::Duration::from_millis(self.timeout_milliseconds)
}
}
pub fn get_configuration() -> Result<Settings, config::ConfigError> {

View file

@ -1,19 +1,22 @@
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<String>,
}
impl EmailClient {
pub fn new(base_url: String, sender: SubscriberEmail, authorization_token: String) -> Self {
let http_client = Client::builder()
.timeout(std::time::Duration::from_secs(10))
.build()
.unwrap();
pub fn new(
base_url: String,
sender: SubscriberEmail,
authorization_token: Secret<String>,
timeout: std::time::Duration,
) -> Self {
let http_client = Client::builder().timeout(timeout).build().unwrap();
Self {
http_client,
base_url,
@ -39,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?
@ -66,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};
@ -103,7 +110,12 @@ mod tests {
/// Get a test instance of `EmailClient`.
fn email_client(base_url: String) -> EmailClient {
EmailClient::new(base_url, email(), Faker.fake())
EmailClient::new(
base_url,
email(),
Secret::new(Faker.fake()),
std::time::Duration::from_millis(200),
)
}
#[tokio::test]

View file

@ -21,10 +21,12 @@ impl Application {
.email_client
.sender()
.expect("Invalid sender email address.");
let timeout = configuration.email_client.timeout();
let email_client = EmailClient::new(
configuration.email_client.base_url,
sender_email,
configuration.email_client.authorization_token,
timeout,
);
let address = format!(