commit db7782aefcc036970b8bd6fbde87aef43740db37
parent 39a0a96415e81c4f2170d3d4efeb65a6f8b837c3
Author: Christian Grothoff <grothoff@gnunet.org>
Date: Fri, 10 Jul 2026 08:47:07 +0200
clean up /abort library endpoint to match spec
Diffstat:
2 files changed, 120 insertions(+), 25 deletions(-)
diff --git a/src/include/taler/merchant/post-orders-ORDER_ID-abort.h b/src/include/taler/merchant/post-orders-ORDER_ID-abort.h
@@ -62,11 +62,6 @@ struct TALER_MERCHANT_PostOrdersAbortCoin
*/
struct TALER_DenominationSignature denom_sig;
- /**
- * Amount contributed without the deposit fee.
- */
- struct TALER_Amount contribution;
-
};
@@ -75,21 +70,73 @@ struct TALER_MERCHANT_PostOrdersAbortCoin
*/
struct TALER_MERCHANT_PostOrdersAbortedCoin
{
-
/**
- * Exchange signature confirming the refund.
+ * Type of status for this coin, determines content of @e details
*/
- struct TALER_ExchangeSignatureP exchange_sig;
+ enum
+ {
+ TALER_MERCHANT_POAC_UNDEPOSITED = 0,
+ TALER_MERCHANT_POAC_SUCCESS,
+ TALER_MERCHANT_POAC_FAILURE,
+ } type;
/**
- * Exchange public key used for @e exchange_sig.
+ * Public key of the coin.
*/
- struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_CoinSpendPublicKeyP coin_pub;
/**
- * Public key of the coin.
+ * Details depending on @e type
*/
- struct TALER_CoinSpendPublicKeyP coin_pub;
+ union
+ {
+
+ /**
+ * Details on #TALER_MERCHANT_POAC_SUCCESS.
+ */
+ struct
+ {
+
+ /**
+ * Exchange signature confirming the refund.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ /**
+ * Exchange public key used for @e exchange_sig.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * HTTP status of the abort from the exchange.
+ */
+ uint32_t exchange_status;
+ } success;
+
+ /**
+ * Details on #TALER_MERCHANT_POAC_FAILURE.
+ */
+ struct
+ {
+
+ /**
+ * HTTP status of the abort from the exchange.
+ */
+ uint32_t exchange_status;
+
+ /**
+ * Error code from the exchange.
+ */
+ enum TALER_ErrorCode exchange_code;
+
+ /**
+ * Full exchange reply, could be NULL.
+ */
+ const json_t *exchange_reply;
+
+ } failure;
+
+ } details;
};
diff --git a/src/lib/merchant_api_post-orders-ORDER_ID-abort.c b/src/lib/merchant_api_post-orders-ORDER_ID-abort.c
@@ -150,34 +150,51 @@ check_abort_refund (struct TALER_MERCHANT_PostOrdersAbortHandle *poah,
{
struct TALER_MERCHANT_PostOrdersAbortedCoin res[GNUNET_NZL (num_refunds)];
+ memset (res,
+ 0,
+ sizeof (res));
for (unsigned int i = 0; i<num_refunds; i++)
{
json_t *refund = json_array_get (refunds, i);
- uint32_t exchange_status;
- struct GNUNET_JSON_Specification spec_es[] = {
- GNUNET_JSON_spec_uint32 ("exchange_status",
- &exchange_status),
+ struct TALER_MERCHANT_PostOrdersAbortedCoin *ac = &res[i];
+ const char *type;
+ struct GNUNET_JSON_Specification spec_type[] = {
+ GNUNET_JSON_spec_string ("type",
+ &type),
GNUNET_JSON_spec_end ()
};
+ ac->coin_pub = poah->coins[i].coin_pub;
if (GNUNET_OK !=
GNUNET_JSON_parse (refund,
- spec_es,
+ spec_type,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- if (MHD_HTTP_OK == exchange_status)
+ if (0 == strcmp (type,
+ "undeposited"))
+ {
+ /* An "undeposited" entry (MerchantAbortPayRefundUndepositedStatus)
+ carries no exchange_status and no refund confirmation to verify. */
+ ac->type = TALER_MERCHANT_POAC_UNDEPOSITED;
+ continue;
+ }
+ if (0 == strcmp (type,
+ "success"))
{
struct GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_uint32 ("exchange_status",
+ &ac->details.success.exchange_status),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
- &res[i].exchange_sig),
+ &ac->details.success.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
- &res[i].exchange_pub),
+ &ac->details.success.exchange_pub),
GNUNET_JSON_spec_end ()
};
+ ac->type = TALER_MERCHANT_POAC_SUCCESS;
if (GNUNET_OK !=
GNUNET_JSON_parse (refund,
spec_detail,
@@ -186,7 +203,11 @@ check_abort_refund (struct TALER_MERCHANT_PostOrdersAbortHandle *poah,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- res[i].coin_pub = poah->coins[i].coin_pub;
+ if (MHD_HTTP_OK != ac->details.success.exchange_status)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
if (GNUNET_OK !=
TALER_exchange_online_refund_confirmation_verify (
@@ -195,13 +216,42 @@ check_abort_refund (struct TALER_MERCHANT_PostOrdersAbortHandle *poah,
&poah->merchant_pub,
0, /* transaction id */
&poah->coins[i].amount_with_fee,
- &res[i].exchange_pub,
- &res[i].exchange_sig))
+ &ac->details.success.exchange_pub,
+ &ac->details.success.exchange_sig))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ continue;
+ }
+ if (0 == strcmp (type,
+ "failure"))
+ {
+ struct GNUNET_JSON_Specification spec_detail[] = {
+ GNUNET_JSON_spec_uint32 ("exchange_status",
+ &ac->details.failure.exchange_status),
+ TALER_JSON_spec_ec ("exchange_code",
+ &ac->details.failure.exchange_code),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_object_const ("exchange_reply",
+ &ac->details.failure.exchange_reply),
+ NULL),
+ GNUNET_JSON_spec_end ()
+ };
+
+ ac->type = TALER_MERCHANT_POAC_FAILURE;
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (refund,
+ spec_detail,
+ NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ continue;
}
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
}
switch (ar->hr.http_status)
{
@@ -394,8 +444,6 @@ TALER_MERCHANT_post_orders_abort_start (
j_coin = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("coin_pub",
&ac->coin_pub),
- TALER_JSON_pack_amount ("contribution",
- &ac->amount_with_fee),
GNUNET_JSON_pack_string ("exchange_url",
ac->exchange_url));
if (0 !=