mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-18 13:14:59 +01:00
Psgl auth db (#1095)
* feat(cdk-mintd): add dedicated auth database configuration support
This commit is contained in:
@@ -295,6 +295,7 @@ fn create_ldk_settings(
|
||||
fake_wallet: None,
|
||||
grpc_processor: None,
|
||||
database: cdk_mintd::config::Database::default(),
|
||||
auth_database: None,
|
||||
mint_management_rpc: None,
|
||||
prometheus: None,
|
||||
auth: None,
|
||||
|
||||
@@ -219,6 +219,7 @@ pub fn create_fake_wallet_settings(
|
||||
engine: DatabaseEngine::from_str(database).expect("valid database"),
|
||||
postgres: None,
|
||||
},
|
||||
auth_database: None,
|
||||
mint_management_rpc: None,
|
||||
auth: None,
|
||||
prometheus: Some(Default::default()),
|
||||
@@ -268,6 +269,7 @@ pub fn create_cln_settings(
|
||||
fake_wallet: None,
|
||||
grpc_processor: None,
|
||||
database: cdk_mintd::config::Database::default(),
|
||||
auth_database: None,
|
||||
mint_management_rpc: None,
|
||||
auth: None,
|
||||
prometheus: Some(Default::default()),
|
||||
@@ -315,6 +317,7 @@ pub fn create_lnd_settings(
|
||||
fake_wallet: None,
|
||||
grpc_processor: None,
|
||||
database: cdk_mintd::config::Database::default(),
|
||||
auth_database: None,
|
||||
mint_management_rpc: None,
|
||||
auth: None,
|
||||
prometheus: Some(Default::default()),
|
||||
|
||||
@@ -74,6 +74,19 @@ max_connections = 20
|
||||
# Connection timeout in seconds (optional, defaults to 10)
|
||||
connection_timeout_seconds = 10
|
||||
|
||||
# Auth database configuration (optional, only used when auth is enabled)
|
||||
[auth_database.postgres]
|
||||
# PostgreSQL connection URL for authentication database
|
||||
# Can also be set via CDK_MINTD_AUTH_POSTGRES_URL environment variable
|
||||
# Environment variables take precedence over config file settings
|
||||
url = "postgresql://user:password@localhost:5432/cdk_mint_auth"
|
||||
# TLS mode: "disable", "prefer", "require" (optional, defaults to "disable")
|
||||
tls_mode = "disable"
|
||||
# Maximum number of connections in the pool (optional, defaults to 20)
|
||||
max_connections = 20
|
||||
# Connection timeout in seconds (optional, defaults to 10)
|
||||
connection_timeout_seconds = 10
|
||||
|
||||
[ln]
|
||||
# Required ln backend `cln`, `lnd`, `fakewallet`, 'lnbits', 'ldknode'
|
||||
ln_backend = "fakewallet"
|
||||
|
||||
@@ -367,6 +367,30 @@ pub struct Database {
|
||||
pub postgres: Option<PostgresConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct AuthDatabase {
|
||||
pub postgres: Option<PostgresAuthConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PostgresAuthConfig {
|
||||
pub url: String,
|
||||
pub tls_mode: Option<String>,
|
||||
pub max_connections: Option<usize>,
|
||||
pub connection_timeout_seconds: Option<u64>,
|
||||
}
|
||||
|
||||
impl Default for PostgresAuthConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
url: String::new(),
|
||||
tls_mode: Some("disable".to_string()),
|
||||
max_connections: Some(20),
|
||||
connection_timeout_seconds: Some(10),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PostgresConfig {
|
||||
pub url: String,
|
||||
@@ -457,6 +481,8 @@ pub struct Settings {
|
||||
pub fake_wallet: Option<FakeWallet>,
|
||||
pub grpc_processor: Option<GrpcProcessor>,
|
||||
pub database: Database,
|
||||
#[cfg(feature = "auth")]
|
||||
pub auth_database: Option<AuthDatabase>,
|
||||
#[cfg(feature = "management-rpc")]
|
||||
pub mint_management_rpc: Option<MintManagementRpc>,
|
||||
pub auth: Option<Auth>,
|
||||
|
||||
@@ -2,13 +2,19 @@
|
||||
|
||||
use std::env;
|
||||
|
||||
use crate::config::PostgresConfig;
|
||||
use crate::config::{PostgresAuthConfig, PostgresConfig};
|
||||
|
||||
pub const ENV_POSTGRES_URL: &str = "CDK_MINTD_POSTGRES_URL";
|
||||
pub const ENV_POSTGRES_TLS_MODE: &str = "CDK_MINTD_POSTGRES_TLS_MODE";
|
||||
pub const ENV_POSTGRES_MAX_CONNECTIONS: &str = "CDK_MINTD_POSTGRES_MAX_CONNECTIONS";
|
||||
pub const ENV_POSTGRES_CONNECTION_TIMEOUT: &str = "CDK_MINTD_POSTGRES_CONNECTION_TIMEOUT_SECONDS";
|
||||
|
||||
pub const ENV_AUTH_POSTGRES_URL: &str = "CDK_MINTD_AUTH_POSTGRES_URL";
|
||||
pub const ENV_AUTH_POSTGRES_TLS_MODE: &str = "CDK_MINTD_AUTH_POSTGRES_TLS_MODE";
|
||||
pub const ENV_AUTH_POSTGRES_MAX_CONNECTIONS: &str = "CDK_MINTD_AUTH_POSTGRES_MAX_CONNECTIONS";
|
||||
pub const ENV_AUTH_POSTGRES_CONNECTION_TIMEOUT: &str =
|
||||
"CDK_MINTD_AUTH_POSTGRES_CONNECTION_TIMEOUT_SECONDS";
|
||||
|
||||
impl PostgresConfig {
|
||||
pub fn from_env(mut self) -> Self {
|
||||
// Check for new PostgreSQL URL env var first, then fallback to legacy DATABASE_URL
|
||||
@@ -38,3 +44,29 @@ impl PostgresConfig {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl PostgresAuthConfig {
|
||||
pub fn from_env(mut self) -> Self {
|
||||
if let Ok(url) = env::var(ENV_AUTH_POSTGRES_URL) {
|
||||
self.url = url;
|
||||
}
|
||||
|
||||
if let Ok(tls_mode) = env::var(ENV_AUTH_POSTGRES_TLS_MODE) {
|
||||
self.tls_mode = Some(tls_mode);
|
||||
}
|
||||
|
||||
if let Ok(max_connections) = env::var(ENV_AUTH_POSTGRES_MAX_CONNECTIONS) {
|
||||
if let Ok(parsed) = max_connections.parse::<usize>() {
|
||||
self.max_connections = Some(parsed);
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(timeout) = env::var(ENV_AUTH_POSTGRES_CONNECTION_TIMEOUT) {
|
||||
if let Ok(parsed) = timeout.parse::<u64>() {
|
||||
self.connection_timeout_seconds = Some(parsed);
|
||||
}
|
||||
}
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,6 +75,21 @@ impl Settings {
|
||||
);
|
||||
}
|
||||
|
||||
// Parse auth database configuration from environment variables (when auth is enabled)
|
||||
#[cfg(feature = "auth")]
|
||||
{
|
||||
self.auth_database = Some(crate::config::AuthDatabase {
|
||||
postgres: Some(
|
||||
self.auth_database
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.postgres
|
||||
.unwrap_or_default()
|
||||
.from_env(),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
self.info = self.info.clone().from_env();
|
||||
self.mint_info = self.mint_info.clone().from_env();
|
||||
self.ln = self.ln.clone().from_env();
|
||||
|
||||
@@ -43,7 +43,7 @@ use cdk_common::database::DynMintDatabase;
|
||||
#[cfg(feature = "prometheus")]
|
||||
use cdk_common::payment::MetricsMintPayment;
|
||||
use cdk_common::payment::MintPayment;
|
||||
#[cfg(feature = "auth")]
|
||||
#[cfg(all(feature = "auth", feature = "postgres"))]
|
||||
use cdk_postgres::MintPgAuthDatabase;
|
||||
#[cfg(feature = "postgres")]
|
||||
use cdk_postgres::MintPgDatabase;
|
||||
@@ -663,16 +663,20 @@ async fn setup_authentication(
|
||||
DatabaseEngine::Postgres => {
|
||||
#[cfg(feature = "postgres")]
|
||||
{
|
||||
// Get the PostgreSQL configuration, ensuring it exists
|
||||
let pg_config = settings.database.postgres.as_ref().ok_or_else(|| {
|
||||
anyhow!("PostgreSQL configuration is required when using PostgreSQL engine")
|
||||
// Require dedicated auth database configuration - no fallback to main database
|
||||
let auth_db_config = settings.auth_database.as_ref().ok_or_else(|| {
|
||||
anyhow!("Auth database configuration is required when using PostgreSQL with authentication. Set [auth_database] section in config file or CDK_MINTD_AUTH_POSTGRES_URL environment variable")
|
||||
})?;
|
||||
|
||||
if pg_config.url.is_empty() {
|
||||
bail!("PostgreSQL URL is required for auth database. Set it in config file [database.postgres] section or via CDK_MINTD_POSTGRES_URL/CDK_MINTD_DATABASE_URL environment variable");
|
||||
let auth_pg_config = auth_db_config.postgres.as_ref().ok_or_else(|| {
|
||||
anyhow!("PostgreSQL auth database configuration is required when using PostgreSQL with authentication. Set [auth_database.postgres] section in config file or CDK_MINTD_AUTH_POSTGRES_URL environment variable")
|
||||
})?;
|
||||
|
||||
if auth_pg_config.url.is_empty() {
|
||||
bail!("Auth database PostgreSQL URL is required and cannot be empty. Set it in config file [auth_database.postgres] section or via CDK_MINTD_AUTH_POSTGRES_URL environment variable");
|
||||
}
|
||||
|
||||
Arc::new(MintPgAuthDatabase::new(pg_config.url.as_str()).await?)
|
||||
Arc::new(MintPgAuthDatabase::new(auth_pg_config.url.as_str()).await?)
|
||||
}
|
||||
#[cfg(not(feature = "postgres"))]
|
||||
{
|
||||
@@ -1188,3 +1192,27 @@ pub async fn run_mintd_with_shutdown(
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_postgres_auth_url_validation() {
|
||||
// Test that the auth database config requires explicit configuration
|
||||
|
||||
// Test empty URL
|
||||
let auth_config = config::PostgresAuthConfig {
|
||||
url: "".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
assert!(auth_config.url.is_empty());
|
||||
|
||||
// Test non-empty URL
|
||||
let auth_config = config::PostgresAuthConfig {
|
||||
url: "postgresql://user:password@localhost:5432/auth_db".to_string(),
|
||||
..Default::default()
|
||||
};
|
||||
assert!(!auth_config.url.is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,4 +27,11 @@ docker exec -e PGPASSWORD="${DB_PASS}" "${CONTAINER_NAME}" \
|
||||
docker exec -e PGPASSWORD="${DB_PASS}" "${CONTAINER_NAME}" \
|
||||
psql -U "${DB_USER}" -d "${DB_NAME}" -c "CREATE DATABASE mintdb_auth;"
|
||||
|
||||
# Export environment variables for both main and auth databases
|
||||
export DATABASE_URL="host=localhost user=${DB_USER} password=${DB_PASS} dbname=${DB_NAME} port=${DB_PORT}"
|
||||
export CDK_MINTD_POSTGRES_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:${DB_PORT}/mintdb"
|
||||
export CDK_MINTD_AUTH_POSTGRES_URL="postgresql://${DB_USER}:${DB_PASS}@localhost:${DB_PORT}/mintdb_auth"
|
||||
|
||||
echo "Database URLs configured:"
|
||||
echo "Main database: ${CDK_MINTD_POSTGRES_URL}"
|
||||
echo "Auth database: ${CDK_MINTD_AUTH_POSTGRES_URL}"
|
||||
|
||||
@@ -198,9 +198,11 @@ where
|
||||
for (endpoint, auth) in protected_endpoints.iter() {
|
||||
if let Err(err) = query(
|
||||
r#"
|
||||
INSERT OR REPLACE INTO protected_endpoints
|
||||
INSERT INTO protected_endpoints
|
||||
(endpoint, auth)
|
||||
VALUES (:endpoint, :auth);
|
||||
VALUES (:endpoint, :auth)
|
||||
ON CONFLICT (endpoint) DO UPDATE SET
|
||||
auth = EXCLUDED.auth;
|
||||
"#,
|
||||
)?
|
||||
.bind("endpoint", serde_json::to_string(endpoint)?)
|
||||
|
||||
Reference in New Issue
Block a user