From 7d81706ca0d905a2d7e8c7c18a6e2d48d0a67bae Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Wed, 7 Oct 2020 12:40:07 +0200 Subject: refuse refunds categorically if refund_delay was 0, instead of trying to give refunds anyway --- ...-merchant-httpd_private-post-orders-ID-refund.c | 96 ++++++++++++++++------ .../taler-merchant-httpd_private-post-orders.c | 46 ++++++----- 2 files changed, 97 insertions(+), 45 deletions(-) diff --git a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c index 859603bb..7af14873 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c +++ b/src/backend/taler-merchant-httpd_private-post-orders-ID-refund.c @@ -115,6 +115,70 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh, enum TALER_MERCHANTDB_RefundStatus rs; struct GNUNET_HashCode h_contract; + { + enum GNUNET_DB_QueryStatus qs; + json_t *contract_terms; + uint64_t order_serial; + struct GNUNET_TIME_Absolute refund_deadline; + struct GNUNET_TIME_Absolute timestamp; + + qs = TMH_db->lookup_contract_terms (TMH_db->cls, + hc->instance->settings.id, + hc->infix, + &contract_terms, + &order_serial); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) + { + struct GNUNET_JSON_Specification spec[] = { + TALER_JSON_spec_absolute_time ("refund_deadline", + &refund_deadline), + TALER_JSON_spec_absolute_time ("timestamp", + ×tamp), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_YES != + GNUNET_JSON_parse (contract_terms, + spec, + NULL, NULL)) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + json_decref (contract_terms); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_INTERNAL_LOGIC_ERROR, + "Failed to parse contract terms from DB"); + } + json_decref (contract_terms); + if (timestamp.abs_value_us == refund_deadline.abs_value_us) + { + /* refund was never allowed, so we should refuse hard */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_FORBIDDEN, +#ifndef TALER_EC_MERCHANT_REFUND_NOT_ALLOWED_BY_CONTRACT + 2609, /* remove post 0.8.0 release */ +#else + TALER_EC_MERCHANT_REFUND_NOT_ALLOWED_BY_CONTRACT, +#endif + NULL); + } + if (0 == GNUNET_TIME_absolute_get_remaining (refund_deadline).rel_value_us) + { + /* it is too late for refunds */ + /* NOTE: We MAY still be lucky that the exchange did not yet + wire the funds, so we will try to give the refund anyway */ + } + } + else + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_REFUND_ORDER_ID_UNKNOWN, + hc->infix); + } + } + { enum GNUNET_GenericReturnValue res; @@ -187,30 +251,14 @@ TMH_private_post_orders_ID_refund (const struct TMH_RequestHandler *rh, NULL); case TALER_MERCHANTDB_RS_NO_SUCH_ORDER: { - enum GNUNET_DB_QueryStatus qs; - json_t *contract_terms; - uint64_t order_serial; - - qs = TMH_db->lookup_contract_terms (TMH_db->cls, - hc->instance->settings.id, - hc->infix, - &contract_terms, - &order_serial); - if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) - { - json_decref (contract_terms); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_REFUND_ORDER_ID_UNPAID, - hc->infix); - } - else - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_REFUND_ORDER_ID_UNKNOWN, - hc->infix); - } + /* We know the order exists from the + "lookup_contract_terms" at the beginning; + so if we get 'no such order' here, it + must be read as "no PAID order" */ + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_REFUND_ORDER_ID_UNPAID, + hc->infix); } case TALER_MERCHANTDB_RS_SUCCESS: { diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c index 0b3bf500..7fc40324 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.c +++ b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -673,31 +673,35 @@ patch_order (struct MHD_Connection *connection, } } - /* Add timestamp if it doesn't exist */ - if (NULL == json_object_get (order, - "timestamp")) { struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - (void) GNUNET_TIME_round_abs (&now); - GNUNET_assert (0 == - json_object_set_new (order, - "timestamp", - GNUNET_JSON_from_time_abs (now))); - } - - /* If no refund_deadline given, set one based on refund_delay. */ - if (NULL == json_object_get (order, - "refund_deadline")) - { - struct GNUNET_TIME_Absolute rd = - GNUNET_TIME_relative_to_absolute (refund_delay); - (void) GNUNET_TIME_round_abs (&rd); - GNUNET_assert (0 == - json_object_set_new (order, - "refund_deadline", - GNUNET_JSON_from_time_abs (rd))); + /* Add timestamp if it doesn't exist */ + if (NULL == json_object_get (order, + "timestamp")) + { + GNUNET_assert (0 == + json_object_set_new (order, + "timestamp", + GNUNET_JSON_from_time_abs (now))); + } + + /* If no refund_deadline given, set one based on refund_delay. */ + if (NULL == json_object_get (order, + "refund_deadline")) + { + struct GNUNET_TIME_Absolute rd = + GNUNET_TIME_relative_to_absolute (refund_delay); + + (void) GNUNET_TIME_round_abs (&rd); + if (0 == refund_delay.rel_value_us) + rd = now; /* if delay was 0, ensure that refund_deadline == timestamp */ + GNUNET_assert (0 == + json_object_set_new (order, + "refund_deadline", + GNUNET_JSON_from_time_abs (rd))); + } } if (NULL == json_object_get (order, -- cgit v1.2.3