mirror of
https://github.com/aljazceru/cdk.git
synced 2025-12-23 07:35:03 +01:00
Refactor MintBuilder (#887)
* Refactor MintBuilder * Validate azp instead of aud for client id
This commit is contained in:
@@ -20,7 +20,7 @@ pub(crate) async fn handle(
|
|||||||
let mut subscription = context
|
let mut subscription = context
|
||||||
.state
|
.state
|
||||||
.mint
|
.mint
|
||||||
.pubsub_manager
|
.pubsub_manager()
|
||||||
.try_subscribe(params)
|
.try_subscribe(params)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| WsError::ParseError)?;
|
.map_err(|_| WsError::ParseError)?;
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ async fn get_device_code_token(mint_info: &MintInfo, client_id: &str) -> (String
|
|||||||
.expect("Nut21 defined")
|
.expect("Nut21 defined")
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the OIDC configuration
|
// Get the OIDC configuration
|
||||||
let oidc_config = oidc_client
|
let oidc_config = oidc_client
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ async fn get_access_token(
|
|||||||
.expect("Nut21 defined")
|
.expect("Nut21 defined")
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the token endpoint from the OIDC configuration
|
// Get the token endpoint from the OIDC configuration
|
||||||
let token_url = oidc_client
|
let token_url = oidc_client
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ async fn refresh_access_token(
|
|||||||
.ok_or_else(|| anyhow::anyhow!("OIDC discovery information not available"))?
|
.ok_or_else(|| anyhow::anyhow!("OIDC discovery information not available"))?
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the token endpoint from the OIDC configuration
|
// Get the token endpoint from the OIDC configuration
|
||||||
let token_url = oidc_client.get_oidc_config().await?.token_endpoint;
|
let token_url = oidc_client.get_oidc_config().await?.token_endpoint;
|
||||||
|
|||||||
@@ -162,8 +162,8 @@ impl PaymentProcessorKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Secs wuotes are valid
|
/// Seconds quotes are valid
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize, Default)]
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct QuoteTTL {
|
pub struct QuoteTTL {
|
||||||
/// Seconds mint quote is valid
|
/// Seconds mint quote is valid
|
||||||
pub mint_ttl: u64,
|
pub mint_ttl: u64,
|
||||||
@@ -178,6 +178,15 @@ impl QuoteTTL {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for QuoteTTL {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mint_ttl: 60 * 60, // 1 hour
|
||||||
|
melt_ttl: 60, // 1 minute
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|||||||
@@ -31,14 +31,10 @@ where
|
|||||||
|
|
||||||
let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
|
let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
|
||||||
|
|
||||||
let mut mint_builder = MintBuilder::new();
|
let mut mint_builder = MintBuilder::new(Arc::new(database));
|
||||||
|
|
||||||
mint_builder = mint_builder
|
mint_builder
|
||||||
.with_localstore(Arc::new(database))
|
.add_payment_processor(
|
||||||
.with_keystore(Arc::new(key_store));
|
|
||||||
|
|
||||||
mint_builder = mint_builder
|
|
||||||
.add_ln_backend(
|
|
||||||
CurrencyUnit::Sat,
|
CurrencyUnit::Sat,
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
MintMeltLimits::new(1, 300),
|
MintMeltLimits::new(1, 300),
|
||||||
@@ -46,10 +42,14 @@ where
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
mint_builder =
|
let auth_database = Arc::new(auth_database);
|
||||||
mint_builder.set_clear_auth_settings(openid_discovery, "cashu-client".to_string());
|
|
||||||
|
|
||||||
mint_builder = mint_builder.set_blind_auth_settings(50);
|
mint_builder = mint_builder.with_auth(
|
||||||
|
auth_database.clone(),
|
||||||
|
openid_discovery,
|
||||||
|
"cashu-client".to_string(),
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
|
||||||
let blind_auth_endpoints = vec![
|
let blind_auth_endpoints = vec![
|
||||||
ProtectedEndpoint::new(Method::Post, RoutePath::MintQuoteBolt11),
|
ProtectedEndpoint::new(Method::Post, RoutePath::MintQuoteBolt11),
|
||||||
@@ -71,6 +71,8 @@ where
|
|||||||
acc
|
acc
|
||||||
});
|
});
|
||||||
|
|
||||||
|
mint_builder = mint_builder.with_blind_auth(50, blind_auth_endpoints.keys().cloned().collect());
|
||||||
|
|
||||||
let mut tx = auth_database.begin_transaction().await?;
|
let mut tx = auth_database.begin_transaction().await?;
|
||||||
|
|
||||||
tx.add_protected_endpoints(blind_auth_endpoints).await?;
|
tx.add_protected_endpoints(blind_auth_endpoints).await?;
|
||||||
@@ -85,15 +87,13 @@ where
|
|||||||
|
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
|
|
||||||
mint_builder = mint_builder.with_auth_localstore(Arc::new(auth_database));
|
|
||||||
|
|
||||||
let mnemonic = Mnemonic::generate(12)?;
|
let mnemonic = Mnemonic::generate(12)?;
|
||||||
|
|
||||||
mint_builder = mint_builder
|
mint_builder = mint_builder.with_description("fake test mint".to_string());
|
||||||
.with_description("fake test mint".to_string())
|
|
||||||
.with_seed(mnemonic.to_seed_normalized("").to_vec());
|
|
||||||
|
|
||||||
let _mint = mint_builder.build().await?;
|
let _mint = mint_builder
|
||||||
|
.build_with_seed(Arc::new(key_store), &mnemonic.to_seed_normalized(""))
|
||||||
|
.await?;
|
||||||
|
|
||||||
todo!("Need to start this a cdk mintd keeping as ref for now");
|
todo!("Need to start this a cdk mintd keeping as ref for now");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use async_trait::async_trait;
|
|||||||
use bip39::Mnemonic;
|
use bip39::Mnemonic;
|
||||||
use cashu::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
|
use cashu::{MeltQuoteBolt12Request, MintQuoteBolt12Request, MintQuoteBolt12Response};
|
||||||
use cdk::amount::SplitTarget;
|
use cdk::amount::SplitTarget;
|
||||||
use cdk::cdk_database::{self, WalletDatabase};
|
use cdk::cdk_database::{self, MintDatabase, WalletDatabase};
|
||||||
use cdk::mint::{MintBuilder, MintMeltLimits};
|
use cdk::mint::{MintBuilder, MintMeltLimits};
|
||||||
use cdk::nuts::nut00::ProofsMethods;
|
use cdk::nuts::nut00::ProofsMethods;
|
||||||
use cdk::nuts::{
|
use cdk::nuts::{
|
||||||
@@ -227,25 +227,22 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
|
|||||||
// Read environment variable to determine database type
|
// Read environment variable to determine database type
|
||||||
let db_type = env::var("CDK_TEST_DB_TYPE").expect("Database type set");
|
let db_type = env::var("CDK_TEST_DB_TYPE").expect("Database type set");
|
||||||
|
|
||||||
let mut mint_builder = match db_type.to_lowercase().as_str() {
|
let localstore = match db_type.to_lowercase().as_str() {
|
||||||
"memory" => MintBuilder::new()
|
"memory" => Arc::new(cdk_sqlite::mint::memory::empty().await?),
|
||||||
.with_localstore(Arc::new(cdk_sqlite::mint::memory::empty().await?))
|
|
||||||
.with_keystore(Arc::new(cdk_sqlite::mint::memory::empty().await?)),
|
|
||||||
_ => {
|
_ => {
|
||||||
// Create a temporary directory for SQLite database
|
// Create a temporary directory for SQLite database
|
||||||
let temp_dir = create_temp_dir("cdk-test-sqlite-mint")?;
|
let temp_dir = create_temp_dir("cdk-test-sqlite-mint")?;
|
||||||
let path = temp_dir.join("mint.db").to_str().unwrap().to_string();
|
let path = temp_dir.join("mint.db").to_str().unwrap().to_string();
|
||||||
let database = Arc::new(
|
Arc::new(
|
||||||
cdk_sqlite::MintSqliteDatabase::new(&path)
|
cdk_sqlite::MintSqliteDatabase::new(&path)
|
||||||
.await
|
.await
|
||||||
.expect("Could not create sqlite db"),
|
.expect("Could not create sqlite db"),
|
||||||
);
|
)
|
||||||
MintBuilder::new()
|
|
||||||
.with_localstore(database.clone())
|
|
||||||
.with_keystore(database)
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut mint_builder = MintBuilder::new(localstore.clone());
|
||||||
|
|
||||||
let fee_reserve = FeeReserve {
|
let fee_reserve = FeeReserve {
|
||||||
min_fee_reserve: 1.into(),
|
min_fee_reserve: 1.into(),
|
||||||
percent_fee_reserve: 1.0,
|
percent_fee_reserve: 1.0,
|
||||||
@@ -258,8 +255,8 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
|
|||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
|
|
||||||
mint_builder = mint_builder
|
mint_builder
|
||||||
.add_ln_backend(
|
.add_payment_processor(
|
||||||
CurrencyUnit::Sat,
|
CurrencyUnit::Sat,
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
MintMeltLimits::new(1, 10_000),
|
MintMeltLimits::new(1, 10_000),
|
||||||
@@ -272,23 +269,18 @@ pub async fn create_and_start_test_mint() -> Result<Mint> {
|
|||||||
mint_builder = mint_builder
|
mint_builder = mint_builder
|
||||||
.with_name("pure test mint".to_string())
|
.with_name("pure test mint".to_string())
|
||||||
.with_description("pure test mint".to_string())
|
.with_description("pure test mint".to_string())
|
||||||
.with_urls(vec!["https://aaa".to_string()])
|
.with_urls(vec!["https://aaa".to_string()]);
|
||||||
.with_seed(mnemonic.to_seed_normalized("").to_vec());
|
|
||||||
|
|
||||||
let localstore = mint_builder
|
let tx_localstore = localstore.clone();
|
||||||
.localstore
|
let mut tx = tx_localstore.begin_transaction().await?;
|
||||||
.as_ref()
|
|
||||||
.map(|x| x.clone())
|
|
||||||
.expect("localstore");
|
|
||||||
|
|
||||||
let mut tx = localstore.begin_transaction().await?;
|
|
||||||
tx.set_mint_info(mint_builder.mint_info.clone()).await?;
|
|
||||||
|
|
||||||
let quote_ttl = QuoteTTL::new(10000, 10000);
|
let quote_ttl = QuoteTTL::new(10000, 10000);
|
||||||
tx.set_quote_ttl(quote_ttl).await?;
|
tx.set_quote_ttl(quote_ttl).await?;
|
||||||
tx.commit().await?;
|
tx.commit().await?;
|
||||||
|
|
||||||
let mint = mint_builder.build().await?;
|
let mint = mint_builder
|
||||||
|
.build_with_seed(localstore.clone(), &mnemonic.to_seed_normalized(""))
|
||||||
|
.await?;
|
||||||
|
|
||||||
let mint_clone = mint.clone();
|
let mint_clone = mint.clone();
|
||||||
let shutdown = Arc::new(Notify::new());
|
let shutdown = Arc::new(Notify::new());
|
||||||
|
|||||||
@@ -753,7 +753,7 @@ async fn get_access_token(mint_info: &MintInfo) -> (String, String) {
|
|||||||
.expect("Nutxx defined")
|
.expect("Nutxx defined")
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the token endpoint from the OIDC configuration
|
// Get the token endpoint from the OIDC configuration
|
||||||
let token_url = oidc_client
|
let token_url = oidc_client
|
||||||
@@ -811,7 +811,7 @@ async fn get_custom_access_token(
|
|||||||
.expect("Nutxx defined")
|
.expect("Nutxx defined")
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the token endpoint from the OIDC configuration
|
// Get the token endpoint from the OIDC configuration
|
||||||
let token_url = oidc_client
|
let token_url = oidc_client
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ pub async fn test_p2pk_swap() {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let mut listener = mint_bob
|
let mut listener = mint_bob
|
||||||
.pubsub_manager
|
.pubsub_manager()
|
||||||
.try_subscribe::<IndexableParams>(
|
.try_subscribe::<IndexableParams>(
|
||||||
Params {
|
Params {
|
||||||
kind: cdk::nuts::nut17::Kind::ProofState,
|
kind: cdk::nuts::nut17::Kind::ProofState,
|
||||||
@@ -773,7 +773,7 @@ async fn test_concurrent_double_spend_swap() {
|
|||||||
|
|
||||||
// Verify that all proofs are marked as spent in the mint
|
// Verify that all proofs are marked as spent in the mint
|
||||||
let states = mint_bob
|
let states = mint_bob
|
||||||
.localstore
|
.localstore()
|
||||||
.get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
|
.get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get proof state");
|
.expect("Failed to get proof state");
|
||||||
@@ -870,7 +870,7 @@ async fn test_concurrent_double_spend_melt() {
|
|||||||
|
|
||||||
// Verify that all proofs are marked as spent in the mint
|
// Verify that all proofs are marked as spent in the mint
|
||||||
let states = mint_bob
|
let states = mint_bob
|
||||||
.localstore
|
.localstore()
|
||||||
.get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
|
.get_proofs_states(&proofs.iter().map(|p| p.y().unwrap()).collect::<Vec<_>>())
|
||||||
.await
|
.await
|
||||||
.expect("Failed to get proof state");
|
.expect("Failed to get proof state");
|
||||||
|
|||||||
@@ -29,14 +29,15 @@ async fn test_correct_keyset() {
|
|||||||
|
|
||||||
let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
|
let fake_wallet = FakeWallet::new(fee_reserve, HashMap::default(), HashSet::default(), 0);
|
||||||
|
|
||||||
let mut mint_builder = MintBuilder::new();
|
|
||||||
let localstore = Arc::new(database);
|
let localstore = Arc::new(database);
|
||||||
mint_builder = mint_builder
|
let mut mint_builder = MintBuilder::new(localstore.clone());
|
||||||
.with_localstore(localstore.clone())
|
|
||||||
.with_keystore(localstore.clone());
|
|
||||||
|
|
||||||
mint_builder = mint_builder
|
mint_builder = mint_builder
|
||||||
.add_ln_backend(
|
.with_name("regtest mint".to_string())
|
||||||
|
.with_description("regtest mint".to_string());
|
||||||
|
|
||||||
|
mint_builder
|
||||||
|
.add_payment_processor(
|
||||||
CurrencyUnit::Sat,
|
CurrencyUnit::Sat,
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
MintMeltLimits::new(1, 5_000),
|
MintMeltLimits::new(1, 5_000),
|
||||||
@@ -44,18 +45,14 @@ async fn test_correct_keyset() {
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
// .with_seed(mnemonic.to_seed_normalized("").to_vec());
|
||||||
|
|
||||||
mint_builder = mint_builder
|
let mint = mint_builder
|
||||||
.with_name("regtest mint".to_string())
|
.build_with_seed(localstore.clone(), &mnemonic.to_seed_normalized(""))
|
||||||
.with_description("regtest mint".to_string())
|
|
||||||
.with_seed(mnemonic.to_seed_normalized("").to_vec());
|
|
||||||
|
|
||||||
let mint = mint_builder.build().await.unwrap();
|
|
||||||
let mut tx = localstore.begin_transaction().await.unwrap();
|
|
||||||
|
|
||||||
tx.set_mint_info(mint_builder.mint_info.clone())
|
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mut tx = localstore.begin_transaction().await.unwrap();
|
||||||
|
|
||||||
let quote_ttl = QuoteTTL::new(10000, 10000);
|
let quote_ttl = QuoteTTL::new(10000, 10000);
|
||||||
tx.set_quote_ttl(quote_ttl).await.unwrap();
|
tx.set_quote_ttl(quote_ttl).await.unwrap();
|
||||||
|
|
||||||
@@ -81,7 +78,6 @@ async fn test_correct_keyset() {
|
|||||||
assert_ne!(keyset_info.id, old_keyset_info.id);
|
assert_ne!(keyset_info.id, old_keyset_info.id);
|
||||||
|
|
||||||
mint.rotate_keyset(CurrencyUnit::Sat, 32, 0).await.unwrap();
|
mint.rotate_keyset(CurrencyUnit::Sat, 32, 0).await.unwrap();
|
||||||
let mint = mint_builder.build().await.unwrap();
|
|
||||||
|
|
||||||
let active = mint.get_active_keysets();
|
let active = mint.get_active_keysets();
|
||||||
|
|
||||||
|
|||||||
@@ -643,7 +643,7 @@ impl CdkMint for MintRPCServer {
|
|||||||
|
|
||||||
let mint_quote = self
|
let mint_quote = self
|
||||||
.mint
|
.mint
|
||||||
.localstore
|
.localstore()
|
||||||
.get_mint_quote("e_id)
|
.get_mint_quote("e_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?
|
.map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?
|
||||||
@@ -659,9 +659,8 @@ impl CdkMint for MintRPCServer {
|
|||||||
payment_identifier: mint_quote.request_lookup_id.clone(),
|
payment_identifier: mint_quote.request_lookup_id.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tx = self
|
let localstore = self.mint.localstore();
|
||||||
.mint
|
let mut tx = localstore
|
||||||
.localstore
|
|
||||||
.begin_transaction()
|
.begin_transaction()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Status::internal("Could not start db transaction".to_string()))?;
|
.map_err(|_| Status::internal("Could not start db transaction".to_string()))?;
|
||||||
@@ -693,9 +692,8 @@ impl CdkMint for MintRPCServer {
|
|||||||
vec![], // payment_ids
|
vec![], // payment_ids
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut tx = self
|
let mint_store = self.mint.localstore();
|
||||||
.mint
|
let mut tx = mint_store
|
||||||
.localstore
|
|
||||||
.begin_transaction()
|
.begin_transaction()
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Status::internal("Could not update quote".to_string()))?;
|
.map_err(|_| Status::internal("Could not update quote".to_string()))?;
|
||||||
@@ -710,7 +708,7 @@ impl CdkMint for MintRPCServer {
|
|||||||
|
|
||||||
let mint_quote = self
|
let mint_quote = self
|
||||||
.mint
|
.mint
|
||||||
.localstore
|
.localstore()
|
||||||
.get_mint_quote("e_id)
|
.get_mint_quote("e_id)
|
||||||
.await
|
.await
|
||||||
.map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?
|
.map_err(|_| Status::invalid_argument("Could not find quote".to_string()))?
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ use bip39::Mnemonic;
|
|||||||
use cdk::cdk_database::{self, MintDatabase, MintKeysDatabase};
|
use cdk::cdk_database::{self, MintDatabase, MintKeysDatabase};
|
||||||
use cdk::cdk_payment;
|
use cdk::cdk_payment;
|
||||||
use cdk::cdk_payment::MintPayment;
|
use cdk::cdk_payment::MintPayment;
|
||||||
use cdk::mint::{MintBuilder, MintMeltLimits};
|
use cdk::mint::{Mint, MintBuilder, MintMeltLimits};
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "cln",
|
feature = "cln",
|
||||||
feature = "lnbits",
|
feature = "lnbits",
|
||||||
@@ -84,16 +84,13 @@ compile_error!(
|
|||||||
async fn main() -> Result<()> {
|
async fn main() -> Result<()> {
|
||||||
let (work_dir, settings, localstore, keystore) = initial_setup().await?;
|
let (work_dir, settings, localstore, keystore) = initial_setup().await?;
|
||||||
|
|
||||||
let mint_builder = MintBuilder::new()
|
let mint_builder = MintBuilder::new(localstore);
|
||||||
.with_localstore(localstore)
|
|
||||||
.with_keystore(keystore);
|
|
||||||
|
|
||||||
let (mint_builder, ln_routers) = configure_mint_builder(&settings, mint_builder).await?;
|
let (mint_builder, ln_routers) = configure_mint_builder(&settings, mint_builder).await?;
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
let mint_builder = setup_authentication(&settings, &work_dir, mint_builder).await?;
|
let mint_builder = setup_authentication(&settings, &work_dir, mint_builder).await?;
|
||||||
let mint_builder_info = mint_builder.mint_info.clone();
|
|
||||||
|
|
||||||
let mint = mint_builder.build().await?;
|
let mint = build_mint(&settings, keystore, mint_builder).await?;
|
||||||
|
|
||||||
tracing::debug!("Mint built from builder.");
|
tracing::debug!("Mint built from builder.");
|
||||||
|
|
||||||
@@ -109,7 +106,7 @@ async fn main() -> Result<()> {
|
|||||||
&settings,
|
&settings,
|
||||||
ln_routers,
|
ln_routers,
|
||||||
&work_dir,
|
&work_dir,
|
||||||
mint_builder_info,
|
mint.mint_info().await?,
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
@@ -236,9 +233,6 @@ async fn configure_mint_builder(
|
|||||||
// Configure lightning backend
|
// Configure lightning backend
|
||||||
let mint_builder = configure_lightning_backend(settings, mint_builder, &mut ln_routers).await?;
|
let mint_builder = configure_lightning_backend(settings, mint_builder, &mut ln_routers).await?;
|
||||||
|
|
||||||
// Configure signatory or seed
|
|
||||||
let mint_builder = configure_signing_method(settings, mint_builder).await?;
|
|
||||||
|
|
||||||
// Configure caching
|
// Configure caching
|
||||||
let mint_builder = configure_cache(settings, mint_builder);
|
let mint_builder = configure_cache(settings, mint_builder);
|
||||||
|
|
||||||
@@ -274,7 +268,7 @@ fn configure_basic_info(settings: &config::Settings, mint_builder: MintBuilder)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for contact in contacts {
|
for contact in contacts {
|
||||||
builder = builder.add_contact_info(contact);
|
builder = builder.with_contact_info(contact);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(pubkey) = settings.mint_info.pubkey {
|
if let Some(pubkey) = settings.mint_info.pubkey {
|
||||||
@@ -435,8 +429,8 @@ async fn configure_backend_for_unit(
|
|||||||
|
|
||||||
if let Some(bolt12) = payment_settings.get("bolt12") {
|
if let Some(bolt12) = payment_settings.get("bolt12") {
|
||||||
if bolt12.as_bool().unwrap_or_default() {
|
if bolt12.as_bool().unwrap_or_default() {
|
||||||
mint_builder = mint_builder
|
mint_builder
|
||||||
.add_ln_backend(
|
.add_payment_processor(
|
||||||
unit.clone(),
|
unit.clone(),
|
||||||
PaymentMethod::Bolt12,
|
PaymentMethod::Bolt12,
|
||||||
mint_melt_limits,
|
mint_melt_limits,
|
||||||
@@ -446,8 +440,8 @@ async fn configure_backend_for_unit(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mint_builder = mint_builder
|
mint_builder
|
||||||
.add_ln_backend(
|
.add_payment_processor(
|
||||||
unit.clone(),
|
unit.clone(),
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
mint_melt_limits,
|
mint_melt_limits,
|
||||||
@@ -456,47 +450,15 @@ async fn configure_backend_for_unit(
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
if let Some(input_fee) = settings.info.input_fee_ppk {
|
if let Some(input_fee) = settings.info.input_fee_ppk {
|
||||||
mint_builder = mint_builder.set_unit_fee(&unit, input_fee)?;
|
mint_builder.set_unit_fee(&unit, input_fee)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nut17_supported = SupportedMethods::default_bolt11(unit);
|
let nut17_supported = SupportedMethods::default_bolt11(unit);
|
||||||
mint_builder = mint_builder.add_supported_websockets(nut17_supported);
|
mint_builder = mint_builder.with_supported_websockets(nut17_supported);
|
||||||
|
|
||||||
Ok(mint_builder)
|
Ok(mint_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configures the signing method (remote signatory or local seed)
|
|
||||||
async fn configure_signing_method(
|
|
||||||
settings: &config::Settings,
|
|
||||||
mint_builder: MintBuilder,
|
|
||||||
) -> Result<MintBuilder> {
|
|
||||||
if let Some(signatory_url) = settings.info.signatory_url.clone() {
|
|
||||||
tracing::info!(
|
|
||||||
"Connecting to remote signatory to {} with certs {:?}",
|
|
||||||
signatory_url,
|
|
||||||
settings.info.signatory_certs.clone()
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(mint_builder.with_signatory(Arc::new(
|
|
||||||
cdk_signatory::SignatoryRpcClient::new(
|
|
||||||
signatory_url,
|
|
||||||
settings.info.signatory_certs.clone(),
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
)))
|
|
||||||
} else if let Some(mnemonic) = settings
|
|
||||||
.info
|
|
||||||
.mnemonic
|
|
||||||
.clone()
|
|
||||||
.map(|s| Mnemonic::from_str(&s))
|
|
||||||
.transpose()?
|
|
||||||
{
|
|
||||||
Ok(mint_builder.with_seed(mnemonic.to_seed_normalized("").to_vec()))
|
|
||||||
} else {
|
|
||||||
bail!("No seed nor remote signatory set");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Configures cache settings
|
/// Configures cache settings
|
||||||
fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> MintBuilder {
|
fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> MintBuilder {
|
||||||
let cached_endpoints = vec![
|
let cached_endpoints = vec![
|
||||||
@@ -506,7 +468,7 @@ fn configure_cache(settings: &config::Settings, mint_builder: MintBuilder) -> Mi
|
|||||||
];
|
];
|
||||||
|
|
||||||
let cache: HttpCache = settings.info.http_cache.clone().into();
|
let cache: HttpCache = settings.info.http_cache.clone().into();
|
||||||
mint_builder.add_cache(Some(cache.ttl.as_secs()), cached_endpoints)
|
mint_builder.with_cache(Some(cache.ttl.as_secs()), cached_endpoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
@@ -532,16 +494,9 @@ async fn setup_authentication(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mint_builder = mint_builder.with_auth_localstore(auth_localstore.clone());
|
|
||||||
|
|
||||||
let mint_blind_auth_endpoint =
|
let mint_blind_auth_endpoint =
|
||||||
ProtectedEndpoint::new(Method::Post, RoutePath::MintBlindAuth);
|
ProtectedEndpoint::new(Method::Post, RoutePath::MintBlindAuth);
|
||||||
|
|
||||||
mint_builder = mint_builder.set_clear_auth_settings(
|
|
||||||
auth_settings.openid_discovery,
|
|
||||||
auth_settings.openid_client_id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let mut protected_endpoints = HashMap::new();
|
let mut protected_endpoints = HashMap::new();
|
||||||
|
|
||||||
protected_endpoints.insert(mint_blind_auth_endpoint, AuthRequired::Clear);
|
protected_endpoints.insert(mint_blind_auth_endpoint, AuthRequired::Clear);
|
||||||
@@ -644,7 +599,14 @@ async fn setup_authentication(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mint_builder = mint_builder.set_blind_auth_settings(auth_settings.mint_max_bat);
|
mint_builder = mint_builder.with_auth(
|
||||||
|
auth_localstore.clone(),
|
||||||
|
auth_settings.openid_discovery,
|
||||||
|
auth_settings.openid_client_id,
|
||||||
|
vec![mint_blind_auth_endpoint],
|
||||||
|
);
|
||||||
|
mint_builder =
|
||||||
|
mint_builder.with_blind_auth(auth_settings.mint_max_bat, blind_auth_endpoints);
|
||||||
|
|
||||||
let mut tx = auth_localstore.begin_transaction().await?;
|
let mut tx = auth_localstore.begin_transaction().await?;
|
||||||
|
|
||||||
@@ -655,6 +617,43 @@ async fn setup_authentication(
|
|||||||
Ok(mint_builder)
|
Ok(mint_builder)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Build mints with the configured the signing method (remote signatory or local seed)
|
||||||
|
async fn build_mint(
|
||||||
|
settings: &config::Settings,
|
||||||
|
keystore: Arc<dyn MintKeysDatabase<Err = cdk_database::Error> + Send + Sync>,
|
||||||
|
mint_builder: MintBuilder,
|
||||||
|
) -> Result<Mint> {
|
||||||
|
if let Some(signatory_url) = settings.info.signatory_url.clone() {
|
||||||
|
tracing::info!(
|
||||||
|
"Connecting to remote signatory to {} with certs {:?}",
|
||||||
|
signatory_url,
|
||||||
|
settings.info.signatory_certs.clone()
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(mint_builder
|
||||||
|
.build_with_signatory(Arc::new(
|
||||||
|
cdk_signatory::SignatoryRpcClient::new(
|
||||||
|
signatory_url,
|
||||||
|
settings.info.signatory_certs.clone(),
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
))
|
||||||
|
.await?)
|
||||||
|
} else if let Some(mnemonic) = settings
|
||||||
|
.info
|
||||||
|
.mnemonic
|
||||||
|
.clone()
|
||||||
|
.map(|s| Mnemonic::from_str(&s))
|
||||||
|
.transpose()?
|
||||||
|
{
|
||||||
|
Ok(mint_builder
|
||||||
|
.build_with_seed(keystore, &mnemonic.to_seed_normalized(""))
|
||||||
|
.await?)
|
||||||
|
} else {
|
||||||
|
bail!("No seed nor remote signatory set");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn start_services(
|
async fn start_services(
|
||||||
mint: Arc<cdk::mint::Mint>,
|
mint: Arc<cdk::mint::Mint>,
|
||||||
settings: &config::Settings,
|
settings: &config::Settings,
|
||||||
@@ -704,7 +703,7 @@ async fn start_services(
|
|||||||
mint.set_mint_info(mint_builder_info).await?;
|
mint.set_mint_info(mint_builder_info).await?;
|
||||||
mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
|
mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
|
||||||
} else {
|
} else {
|
||||||
if mint.localstore.get_quote_ttl().await.is_err() {
|
if mint.localstore().get_quote_ttl().await.is_err() {
|
||||||
mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
|
mint.set_quote_ttl(QuoteTTL::new(10_000, 10_000)).await?;
|
||||||
}
|
}
|
||||||
// Add version information
|
// Add version information
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ async fn get_access_token(mint_info: &MintInfo) -> String {
|
|||||||
.expect("Nut21 defined")
|
.expect("Nut21 defined")
|
||||||
.openid_discovery;
|
.openid_discovery;
|
||||||
|
|
||||||
let oidc_client = OidcClient::new(openid_discovery);
|
let oidc_client = OidcClient::new(openid_discovery, None);
|
||||||
|
|
||||||
// Get the token endpoint from the OIDC configuration
|
// Get the token endpoint from the OIDC configuration
|
||||||
let token_url = oidc_client
|
let token_url = oidc_client
|
||||||
|
|||||||
@@ -3,13 +3,13 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
|
||||||
use bitcoin::bip32::DerivationPath;
|
use bitcoin::bip32::DerivationPath;
|
||||||
use cdk_common::database::{self, MintDatabase, MintKeysDatabase};
|
use cdk_common::database::{self, MintDatabase, MintKeysDatabase};
|
||||||
use cdk_common::error::Error;
|
use cdk_common::error::Error;
|
||||||
use cdk_common::nut04::MintMethodOptions;
|
use cdk_common::nut04::MintMethodOptions;
|
||||||
use cdk_common::nut05::MeltMethodOptions;
|
use cdk_common::nut05::MeltMethodOptions;
|
||||||
use cdk_common::payment::Bolt11Settings;
|
use cdk_common::payment::Bolt11Settings;
|
||||||
|
#[cfg(feature = "auth")]
|
||||||
use cdk_common::{nut21, nut22};
|
use cdk_common::{nut21, nut22};
|
||||||
use cdk_signatory::signatory::Signatory;
|
use cdk_signatory::signatory::Signatory;
|
||||||
|
|
||||||
@@ -19,103 +19,91 @@ use super::nut19::{self, CachedEndpoint};
|
|||||||
use super::MintAuthDatabase;
|
use super::MintAuthDatabase;
|
||||||
use super::Nuts;
|
use super::Nuts;
|
||||||
use crate::amount::Amount;
|
use crate::amount::Amount;
|
||||||
#[cfg(feature = "auth")]
|
|
||||||
use crate::cdk_database;
|
use crate::cdk_database;
|
||||||
use crate::cdk_payment::{self, MintPayment};
|
use crate::cdk_payment::{self, MintPayment};
|
||||||
use crate::mint::Mint;
|
use crate::mint::Mint;
|
||||||
|
#[cfg(feature = "auth")]
|
||||||
|
use crate::nuts::ProtectedEndpoint;
|
||||||
use crate::nuts::{
|
use crate::nuts::{
|
||||||
ContactInfo, CurrencyUnit, MeltMethodSettings, MintInfo, MintMethodSettings, MintVersion,
|
ContactInfo, CurrencyUnit, MeltMethodSettings, MintInfo, MintMethodSettings, MintVersion,
|
||||||
MppMethodSettings, PaymentMethod,
|
MppMethodSettings, PaymentMethod,
|
||||||
};
|
};
|
||||||
use crate::types::PaymentProcessorKey;
|
use crate::types::PaymentProcessorKey;
|
||||||
|
|
||||||
/// Cashu Mint
|
/// Cashu Mint Builder
|
||||||
#[derive(Default)]
|
|
||||||
pub struct MintBuilder {
|
pub struct MintBuilder {
|
||||||
/// Mint Info
|
mint_info: MintInfo,
|
||||||
pub mint_info: MintInfo,
|
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
||||||
/// Mint Storage backend
|
|
||||||
pub localstore: Option<Arc<dyn MintDatabase<database::Error> + Send + Sync>>,
|
|
||||||
/// Database for the Signatory
|
|
||||||
keystore: Option<Arc<dyn MintKeysDatabase<Err = database::Error> + Send + Sync>>,
|
|
||||||
/// Mint Storage backend
|
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>>,
|
auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>>,
|
||||||
/// Ln backends for mint
|
payment_processors:
|
||||||
ln: Option<
|
|
||||||
HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
|
HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
|
||||||
>,
|
|
||||||
seed: Option<Vec<u8>>,
|
|
||||||
supported_units: HashMap<CurrencyUnit, (u64, u8)>,
|
supported_units: HashMap<CurrencyUnit, (u64, u8)>,
|
||||||
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
|
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
|
||||||
// protected_endpoints: HashMap<ProtectedEndpoint, AuthRequired>,
|
|
||||||
openid_discovery: Option<String>,
|
|
||||||
signatory: Option<Arc<dyn Signatory + Sync + Send + 'static>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MintBuilder {
|
impl MintBuilder {
|
||||||
/// New mint builder
|
/// New [`MintBuilder`]
|
||||||
pub fn new() -> MintBuilder {
|
pub fn new(localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>) -> MintBuilder {
|
||||||
let mut builder = MintBuilder::default();
|
let mint_info = MintInfo {
|
||||||
|
nuts: Nuts::new()
|
||||||
let nuts = Nuts::new()
|
|
||||||
.nut07(true)
|
.nut07(true)
|
||||||
.nut08(true)
|
.nut08(true)
|
||||||
.nut09(true)
|
.nut09(true)
|
||||||
.nut10(true)
|
.nut10(true)
|
||||||
.nut11(true)
|
.nut11(true)
|
||||||
.nut12(true)
|
.nut12(true),
|
||||||
.nut14(true)
|
..Default::default()
|
||||||
.nut20(true);
|
};
|
||||||
|
|
||||||
builder.mint_info.nuts = nuts;
|
MintBuilder {
|
||||||
|
mint_info,
|
||||||
builder
|
localstore,
|
||||||
}
|
|
||||||
|
|
||||||
/// Set signatory service
|
|
||||||
pub fn with_signatory(mut self, signatory: Arc<dyn Signatory + Sync + Send + 'static>) -> Self {
|
|
||||||
self.signatory = Some(signatory);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set seed
|
|
||||||
pub fn with_seed(mut self, seed: Vec<u8>) -> Self {
|
|
||||||
self.seed = Some(seed);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set localstore
|
|
||||||
pub fn with_localstore(
|
|
||||||
mut self,
|
|
||||||
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
|
||||||
) -> MintBuilder {
|
|
||||||
self.localstore = Some(localstore);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set keystore database
|
|
||||||
pub fn with_keystore(
|
|
||||||
mut self,
|
|
||||||
keystore: Arc<dyn MintKeysDatabase<Err = database::Error> + Send + Sync>,
|
|
||||||
) -> MintBuilder {
|
|
||||||
self.keystore = Some(keystore);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set auth localstore
|
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
pub fn with_auth_localstore(
|
auth_localstore: None,
|
||||||
|
payment_processors: HashMap::new(),
|
||||||
|
supported_units: HashMap::new(),
|
||||||
|
custom_paths: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set clear auth settings
|
||||||
|
#[cfg(feature = "auth")]
|
||||||
|
pub fn with_auth(
|
||||||
mut self,
|
mut self,
|
||||||
localstore: Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>,
|
auth_localstore: Arc<dyn MintAuthDatabase<Err = cdk_database::Error> + Send + Sync>,
|
||||||
) -> MintBuilder {
|
openid_discovery: String,
|
||||||
self.auth_localstore = Some(localstore);
|
client_id: String,
|
||||||
|
protected_endpoints: Vec<ProtectedEndpoint>,
|
||||||
|
) -> Self {
|
||||||
|
self.auth_localstore = Some(auth_localstore);
|
||||||
|
self.mint_info.nuts.nut21 = Some(nut21::Settings::new(
|
||||||
|
openid_discovery,
|
||||||
|
client_id,
|
||||||
|
protected_endpoints,
|
||||||
|
));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set Openid discovery url
|
/// Set blind auth settings
|
||||||
pub fn with_openid_discovery(mut self, openid_discovery: String) -> Self {
|
#[cfg(feature = "auth")]
|
||||||
self.openid_discovery = Some(openid_discovery);
|
pub fn with_blind_auth(
|
||||||
|
mut self,
|
||||||
|
bat_max_mint: u64,
|
||||||
|
protected_endpoints: Vec<ProtectedEndpoint>,
|
||||||
|
) -> Self {
|
||||||
|
let mut nuts = self.mint_info.nuts;
|
||||||
|
|
||||||
|
nuts.nut22 = Some(nut22::Settings::new(bat_max_mint, protected_endpoints));
|
||||||
|
|
||||||
|
self.mint_info.nuts = nuts;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set mint info
|
||||||
|
pub fn with_mint_info(mut self, mint_info: MintInfo) -> Self {
|
||||||
|
self.mint_info = mint_info;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,32 +156,68 @@ impl MintBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Set contact info
|
/// Set contact info
|
||||||
pub fn add_contact_info(mut self, contact_info: ContactInfo) -> Self {
|
pub fn with_contact_info(mut self, contact_info: ContactInfo) -> Self {
|
||||||
let mut contacts = self.mint_info.contact.clone().unwrap_or_default();
|
let mut contacts = self.mint_info.contact.clone().unwrap_or_default();
|
||||||
contacts.push(contact_info);
|
contacts.push(contact_info);
|
||||||
self.mint_info.contact = Some(contacts);
|
self.mint_info.contact = Some(contacts);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add ln backend
|
/// Set pubkey
|
||||||
pub async fn add_ln_backend(
|
pub fn with_pubkey(mut self, pubkey: crate::nuts::PublicKey) -> Self {
|
||||||
|
self.mint_info.pubkey = Some(pubkey);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Support websockets
|
||||||
|
pub fn with_supported_websockets(mut self, supported_method: SupportedMethods) -> Self {
|
||||||
|
let mut supported_settings = self.mint_info.nuts.nut17.supported.clone();
|
||||||
|
|
||||||
|
if !supported_settings.contains(&supported_method) {
|
||||||
|
supported_settings.push(supported_method);
|
||||||
|
|
||||||
|
self.mint_info.nuts = self.mint_info.nuts.nut17(supported_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add support for NUT19
|
||||||
|
pub fn with_cache(mut self, ttl: Option<u64>, cached_endpoints: Vec<CachedEndpoint>) -> Self {
|
||||||
|
let nut19_settings = nut19::Settings {
|
||||||
|
ttl,
|
||||||
|
cached_endpoints,
|
||||||
|
};
|
||||||
|
|
||||||
|
self.mint_info.nuts.nut19 = nut19_settings;
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set custom derivation paths for mint units
|
||||||
|
pub fn with_custom_derivation_paths(
|
||||||
mut self,
|
mut self,
|
||||||
|
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
|
||||||
|
) -> Self {
|
||||||
|
self.custom_paths = custom_paths;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Add payment processor
|
||||||
|
pub async fn add_payment_processor(
|
||||||
|
&mut self,
|
||||||
unit: CurrencyUnit,
|
unit: CurrencyUnit,
|
||||||
method: PaymentMethod,
|
method: PaymentMethod,
|
||||||
limits: MintMeltLimits,
|
limits: MintMeltLimits,
|
||||||
ln_backend: Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
payment_processor: Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<(), Error> {
|
||||||
let ln_key = PaymentProcessorKey {
|
let key = PaymentProcessorKey {
|
||||||
unit: unit.clone(),
|
unit: unit.clone(),
|
||||||
method: method.clone(),
|
method: method.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
tracing::debug!("Adding ln backed for {}, {}", unit, method);
|
let settings = payment_processor.get_settings().await?;
|
||||||
tracing::debug!("with limits {:?}", limits);
|
|
||||||
|
|
||||||
let mut ln = self.ln.unwrap_or_default();
|
|
||||||
|
|
||||||
let settings = ln_backend.get_settings().await?;
|
|
||||||
|
|
||||||
let settings: Bolt11Settings = settings.try_into()?;
|
let settings: Bolt11Settings = settings.try_into()?;
|
||||||
|
|
||||||
@@ -235,91 +259,19 @@ impl MintBuilder {
|
|||||||
self.mint_info.nuts.nut05.methods.push(melt_method_settings);
|
self.mint_info.nuts.nut05.methods.push(melt_method_settings);
|
||||||
self.mint_info.nuts.nut05.disabled = false;
|
self.mint_info.nuts.nut05.disabled = false;
|
||||||
|
|
||||||
ln.insert(ln_key.clone(), ln_backend);
|
|
||||||
|
|
||||||
let mut supported_units = self.supported_units.clone();
|
let mut supported_units = self.supported_units.clone();
|
||||||
|
|
||||||
supported_units.insert(ln_key.unit, (0, 32));
|
supported_units.insert(key.unit.clone(), (0, 32));
|
||||||
self.supported_units = supported_units;
|
self.supported_units = supported_units;
|
||||||
|
|
||||||
self.ln = Some(ln);
|
self.payment_processors.insert(key, payment_processor);
|
||||||
|
Ok(())
|
||||||
Ok(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set pubkey
|
|
||||||
pub fn with_pubkey(mut self, pubkey: crate::nuts::PublicKey) -> Self {
|
|
||||||
self.mint_info.pubkey = Some(pubkey);
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Support websockets
|
|
||||||
pub fn add_supported_websockets(mut self, supported_method: SupportedMethods) -> Self {
|
|
||||||
let mut supported_settings = self.mint_info.nuts.nut17.supported.clone();
|
|
||||||
|
|
||||||
if !supported_settings.contains(&supported_method) {
|
|
||||||
supported_settings.push(supported_method);
|
|
||||||
|
|
||||||
self.mint_info.nuts = self.mint_info.nuts.nut17(supported_settings);
|
|
||||||
}
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add support for NUT19
|
|
||||||
pub fn add_cache(mut self, ttl: Option<u64>, cached_endpoints: Vec<CachedEndpoint>) -> Self {
|
|
||||||
let nut19_settings = nut19::Settings {
|
|
||||||
ttl,
|
|
||||||
cached_endpoints,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.mint_info.nuts.nut19 = nut19_settings;
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set custom derivation paths for mint units
|
|
||||||
pub fn add_custom_derivation_paths(
|
|
||||||
mut self,
|
|
||||||
custom_paths: HashMap<CurrencyUnit, DerivationPath>,
|
|
||||||
) -> Self {
|
|
||||||
self.custom_paths = custom_paths;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set clear auth settings
|
|
||||||
pub fn set_clear_auth_settings(mut self, openid_discovery: String, client_id: String) -> Self {
|
|
||||||
let mut nuts = self.mint_info.nuts;
|
|
||||||
|
|
||||||
nuts.nut21 = Some(nut21::Settings::new(
|
|
||||||
openid_discovery.clone(),
|
|
||||||
client_id,
|
|
||||||
vec![],
|
|
||||||
));
|
|
||||||
|
|
||||||
self.openid_discovery = Some(openid_discovery);
|
|
||||||
|
|
||||||
self.mint_info.nuts = nuts;
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set blind auth settings
|
|
||||||
pub fn set_blind_auth_settings(mut self, bat_max_mint: u64) -> Self {
|
|
||||||
let mut nuts = self.mint_info.nuts;
|
|
||||||
|
|
||||||
nuts.nut22 = Some(nut22::Settings::new(bat_max_mint, vec![]));
|
|
||||||
|
|
||||||
self.mint_info.nuts = nuts;
|
|
||||||
|
|
||||||
self
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the input fee ppk for a given unit
|
/// Sets the input fee ppk for a given unit
|
||||||
///
|
///
|
||||||
/// The unit **MUST** already have been added with a ln backend
|
/// The unit **MUST** already have been added with a ln backend
|
||||||
pub fn set_unit_fee(mut self, unit: &CurrencyUnit, input_fee_ppk: u64) -> Result<Self, Error> {
|
pub fn set_unit_fee(&mut self, unit: &CurrencyUnit, input_fee_ppk: u64) -> Result<(), Error> {
|
||||||
let (input_fee, _max_order) = self
|
let (input_fee, _max_order) = self
|
||||||
.supported_units
|
.supported_units
|
||||||
.get_mut(unit)
|
.get_mut(unit)
|
||||||
@@ -327,59 +279,53 @@ impl MintBuilder {
|
|||||||
|
|
||||||
*input_fee = input_fee_ppk;
|
*input_fee = input_fee_ppk;
|
||||||
|
|
||||||
Ok(self)
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build mint
|
/// Build the mint with the provided signatory
|
||||||
pub async fn build(&self) -> anyhow::Result<Mint> {
|
pub async fn build_with_signatory(
|
||||||
let localstore = self
|
self,
|
||||||
.localstore
|
signatory: Arc<dyn Signatory + Send + Sync>,
|
||||||
.clone()
|
) -> Result<Mint, Error> {
|
||||||
.ok_or(anyhow!("Localstore not set"))?;
|
#[cfg(feature = "auth")]
|
||||||
let ln = self.ln.clone().ok_or(anyhow!("Ln backends not set"))?;
|
if let Some(auth_localstore) = self.auth_localstore {
|
||||||
|
return Mint::new_with_auth(
|
||||||
|
self.mint_info,
|
||||||
|
signatory,
|
||||||
|
self.localstore,
|
||||||
|
auth_localstore,
|
||||||
|
self.payment_processors,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
Mint::new(
|
||||||
|
self.mint_info,
|
||||||
|
signatory,
|
||||||
|
self.localstore,
|
||||||
|
self.payment_processors,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
let signatory = if let Some(signatory) = self.signatory.as_ref() {
|
/// Build the mint with the provided keystore and seed
|
||||||
signatory.clone()
|
pub async fn build_with_seed(
|
||||||
} else {
|
self,
|
||||||
let seed = self.seed.as_ref().ok_or(anyhow!("Mint seed not set"))?;
|
keystore: Arc<dyn MintKeysDatabase<Err = cdk_database::Error> + Send + Sync>,
|
||||||
|
seed: &[u8],
|
||||||
|
) -> Result<Mint, Error> {
|
||||||
let in_memory_signatory = cdk_signatory::db_signatory::DbSignatory::new(
|
let in_memory_signatory = cdk_signatory::db_signatory::DbSignatory::new(
|
||||||
self.keystore.clone().ok_or(anyhow!("keystore not set"))?,
|
keystore,
|
||||||
seed,
|
seed,
|
||||||
self.supported_units.clone(),
|
self.supported_units.clone(),
|
||||||
HashMap::new(),
|
HashMap::new(),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Arc::new(cdk_signatory::embedded::Service::new(Arc::new(
|
let signatory = Arc::new(cdk_signatory::embedded::Service::new(Arc::new(
|
||||||
in_memory_signatory,
|
in_memory_signatory,
|
||||||
)))
|
)));
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "auth")]
|
self.build_with_signatory(signatory).await
|
||||||
if let Some(openid_discovery) = &self.openid_discovery {
|
|
||||||
let auth_localstore = self
|
|
||||||
.auth_localstore
|
|
||||||
.clone()
|
|
||||||
.ok_or(anyhow!("Auth localstore not set"))?;
|
|
||||||
|
|
||||||
return Ok(Mint::new_with_auth(
|
|
||||||
signatory,
|
|
||||||
localstore,
|
|
||||||
auth_localstore,
|
|
||||||
ln,
|
|
||||||
openid_discovery.clone(),
|
|
||||||
)
|
|
||||||
.await?);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "auth"))]
|
|
||||||
if self.openid_discovery.is_some() {
|
|
||||||
return Err(anyhow!(
|
|
||||||
"OpenID discovery URL provided but auth feature is not enabled"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(Mint::new(signatory, localstore, ln).await?)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ impl Mint {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let ln = match self.ln.get(&PaymentProcessorKey::new(
|
let ln = match self.payment_processors.get(&PaymentProcessorKey::new(
|
||||||
quote.unit.clone(),
|
quote.unit.clone(),
|
||||||
quote.payment_method.clone(),
|
quote.payment_method.clone(),
|
||||||
)) {
|
)) {
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ impl Mint {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let ln = self
|
let ln = self
|
||||||
.ln
|
.payment_processors
|
||||||
.get(&PaymentProcessorKey::new(
|
.get(&PaymentProcessorKey::new(
|
||||||
unit.clone(),
|
unit.clone(),
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
@@ -250,7 +250,7 @@ impl Mint {
|
|||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let ln = self
|
let ln = self
|
||||||
.ln
|
.payment_processors
|
||||||
.get(&PaymentProcessorKey::new(
|
.get(&PaymentProcessorKey::new(
|
||||||
unit.clone(),
|
unit.clone(),
|
||||||
PaymentMethod::Bolt12,
|
PaymentMethod::Bolt12,
|
||||||
@@ -586,7 +586,7 @@ impl Mint {
|
|||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
tracing::debug!("partial_amount: {:?}", partial_amount);
|
tracing::debug!("partial_amount: {:?}", partial_amount);
|
||||||
let ln = match self.ln.get(&PaymentProcessorKey::new(
|
let ln = match self.payment_processors.get(&PaymentProcessorKey::new(
|
||||||
quote.unit.clone(),
|
quote.unit.clone(),
|
||||||
PaymentMethod::Bolt11,
|
PaymentMethod::Bolt11,
|
||||||
)) {
|
)) {
|
||||||
|
|||||||
@@ -53,17 +53,17 @@ pub struct Mint {
|
|||||||
///
|
///
|
||||||
/// It is implemented in the cdk-signatory crate, and it can be embedded in the mint or it can
|
/// It is implemented in the cdk-signatory crate, and it can be embedded in the mint or it can
|
||||||
/// be a gRPC client to a remote signatory server.
|
/// be a gRPC client to a remote signatory server.
|
||||||
pub signatory: Arc<dyn Signatory + Send + Sync>,
|
signatory: Arc<dyn Signatory + Send + Sync>,
|
||||||
/// Mint Storage backend
|
/// Mint Storage backend
|
||||||
pub localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
||||||
/// Auth Storage backend (only available with auth feature)
|
/// Auth Storage backend (only available with auth feature)
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
pub auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>>,
|
auth_localstore: Option<Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>>,
|
||||||
/// Ln backends for mint
|
/// Payment processors for mint
|
||||||
pub ln:
|
payment_processors:
|
||||||
HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
|
HashMap<PaymentProcessorKey, Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>>,
|
||||||
/// Subscription manager
|
/// Subscription manager
|
||||||
pub pubsub_manager: Arc<PubSubManager>,
|
pubsub_manager: Arc<PubSubManager>,
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
oidc_client: Option<OidcClient>,
|
oidc_client: Option<OidcClient>,
|
||||||
/// In-memory keyset
|
/// In-memory keyset
|
||||||
@@ -71,40 +71,23 @@ pub struct Mint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Mint {
|
impl Mint {
|
||||||
/// Get the payment processor for the given unit and payment method
|
|
||||||
pub fn get_payment_processor(
|
|
||||||
&self,
|
|
||||||
unit: CurrencyUnit,
|
|
||||||
payment_method: PaymentMethod,
|
|
||||||
) -> Result<Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>, Error> {
|
|
||||||
let key = PaymentProcessorKey::new(unit.clone(), payment_method.clone());
|
|
||||||
self.ln.get(&key).cloned().ok_or_else(|| {
|
|
||||||
tracing::info!(
|
|
||||||
"No payment processor set for pair {}, {}",
|
|
||||||
unit,
|
|
||||||
payment_method
|
|
||||||
);
|
|
||||||
Error::UnsupportedUnit
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create new [`Mint`] without authentication
|
/// Create new [`Mint`] without authentication
|
||||||
pub async fn new(
|
pub async fn new(
|
||||||
|
mint_info: MintInfo,
|
||||||
signatory: Arc<dyn Signatory + Send + Sync>,
|
signatory: Arc<dyn Signatory + Send + Sync>,
|
||||||
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
||||||
ln: HashMap<
|
payment_processors: HashMap<
|
||||||
PaymentProcessorKey,
|
PaymentProcessorKey,
|
||||||
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
||||||
>,
|
>,
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
Self::new_internal(
|
Self::new_internal(
|
||||||
|
mint_info,
|
||||||
signatory,
|
signatory,
|
||||||
localstore,
|
localstore,
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
None,
|
None,
|
||||||
ln,
|
payment_processors,
|
||||||
#[cfg(feature = "auth")]
|
|
||||||
None,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -112,21 +95,21 @@ impl Mint {
|
|||||||
/// Create new [`Mint`] with authentication support
|
/// Create new [`Mint`] with authentication support
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
pub async fn new_with_auth(
|
pub async fn new_with_auth(
|
||||||
|
mint_info: MintInfo,
|
||||||
signatory: Arc<dyn Signatory + Send + Sync>,
|
signatory: Arc<dyn Signatory + Send + Sync>,
|
||||||
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
||||||
auth_localstore: Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>,
|
auth_localstore: Arc<dyn MintAuthDatabase<Err = database::Error> + Send + Sync>,
|
||||||
ln: HashMap<
|
payment_processors: HashMap<
|
||||||
PaymentProcessorKey,
|
PaymentProcessorKey,
|
||||||
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
||||||
>,
|
>,
|
||||||
open_id_discovery: String,
|
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
Self::new_internal(
|
Self::new_internal(
|
||||||
|
mint_info,
|
||||||
signatory,
|
signatory,
|
||||||
localstore,
|
localstore,
|
||||||
Some(auth_localstore),
|
Some(auth_localstore),
|
||||||
ln,
|
payment_processors,
|
||||||
Some(open_id_discovery),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
@@ -134,21 +117,17 @@ impl Mint {
|
|||||||
/// Internal function to create a new [`Mint`] with shared logic
|
/// Internal function to create a new [`Mint`] with shared logic
|
||||||
#[inline]
|
#[inline]
|
||||||
async fn new_internal(
|
async fn new_internal(
|
||||||
|
mint_info: MintInfo,
|
||||||
signatory: Arc<dyn Signatory + Send + Sync>,
|
signatory: Arc<dyn Signatory + Send + Sync>,
|
||||||
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
localstore: Arc<dyn MintDatabase<database::Error> + Send + Sync>,
|
||||||
#[cfg(feature = "auth")] auth_localstore: Option<
|
#[cfg(feature = "auth")] auth_localstore: Option<
|
||||||
Arc<dyn database::MintAuthDatabase<Err = database::Error> + Send + Sync>,
|
Arc<dyn database::MintAuthDatabase<Err = database::Error> + Send + Sync>,
|
||||||
>,
|
>,
|
||||||
ln: HashMap<
|
payment_processors: HashMap<
|
||||||
PaymentProcessorKey,
|
PaymentProcessorKey,
|
||||||
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>,
|
||||||
>,
|
>,
|
||||||
#[cfg(feature = "auth")] open_id_discovery: Option<String>,
|
|
||||||
) -> Result<Self, Error> {
|
) -> Result<Self, Error> {
|
||||||
#[cfg(feature = "auth")]
|
|
||||||
let oidc_client =
|
|
||||||
open_id_discovery.map(|openid_discovery| OidcClient::new(openid_discovery.clone()));
|
|
||||||
|
|
||||||
let keysets = signatory.keysets().await?;
|
let keysets = signatory.keysets().await?;
|
||||||
if !keysets
|
if !keysets
|
||||||
.keysets
|
.keysets
|
||||||
@@ -168,19 +147,57 @@ impl Mint {
|
|||||||
.count()
|
.count()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mint_store = localstore.clone();
|
||||||
|
let mut tx = mint_store.begin_transaction().await?;
|
||||||
|
tx.set_mint_info(mint_info.clone()).await?;
|
||||||
|
tx.set_quote_ttl(QuoteTTL::default()).await?;
|
||||||
|
tx.commit().await?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
signatory,
|
signatory,
|
||||||
pubsub_manager: Arc::new(localstore.clone().into()),
|
pubsub_manager: Arc::new(localstore.clone().into()),
|
||||||
localstore,
|
localstore,
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
oidc_client,
|
oidc_client: mint_info.nuts.nut21.as_ref().map(|nut21| {
|
||||||
ln,
|
OidcClient::new(
|
||||||
|
nut21.openid_discovery.clone(),
|
||||||
|
Some(nut21.client_id.clone()),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
payment_processors,
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
auth_localstore,
|
auth_localstore,
|
||||||
keysets: Arc::new(ArcSwap::new(keysets.keysets.into())),
|
keysets: Arc::new(ArcSwap::new(keysets.keysets.into())),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the payment processor for the given unit and payment method
|
||||||
|
pub fn get_payment_processor(
|
||||||
|
&self,
|
||||||
|
unit: CurrencyUnit,
|
||||||
|
payment_method: PaymentMethod,
|
||||||
|
) -> Result<Arc<dyn MintPayment<Err = cdk_payment::Error> + Send + Sync>, Error> {
|
||||||
|
let key = PaymentProcessorKey::new(unit.clone(), payment_method.clone());
|
||||||
|
self.payment_processors.get(&key).cloned().ok_or_else(|| {
|
||||||
|
tracing::info!(
|
||||||
|
"No payment processor set for pair {}, {}",
|
||||||
|
unit,
|
||||||
|
payment_method
|
||||||
|
);
|
||||||
|
Error::UnsupportedUnit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Localstore
|
||||||
|
pub fn localstore(&self) -> Arc<dyn MintDatabase<database::Error> + Send + Sync> {
|
||||||
|
Arc::clone(&self.localstore)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Pub Sub manager
|
||||||
|
pub fn pubsub_manager(&self) -> Arc<PubSubManager> {
|
||||||
|
Arc::clone(&self.pubsub_manager)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get mint info
|
/// Get mint info
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
pub async fn mint_info(&self) -> Result<MintInfo, Error> {
|
pub async fn mint_info(&self) -> Result<MintInfo, Error> {
|
||||||
@@ -259,7 +276,7 @@ impl Mint {
|
|||||||
Vec<PaymentProcessorKey>,
|
Vec<PaymentProcessorKey>,
|
||||||
)> = Vec::new();
|
)> = Vec::new();
|
||||||
|
|
||||||
for (key, ln) in self.ln.iter() {
|
for (key, ln) in self.payment_processors.iter() {
|
||||||
// Check if we already have this processor
|
// Check if we already have this processor
|
||||||
let found = processor_groups.iter_mut().find(|(proc_ref, _)| {
|
let found = processor_groups.iter_mut().find(|(proc_ref, _)| {
|
||||||
// Compare Arc pointer equality using ptr_eq
|
// Compare Arc pointer equality using ptr_eq
|
||||||
@@ -609,7 +626,7 @@ mod tests {
|
|||||||
.expect("Failed to create signatory"),
|
.expect("Failed to create signatory"),
|
||||||
);
|
);
|
||||||
|
|
||||||
Mint::new(signatory, localstore, HashMap::new())
|
Mint::new(MintInfo::default(), signatory, localstore, HashMap::new())
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ impl Mint {
|
|||||||
method: PaymentMethod::Bolt11,
|
method: PaymentMethod::Bolt11,
|
||||||
};
|
};
|
||||||
|
|
||||||
let ln_backend = match self.ln.get(&ln_key) {
|
let ln_backend = match self.payment_processors.get(&ln_key) {
|
||||||
Some(ln_backend) => ln_backend,
|
Some(ln_backend) => ln_backend,
|
||||||
None => {
|
None => {
|
||||||
tracing::warn!("No backend for ln key: {:?}", ln_key);
|
tracing::warn!("No backend for ln key: {:?}", ln_key);
|
||||||
|
|||||||
@@ -32,9 +32,9 @@ pub enum Error {
|
|||||||
/// Unsupported Algo
|
/// Unsupported Algo
|
||||||
#[error("Unsupported signing algo")]
|
#[error("Unsupported signing algo")]
|
||||||
UnsupportedSigningAlgo,
|
UnsupportedSigningAlgo,
|
||||||
/// Access token not returned
|
/// Invalid Client ID
|
||||||
#[error("Error getting access token")]
|
#[error("Invalid Client ID")]
|
||||||
AccessTokenMissing,
|
InvalidClientId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for cdk_common::error::Error {
|
impl From<Error> for cdk_common::error::Error {
|
||||||
@@ -58,6 +58,7 @@ pub struct OidcConfig {
|
|||||||
pub struct OidcClient {
|
pub struct OidcClient {
|
||||||
client: Client,
|
client: Client,
|
||||||
openid_discovery: String,
|
openid_discovery: String,
|
||||||
|
client_id: Option<String>,
|
||||||
oidc_config: Arc<RwLock<Option<OidcConfig>>>,
|
oidc_config: Arc<RwLock<Option<OidcConfig>>>,
|
||||||
jwks_set: Arc<RwLock<Option<JwkSet>>>,
|
jwks_set: Arc<RwLock<Option<JwkSet>>>,
|
||||||
}
|
}
|
||||||
@@ -88,10 +89,11 @@ pub struct TokenResponse {
|
|||||||
|
|
||||||
impl OidcClient {
|
impl OidcClient {
|
||||||
/// Create new [`OidcClient`]
|
/// Create new [`OidcClient`]
|
||||||
pub fn new(openid_discovery: String) -> Self {
|
pub fn new(openid_discovery: String, client_id: Option<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
client: Client::new(),
|
client: Client::new(),
|
||||||
openid_discovery,
|
openid_discovery,
|
||||||
|
client_id,
|
||||||
oidc_config: Arc::new(RwLock::new(None)),
|
oidc_config: Arc::new(RwLock::new(None)),
|
||||||
jwks_set: Arc::new(RwLock::new(None)),
|
jwks_set: Arc::new(RwLock::new(None)),
|
||||||
}
|
}
|
||||||
@@ -192,12 +194,41 @@ impl OidcClient {
|
|||||||
validation
|
validation
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) =
|
match decode::<HashMap<String, serde_json::Value>>(cat_jwt, &decoding_key, &validation) {
|
||||||
decode::<HashMap<String, serde_json::Value>>(cat_jwt, &decoding_key, &validation)
|
Ok(claims) => {
|
||||||
{
|
tracing::debug!("Successfully verified cat");
|
||||||
|
tracing::debug!("Claims: {:?}", claims.claims);
|
||||||
|
if let Some(client_id) = &self.client_id {
|
||||||
|
if let Some(token_client_id) = claims.claims.get("client_id") {
|
||||||
|
if let Some(token_client_id_value) = token_client_id.as_str() {
|
||||||
|
if token_client_id_value != client_id {
|
||||||
|
tracing::warn!(
|
||||||
|
"Client ID mismatch: expected {}, got {}",
|
||||||
|
client_id,
|
||||||
|
token_client_id_value
|
||||||
|
);
|
||||||
|
return Err(Error::InvalidClientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if let Some(azp) = claims.claims.get("azp") {
|
||||||
|
if let Some(azp_value) = azp.as_str() {
|
||||||
|
if azp_value != client_id {
|
||||||
|
tracing::warn!(
|
||||||
|
"Client ID (azp) mismatch: expected {}, got {}",
|
||||||
|
client_id,
|
||||||
|
azp_value
|
||||||
|
);
|
||||||
|
return Err(Error::InvalidClientId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
tracing::debug!("Could not verify cat: {}", err);
|
tracing::debug!("Could not verify cat: {}", err);
|
||||||
return Err(err.into());
|
return Err(err.into());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -268,8 +268,9 @@ impl Wallet {
|
|||||||
auth_wallet.protected_endpoints.write().await;
|
auth_wallet.protected_endpoints.write().await;
|
||||||
*protected_endpoints = mint_info.protected_endpoints();
|
*protected_endpoints = mint_info.protected_endpoints();
|
||||||
|
|
||||||
if let Some(oidc_client) =
|
if let Some(oidc_client) = mint_info
|
||||||
mint_info.openid_discovery().map(OidcClient::new)
|
.openid_discovery()
|
||||||
|
.map(|url| OidcClient::new(url, None))
|
||||||
{
|
{
|
||||||
auth_wallet.set_oidc_client(Some(oidc_client)).await;
|
auth_wallet.set_oidc_client(Some(oidc_client)).await;
|
||||||
}
|
}
|
||||||
@@ -277,7 +278,9 @@ impl Wallet {
|
|||||||
None => {
|
None => {
|
||||||
tracing::info!("Mint has auth enabled creating auth wallet");
|
tracing::info!("Mint has auth enabled creating auth wallet");
|
||||||
|
|
||||||
let oidc_client = mint_info.openid_discovery().map(OidcClient::new);
|
let oidc_client = mint_info
|
||||||
|
.openid_discovery()
|
||||||
|
.map(|url| OidcClient::new(url, None));
|
||||||
let new_auth_wallet = AuthWallet::new(
|
let new_auth_wallet = AuthWallet::new(
|
||||||
self.mint_url.clone(),
|
self.mint_url.clone(),
|
||||||
None,
|
None,
|
||||||
|
|||||||
Reference in New Issue
Block a user