exchange

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

commit 702b929080885825309044348d24559471cd46a9
parent 728c4fd49e63140895575fbb30f0fd9cbaacee65
Author: Christian Grothoff <christian@grothoff.org>
Date:   Sat,  4 Apr 2026 23:24:14 +0200

de-duplicate 451 response parsing logic

Diffstat:
Msrc/include/taler/taler-exchange/common.h | 13+++++++++++++
Msrc/lib/exchange_api_common.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/lib/exchange_api_post-batch-deposit.c | 39+++++++++------------------------------
Msrc/lib/exchange_api_post-kyc-wallet.c | 39+++++++++------------------------------
Msrc/lib/exchange_api_post-purses-PURSE_PUB-merge.c | 39+++++++++------------------------------
Msrc/lib/exchange_api_post-reserves-RESERVE_PUB-close.c | 49++++---------------------------------------------
Msrc/lib/exchange_api_post-reserves-RESERVE_PUB-open.c | 53-----------------------------------------------------
Msrc/lib/exchange_api_post-reserves-RESERVE_PUB-purse.c | 39+++++++++------------------------------
Msrc/lib/exchange_api_post-withdraw.c | 2+-
Msrc/lib/exchange_api_post-withdraw_blinded.c | 42+++++++++---------------------------------
10 files changed, 108 insertions(+), 252 deletions(-)

