cash2ecash

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

commit 01d76ab69fa5f99e3a66d6bd3e9e87699f3fd352
parent c3347d0e469b617a0cac1dbb2f8d9ec23f08f1a8
Author: Tellenbach Reto <tellr1@bfh.ch>
Date:   Mon,  8 Jun 2026 00:48:57 +0200

[wip] Tapler-api: GET /withdrawals/ created, but longpoll options missing

Diffstat:
Msrc/lib/CMakeLists.txt | 4+++-
Asrc/lib/bank_api_get_withdrawals.c | 278+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/lib/bank_api_get_withdrawals.h | 154+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/bank_api_post_accounts_withdrawals_confirm.c | 19+++++++++++++------
Msrc/lib/bank_api_post_accounts_withdrawals_confirm.h | 2+-
5 files changed, 449 insertions(+), 8 deletions(-)

diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt @@ -3,7 +3,9 @@ add_library(bank bank_api_get_config.c bank_api_curl_defaults.c bank_api_get_accounts.c - bank_api_post_accounts_withdrawals.c) + bank_api_get_withdrawals.c + bank_api_post_accounts_withdrawals.c + bank_api_post_accounts_withdrawals_confirm.c) add_library(common api_common.c api_parse.c) diff --git a/src/lib/bank_api_get_withdrawals.c b/src/lib/bank_api_get_withdrawals.c @@ -0,0 +1,278 @@ +/* + This file is part of TALER cash2ecash + Copyright (C) 2026 GNUnet e.V. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +/** + * @file bank-lib/bank_api_get_withdrawals.c + * @brief implements the Taler Bank API "GET /withdrawals/$WITHDRAWAL_ID" handler + * @author Reto Tellenbach + */ + +#include <microhttpd.h> +#include "taler/taler_json_lib.h" +#include "taler/taler_bank_service.h" +#include "bank_api_get_withdrawals.h" +#include "bank_api_curl_defaults.h" + +/** + * Log error related to CURL operations. + * + * @param type log level + * @param function which function failed to run + * @param code what was the curl error code + */ +#define CURL_STRERROR(type, function, code) \ + GNUNET_log (type, \ + "Curl function `%s' has failed at `%s:%d' with error: %s", \ + function, __FILE__, __LINE__, curl_easy_strerror (code)); + +/** + * Handle for the accounts request. + */ +struct TALER_BANK_GetWithdrawalHandle +{ + /** + * The context of this handle + */ + struct GNUNET_CURL_Context *ctx; + + /** + * Function to call with the , + * NULL if this has already been done. + */ + TALER_BANK_WithdrawalCallback withdrawals_cb; + + /** + * Closure to pass to + */ + void *withdrawals_cb_cls; + + /** + * Data for the request to get the /withdrawals/$WITHDRAWAL_ID of a bank, + * NULL once we are past stage #MHS_INIT. + */ + struct GNUNET_CURL_Job *job; + + /** + * The whole request line + */ + char *job_url; +}; + + +/** + * Decode the JSON in @a resp_obj from the /withdrawals/$WITHDRAWAL_ID response + * + * @param[in] resp_obj JSON object to parse + * @param[in,out] vi where to store the results we decoded + * @param[out] vc where to store account info data + * @return #TALER_EC_NONE on success + */ +static enum TALER_ErrorCode +decode_withdrawals_json (const json_t *resp_obj, + struct TALER_BANK_WithdrawalInfo *vi) +{ + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received body\n`%s'\n", + json_dumps(resp_obj, 0)); + + + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("status", + &vi->status), + NULL), + GNUNET_JSON_spec_mark_optional ( + TALER_JSON_spec_amount_any ("amount", + &vi->amount),NULL), + GNUNET_JSON_spec_mark_optional ( + TALER_JSON_spec_amount_any ("suggested_amount", + &vi->suggested_amount),NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_bool ("no_amount_to_wallet", + &vi->no_amount_to_wallet),NULL), + GNUNET_JSON_spec_string ("username", + &vi->username), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("selected_reserve_pub", + &vi->selected_reserve_pub),NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("selected_exchange_account", + &vi->selected_exchange_account),NULL), + GNUNET_JSON_spec_end () + }; + + if (JSON_OBJECT != json_typeof (resp_obj)) + { + GNUNET_break_op (0); + return TALER_EC_GENERIC_JSON_INVALID; + } + if (GNUNET_OK != + GNUNET_JSON_parse (resp_obj, + spec, + NULL, NULL)) + { + GNUNET_break_op (0); + return TALER_EC_GENERIC_JSON_INVALID; + } + + return TALER_EC_NONE; +} + + +/** + * Callback used when http reply arived to a /withdrawals/$WITHDRAWAL_ID request. + * + * @param cls the `struct TALER_BANK_GetWithdrawalHandle` + * @param response_code HTTP response code or 0 on error + * @param gresp_obj JSON result, NULL on error, must be a `const json_t *` + */ +static void +response_cb(void *cls, + long response_code, + const void *gresp_obj) +{ + struct TALER_BANK_GetWithdrawalHandle *withdrawal = cls; + const json_t *resp_obj = gresp_obj; + + struct TALER_BANK_WithdrawalResponse wr = { + .hr.response = resp_obj, + .hr.http_status = (unsigned int)response_code + }; + + withdrawal->job = NULL; //job was successfull, curl job cancel not needed anymore in cleanup + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Received withdrawal info from URL `%s' with status %ld.\n", + withdrawal->job_url, + response_code); + + switch (response_code) + { + case 0: + GNUNET_break_op (0); + wr.hr.ec = TALER_EC_INVALID; + break; + case MHD_HTTP_OK: + if (NULL == resp_obj) + { + GNUNET_break_op (0); + wr.hr.http_status = 0; + wr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + } + wr.hr.ec = decode_withdrawals_json (resp_obj, + &wr.details.ok.acc); + if (TALER_EC_NONE != wr.hr.ec) + { + GNUNET_break_op (0); + wr.hr.http_status = 0; + break; + } + break; + case MHD_HTTP_NOT_FOUND: + wr.hr.ec = TALER_JSON_get_error_code (resp_obj); + wr.hr.hint = TALER_JSON_get_error_hint (resp_obj); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "The operation was not found %u/%d\n", + (unsigned int) response_code, + (int) wr.hr.ec); + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + wr.hr.ec = TALER_JSON_get_error_code (resp_obj); + wr.hr.hint = TALER_JSON_get_error_hint (resp_obj); + break; + default: + wr.hr.ec = TALER_JSON_get_error_code (resp_obj); + wr.hr.hint = TALER_JSON_get_error_hint (resp_obj); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) wr.hr.ec); + break; + } + + withdrawal->withdrawals_cb (withdrawal->withdrawals_cb_cls, &wr); + TALER_BANK_get_withdrawal_cancel(withdrawal); +} + + +struct TALER_BANK_GetWithdrawalHandle * +TALER_BANK_get_withdrawal ( struct GNUNET_CURL_Context *ctx, + const char *base_url, + const char *wopid, + + TALER_BANK_WithdrawalCallback withdrawals_cb, + void *withdrawals_cb_cls) +{ + struct TALER_BANK_GetWithdrawalHandle *withdrawal; + char *url; + CURL *eh; + + withdrawal = GNUNET_new(struct TALER_BANK_GetWithdrawalHandle); + withdrawal->withdrawals_cb = withdrawals_cb; + withdrawal->withdrawals_cb_cls = withdrawals_cb_cls; + withdrawal->ctx = ctx; + GNUNET_asprintf(&url, + "withdrawals/%s", + wopid); + withdrawal->job_url = TALER_url_join(base_url, + url, + NULL); + if(NULL == withdrawal->job_url) + { + GNUNET_break(0); + GNUNET_free(withdrawal); + return NULL; + } + GNUNET_log( GNUNET_ERROR_TYPE_INFO, + "Requesting bank account information with URL `%s'.\n", + withdrawal->job_url); + eh = TALER_BANK_curl_easy_get_(withdrawal->job_url); + if(NULL == eh) + { + GNUNET_break(0); + TALER_BANK_get_withdrawal_cancel(withdrawal); + return NULL; + } + withdrawal->job = + GNUNET_CURL_job_add(withdrawal->ctx, + eh, + &response_cb, + withdrawal); + if(NULL == withdrawal->job) + { + GNUNET_break(0); + TALER_BANK_get_withdrawal_cancel(withdrawal); + return NULL; + } + + return withdrawal; +} + + + +void +TALER_BANK_get_withdrawals_cancel ( struct TALER_BANK_GetWithdrawalHandle *withdrawal) +{ + if(NULL != withdrawal->job) + { + GNUNET_CURL_job_cancel(withdrawal->job); + withdrawal->job = NULL; + } + GNUNET_free(withdrawal->job_url); + GNUNET_free(withdrawal); +} diff --git a/src/lib/bank_api_get_withdrawals.h b/src/lib/bank_api_get_withdrawals.h @@ -0,0 +1,154 @@ +/* + This file is part of TALER cash2ecash + Copyright (C) 2026 GNUnet e.V. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ +/** + * @file lib/bank_api_get_withdrawals.h + * @brief implements the Taler Bank API "GET /withdrawals/$WITHDRAWAL_ID" handler + * @author Reto Tellenbach + */ +#ifndef BANK_API_GET_WITHDRAWALS_H +#define BANK_API_GET_WITHDRAWALS_H + +#include "api_common.h" + + +/** + * @brief Information about withrawal operation + */ +struct TALER_BANK_WithdrawalInfo +{ + /** + * Current status of the account + * active: the account can be used + * locked: the account can be used but cannot create new tokens + * deleted: the account has been deleted but is retained for compliance + */ + const char *status; + + /** + * Amount that will be withdrawn with this operation + */ + struct TALER_Amount amount; + + /** + * Suggestion for the amount to be withdrawn with this + * operation + */ + struct TALER_Amount suggested_amount; + + /** + * indication that no amount was set at creation. + * therfor amount must be set in confirm step + */ + bool no_amount_to_wallet; + + /** + * Bank 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; +}; + +/** + * Response details for a /withdrawals/$WITHDRAWAL_ID request + */ +struct TALER_BANK_WithdrawalResponse +{ + + /** + * HTTP response + */ + struct TALER_BANK_HttpResponse hr; + + /** + * Details returned depending on the @e http_status. + */ + union + { + + /** + * Details if status was request was succesfull + */ + struct + { + + /** + * Config data returned by accounts/$USERNAME + */ + struct TALER_BANK_WithdrawalInfo acc; + + } ok; + + } details; + +}; + + +/** + * Function called with information about the withdrawal operation + * + * @param cls closure + * @param vr response data + */ +typedef void +(*TALER_BANK_WithdrawalCallback) ( + void *cls, + const struct TALER_BANK_WithdrawalResponse *vr); + + +/** + * Handle for the get withdrawal request. + */ +struct TALER_BANK_GetWithdrawalHandle; + + +/** + * Obtain wopid inforamtion + * @param ctx curl context + * @param url bank url + * @param wopid withdrawal operation id + * @param withdrawal_cb callback + * @param withdrawal_cb_cls callback context + * @return NULL on failure + */ +struct TALER_BANK_GetWithdrawalHandle * +TALER_BANK_get_withdrawal ( struct GNUNET_CURL_Context *ctx, + const char *base_url, + const char *wopid, + TALER_BANK_WithdrawalCallback withdrawals_cb, + void *withdrawals_cb_cls); + + +/** + * Cancel withdrawal request. Frees if neccessary + * @param withdrawal handle + */ +void TALER_BANK_get_withdrawal_cancel ( struct TALER_BANK_GetWithdrawalHandle *withdrawal); + +#endif diff --git a/src/lib/bank_api_post_accounts_withdrawals_confirm.c b/src/lib/bank_api_post_accounts_withdrawals_confirm.c @@ -169,10 +169,17 @@ response_cb(void *cls, { GNUNET_break_op (0); pacwr.hr.http_status = 0; - pacwr.hr.ec = decode_challenge_json (resp_obj, + break; + } + pacwr.hr.ec = decode_challenge_json (resp_obj, &pacwr.details.ok.challenge); + if (TALER_EC_NONE != pacwr.hr.ec) + { + GNUNET_break_op (0); + pacwr.hr.http_status = 0; break; } + break; case MHD_HTTP_OK: if (NULL == resp_obj) { @@ -235,7 +242,7 @@ response_cb(void *cls, } pcwh->woc_cb (pcwh->woc_cb_cls, &pacwr); - TALER_BANK_post_withdrawal_create_cancel(pcwh); + TALER_BANK_post_withdrawal_confirm_cancel(pcwh); } /** @@ -267,7 +274,7 @@ TALER_BANK_post_withdrawal_confirm_create ( struct GNUNET_CURL_Context *ctx, { GNUNET_free (usr); GNUNET_break (0); - TALER_BANK_post_withdrawal_create_cancel (pwc); + TALER_BANK_post_withdrawal_confirm_cancel (pwc); return GNUNET_NO; } GNUNET_free (usr); @@ -299,7 +306,7 @@ TALER_BANK_post_withdrawal_confirm ( struct TALER_BANK_PostWithdrawalConfirmHand if(GNUNET_OK != DIGITIZER_setup_auth_(handle->easy_handle,handle->authorization)) { GNUNET_break(0); - TALER_BANK_post_withdrawal_create_cancel(handle); + TALER_BANK_post_withdrawal_confirm_cancel(handle); return GNUNET_NO; } if(GNUNET_OK != @@ -308,7 +315,7 @@ TALER_BANK_post_withdrawal_confirm ( struct TALER_BANK_PostWithdrawalConfirmHand req)) { GNUNET_break(0); - TALER_BANK_post_withdrawal_create_cancel(handle); + TALER_BANK_post_withdrawal_confirm_cancel(handle); return GNUNET_NO; } @@ -324,7 +331,7 @@ TALER_BANK_post_withdrawal_confirm ( struct TALER_BANK_PostWithdrawalConfirmHand if(NULL == handle->job) { GNUNET_break(0); - TALER_BANK_post_withdrawal_create_cancel(handle); + TALER_BANK_post_withdrawal_confirm_cancel(handle); return GNUNET_NO; } diff --git a/src/lib/bank_api_post_accounts_withdrawals_confirm.h b/src/lib/bank_api_post_accounts_withdrawals_confirm.h @@ -51,7 +51,7 @@ struct TALER_BANK_ChallengeResponse /** * temporal json object for parsing */ - json_t blc; + json_t *blc; }; /**