From 974b2b2c3077c929850c1598af1e1e124f530a7f Mon Sep 17 00:00:00 2001 From: Jonathan Buchanan Date: Fri, 24 Jul 2020 03:15:16 -0400 Subject: implement & test POST /paid --- .../taler-merchant-httpd_post-orders-ID-paid.c | 112 +++++++++++++++++---- 1 file changed, 94 insertions(+), 18 deletions(-) (limited to 'src/backend/taler-merchant-httpd_post-orders-ID-paid.c') diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-paid.c b/src/backend/taler-merchant-httpd_post-orders-ID-paid.c index 6e6f64aa..623b2760 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-paid.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-paid.c @@ -46,15 +46,18 @@ TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh, .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK), .purpose.size = htonl (sizeof (pr)) }; + const char *order_id = hc->infix; struct TALER_MerchantSignatureP merchant_sig; const char *session_id; + json_t *contract_terms; + enum GNUNET_DB_QueryStatus qs; { struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &pr.h_contract_terms), - GNUNET_JSON_spec_fixed_auto ("merchant_sig", + GNUNET_JSON_spec_fixed_auto ("sig", &merchant_sig), + GNUNET_JSON_spec_fixed_auto ("h_contract", + &pr.h_contract_terms), GNUNET_JSON_spec_string ("session_id", &session_id), GNUNET_JSON_spec_end () @@ -73,7 +76,7 @@ TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh, } } -#if FIXME + if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK, &pr, @@ -86,31 +89,104 @@ TMH_post_orders_ID_paid (const struct TMH_RequestHandler *rh, MHD_HTTP_FORBIDDEN, "{s:s, s:I}", "hint", "deposit signature invalid", - "code", (json_int_t) TALER_EC_PAID_SIGNATURE_INVALID); + "code", (json_int_t) TALER_EC_PAID_COIN_SIGNATURE_INVALID); } - // FIXME: check that h_contract_terms matches - // this order-id (and that the order is known), - // and if it does, update 'session_id' (if non-NULL) - if (0) + TMH_db->preflight (TMH_db->cls); + { + uint64_t order_serial; + qs = TMH_db->lookup_contract_terms (TMH_db->cls, + hc->instance->settings.id, + order_id, + &contract_terms, + &order_serial); + } + if (0 > qs) + { + /* single, read-only SQL statements should never cause + serialization problems */ + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + /* Always report on hard error as well to enable diagnostics */ + GNUNET_break (GNUNET_DB_STATUS_HARD_ERROR == qs); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAID_DB_ERROR, + "database error looking up contract"); + } + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Unknown order id given: `%s'\n", + order_id); return TALER_MHD_reply_json_pack ( connection, MHD_HTTP_NOT_FOUND, "{s:s, s:I}", - "hint", "order unknwown", + "hint", "order unknown", "code", (json_int_t) TALER_EC_PAID_ORDER_UNKNOWN); } - if (0) + { - return TALER_MHD_reply_json_pack ( - connection, - MHD_HTTP_CONFLICT, - "{s:s, s:I}", - "hint", "contract hash does not match this order", - "code", (json_int_t) TALER_EC_PAID_CONTRACT_HASH_MISMATCH); + struct GNUNET_HashCode h_contract_terms; + + if (GNUNET_OK != + TALER_JSON_contract_hash (contract_terms, + &h_contract_terms)) + { + GNUNET_break (0); + json_decref (contract_terms); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_INTERNAL_LOGIC_ERROR, + "Could not hash contract terms"); + } + if (0 != GNUNET_memcmp (&pr.h_contract_terms, + &h_contract_terms)) + { + json_decref (contract_terms); + return TALER_MHD_reply_json_pack ( + connection, + MHD_HTTP_CONFLICT, + "{s:s, s:I}", + "hint", "contract hash does not match this order", + "code", (json_int_t) TALER_EC_PAID_CONTRACT_HASH_MISMATCH); + } + } + if (NULL != session_id) + { + if (GNUNET_OK != + TMH_db->start (TMH_db->cls, + "post /paid")) + { + json_decref (contract_terms); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAID_DB_ERROR, + "failed to start database transaction"); + } + qs = TMH_db->mark_contract_paid (TMH_db->cls, + hc->instance->settings.id, + &pr.h_contract_terms, + session_id); + /* Since the order was paid already, we get qs == 0. */ + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + qs = TMH_db->commit (TMH_db->cls); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; + } + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) + { + TMH_db->rollback (TMH_db->cls); + json_decref (contract_terms); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_PAID_DB_ERROR, + "failed to update contract's session id"); + } } -#endif + json_decref (contract_terms); + return TALER_MHD_reply_static (connection, MHD_HTTP_NO_CONTENT, NULL, -- cgit v1.2.3