sync

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

commit 0301428cc8d1cc3bc0006003a9abbdf9bcdfdb0b
parent bb2d5e75a9e44689c2020a12a524835d4e586bb9
Author: Iván Ávalos <avalos@disroot.org>
Date:   Sun,  9 Aug 2026 16:48:18 +0200

serve the account pay URI on object upload 402s

Diffstat:
Msrc/sync/sync-httpd2_post-backups-KEY-objects-UID.c | 77++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 72 insertions(+), 5 deletions(-)

diff --git a/src/sync/sync-httpd2_post-backups-KEY-objects-UID.c b/src/sync/sync-httpd2_post-backups-KEY-objects-UID.c @@ -26,6 +26,7 @@ #include <taler/taler_mhd2_lib.h> #include <taler/taler_signatures.h> #include <sync/sync_signatures.h> +#include "sync-httpd2_payments.h" #include "sync-httpd2_post-backups-KEY-objects-UID.h" @@ -80,6 +81,17 @@ struct ObjectUploadContext * Signature from the request. */ struct SYNC_AccountSignatureP object_sig; + + /** + * Context for a merchant payment. + * + * The object store answers `402 Payment required' on a not-yet-paid + * account. Like block uploads, the response must carry the `Taler:' + * pay URI so the wallet can prepare the account payment -- the request + * is suspended while the payment order is created and resumed with the + * response (or, once the payment went through, to retry the store). + */ + struct BackupPaymentContext bpc; }; @@ -94,6 +106,7 @@ cleanup_object_upload_free (struct TM_HandlerContext *hc) struct ObjectUploadContext *ouc; ouc = (struct ObjectUploadContext *) hc; + SH_payment_cleanup (&ouc->bpc); GNUNET_free (ouc->data); GNUNET_free (ouc); } @@ -117,6 +130,19 @@ handle_object_upload (void *upload_cls, { struct ObjectUploadContext *ouc = upload_cls; + if (NULL != ouc->bpc.resp) + { + /* Resume after the payment order was created; answer with it. */ + return MHD_upload_action_from_response (request, + ouc->bpc.resp); + } + if (NULL != ouc->data) + { + /* Resume after the account was paid; body was already parsed and + verified, retry the store. */ + goto store_object; + } + if ( (0 == content_data_size) && (NULL == content_data) ) { @@ -191,6 +217,7 @@ handle_object_upload (void *upload_cls, NULL)); } +store_object: /* Store object */ { enum SYNC_DB_QueryStatus qs; @@ -218,11 +245,37 @@ handle_object_upload (void *upload_cls, case SYNC_DB_PAYMENT_REQUIRED: GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Object upload failed: payment required\n"); - return MHD_upload_action_from_response ( - request, - SYNC_MHD_MAKE_ERROR (MHD_HTTP_STATUS_PAYMENT_REQUIRED, - TALER_EC_SYNC_ACCOUNT_UNKNOWN, - NULL)); + { + struct MHD_StringNullable order_id; + bool suspend; + + if ( (MHD_YES != + MHD_request_get_value (ouc->bpc.request, + MHD_VK_URI_QUERY_PARAM, + "paying", + &order_id)) || + (NULL == order_id.cstr) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Payment required, starting payment process\n"); + SH_begin_payment (&ouc->bpc, + GNUNET_NO, + &suspend); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Payment required, awaiting completion of `%s'\n", + order_id.cstr); + SH_await_payment (&ouc->bpc, + order_id.cstr, + &suspend); + } + if (suspend) + return MHD_upload_action_suspend (request); + return MHD_upload_action_from_response (request, + ouc->bpc.resp); + } case SYNC_DB_HARD_ERROR: GNUNET_break (0); return MHD_upload_action_from_response ( @@ -270,6 +323,8 @@ SH_backup_object_post (struct MHD_Request *request, ouc = GNUNET_new (struct ObjectUploadContext); ouc->hc.cc = &cleanup_object_upload_free; ouc->account_pub = *account_pub; + ouc->bpc.request = request; + ouc->bpc.account_pub = *account_pub; *fi.v_app_context_ppvoid = ouc; /* Parse UID from URL */ @@ -289,6 +344,18 @@ SH_backup_object_post (struct MHD_Request *request, } } + if (NULL != ouc->bpc.resp) + { + /* Resume after the payment order was created; answer with it and + release the upload context. */ + struct MHD_Response *resp = ouc->bpc.resp; + + cleanup_object_upload_free (&ouc->hc); + *fi.v_app_context_ppvoid = NULL; + return MHD_action_from_response (request, + resp); + } + /* Same upload limit as for blocks */ if (SH_upload_too_large (upload_size, &ouc->buff_size))