feat(api): wrap database password with Secret

This commit is contained in:
minhtrannhat 2024-05-08 17:53:41 -04:00
parent 3a0576ba48
commit 444e42351e
Signed by: minhtrannhat
GPG Key ID: E13CFA85C53F8062
5 changed files with 38 additions and 14 deletions

11
Cargo.lock generated
View File

@ -615,6 +615,7 @@ dependencies = [
"config", "config",
"once_cell", "once_cell",
"reqwest", "reqwest",
"secrecy",
"serde", "serde",
"sqlx", "sqlx",
"tokio", "tokio",
@ -1930,6 +1931,16 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "secrecy"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9bd1c54ea06cfd2f6b63219704de0b9b4f72dcc2b8fdef820be6cd799780e91e"
dependencies = [
"serde",
"zeroize",
]
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.9.2" version = "2.9.2"

View File

@ -27,6 +27,7 @@ tracing-subscriber = { version = "0.3.18", features = ["registry", "env-filter"]
tracing-bunyan-formatter = "0.3.9" tracing-bunyan-formatter = "0.3.9"
tracing-log = "0.2.0" tracing-log = "0.2.0"
once_cell = "1.19.0" once_cell = "1.19.0"
secrecy = { version = "0.8.0", features = ["serde"] }
[dependencies.sqlx] [dependencies.sqlx]
version = "0.7" version = "0.7"

View File

@ -1,3 +1,5 @@
use secrecy::{ExposeSecret, Secret};
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct Settings { pub struct Settings {
pub database: DatabaseSettings, pub database: DatabaseSettings,
@ -7,7 +9,7 @@ pub struct Settings {
#[derive(serde::Deserialize)] #[derive(serde::Deserialize)]
pub struct DatabaseSettings { pub struct DatabaseSettings {
pub username: String, pub username: String,
pub password: String, pub password: Secret<String>,
pub port: u16, pub port: u16,
pub host: String, pub host: String,
pub database_name: String, pub database_name: String,
@ -25,17 +27,24 @@ pub fn get_configuration() -> Result<Settings, config::ConfigError> {
} }
impl DatabaseSettings { impl DatabaseSettings {
pub fn connection_string(&self) -> String { pub fn connection_string(&self) -> Secret<String> {
format!( Secret::new(format!(
"postgres://{}:{}@{}:{}/{}", "postgres://{}:{}@{}:{}/{}",
self.username, self.password, self.host, self.port, self.database_name self.username,
) self.password.expose_secret(),
self.host,
self.port,
self.database_name
))
} }
pub fn connection_string_without_db(&self) -> String { pub fn connection_string_without_db(&self) -> Secret<String> {
format!( Secret::new(format!(
"postgres://{}:{}@{}:{}", "postgres://{}:{}@{}:{}",
self.username, self.password, self.host, self.port self.username,
) self.password.expose_secret(),
self.host,
self.port
))
} }
} }

View File

@ -2,6 +2,7 @@ use std::net::TcpListener;
use email_newsletter_api::telemetry::{get_subscriber, init_subscriber}; use email_newsletter_api::telemetry::{get_subscriber, init_subscriber};
use email_newsletter_api::{configuration::get_configuration, startup}; use email_newsletter_api::{configuration::get_configuration, startup};
use secrecy::ExposeSecret;
use sqlx::PgPool; use sqlx::PgPool;
#[tokio::main] #[tokio::main]
@ -15,7 +16,7 @@ async fn main() -> Result<(), std::io::Error> {
); );
init_subscriber(subscriber); init_subscriber(subscriber);
let db_conn = PgPool::connect(&configuration.database.connection_string()) let db_conn = PgPool::connect(configuration.database.connection_string().expose_secret())
.await .await
.expect("Failed to connect to PostgreSQL"); .expect("Failed to connect to PostgreSQL");

View File

@ -3,6 +3,7 @@ use email_newsletter_api::{
telemetry::{get_subscriber, init_subscriber}, telemetry::{get_subscriber, init_subscriber},
}; };
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use secrecy::ExposeSecret;
use sqlx::{Connection, Executor, PgConnection, PgPool}; use sqlx::{Connection, Executor, PgConnection, PgPool};
use std::net::TcpListener; use std::net::TcpListener;
use uuid::Uuid; use uuid::Uuid;
@ -57,7 +58,8 @@ pub async fn spawn_app() -> TestApp {
} }
pub async fn configure_test_database(db_config: &DatabaseSettings) -> PgPool { pub async fn configure_test_database(db_config: &DatabaseSettings) -> PgPool {
let mut connection = PgConnection::connect(&db_config.connection_string_without_db()) let mut connection =
PgConnection::connect(db_config.connection_string_without_db().expose_secret())
.await .await
.expect("Failed to connect to Postgres"); .expect("Failed to connect to Postgres");
@ -66,7 +68,7 @@ pub async fn configure_test_database(db_config: &DatabaseSettings) -> PgPool {
.await .await
.expect("Failed to create database"); .expect("Failed to create database");
let conn_pool = PgPool::connect(&db_config.connection_string()) let conn_pool = PgPool::connect(db_config.connection_string().expose_secret())
.await .await
.expect("Failed to connect to PostgreSQL pool"); .expect("Failed to connect to PostgreSQL pool");