diff --git a/src/include/taler/taler-exchange/common.h b/src/include/taler/taler-exchange/common.h @@ -112,6 +112,19 @@ struct TALER_EXCHANGE_KycNeededRedirect /** + * We received an #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS response code. + * Parse the JSON response and initialize the @a uflr object. + * + * @param[out] uflr data structure to initialize + * @param j JSON response to parse + * @return #GNUNET_OK on success + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_451 (struct TALER_EXCHANGE_KycNeededRedirect *uflr, + const json_t *j); + + +/** * Information about a coin to be deposited into a purse or reserve. */ struct TALER_EXCHANGE_PurseDeposit diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c @@ -707,4 +707,49 @@ TALER_EXCHANGE_keys_test_account_allowed ( } +/** + * We received an #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS response code. + * Parse the JSON response and initialize the @a uflr object. + * + * @param[out] uflr data structure to initialize + * @param j JSON response to parse + * @return #GNUNET_OK on success + */ +enum GNUNET_GenericReturnValue +TALER_EXCHANGE_parse_451 (struct TALER_EXCHANGE_KycNeededRedirect *uflr, + const json_t *j) +{ + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ( + "h_payto", + &uflr->h_payto), + GNUNET_JSON_spec_uint64 ( + "requirement_row", + &uflr->requirement_row), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_fixed_auto ( + "account_pub", + &uflr->account_pub), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_bool ( + "bad_kyc_auth", + &uflr->bad_kyc_auth), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (j, + spec, + NULL, + NULL)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + /* end of exchange_api_common.c */ diff --git a/src/lib/exchange_api_post-batch-deposit.c b/src/lib/exchange_api_post-batch-deposit.c @@ -560,37 +560,16 @@ handle_deposit_finished (void *cls, dr->hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + dr->hr.ec = TALER_JSON_get_error_code (j); + dr->hr.hint = TALER_JSON_get_error_hint (j); + if (GNUNET_OK != + TALER_EXCHANGE_parse_451 (&dr->details.unavailable_for_legal_reasons, + j)) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &dr->details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &dr->details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "account_pub", - &dr->details.unavailable_for_legal_reasons.account_pub), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ( - "bad_kyc_auth", - &dr->details.unavailable_for_legal_reasons.bad_kyc_auth), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - dr->hr.http_status = 0; - dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + GNUNET_break_op (0); + dr->hr.http_status = 0; + dr->hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; } break; case MHD_HTTP_INTERNAL_SERVER_ERROR: diff --git a/src/lib/exchange_api_post-kyc-wallet.c b/src/lib/exchange_api_post-kyc-wallet.c @@ -149,39 +149,18 @@ handle_kyc_wallet_finished (void *cls, ks.hr.ec = TALER_JSON_get_error_code (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + ks.hr.ec = TALER_JSON_get_error_code (j); + ks.hr.hint = TALER_JSON_get_error_hint (j); + if (GNUNET_OK != + TALER_EXCHANGE_parse_451 (&ks.details.unavailable_for_legal_reasons, + j)) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &ks.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &ks.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "account_pub", - &ks.details.unavailable_for_legal_reasons.account_pub), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ( - "bad_kyc_auth", - &ks.details.unavailable_for_legal_reasons.bad_kyc_auth), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - ks.hr.http_status = 0; - ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - } + GNUNET_break_op (0); + ks.hr.http_status = 0; + ks.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; break; } + break; case MHD_HTTP_INTERNAL_SERVER_ERROR: ks.hr.ec = TALER_JSON_get_error_code (j); /* Server had an internal issue; we should retry, but this API diff --git a/src/lib/exchange_api_post-purses-PURSE_PUB-merge.c b/src/lib/exchange_api_post-purses-PURSE_PUB-merge.c @@ -269,37 +269,16 @@ handle_purse_merge_finished (void *cls, dr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + if (GNUNET_OK != + TALER_EXCHANGE_parse_451 (&dr.details.unavailable_for_legal_reasons, + j)) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &dr.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &dr.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "account_pub", - &dr.details.unavailable_for_legal_reasons.account_pub), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ( - "bad_kyc_auth", - &dr.details.unavailable_for_legal_reasons.bad_kyc_auth), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; } break; case MHD_HTTP_INTERNAL_SERVER_ERROR: diff --git a/src/lib/exchange_api_post-reserves-RESERVE_PUB-close.c b/src/lib/exchange_api_post-reserves-RESERVE_PUB-close.c @@ -137,49 +137,6 @@ handle_reserves_close_ok (struct TALER_EXCHANGE_PostReservesCloseHandle *prch, /** - * We received an #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS close code. Handle the JSON - * response. - * - * @param prch handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_close_kyc (struct TALER_EXCHANGE_PostReservesCloseHandle *prch, - const json_t *j) -{ - struct TALER_EXCHANGE_PostReservesCloseResponse rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, - }; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &rs.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &rs.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - prch->cb (prch->cb_cls, - &rs); - prch->cb = NULL; - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** * Function called when we're done processing the * HTTP /reserves/$RID/close request. * @@ -241,9 +198,11 @@ handle_reserves_close_finished (void *cls, rs.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + rs.hr.ec = TALER_JSON_get_error_code (j); + rs.hr.hint = TALER_JSON_get_error_hint (j); if (GNUNET_OK != - handle_reserves_close_kyc (prch, - j)) + TALER_EXCHANGE_parse_451 (&rs.details.unavailable_for_legal_reasons, + j)) { GNUNET_break_op (0); rs.hr.http_status = 0; diff --git a/src/lib/exchange_api_post-reserves-RESERVE_PUB-open.c b/src/lib/exchange_api_post-reserves-RESERVE_PUB-open.c @@ -213,49 +213,6 @@ handle_reserves_open_pr (struct TALER_EXCHANGE_PostReservesOpenHandle *proh, /** - * We received an #MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS open code. Handle the JSON - * response. - * - * @param proh handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_open_kyc (struct TALER_EXCHANGE_PostReservesOpenHandle *proh, - const json_t *j) -{ - struct TALER_EXCHANGE_PostReservesOpenResponse rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, - }; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &rs.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &rs.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - proh->cb (proh->cb_cls, - &rs); - proh->cb = NULL; - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** * Function called when we're done processing the * HTTP /reserves/$RID/open request. * @@ -366,16 +323,6 @@ handle_reserves_open_finished (void *cls, rs.hr.hint = TALER_JSON_get_error_hint (j); break; } - case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: - if (GNUNET_OK != - handle_reserves_open_kyc (proh, - j)) - { - GNUNET_break_op (0); - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */ diff --git a/src/lib/exchange_api_post-reserves-RESERVE_PUB-purse.c b/src/lib/exchange_api_post-reserves-RESERVE_PUB-purse.c @@ -344,37 +344,16 @@ handle_purse_create_with_merge_finished (void *cls, dr.hr.hint = TALER_JSON_get_error_hint (j); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + dr.hr.ec = TALER_JSON_get_error_code (j); + dr.hr.hint = TALER_JSON_get_error_hint (j); + if (GNUNET_OK != + TALER_EXCHANGE_parse_451 (&dr.details.unavailable_for_legal_reasons, + j)) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &dr.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &dr.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "account_pub", - &dr.details.unavailable_for_legal_reasons.account_pub), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ( - "bad_kyc_auth", - &dr.details.unavailable_for_legal_reasons.bad_kyc_auth), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - dr.hr.http_status = 0; - dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + GNUNET_break_op (0); + dr.hr.http_status = 0; + dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; + break; } break; case MHD_HTTP_INTERNAL_SERVER_ERROR: diff --git a/src/lib/exchange_api_post-withdraw.c b/src/lib/exchange_api_post-withdraw.c @@ -385,7 +385,7 @@ copy_results ( break; } case MHD_HTTP_CREATED: - resp.details.created = wbr->details.created; + resp.details.created = wbr->details.created; break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: resp.details.unavailable_for_legal_reasons = diff --git a/src/lib/exchange_api_post-withdraw_blinded.c b/src/lib/exchange_api_post-withdraw_blinded.c @@ -441,42 +441,18 @@ handle_withdraw_blinded_finished ( wbr.hr.hint = TALER_JSON_get_error_hint (j_response); break; case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: - /* only validate reply is well-formed */ + wbr.hr.ec = TALER_JSON_get_error_code (j_response); + wbr.hr.hint = TALER_JSON_get_error_hint (j_response); + if (GNUNET_OK != + TALER_EXCHANGE_parse_451 (&wbr.details.unavailable_for_legal_reasons, + j_response)) { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ( - "h_payto", - &wbr.details.unavailable_for_legal_reasons.h_payto), - GNUNET_JSON_spec_uint64 ( - "requirement_row", - &wbr.details.unavailable_for_legal_reasons.requirement_row), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ( - "account_pub", - &wbr.details.unavailable_for_legal_reasons.account_pub), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_bool ( - "bad_kyc_auth", - &wbr.details.unavailable_for_legal_reasons.bad_kyc_auth), - NULL), - GNUNET_JSON_spec_end () - }; - - wbr.hr.ec = TALER_JSON_get_error_code (j_response); - wbr.hr.hint = TALER_JSON_get_error_hint (j_response); - if (GNUNET_OK != - GNUNET_JSON_parse (j_response, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - wbr.hr.http_status = 0; - wbr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } + GNUNET_break_op (0); + wbr.hr.http_status = 0; + wbr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; break; } + break; case MHD_HTTP_INTERNAL_SERVER_ERROR: /* Server had an internal issue; we should retry, but this API leaves this to the application */