diff --git a/crates/cdk-integration-tests/src/bin/start_fake_auth_mint.rs b/crates/cdk-integration-tests/src/bin/start_fake_auth_mint.rs index 4cb3ad9d..5846a53c 100644 --- a/crates/cdk-integration-tests/src/bin/start_fake_auth_mint.rs +++ b/crates/cdk-integration-tests/src/bin/start_fake_auth_mint.rs @@ -17,6 +17,7 @@ use anyhow::Result; use bip39::Mnemonic; use cdk_integration_tests::cli::CommonArgs; use cdk_integration_tests::shared; +use cdk_mintd::config::AuthType; use clap::Parser; use tokio::sync::Notify; @@ -68,16 +69,19 @@ async fn start_fake_auth_mint( // Enable authentication settings.auth = Some(cdk_mintd::config::Auth { + auth_enabled: true, openid_discovery, openid_client_id: "cashu-client".to_string(), mint_max_bat: 50, - enabled_mint: true, - enabled_melt: true, - enabled_swap: true, - enabled_check_mint_quote: true, - enabled_check_melt_quote: true, - enabled_restore: true, - enabled_check_proof_state: true, + mint: AuthType::Blind, + get_mint_quote: AuthType::Blind, + check_mint_quote: AuthType::Blind, + melt: AuthType::Blind, + get_melt_quote: AuthType::Blind, + check_melt_quote: AuthType::Blind, + swap: AuthType::Blind, + restore: AuthType::Blind, + check_proof_state: AuthType::Blind, }); // Set description for the mint diff --git a/crates/cdk-mintd/example.config.toml b/crates/cdk-mintd/example.config.toml index 8828a65a..1e4d3c3e 100644 --- a/crates/cdk-mintd/example.config.toml +++ b/crates/cdk-mintd/example.config.toml @@ -83,13 +83,23 @@ reserve_fee_min = 4 # tls_dir = "/path/to/tls" # [auth] +# Set to true to enable authentication features (defaults to false) +# auth_enabled = false # openid_discovery = "http://127.0.0.1:8080/realms/cdk-test-realm/.well-known/openid-configuration" # openid_client_id = "cashu-client" # mint_max_bat=50 -# enabled_mint=true -# enabled_melt=true -# enabled_swap=true -# enabled_check_mint_quote=true -# enabled_check_melt_quote=true -# enabled_restore=true -# enabled_check_proof_state=true + +# Authentication settings for endpoints +# Options: "clear", "blind", "none" (none = disabled) + +# mint = "blind" +# get_mint_quote = "none" +# check_mint_quote = "none" + +# melt = "none" +# get_melt_quote = "none" +# check_melt_quote = "none" + +# swap = "blind" +# restore = "blind" +# check_proof_state = "none" diff --git a/crates/cdk-mintd/src/config.rs b/crates/cdk-mintd/src/config.rs index 636080fb..bd245e72 100644 --- a/crates/cdk-mintd/src/config.rs +++ b/crates/cdk-mintd/src/config.rs @@ -208,30 +208,59 @@ pub struct Database { pub engine: DatabaseEngine, } +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)] +#[serde(rename_all = "lowercase")] +pub enum AuthType { + Clear, + Blind, + #[default] + None, +} + +impl std::str::FromStr for AuthType { + type Err = String; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "clear" => Ok(AuthType::Clear), + "blind" => Ok(AuthType::Blind), + "none" => Ok(AuthType::None), + _ => Err(format!("Unknown auth type: {s}")), + } + } +} + #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Auth { + #[serde(default)] + pub auth_enabled: bool, pub openid_discovery: String, pub openid_client_id: String, pub mint_max_bat: u64, - #[serde(default = "default_true")] - pub enabled_mint: bool, - #[serde(default = "default_true")] - pub enabled_melt: bool, - #[serde(default = "default_true")] - pub enabled_swap: bool, - #[serde(default = "default_true")] - pub enabled_check_mint_quote: bool, - #[serde(default = "default_true")] - pub enabled_check_melt_quote: bool, - #[serde(default = "default_true")] - pub enabled_restore: bool, - #[serde(default = "default_true")] - pub enabled_check_proof_state: bool, + #[serde(default = "default_blind")] + pub mint: AuthType, + #[serde(default)] + pub get_mint_quote: AuthType, + #[serde(default)] + pub check_mint_quote: AuthType, + #[serde(default)] + pub melt: AuthType, + #[serde(default)] + pub get_melt_quote: AuthType, + #[serde(default)] + pub check_melt_quote: AuthType, + #[serde(default = "default_blind")] + pub swap: AuthType, + #[serde(default = "default_blind")] + pub restore: AuthType, + #[serde(default)] + pub check_proof_state: AuthType, } -fn default_true() -> bool { - true +fn default_blind() -> AuthType { + AuthType::Blind } + /// CDK settings, derived from `config.toml` #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Settings { diff --git a/crates/cdk-mintd/src/env_vars/auth.rs b/crates/cdk-mintd/src/env_vars/auth.rs index 93a324d2..62d32597 100644 --- a/crates/cdk-mintd/src/env_vars/auth.rs +++ b/crates/cdk-mintd/src/env_vars/auth.rs @@ -4,19 +4,28 @@ use std::env; use crate::config::Auth; +pub const ENV_AUTH_ENABLED: &str = "CDK_MINTD_AUTH_ENABLED"; pub const ENV_AUTH_OPENID_DISCOVERY: &str = "CDK_MINTD_AUTH_OPENID_DISCOVERY"; pub const ENV_AUTH_OPENID_CLIENT_ID: &str = "CDK_MINTD_AUTH_OPENID_CLIENT_ID"; pub const ENV_AUTH_MINT_MAX_BAT: &str = "CDK_MINTD_AUTH_MINT_MAX_BAT"; -pub const ENV_AUTH_ENABLED_MINT: &str = "CDK_MINTD_AUTH_ENABLED_MINT"; -pub const ENV_AUTH_ENABLED_MELT: &str = "CDK_MINTD_AUTH_ENABLED_MELT"; -pub const ENV_AUTH_ENABLED_SWAP: &str = "CDK_MINTD_AUTH_ENABLED_SWAP"; -pub const ENV_AUTH_ENABLED_CHECK_MINT_QUOTE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_MINT_QUOTE"; -pub const ENV_AUTH_ENABLED_CHECK_MELT_QUOTE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_MELT_QUOTE"; -pub const ENV_AUTH_ENABLED_RESTORE: &str = "CDK_MINTD_AUTH_ENABLED_RESTORE"; -pub const ENV_AUTH_ENABLED_CHECK_PROOF_STATE: &str = "CDK_MINTD_AUTH_ENABLED_CHECK_PROOF_STATE"; +pub const ENV_AUTH_MINT: &str = "CDK_MINTD_AUTH_MINT"; +pub const ENV_AUTH_GET_MINT_QUOTE: &str = "CDK_MINTD_AUTH_GET_MINT_QUOTE"; +pub const ENV_AUTH_CHECK_MINT_QUOTE: &str = "CDK_MINTD_AUTH_CHECK_MINT_QUOTE"; +pub const ENV_AUTH_MELT: &str = "CDK_MINTD_AUTH_MELT"; +pub const ENV_AUTH_GET_MELT_QUOTE: &str = "CDK_MINTD_AUTH_GET_MELT_QUOTE"; +pub const ENV_AUTH_CHECK_MELT_QUOTE: &str = "CDK_MINTD_AUTH_CHECK_MELT_QUOTE"; +pub const ENV_AUTH_SWAP: &str = "CDK_MINTD_AUTH_SWAP"; +pub const ENV_AUTH_RESTORE: &str = "CDK_MINTD_AUTH_RESTORE"; +pub const ENV_AUTH_CHECK_PROOF_STATE: &str = "CDK_MINTD_AUTH_CHECK_PROOF_STATE"; impl Auth { pub fn from_env(mut self) -> Self { + if let Ok(enabled_str) = env::var(ENV_AUTH_ENABLED) { + if let Ok(enabled) = enabled_str.parse() { + self.auth_enabled = enabled; + } + } + if let Ok(discovery) = env::var(ENV_AUTH_OPENID_DISCOVERY) { self.openid_discovery = discovery; } @@ -31,45 +40,57 @@ impl Auth { } } - if let Ok(enabled_mint_str) = env::var(ENV_AUTH_ENABLED_MINT) { - if let Ok(enabled) = enabled_mint_str.parse() { - self.enabled_mint = enabled; + if let Ok(mint_str) = env::var(ENV_AUTH_MINT) { + if let Ok(auth_type) = mint_str.parse() { + self.mint = auth_type; } } - if let Ok(enabled_melt_str) = env::var(ENV_AUTH_ENABLED_MELT) { - if let Ok(enabled) = enabled_melt_str.parse() { - self.enabled_melt = enabled; + if let Ok(get_mint_quote_str) = env::var(ENV_AUTH_GET_MINT_QUOTE) { + if let Ok(auth_type) = get_mint_quote_str.parse() { + self.get_mint_quote = auth_type; } } - if let Ok(enabled_swap_str) = env::var(ENV_AUTH_ENABLED_SWAP) { - if let Ok(enabled) = enabled_swap_str.parse() { - self.enabled_swap = enabled; + if let Ok(check_mint_quote_str) = env::var(ENV_AUTH_CHECK_MINT_QUOTE) { + if let Ok(auth_type) = check_mint_quote_str.parse() { + self.check_mint_quote = auth_type; } } - if let Ok(enabled_check_mint_str) = env::var(ENV_AUTH_ENABLED_CHECK_MINT_QUOTE) { - if let Ok(enabled) = enabled_check_mint_str.parse() { - self.enabled_check_mint_quote = enabled; + if let Ok(melt_str) = env::var(ENV_AUTH_MELT) { + if let Ok(auth_type) = melt_str.parse() { + self.melt = auth_type; } } - if let Ok(enabled_check_melt_str) = env::var(ENV_AUTH_ENABLED_CHECK_MELT_QUOTE) { - if let Ok(enabled) = enabled_check_melt_str.parse() { - self.enabled_check_melt_quote = enabled; + if let Ok(get_melt_quote_str) = env::var(ENV_AUTH_GET_MELT_QUOTE) { + if let Ok(auth_type) = get_melt_quote_str.parse() { + self.get_melt_quote = auth_type; } } - if let Ok(enabled_restore_str) = env::var(ENV_AUTH_ENABLED_RESTORE) { - if let Ok(enabled) = enabled_restore_str.parse() { - self.enabled_restore = enabled; + if let Ok(check_melt_quote_str) = env::var(ENV_AUTH_CHECK_MELT_QUOTE) { + if let Ok(auth_type) = check_melt_quote_str.parse() { + self.check_melt_quote = auth_type; } } - if let Ok(enabled_check_proof_str) = env::var(ENV_AUTH_ENABLED_CHECK_PROOF_STATE) { - if let Ok(enabled) = enabled_check_proof_str.parse() { - self.enabled_check_proof_state = enabled; + if let Ok(swap_str) = env::var(ENV_AUTH_SWAP) { + if let Ok(auth_type) = swap_str.parse() { + self.swap = auth_type; + } + } + + if let Ok(restore_str) = env::var(ENV_AUTH_RESTORE) { + if let Ok(auth_type) = restore_str.parse() { + self.restore = auth_type; + } + } + + if let Ok(check_proof_state_str) = env::var(ENV_AUTH_CHECK_PROOF_STATE) { + if let Ok(auth_type) = check_proof_state_str.parse() { + self.check_proof_state = auth_type; } } diff --git a/crates/cdk-mintd/src/env_vars/mod.rs b/crates/cdk-mintd/src/env_vars/mod.rs index 662432bd..aab0f327 100644 --- a/crates/cdk-mintd/src/env_vars/mod.rs +++ b/crates/cdk-mintd/src/env_vars/mod.rs @@ -63,14 +63,8 @@ impl Settings { // Check env vars for auth config even if None let auth = self.auth.clone().unwrap_or_default().from_env(); - // Only set auth if env vars are present and have non-default values - if auth.openid_discovery != String::default() - || auth.openid_client_id != String::default() - || auth.mint_max_bat != 0 - || auth.enabled_mint - || auth.enabled_melt - || auth.enabled_swap - { + // Only set auth if auth_enabled flag is true + if auth.auth_enabled { self.auth = Some(auth); } else { self.auth = None; diff --git a/crates/cdk-mintd/src/lib.rs b/crates/cdk-mintd/src/lib.rs index 86adbf1b..89121e77 100644 --- a/crates/cdk-mintd/src/lib.rs +++ b/crates/cdk-mintd/src/lib.rs @@ -43,7 +43,7 @@ use cdk_axum::cache::HttpCache; use cdk_sqlite::mint::MintSqliteAuthDatabase; use cdk_sqlite::MintSqliteDatabase; use cli::CLIArgs; -use config::{DatabaseEngine, LnBackend}; +use config::{AuthType, DatabaseEngine, LnBackend}; use env_vars::ENV_WORK_DIR; use setup::LnBackendSetup; use tower::ServiceBuilder; @@ -456,116 +456,110 @@ async fn setup_authentication( } }; + let mut protected_endpoints = HashMap::new(); + let mut blind_auth_endpoints = vec![]; + let mut clear_auth_endpoints = vec![]; + let mut unprotected_endpoints = vec![]; + let mint_blind_auth_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::MintBlindAuth); - let mut protected_endpoints = HashMap::new(); - protected_endpoints.insert(mint_blind_auth_endpoint, AuthRequired::Clear); - let mut blind_auth_endpoints = vec![]; - let mut unprotected_endpoints = vec![]; + clear_auth_endpoints.push(mint_blind_auth_endpoint); + // Helper function to add endpoint based on auth type + let mut add_endpoint = |endpoint: ProtectedEndpoint, auth_type: &AuthType| { + match auth_type { + AuthType::Blind => { + protected_endpoints.insert(endpoint, AuthRequired::Blind); + blind_auth_endpoints.push(endpoint); + } + AuthType::Clear => { + protected_endpoints.insert(endpoint, AuthRequired::Clear); + clear_auth_endpoints.push(endpoint); + } + AuthType::None => { + unprotected_endpoints.push(endpoint); + } + }; + }; + + // Get mint quote endpoint { let mint_quote_protected_endpoint = - ProtectedEndpoint::new(Method::Post, RoutePath::MintQuoteBolt11); - let mint_protected_endpoint = - ProtectedEndpoint::new(Method::Post, RoutePath::MintBolt11); - if auth_settings.enabled_mint { - protected_endpoints.insert(mint_quote_protected_endpoint, AuthRequired::Blind); - - protected_endpoints.insert(mint_protected_endpoint, AuthRequired::Blind); - - blind_auth_endpoints.push(mint_quote_protected_endpoint); - blind_auth_endpoints.push(mint_protected_endpoint); - } else { - unprotected_endpoints.push(mint_protected_endpoint); - unprotected_endpoints.push(mint_quote_protected_endpoint); - } - } - - { - let melt_quote_protected_endpoint = - ProtectedEndpoint::new(Method::Post, RoutePath::MeltQuoteBolt11); - let melt_protected_endpoint = - ProtectedEndpoint::new(Method::Post, RoutePath::MeltBolt11); - - if auth_settings.enabled_melt { - protected_endpoints.insert(melt_quote_protected_endpoint, AuthRequired::Blind); - protected_endpoints.insert(melt_protected_endpoint, AuthRequired::Blind); - - blind_auth_endpoints.push(melt_quote_protected_endpoint); - blind_auth_endpoints.push(melt_protected_endpoint); - } else { - unprotected_endpoints.push(melt_quote_protected_endpoint); - unprotected_endpoints.push(melt_protected_endpoint); - } - } - - { - let swap_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Swap); - - if auth_settings.enabled_swap { - protected_endpoints.insert(swap_protected_endpoint, AuthRequired::Blind); - blind_auth_endpoints.push(swap_protected_endpoint); - } else { - unprotected_endpoints.push(swap_protected_endpoint); - } + ProtectedEndpoint::new(cdk::nuts::Method::Post, RoutePath::MintQuoteBolt11); + add_endpoint(mint_quote_protected_endpoint, &auth_settings.get_mint_quote); } + // Check mint quote endpoint { let check_mint_protected_endpoint = ProtectedEndpoint::new(Method::Get, RoutePath::MintQuoteBolt11); - - if auth_settings.enabled_check_mint_quote { - protected_endpoints.insert(check_mint_protected_endpoint, AuthRequired::Blind); - blind_auth_endpoints.push(check_mint_protected_endpoint); - } else { - unprotected_endpoints.push(check_mint_protected_endpoint); - } + add_endpoint( + check_mint_protected_endpoint, + &auth_settings.check_mint_quote, + ); } + // Mint endpoint + { + let mint_protected_endpoint = + ProtectedEndpoint::new(cdk::nuts::Method::Post, RoutePath::MintBolt11); + add_endpoint(mint_protected_endpoint, &auth_settings.mint); + } + + // Get melt quote endpoint + { + let melt_quote_protected_endpoint = ProtectedEndpoint::new( + cdk::nuts::Method::Post, + cdk::nuts::RoutePath::MeltQuoteBolt11, + ); + add_endpoint(melt_quote_protected_endpoint, &auth_settings.get_melt_quote); + } + + // Check melt quote endpoint { let check_melt_protected_endpoint = ProtectedEndpoint::new(Method::Get, RoutePath::MeltQuoteBolt11); - - if auth_settings.enabled_check_melt_quote { - protected_endpoints.insert(check_melt_protected_endpoint, AuthRequired::Blind); - blind_auth_endpoints.push(check_melt_protected_endpoint); - } else { - unprotected_endpoints.push(check_melt_protected_endpoint); - } + add_endpoint( + check_melt_protected_endpoint, + &auth_settings.check_melt_quote, + ); } + // Melt endpoint + { + let melt_protected_endpoint = + ProtectedEndpoint::new(Method::Post, RoutePath::MeltBolt11); + add_endpoint(melt_protected_endpoint, &auth_settings.melt); + } + + // Swap endpoint + { + let swap_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Swap); + add_endpoint(swap_protected_endpoint, &auth_settings.swap); + } + + // Restore endpoint { let restore_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Restore); - - if auth_settings.enabled_restore { - protected_endpoints.insert(restore_protected_endpoint, AuthRequired::Blind); - blind_auth_endpoints.push(restore_protected_endpoint); - } else { - unprotected_endpoints.push(restore_protected_endpoint); - } + add_endpoint(restore_protected_endpoint, &auth_settings.restore); } + // Check proof state endpoint { let state_protected_endpoint = ProtectedEndpoint::new(Method::Post, RoutePath::Checkstate); - - if auth_settings.enabled_check_proof_state { - protected_endpoints.insert(state_protected_endpoint, AuthRequired::Blind); - blind_auth_endpoints.push(state_protected_endpoint); - } else { - unprotected_endpoints.push(state_protected_endpoint); - } + add_endpoint(state_protected_endpoint, &auth_settings.check_proof_state); } mint_builder = mint_builder.with_auth( auth_localstore.clone(), auth_settings.openid_discovery, auth_settings.openid_client_id, - vec![mint_blind_auth_endpoint], + clear_auth_endpoints, ); mint_builder = mint_builder.with_blind_auth(auth_settings.mint_max_bat, blind_auth_endpoints);