cash2ecash

cash2ecash: cash acceptor that issues digital cash (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit d633387c68d7db430d39cfa34fb1b9006a38db20
parent eef31e7165acce15ac473a8f4cfc3b2a1dfb9a0d
Author: Manuel Geissbühler <manuel@debian>
Date:   Wed,  1 Jan 2025 15:32:43 +0100

some progress on bank communication

Diffstat:
Msrc/bank/bank_api_account_withdrawal.c | 202+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/bank/bank_lib.c | 222++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/bank/bank_lib.h | 8++++----
Msrc/bank/taler_bank_service_cash2ecash.h | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 516 insertions(+), 43 deletions(-)

diff --git a/src/bank/bank_api_account_withdrawal.c b/src/bank/bank_api_account_withdrawal.c @@ -1,4 +1,5 @@ #include <curl/curl.h> +#include <curl/easy.h> #include <gnunet/gnunet_common.h> #include <jansson.h> #include <microhttpd.h> @@ -245,9 +246,6 @@ TALER_BANK_account_withdrawal_cancel ( /* ********************* /accounts/$ACC/withdrawals/$WITHDRAWAL_ID/confirm *********************** */ - - - struct TALER_BANK_AccountWithdrawalConfirmHandle { /** @@ -450,3 +448,201 @@ TALER_BANK_account_withdrawal_confirm_cancel ( GNUNET_free (awch); } +/* ********************* /withdrawals/$WITHDRAWAL_ID *********************** */ + +struct TALER_BANK_WithdrawalIDInfoHandle +{ + /** + *The url for this request. + */ + char *request_url; + + /** + POST context. + */ + struct TALER_CURL_PostContext post_ctx; + + /** + * Handle for the request. + */ + struct GNUNET_CURL_Job *job; + + /** + * Function to call with the result. + */ + TALER_BANK_WithdrawalIDInfoCallback cb; + + /** + * Closure for @a cb. + */ + void *cb_cls; +}; + +/** + * Function called when we're done processing the + * HTTP /withdrawals/$WITHDRAWAL_ID request. + * + * @param cls the `struct TALER_BANK_WithdrawalIDInfoandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_withdrawalID_info_finished (void *cls, + long response_code, + const void *response) +{ + struct TALER_BANK_WithdrawalIDInfoHandle *aai = cls; + const json_t *j = response; + struct TALER_BANK_WithdrawalIDInfoResponse ir = { + .http_status = response_code, + .response = response + }; + + aai->job = NULL; + switch (response_code) + { + case 0: + ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + { + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("status", + &ir.details.ok.status), + TALER_JSON_spec_amount_any("amount", + &ir.details.ok.amount), + TALER_JSON_spec_amount_any("suggested_amount", + &ir.details.ok.suggested_amount), + GNUNET_JSON_spec_string ("username", + &ir.details.ok.username), + GNUNET_JSON_spec_string ("selected_reserve_pub", + &ir.details.ok.selected_reserve_pub), + GNUNET_JSON_spec_string ("selected_exchange_account", + &ir.details.ok.selected_exchange_account), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + ir.http_status = 0; + ir.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + } + break; + case MHD_HTTP_BAD_REQUEST: + /* This should never happen, either us or the bank is buggy + (or API version conflict); just pass JSON reply to the application */ + GNUNET_break_op (0); + ir.ec = TALER_JSON_get_error_code (j); + break; + case MHD_HTTP_NOT_FOUND: + /* Nothing really to verify, maybe withdrawal id really does not exist. + We should pass the JSON reply to the application */ + ir.ec = TALER_JSON_get_error_code (j); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + /* Server had an internal issue; we should retry, but this API + leaves this to the application */ + ir.ec = TALER_JSON_get_error_code (j); + break; + default: + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u\n", + (unsigned int) response_code); + GNUNET_break (0); + ir.ec = TALER_JSON_get_error_code (j); + break; + } + aai->cb (aai->cb_cls, + &ir); + TALER_BANK_withdrawalID_info_cancel (aai); +} + + + + +struct TALER_BANK_WithdrawalIDInfoHandle * +TALER_BANK_withdrawalID_info ( + struct GNUNET_CURL_Context *ctx, + const struct TALER_BANK_AuthenticationData *auth, + const char *withdrawal_id, + TALER_BANK_WithdrawalIDInfoCallback res_cb, + void *res_cb_cls) +{ + struct TALER_BANK_WithdrawalIDInfoHandle *awch; + CURL *eh; + + awch = GNUNET_new (struct TALER_BANK_WithdrawalIDInfoHandle); + awch->cb = res_cb; + awch->cb_cls = res_cb_cls; + { + char *path; + + GNUNET_asprintf (&path, + "/withdrawals/%s", + withdrawal_id); + awch->request_url = TALER_url_join (auth->wire_gateway_url, + path, + NULL); + GNUNET_free (path); + } + if (NULL == awch->request_url) + { + GNUNET_free (awch); + return NULL; + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Posting withdrawal id info request at `%s'\n", + awch->request_url); + + eh = curl_easy_init (); + if ( (NULL == eh) || + (CURLE_OK != + curl_easy_setopt (eh, + CURLOPT_URL, + awch->request_url)) || + (GNUNET_OK != + curl_easy_setopt(eh, CURLOPT_HTTPGET, 1))) + { + GNUNET_break (0); + TALER_BANK_withdrawalID_info_cancel (awch); + if (NULL != eh) + curl_easy_cleanup (eh); + return NULL; + } + awch->job = GNUNET_CURL_job_add (ctx, + eh, + &handle_withdrawalID_info_finished, + awch); + GNUNET_assert (NULL != awch->job); + return awch; +} + +void +TALER_BANK_withdrawalID_info_cancel ( + struct TALER_BANK_WithdrawalIDInfoHandle *awch) +{ + if (NULL != awch->job) + { + GNUNET_CURL_job_cancel (awch->job); + awch->job = NULL; + } + + TALER_curl_easy_post_finished (&awch->post_ctx); //might not work; are there any headers? + /*Inside easy post finished + curl_slist_free_all (ctx->headers); + ctx->headers = NULL; + GNUNET_free (ctx->json_enc); + ctx->json_enc = NULL; + */ + GNUNET_free (awch->request_url); + GNUNET_free (awch); +} + + diff --git a/src/bank/bank_lib.c b/src/bank/bank_lib.c @@ -19,6 +19,7 @@ static struct GNUNET_CURL_RescheduleContext *rc; static struct TALER_BANK_AccountTokenHandle *ath; static struct TALER_BANK_AccountWithdrawalHandle *awh; static struct TALER_BANK_AccountWithdrawalConfirmHandle *awch; +static struct TALER_BANK_WithdrawalIDInfoHandle *awih; // static const char *configfilename = // "/home/manuel/.config/taler-exchange.conf"; static const char *withdrawal_id; // static const char *taler_withdraw_uri; @@ -27,9 +28,23 @@ static struct TALER_BANK_AccountWithdrawalConfirmHandle *awch; *Parameters of Withdrawal Request call. */ static bankCommunicationWithdrawalCallback_t extWithdrawalCallback; +static struct TALER_Amount parAmount, parSuggestedAmount; /** + *Parameters of Withdrawal Confirm Request call. + */ +static bankCommunicationWithdrawalConfirmatCallback_t extWithdrawalConfirmCallback; +static char *parWithdrawal_id; +static struct TALER_Amount parConfirmAmount; + +/** + *Parameters of Withdrawal ID info Request call. + */ +static bankCommunicationWithdrawalIDInfoCallback_t extWithdrawalIDInfoCallback; +static char *parInfoWithdrawal_id; + +/** *Function to do the cleanup */ static void do_shutdown(void *cls){ @@ -109,45 +124,75 @@ static void account_token_cb(void *cls, const struct TALER_BANK_AccountTokenResp auth.details.bearer.token = GNUNET_strdup(atr->details.ok.access_token); printf("fertig in bankcomu\n"); + GNUNET_SCHEDULER_shutdown(); } -static void runStartup(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg){ +/** + *Callback function for TALER_BANK_account_withdrawal_confirm + */ +static void account_withdrawal_confirm_cb(void *cls, const struct TALER_BANK_AccountWithdrawalConfirmResponse *awcr){ (void) cls; - (void) args; - (void) cfgfile; - (void) cfg; - //Shutdown for the GNUNET scheduler - GNUNET_SCHEDULER_add_shutdown(&do_shutdown, NULL); + awch = NULL; + switch (awcr->http_status) { + case 0: + fprintf(stderr, "Failed to obtain HTTP reply from `%s'\n", + auth.wire_gateway_url); + break; + default: + fprintf (stderr, + "Failed to obtain debit history from `%s': HTTP status %u (%s)\n", + auth.wire_gateway_url, + awcr->http_status, + TALER_ErrorCode_get_hint (awcr->ec)); + if (NULL != awcr->response) + json_dumpf (awcr->response, + stderr, + JSON_INDENT (2)); + break; + } - //Initialize Curl - ctx = GNUNET_CURL_init(&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); - GNUNET_assert(NULL != ctx); - rc = GNUNET_CURL_gnunet_rc_create(ctx); + //Call callback with the results + extWithdrawalConfirmCallback(); - //Parse config to obtain authentification data - if (GNUNET_OK != TALER_BANK_auth_parse_cfg(cfg, account_section, &auth)){ - printf("error parsing authentification Data"); + GNUNET_SCHEDULER_shutdown(); +} + +/** + *Callback function for TALER_BANK__withdrawalID_info + */ +static void withdrawalID_info_cb(void *cls, const struct TALER_BANK_WithdrawalIDInfoResponse *widr){ + (void) cls; + + awih = NULL; + switch (widr->http_status) { + case 0: + fprintf(stderr, "Failed to obtain HTTP reply from `%s'\n", + auth.wire_gateway_url); + break; + default: + fprintf (stderr, + "Failed to obtain debit history from `%s': HTTP status %u (%s)\n", + auth.wire_gateway_url, + widr->http_status, + TALER_ErrorCode_get_hint (widr->ec)); + if (NULL != widr->response) + json_dumpf (widr->response, + stderr, + JSON_INDENT (2)); + break; } - //Request an access Token - //Make Token request - struct GNUNET_TIME_Relative duration = {UINT64_MAX}; - ath = TALER_BANK_account_token(ctx, - &auth, - "finsteraarhorn", - TALER_BANK_TOKEN_SCOPE_READWRITE, - true, - "this is a description", - duration, - &account_token_cb, - NULL); + //Call callback with the results + extWithdrawalIDInfoCallback(); + GNUNET_SCHEDULER_shutdown(); } -int bankCommunicationInit(){ + +int bankCommunicationRun(GNUNET_PROGRAM_Main task){ int argc = 1; char *const *argv = &programname; int retval; @@ -161,7 +206,7 @@ int bankCommunicationInit(){ "cash2ecash", gettext_noop("cash2ecash bank communication library"), options, - &runStartup, NULL); + task, NULL); if (GNUNET_SYSERR == retval) return 3; if (GNUNET_NO == retval) @@ -170,28 +215,133 @@ int bankCommunicationInit(){ return 0; } +static void bankCommunicationRunInit(const struct GNUNET_CONFIGURATION_Handle *cfg){ + //Shutdown for the GNUNET scheduler + GNUNET_SCHEDULER_add_shutdown(&do_shutdown, NULL); + + //Initialize Curl + ctx = GNUNET_CURL_init(&GNUNET_CURL_gnunet_scheduler_reschedule, &rc); + GNUNET_assert(NULL != ctx); + rc = GNUNET_CURL_gnunet_rc_create(ctx); + + //Parse config to obtain authentification data + if (GNUNET_OK != TALER_BANK_auth_parse_cfg(cfg, account_section, &auth)){ + printf("error parsing authentification Data"); + } +} + + +static void runToken(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg){ + (void) cls; + (void) args; + (void) cfgfile; + (void) cfg; + bankCommunicationRunInit(cfg); -int bankCommunicationWithdrawalRequest(struct TALER_Amount amount, struct TALER_Amount suggestedAmount, bankCommunicationWithdrawalCallback_t callback){ - //Store the function callback globally - extWithdrawalCallback = callback; + //Request an access Token + //Make Token request + struct GNUNET_TIME_Relative duration = {UINT64_MAX}; + ath = TALER_BANK_account_token(ctx, + &auth, + "finsteraarhorn", + TALER_BANK_TOKEN_SCOPE_READWRITE, + true, + "this is a description", + duration, + account_token_cb, + NULL); + + if (NULL == ath){ + printf("error with ath"); + GNUNET_SCHEDULER_shutdown(); + } +} + +static void runWithdrawalRequest(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg){ + (void) cls; + (void) args; + (void) cfgfile; + (void) cfg; + + bankCommunicationRunInit(cfg); - //Make Withdrawal request (Do I have to check if the account Token request did allready run completely?) + //Make Withdrawal request awh = TALER_BANK_account_withdrawal(ctx, &auth, "finsteraarhorn", - &amount, - &suggestedAmount, - &account_withdrawal_cb, + &parAmount, + &parSuggestedAmount, + account_withdrawal_cb, NULL); if (NULL == awh){ printf("error with awh"); GNUNET_SCHEDULER_shutdown(); } +} + + +static void runWithdrawalConfirmRequest(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg){ + (void) cls; + (void) args; + (void) cfgfile; + (void) cfg; + + bankCommunicationRunInit(cfg); + + //Make Withdrawal Confirm request + awch = TALER_BANK_account_withdrawal_confirm(ctx, + &auth, + "finsteraarhorn", + parWithdrawal_id, + &parConfirmAmount, + account_withdrawal_confirm_cb, + NULL); + + if (NULL == awch){ + printf("error with awch"); + GNUNET_SCHEDULER_shutdown(); + } +} + +static void runWithdrawalIDInfoRequest(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *cfg){ + (void) cls; + (void) args; + (void) cfgfile; + (void) cfg; - //GNUNET_SCHEDULER_shutdown(); + bankCommunicationRunInit(cfg); + + //Make Withdrawal ID info request + awih = TALER_BANK_withdrawalID_info(ctx, + &auth, + parInfoWithdrawal_id, + withdrawalID_info_cb, + NULL); + + if (NULL == awih){ + printf("error with awih"); + GNUNET_SCHEDULER_shutdown(); + } +} + + + +/** + *Interface functions + */ + +void bankCommunicationInit() { bankCommunicationRun(runToken); } + + +void bankCommunicationWithdrawalRequest(struct TALER_Amount amount, struct TALER_Amount suggestedAmount, bankCommunicationWithdrawalCallback_t callback){ + //Store the parameters globaly + extWithdrawalCallback = callback; + parAmount = amount; + parSuggestedAmount = suggestedAmount; - return 0; + //Run request trough gnunet program run + bankCommunicationRun(runWithdrawalRequest); } diff --git a/src/bank/bank_lib.h b/src/bank/bank_lib.h @@ -9,12 +9,12 @@ extern "C" typedef void (*bankCommunicationWithdrawalCallback_t)(const char *withdrawal_id, const char *taler_withdraw_uri); -//typedef void (*bankCommunicationCallback_t)(); -//typedef void (*bankCommunicationCallback_t)(); +typedef void (*bankCommunicationWithdrawalConfirmatCallback_t)(); +typedef void (*bankCommunicationWithdrawalIDInfoCallback_t)(); -int bankCommunicationInit(); -int bankCommunicationWithdrawalRequest(struct TALER_Amount amount, struct TALER_Amount suggestedAmount, bankCommunicationWithdrawalCallback_t callback); +void bankCommunicationInit(); +void bankCommunicationWithdrawalRequest(struct TALER_Amount amount, struct TALER_Amount suggestedAmount, bankCommunicationWithdrawalCallback_t callback); diff --git a/src/bank/taler_bank_service_cash2ecash.h b/src/bank/taler_bank_service_cash2ecash.h @@ -198,3 +198,130 @@ void TALER_BANK_account_withdrawal_confirm_cancel ( struct TALER_BANK_AccountWithdrawalConfirmHandle *awch); + + +/* ********************* /withdrawals/$WITHDRAWAL_ID *********************** */ + +/** + * @brief A /withdrawals/$WITHDRAWAL_ID request handle + */ +struct TALER_BANK_ithdrawalIDInfoHandle; + + +/** + * Response details for a withdrawalID info request. + */ +struct TALER_BANK_WithdrawalIDInfoResponse +{ + + /** + * HTTP status. + */ + unsigned int http_status; + + /** + * Taler error code, #TALER_EC_NONE on success. + */ + enum TALER_ErrorCode ec; + + /** + * Full response, NULL if body was not in JSON format. + */ + const json_t *response; + + /** + * Details returned depending on the @e http_status. + */ + union + { + + /** + * Details if status was #MHD_HTTP_OK + */ + struct + { + /** + * Status + */ + const char *status; + + /** + * Amount (optional) + */ + struct TALER_Amount amount; + + /** + * Suggested Amount (optional) + */ + struct TALER_Amount suggested_amount; + + /** + * Account username + */ + const char *username; + + /** + * Reserve public key selected by the exchange, + * only non-null, if status is selected or confirmed + */ + const char *selected_reserve_pub; + + /** + * Exchange account selected by the wallet + * only non-null if status is selected or confirmed + */ + const char *selected_exchange_account; + + } ok; + + } details; + +}; + + +/** + * Callbacks of this type are used to return the result of submitting + * a request for an withdrawal id info to the bank. + * + * @param cls closure + * @param awr response details + */ +typedef void +(*TALER_BANK_WithdrawalIDInfoCallback) ( + void *cls, + const struct TALER_BANK_WithdrawalIDInfoResponse *awcr); + + + + +/** + * Posts a withdrawal id info request to the bank + * + * @param ctx curl context for the event loop + * @param auth authentication data to send to the bank, only url is used for this request + * #param withdrawal_id id of the withdrawal for which information should be obtained. + * @param res_cb the callback to call when the final result for this request is available + * @param res_cb_cls closure for the above callback + * @return NULL + * if the inputs are invalid (i.e. invalid amount) or internal errors. + * In this case, the callback is not called. + */ +struct TALER_BANK_WithdrawalIDInfoHandle * +TALER_BANK_withdrawalID_info ( + struct GNUNET_CURL_Context *ctx, + const struct TALER_BANK_AuthenticationData *auth, + const char *withdrawal_id, + TALER_BANK_WithdrawalIDInfoCallback res_cb, + void *res_cb_cls); + + +/** + * Cancel an withdrawal id info operation. This function cannot be used on a + * request handle if a response is already served for it. + * + * @param[in] awch the withdrawal id info request handle + */ +void +TALER_BANK_withdrawalID_info_cancel ( + struct TALER_BANK_WithdrawalIDInfoHandle *awch); +