From 915480618b84f281aaa9bac3f711cf6e5fd555c1 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sun, 31 May 2020 20:34:39 +0200 Subject: implement GET /reserves/RPUB --- src/backend/Makefile.am | 2 + src/backend/taler-merchant-httpd.c | 8 + .../taler-merchant-httpd_private-get-reserves-ID.c | 305 +++++++++------------ .../taler-merchant-httpd_private-get-reserves-ID.h | 22 +- .../taler-merchant-httpd_private-get-tips-ID.c | 5 +- 5 files changed, 154 insertions(+), 188 deletions(-) (limited to 'src/backend') diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index 8960b15f..e70a1884 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -47,6 +47,8 @@ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd_private-get-orders.h \ taler-merchant-httpd_private-get-reserves.c \ taler-merchant-httpd_private-get-reserves.h \ + taler-merchant-httpd_private-get-reserves-ID.c \ + taler-merchant-httpd_private-get-reserves-ID.h \ taler-merchant-httpd_private-get-transfers.c \ taler-merchant-httpd_private-get-transfers.h \ taler-merchant-httpd_private-patch-instances-ID.c \ diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c index 3a43f8e4..9a71440a 100644 --- a/src/backend/taler-merchant-httpd.c +++ b/src/backend/taler-merchant-httpd.c @@ -41,6 +41,7 @@ #include "taler-merchant-httpd_private-get-orders.h" // #include "taler-merchant-httpd_private-get-orders-ID.h" #include "taler-merchant-httpd_private-get-reserves.h" +#include "taler-merchant-httpd_private-get-reserves-ID.h" #include "taler-merchant-httpd_private-get-tips-ID.h" #include "taler-merchant-httpd_private-get-transfers.h" #include "taler-merchant-httpd_private-patch-instances-ID.h" @@ -872,6 +873,13 @@ url_handler (void *cls, .method = MHD_HTTP_METHOD_GET, .handler = &TMH_private_get_reserves }, + /* GET /reserves: */ + { + .url_prefix = "/reserves", + .have_id_segment = true, + .method = MHD_HTTP_METHOD_GET, + .handler = &TMH_private_get_reserves_ID + }, /* POST /transfers: */ { .url_prefix = "/transfers", diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c index f7aa0ab0..d77a7bf9 100644 --- a/src/backend/taler-merchant-httpd_private-get-reserves-ID.c +++ b/src/backend/taler-merchant-httpd_private-get-reserves-ID.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2018 Taler Systems SA + (C) 2018, 2020 Taler Systems SA TALER 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 @@ -14,10 +14,9 @@ TALER; see the file COPYING. If not, see */ /** - * @file backend/taler-merchant-httpd_tip-query.c - * @brief implement API for authorizing tips to be paid to visitors + * @file backend/taler-merchant-httpd_private-get-reserves-ID.c + * @brief implement GET /reserves/$RESERVE_PUB endpoint * @author Christian Grothoff - * @author Florian Dold */ #include "platform.h" #include @@ -26,223 +25,185 @@ #include "taler-merchant-httpd.h" #include "taler-merchant-httpd_mhd.h" #include "taler-merchant-httpd_exchanges.h" -#include "taler-merchant-httpd_tip-query.h" -#include "taler-merchant-httpd_tip-reserve-helper.h" +#include "taler-merchant-httpd_private-get-reserves-ID.h" /** - * Maximum number of retries for database operations. + * Closure for handle_reserve_details(). */ -#define MAX_RETRIES 5 - - -/** - * Internal per-request state for processing tip queries. - */ -struct TipQueryContext +struct GetReserveContext { /** - * This field MUST be first for handle_mhd_completion_callback() to work - * when it treats this struct as a `struct TM_HandlerContext`. - */ - struct TM_HandlerContext hc; - - /** - * Merchant instance to use. + * Connection we are handling. */ - const char *instance; + struct MHD_Connection *connection; /** - * Context for checking the tipping reserve's status. + * Value to return from the callback. */ - struct TMH_CheckTipReserve ctr; + MHD_RESULT res; /** - * #GNUNET_YES if the tip query has already been processed - * and we can queue the response. + * Should we return details about tips? */ - int processed; - + bool tips; }; /** - * Custom cleanup routine for a `struct TipQueryContext`. + * Callback with reserve details. * - * @param hc the `struct TMH_JsonParseContext` to clean up. + * @param cls closure with a `struct GetReserveContext` + * @param creation_time time when the reserve was setup + * @param expiration_time time when the reserve will be closed by the exchange + * @param merchant_initial_amount initial amount that the merchant claims to have filled the + * reserve with + * @param exchange_initial_amount initial amount that the exchange claims to have received + * @param picked_up_amount total of tips that were picked up from this reserve + * @param committed_amount total of tips that the merchant committed to, but that were not + * picked up yet + * @param tips_length length of the @a tips array + * @param tips information about the tips created by this reserve */ static void -cleanup_tqc (struct TM_HandlerContext *hc) +handle_reserve_details (void *cls, + struct GNUNET_TIME_Absolute creation_time, + struct GNUNET_TIME_Absolute expiration_time, + const struct TALER_Amount *merchant_initial_amount, + const struct TALER_Amount *exchange_initial_amount, + const struct TALER_Amount *picked_up_amount, + const struct TALER_Amount *committed_amount, + unsigned int tips_length, + const struct TALER_MERCHANTDB_TipDetails *tips) { - struct TipQueryContext *tqc = (struct TipQueryContext *) hc; - - TMH_check_tip_reserve_cleanup (&tqc->ctr); - GNUNET_free (tqc); -} - + struct GetReserveContext *ctx = cls; + json_t *tips_json; -/** - * We've been resumed after processing the reserve data from the - * exchange without error. Generate the final response. - * - * @param tqc context for which to generate the response. - */ -static int -generate_final_response (struct TipQueryContext *tqc) -{ - struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub; - struct TALER_Amount amount_available; - - GNUNET_CRYPTO_eddsa_key_get_public (&tqc->ctr.reserve_priv.eddsa_priv, - &reserve_pub); - if (0 > - TALER_amount_subtract (&amount_available, - &tqc->ctr.amount_deposited, - &tqc->ctr.amount_withdrawn)) + if (tips) { - char *a1; - char *a2; + tips_json = json_array (); + GNUNET_assert (NULL != tips_json); - GNUNET_break_op (0); - a1 = TALER_amount_to_string (&tqc->ctr.amount_deposited); - a2 = TALER_amount_to_string (&tqc->ctr.amount_withdrawn); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "amount overflow, deposited %s but withdrawn %s\n", - a1, - a2); - GNUNET_free (a2); - GNUNET_free (a1); - return TALER_MHD_reply_with_error ( - tqc->ctr.connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_TIP_QUERY_RESERVE_HISTORY_ARITHMETIC_ISSUE_INCONSISTENT, - "Exchange returned invalid reserve history (amount overflow)"); + for (unsigned int i = 0; ictr.connection, + else + { + tips_json = NULL; + } + ctx->res = TALER_MHD_reply_json_pack ( + ctx->connection, MHD_HTTP_OK, - "{s:o, s:o, s:o, s:o, s:o}", - "reserve_pub", - GNUNET_JSON_from_data_auto (&reserve_pub), - "reserve_expiration", - GNUNET_JSON_from_time_abs (tqc->ctr.reserve_expiration), - "amount_authorized", - TALER_JSON_from_amount (&tqc->ctr.amount_authorized), - "amount_picked_up", - TALER_JSON_from_amount (&tqc->ctr.amount_withdrawn), - "amount_available", - TALER_JSON_from_amount (&amount_available)); + "{s:o, s:o, s:o, s:o, s:o, s:o, s:o?}", + "creation_time", GNUNET_JSON_from_time_abs (creation_time), + "expiration_time", GNUNET_JSON_from_time_abs (expiration_time), + "merchant_initial_amount", TALER_JSON_from_amount (merchant_initial_amount), + "exchange_initial_amount", TALER_JSON_from_amount (exchange_initial_amount), + "pickup_amount", TALER_JSON_from_amount (picked_up_amount), + "committed_amount", TALER_JSON_from_amount (committed_amount), + "tips", tips_json); } /** - * Handle a "/tip-query" request. + * Manages a GET /reserves/$RESERVE_PUB call. * * @param rh context of the handler * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @param mi merchant backend instance, never NULL + * @param[in,out] hc context with further information about the request * @return MHD result code */ MHD_RESULT -MH_handler_tip_query (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size, - struct MerchantInstance *mi) +TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) { - struct TipQueryContext *tqc; - - if (NULL == *connection_cls) + struct TALER_ReservePublicKeyP reserve_pub; + bool tips; + + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (hc->infix, + strlen (hc->infix), + &reserve_pub, + sizeof (reserve_pub))) { - tqc = GNUNET_new (struct TipQueryContext); - tqc->hc.cc = &cleanup_tqc; - tqc->ctr.connection = connection; - *connection_cls = tqc; - } - else - { - tqc = *connection_cls; - } - - if (0 != tqc->ctr.response_code) - { - MHD_RESULT res; - - /* We are *done* processing the request, just queue the response (!) */ - if (UINT_MAX == tqc->ctr.response_code) - { - GNUNET_break (0); - return MHD_NO; /* hard error */ - } - res = MHD_queue_response (connection, - tqc->ctr.response_code, - tqc->ctr.response); - MHD_destroy_response (tqc->ctr.response); - tqc->ctr.response = NULL; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Queueing response (%u) for /tip-query (%s).\n", - (unsigned int) tqc->ctr.response_code, - res ? "OK" : "FAILED"); - return res; - } - - if (GNUNET_YES == tqc->processed) - { - /* We've been here before, so TMH_check_tip_reserve() must have - finished and left the result for us. Finish processing. */ - return generate_final_response (tqc); + /* tip_id has wrong encoding */ + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_PARAMETER_MALFORMED, + "reserve_pub malformed"); } - - if (NULL == mi->tip_exchange) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Instance `%s' not configured for tipping\n", - mi->id); - return TALER_MHD_reply_with_error ( - connection, - MHD_HTTP_PRECONDITION_FAILED, - TALER_EC_TIP_QUERY_INSTANCE_DOES_NOT_TIP, - "exchange for tipping not configured for the instance"); + const char *tstr; + + tstr = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + "tips"); + tips = (NULL != tstr) + ? 0 == strcasecmp (tstr, "yes") + : false; } - tqc->ctr.reserve_priv = mi->tip_reserve; - { + struct GetReserveContext ctx = { + .connection = connection, + .tips = tips + }; enum GNUNET_DB_QueryStatus qs; - for (unsigned int i = 0; ipreflight (TMH_db->cls); + qs = TMH_db->lookup_reserve (TMH_db->cls, + hc->instance->settings.id, + &reserve_pub, + tips, + &handle_reserve_details, + &ctx); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) { - db->preflight (db->cls); - qs = db->get_authorized_tip_amount (db->cls, - &tqc->ctr.reserve_priv, - &tqc->ctr.amount_authorized); - if (GNUNET_DB_STATUS_SOFT_ERROR != qs) + unsigned int response_code; + enum TALER_ErrorCode ec; + + switch (qs) + { + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + ec = TALER_EC_TIP_PICKUP_TIP_ID_UNKNOWN; + response_code = MHD_HTTP_NOT_FOUND; break; - } - if (0 > qs) - { - GNUNET_break (0); + case GNUNET_DB_STATUS_SOFT_ERROR: + ec = TALER_EC_TIP_PICKUP_DB_ERROR_SOFT; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + case GNUNET_DB_STATUS_HARD_ERROR: + ec = TALER_EC_TIP_PICKUP_DB_ERROR_HARD; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + default: + GNUNET_break (0); + ec = TALER_EC_INTERNAL_LOGIC_ERROR; + response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; + break; + } return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_TIP_QUERY_DB_ERROR, - "Merchant database error"); - } - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - /* we'll set amount_authorized to zero later once - we know the currency */ - tqc->ctr.none_authorized = GNUNET_YES; + response_code, + ec, + "Could not determine exchange URL for the given tip id"); } + return ctx.res; } - - tqc->processed = GNUNET_YES; - TMH_check_tip_reserve (&tqc->ctr, - mi->tip_exchange); - return MHD_YES; } -/* end of taler-merchant-httpd_tip-query.c */ +/* end of taler-merchant-httpd_private-get-reserves-ID.c */ diff --git a/src/backend/taler-merchant-httpd_private-get-reserves-ID.h b/src/backend/taler-merchant-httpd_private-get-reserves-ID.h index 3123486c..4b9fa067 100644 --- a/src/backend/taler-merchant-httpd_private-get-reserves-ID.h +++ b/src/backend/taler-merchant-httpd_private-get-reserves-ID.h @@ -14,32 +14,26 @@ TALER; see the file COPYING. If not, see */ /** - * @file backend/taler-merchant-httpd_tip-query.h + * @file backend/taler-merchant-httpd_private-get-reserves-ID.h * @brief headers for /tip-query handler * @author Florian Dold */ -#ifndef TALER_MERCHANT_HTTPD_TIP_QUERY_H -#define TALER_MERCHANT_HTTPD_TIP_QUERY_H +#ifndef TALER_MERCHANT_HTTPD_GET_RESERVES_ID_H +#define TALER_MERCHANT_HTTPD_GET_RESERVES_ID_H #include #include "taler-merchant-httpd.h" /** - * Manages a /tip-query call. + * Manages a GET /reserves/$RESERVE_PUB call. * * @param rh context of the handler * @param connection the MHD connection to handle - * @param[in,out] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[in,out] upload_data_size number of bytes (left) in @a upload_data - * @param mi merchant backend instance, never NULL + * @param[in,out] hc context with further information about the request * @return MHD result code */ MHD_RESULT -MH_handler_tip_query (struct TMH_RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size, - struct MerchantInstance *mi); +TMH_private_get_reserves_ID (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc); #endif diff --git a/src/backend/taler-merchant-httpd_private-get-tips-ID.c b/src/backend/taler-merchant-httpd_private-get-tips-ID.c index fc9ef060..59de1b68 100644 --- a/src/backend/taler-merchant-httpd_private-get-tips-ID.c +++ b/src/backend/taler-merchant-httpd_private-get-tips-ID.c @@ -72,8 +72,9 @@ TMH_private_get_tips_ID (const struct TMH_RequestHandler *rh, pstr = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, "pickups"); - fpu = (NULL != pstr) ? 0 == strcasecmp (pstr, "yes") : - false; + fpu = (NULL != pstr) + ? 0 == strcasecmp (pstr, "yes") + : false; } db->preflight (db->cls); qs = db->lookup_tip_details (db->cls, -- cgit v1.2.3