diff options
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-reserves.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-reserves.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-reserves.c b/src/backend/taler-merchant-httpd_private-post-reserves.c new file mode 100644 index 00000000..abb6d0b5 --- /dev/null +++ b/src/backend/taler-merchant-httpd_private-post-reserves.c @@ -0,0 +1,288 @@ +/* + This file is part of TALER + (C) 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 Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ + +/** + * @file backend/taler-merchant-httpd_private-post-reserves.c + * @brief implementing POST /reserves request handling + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler-merchant-httpd_exchanges.h" +#include "taler-merchant-httpd_private-post-reserves.h" +#include <taler/taler_json_lib.h> + + +/** + * Information we keep for an individual call to the POST /reserves handler. + */ +struct PostReserveContext +{ + + /** + * Stored in a DLL. + */ + struct PostReserveContext *next; + + /** + * Stored in a DLL. + */ + struct PostReserveContext *prev; + + /** + * Array with @e coins_cnt coins we are despositing. + */ + struct DepositConfirmation *dc; + + /** + * MHD connection to return to + */ + struct MHD_Connection *connection; + + /** + * Details about the client's request. + */ + struct TMH_HandlerContext *hc; + + /** + * URL of the exchange. + */ + const char *exchange_url; + + /** + * URI of the exchange where the payment needs to be made to. + */ + char *payto_uri; + + /** + * Handle for contacting the exchange. + */ + struct TMH_EXCHANGES_FindOperation *fo; + + /** + * Initial balance of the reserve. + */ + struct TALER_Amount initial_balance; + + /** + * When will the reserve expire. + */ + struct GNUNET_TIME_Absolute reserve_expiration; + + /** + * Are we suspended? + */ + bool suspended; +}; + + +/** + * Stored in a DLL. + */ +static struct PostReserveContext *rc_head; + +/** + * Stored in a DLL. + */ +static struct PostReserveContext *rc_tail; + + +/** + * Force all post reserve contexts to be resumed as we are about + * to shut down MHD. + */ +void +TMH_force_rc_resume () +{ + for (struct PostReserveContext *rc = rc_head; + NULL != rc; + rc = rc->next) + { + if (rc->suspended) + { + rc->suspended = false; + MHD_resume_connection (rc->connection); + GNUNET_CONTAINER_DLL_remove (rc_head, + rc_tail, + rc); + } + if (NULL != rc->fo) + { + TMH_EXCHANGES_find_exchange_cancel (rc->fo); + rc->fo = NULL; + } + } +} + + +/** + * Custom cleanup routine for a `struct PostReserveContext`. + * + * @param cls the `struct PostReserveContext` to clean up. + */ +static void +reserve_context_cleanup (void *cls) +{ + struct PostReserveContext *rc = cls; + + if (NULL != rc->fo) + { + TMH_EXCHANGES_find_exchange_cancel (rc->fo); + rc->fo = NULL; + } + GNUNET_assert (! rc->suspended); + GNUNET_free_non_null (rc->payto_uri); + GNUNET_free (rc); +} + + +/** + * Function called with the result of a #TMH_EXCHANGES_find_exchange() + * operation. + * + * @param cls closure with our `struct PostReserveContext *` + * @param hr HTTP response details + * @param payto_uri URI of the exchange for the wire transfer, NULL on errors + * @param eh handle to the exchange context + * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available + * @param exchange_trusted true if this exchange is trusted by config + */ +static void +handle_exchange (void *cls, + const struct TALER_EXCHANGE_HttpResponse *hr, + struct TALER_EXCHANGE_Handle *eh, + const char *payto_uri, + const struct TALER_Amount *wire_fee, + bool exchange_trusted) +{ + struct PostReserveContext *rc = cls; + const struct TALER_EXCHANGE_Keys *keys; + + rc->suspended = false; + MHD_resume_connection (rc->connection); + keys = TALER_EXCHANGE_get_keys (eh); + if ( (NULL != keys) && + (NULL != payto_uri) ) + { + rc->reserve_expiration + = GNUNET_TIME_relative_to_absolute (keys->reserve_closing_delay); + rc->payto_uri = GNUNET_strdup (payto_uri); + } +} + + +/** + * Generate a reserve, given its keys and balance. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[in,out] hc context with further information about the request + * @return MHD result code + */ +MHD_RESULT +TMH_private_post_reserves (const struct TMH_RequestHandler *rh, + struct MHD_Connection *connection, + struct TMH_HandlerContext *hc) +{ + struct PostReserveContext *rc = hc->ctx; + struct TMH_MerchantInstance *mi = hc->instance; + + GNUNET_assert (NULL != mi); + if (NULL == rc) + { + const char *wire_method; + + rc = GNUNET_new (struct PostReserveContext); + rc->connection = connection; + rc->hc = hc; + hc->ctx = rc; + hc->cc = &reserve_context_cleanup; + + { + enum GNUNET_GenericReturnValue res; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_string ("exchange_url", + &rc->exchange_url), + GNUNET_JSON_spec_string ("wire_method", + &wire_method), + TALER_JSON_spec_amount ("initial_balance", + &rc->initial_balance), + GNUNET_JSON_spec_end () + }; + res = TALER_MHD_parse_json_data (connection, + hc->request_body, + spec); + if (GNUNET_OK != res) + return (GNUNET_NO == res) + ? MHD_YES + : MHD_NO; + } + rc->fo = TMH_EXCHANGES_find_exchange (rc->exchange_url, + wire_method, + GNUNET_NO, + &handle_exchange, + rc); + rc->suspended = true; + GNUNET_CONTAINER_DLL_insert (rc_head, + rc_tail, + rc); + MHD_suspend_connection (connection); + return MHD_YES; + } + + GNUNET_assert (! rc->suspended); + if (NULL == rc->payto_uri) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_RESERVES_POST_UNSUPPORTED_WIRE_METHOD, + "Exchange does not support wire method"); + } + { + struct TALER_ReservePublicKeyP reserve_pub; + struct TALER_ReservePrivateKeyP reserve_priv; + enum GNUNET_DB_QueryStatus qs; + + GNUNET_CRYPTO_eddsa_key_create (&reserve_priv.eddsa_priv); + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv.eddsa_priv, + &reserve_pub.eddsa_pub); + qs = TMH_db->insert_reserve (TMH_db->cls, + mi->settings.id, + &reserve_priv, + &reserve_pub, + rc->exchange_url, + &rc->initial_balance, + rc->reserve_expiration); + GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); + if (qs < 0) + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_RESERVES_POST_DB_COMMIT_HARD_ERROR, + "Failed to commit transaction"); + return TALER_MHD_reply_json_pack (connection, + MHD_HTTP_OK, + "{s:o,s:s}", + "reserve_pub", + GNUNET_JSON_from_data_auto (&reserve_pub), + "payto_uri", + rc->payto_uri); + } +} + + +/* end of taler-merchant-httpd_private-post-reserves.c */ |