sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit 24227de303ceeecd73c447bd1058851081d23352
parent 0301428cc8d1cc3bc0006003a9abbdf9bcdfdb0b
Author: Iván Ávalos <avalos@disroot.org>
Date:   Sun,  9 Aug 2026 17:16:54 +0200

create a fresh payment order when the merchant lost the pending one

Diffstat:
Msrc/sync/sync-httpd2_payments.c | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 57 insertions(+), 10 deletions(-)

diff --git a/src/sync/sync-httpd2_payments.c b/src/sync/sync-httpd2_payments.c @@ -242,8 +242,11 @@ ongoing_payment_cb (void *cls, * * @param bpc our payment context * @param osr order status + * @return true if the caller should resume the request, false if a + * fresh order creation was initiated instead (the request was + * re-suspended and will be resumed once that order exists) */ -static void +static bool set_payment_response ( struct BackupPaymentContext *bpc, const struct TALER_MERCHANT_GetPrivateOrderResponse *osr) @@ -257,7 +260,48 @@ set_payment_response ( bpc->resp = TALER_MHD2_make_error ( TALER_EC_SYNC_GENERIC_BACKEND_TIMEOUT, NULL); - return; + return true; + case MHD_HTTP_STATUS_NOT_FOUND: + /* The merchant no longer knows the order we stored as pending (it + expired, or the merchant's data was reset). The stored order is + stale and can never be paid: forget it and create a fresh one, so + the account payment can still be set up instead of failing every + upload with a 502 until the order expires from our own database. */ + if (NULL != bpc->existing_order_id) + { + bool suspend; + + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Pending order `%s' no longer exists at the merchant," + " creating a fresh order\n", + bpc->existing_order_id); + GNUNET_free (bpc->existing_order_id); + bpc->existing_order_id = NULL; + bpc->force_fresh_order = true; + bpc->resp = SH_begin_payment (bpc, + GNUNET_NO, + &suspend); + if (suspend) + return false; /* fresh order is being created; do not resume yet */ + return true; + } + /* The order the client promised to pay (`paying') is gone; tell + them to start over. */ + bpc->resp = TALER_MHD2_MAKE_JSON_PACK ( + MHD_HTTP_STATUS_BAD_GATEWAY, + GNUNET_JSON_pack_uint64 ("code", + TALER_EC_SYNC_GENERIC_BACKEND_ERROR), + GNUNET_JSON_pack_string ("hint", + TALER_ErrorCode_get_hint ( + TALER_EC_SYNC_GENERIC_BACKEND_ERROR)), + GNUNET_JSON_pack_uint64 ("backend-ec", + (json_int_t) hr->ec), + GNUNET_JSON_pack_uint64 ("backend-http-status", + (json_int_t) hr->http_status), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("backend-reply", + (json_t *) hr->reply))); + return true; case MHD_HTTP_STATUS_OK: break; /* handled below */ default: @@ -276,7 +320,7 @@ set_payment_response ( GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_incref ("backend-reply", (json_t *) hr->reply))); - return; + return true; } GNUNET_assert (MHD_HTTP_STATUS_OK == hr->http_status); @@ -294,12 +338,12 @@ set_payment_response ( bpc->order_id, GNUNET_TIME_UNIT_YEARS); /* always annual */ if (0 <= qs) - return; /* continue as planned */ + return true; /* continue as planned */ GNUNET_break (0); bpc->resp = TALER_MHD2_make_error (TALER_EC_GENERIC_DB_STORE_FAILED, "increment lifetime"); GNUNET_assert (NULL != bpc->resp); - return; /* continue as planned */ + return true; /* continue as planned */ } case TALER_MERCHANT_OSC_UNPAID: case TALER_MERCHANT_OSC_CLAIMED: @@ -316,13 +360,14 @@ set_payment_response ( ? NULL : &bpc->token); GNUNET_assert (NULL != bpc->resp); - return; + return true; } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Timeout waiting for payment\n"); bpc->resp = TALER_MHD2_make_error (TALER_EC_SYNC_PAYMENT_GENERIC_TIMEOUT, "Timeout awaiting promised payment"); GNUNET_assert (NULL != bpc->resp); + return true; } @@ -341,10 +386,12 @@ check_payment_cb ( GNUNET_CONTAINER_DLL_remove (bpc_head, bpc_tail, bpc); - /* Set the response before resuming, MHD needs it in place */ - set_payment_response (bpc, - osr); - resume_request (bpc); + /* Set the response before resuming, MHD needs it in place. A 404 from + the merchant for a stale order re-runs the payment initiation (which + re-suspends the request); only resume when a final response is set. */ + if (set_payment_response (bpc, + osr)) + resume_request (bpc); }