exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

commit 288dfa72e86680173f3a6943e95f46807de1626b
parent 656eaab60f20fb3136bcc268a390674404c44908
Author: Christian Grothoff <christian@grothoff.org>
Date:   Mon,  2 Feb 2026 18:23:48 +0100

fix #9703

Diffstat:
Msrc/bank-lib/bank_api_account_token.c | 18+++---------------
Msrc/bank-lib/bank_api_parse.c | 17++++++++++++++++-
Msrc/bank-lib/taler-exchange-wire-gateway-client.c | 130++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/include/taler/taler_bank_service.h | 9+++++++++
Msrc/testing/test_exchange_api.conf | 20++++++++++++++++++++
5 files changed, 157 insertions(+), 37 deletions(-)

diff --git a/src/bank-lib/bank_api_account_token.c b/src/bank-lib/bank_api_account_token.c @@ -206,17 +206,9 @@ TALER_BANK_account_token ( ath = GNUNET_new (struct TALER_BANK_AccountTokenHandle); ath->cb = res_cb; ath->cb_cls = res_cb_cls; - { - char *path; - - GNUNET_asprintf (&path, - "accounts/%s/token", - account_name); - ath->request_url = TALER_url_join (auth->wire_gateway_url, - path, - NULL); - GNUNET_free (path); - } + ath->request_url = TALER_url_join (auth->core_bank_url, + "token", + NULL); if (NULL == ath->request_url) { GNUNET_free (ath); @@ -226,10 +218,6 @@ TALER_BANK_account_token ( GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting access token at `%s'\n", ath->request_url); - ath->post_ctx.headers - = curl_slist_append ( - ath->post_ctx.headers, - "Content-Type: application/json"); eh = curl_easy_init (); if ( (NULL == eh) || (GNUNET_OK != diff --git a/src/bank-lib/bank_api_parse.c b/src/bank-lib/bank_api_parse.c @@ -40,6 +40,22 @@ TALER_BANK_auth_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, }; char *method; + auth->core_bank_url = NULL; + if (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_string (cfg, + section, + "CORE_BANK_URL", + &auth->core_bank_url)) + { + if (! TALER_is_web_url (auth->core_bank_url)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "CORE_BANK_URL", + "Not a valid URL"); + return GNUNET_SYSERR; + } + } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, @@ -51,7 +67,6 @@ TALER_BANK_auth_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, "WIRE_GATEWAY_URL"); return GNUNET_SYSERR; } - if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, section, diff --git a/src/bank-lib/taler-exchange-wire-gateway-client.c b/src/bank-lib/taler-exchange-wire-gateway-client.c @@ -93,6 +93,11 @@ static struct TALER_BANK_CreditHistoryHandle *chh; static struct TALER_BANK_DebitHistoryHandle *dhh; /** + * Handle to fetch an access token. + */ +static struct TALER_BANK_AccountTokenHandle *ath; + +/** * Handle for executing the wire transfer. */ static struct TALER_BANK_TransferHandle *eh; @@ -133,6 +138,11 @@ do_shutdown (void *cls) TALER_BANK_debit_history_cancel (dhh); dhh = NULL; } + if (NULL != ath) + { + TALER_BANK_account_token_cancel (ath); + ath = NULL; + } if (NULL != eh) { TALER_BANK_transfer_cancel (eh); @@ -554,6 +564,76 @@ execute_admin_transfer (void) /** + * Run the actual main operation requested by the user. + */ +static void +execute_tasks (void) +{ + if (GNUNET_YES == incoming_history) + { + execute_credit_history (); + return; + } + if (GNUNET_YES == outgoing_history) + { + execute_debit_history (); + return; + } + if (NULL != credit_account.full_payto) + { + execute_wire_transfer (); + return; + } + if (NULL != debit_account.full_payto) + { + execute_admin_transfer (); + return; + } + + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No operation specified.\n"); + global_ret = 0; + GNUNET_SCHEDULER_shutdown (); +} + + +/** + * Receives an access token to the bank. + * + * @param cls closure + * @param atr response details + */ +static void +access_token_cb ( + void *cls, + const struct TALER_BANK_AccountTokenResponse *atr) +{ + (void) cls; + ath = NULL; + switch (atr->ec) + { + case TALER_EC_NONE: + break; /* continued below */ + default: + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to get access token: %s (%u/%d)\n", + TALER_ErrorCode_get_hint (atr->ec), + atr->http_status, + (int) atr->ec); + global_ret = EXIT_NOPERMISSION; + GNUNET_SCHEDULER_shutdown (); + return; + } + GNUNET_assert (TALER_BANK_AUTH_BASIC == auth.method); + GNUNET_free (auth.details.basic.username); + GNUNET_free (auth.details.basic.password); + auth.method = TALER_BANK_AUTH_BEARER; + auth.details.bearer.token = GNUNET_strdup (atr->details.ok.access_token); + execute_tasks (); +} + + +/** * Main function that will be run. * * @param cls closure @@ -567,6 +647,7 @@ run (void *cls, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg) { + enum TALER_BANK_TokenScope scope; (void) cls; (void) args; (void) cfgfile; @@ -653,31 +734,38 @@ run (void *cls, GNUNET_SCHEDULER_shutdown (); return; } - if (GNUNET_YES == incoming_history) - { - execute_credit_history (); - return; - } - if (GNUNET_YES == outgoing_history) + if ( (NULL != auth.core_bank_url) && + (TALER_BANK_AUTH_BASIC == auth.method) ) { - execute_debit_history (); - return; - } - if (NULL != credit_account.full_payto) - { - execute_wire_transfer (); - return; + scope = TALER_BANK_TOKEN_SCOPE_READONLY; + if (NULL != credit_account.full_payto) + scope = TALER_BANK_TOKEN_SCOPE_WIREGATEWAY; + if (NULL != debit_account.full_payto) + scope = TALER_BANK_TOKEN_SCOPE_READWRITE; + ath = TALER_BANK_account_token (ctx, + &auth, + auth.details.basic.username, // FIXME: why? correct? + scope, + false, /* refreshable */ + "taler-exchange-wire-gateway-client CLI token", + GNUNET_TIME_UNIT_MINUTES, + &access_token_cb, + NULL); + if (NULL == ath) + { + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + } } - if (NULL != debit_account.full_payto) + else { - execute_admin_transfer (); - return; + if (TALER_BANK_AUTH_BASIC == auth.method) + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No CORE_BANK_URL given in `%s' and using basic authentication. Not all taler-wire-gateway implementations allow this.\n", + account_section); + execute_tasks (); } - - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "No operation specified.\n"); - global_ret = 0; - GNUNET_SCHEDULER_shutdown (); } diff --git a/src/include/taler/taler_bank_service.h b/src/include/taler/taler_bank_service.h @@ -69,6 +69,15 @@ struct TALER_BANK_AuthenticationData char *wire_gateway_url; /** + * Base URL including "/accpunts/$USERNAME/" to use + * to talk to the core bank API. Useful to get a more + * specific access token instead of using basic authentication + * the whole time. Optional, can be NULL (as we do not + * require the core bank API to actually always be available). + */ + char *core_bank_url; + + /** * Which authentication method should we use? */ enum TALER_BANK_AuthenticationMethod method; diff --git a/src/testing/test_exchange_api.conf b/src/testing/test_exchange_api.conf @@ -27,6 +27,7 @@ SERVE = tcp PORT = 8082 PWD_HASH_CONFIG = { "cost": 4 } PWD_AUTH_COMPAT = yes +BASE_URL = http://localhost:8082/ [libeufin-bankdb-postgres] CONFIG = postgresql:///talercheck @@ -113,6 +114,7 @@ WIRE_GATEWAY_AUTH_METHOD = basic USERNAME = Exchange PASSWORD = password WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" +CORE_BANK_URL = "http://localhost:8082/accounts/2/" [admin-accountcredentials-2] WIRE_GATEWAY_AUTH_METHOD = basic @@ -121,6 +123,24 @@ USERNAME = Exchange PASSWORD = password WIRE_GATEWAY_URL = "http://localhost:8082/accounts/2/taler-wire-gateway/" +[exchange-account-3] +PAYTO_URI = "payto://x-taler-bank/localhost/exchange?receiver-name=Exchange" +ENABLE_DEBIT = YES +ENABLE_CREDIT = YES + +[exchange-accountcredentials-3] +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = exchange +PASSWORD = password +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/exchange/taler-wire-gateway/" +CORE_BANK_URL = "http://localhost:8082/accounts/exchange/" + +[admin-accountcredentials-3] +WIRE_GATEWAY_AUTH_METHOD = basic +USERNAME = exchange +PASSWORD = password +WIRE_GATEWAY_URL = "http://localhost:8082/accounts/exchange/taler-wire-gateway/" + [exchange-offline]