/* This file is part of TALER Copyright (C) 2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1, 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with TALER; see the file COPYING.LGPL. If not, see */ /** * @file lib/merchant_api_delete_reserve.c * @brief Implementation of the DELETE /reserves/$RESERVE_PUB request of the merchant's HTTP API * @author Jonathan Buchanan */ #include "platform.h" #include #include #include /* just for HTTP status codes */ #include #include #include "taler_merchant_service.h" #include #include /** * Handle for a DELETE /reserves/$RESERVE_PUB operation. */ struct TALER_MERCHANT_ReserveDeleteHandle { /** * The url for this request. */ char *url; /** * Handle for the request. */ struct GNUNET_CURL_Job *job; /** * Function to call with the result. */ TALER_MERCHANT_ReserveDeleteCallback cb; /** * Closure for @a cb. */ void *cb_cls; /** * Reference to the execution context. */ struct GNUNET_CURL_Context *ctx; }; /** * Function called when we're done processing the * HTTP DELETE /reserves/$RESERVE_PUB request. * * @param cls the `struct TALER_MERCHANT_InstanceDeleteHandle` * @param response_code HTTP response code, 0 on error * @param json response body, NULL if not in JSON */ static void handle_delete_reserve_finished (void *cls, long response_code, const void *response) { struct TALER_MERCHANT_ReserveDeleteHandle *rdh = cls; const json_t *json = response; struct TALER_MERCHANT_HttpResponse hr = { .http_status = (unsigned int) response_code, .reply = json }; rdh->job = NULL; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got /reserves/$ID response with status code %u\n", (unsigned int) response_code); switch (response_code) { case MHD_HTTP_NO_CONTENT: break; default: /* unexpected response code */ hr.ec = TALER_JSON_get_error_code (json); hr.hint = TALER_JSON_get_error_hint (json); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Unexpected response code %u/%d\n", (unsigned int) response_code, (int) hr.ec); break; } rdh->cb (rdh->cb_cls, &hr); TALER_MERCHANT_reserve_delete_cancel (rdh); } /** * Delete the private key of a reserve. * * @param ctx the context * @param backend_url HTTP base URL for the backend * @param instance_id which instance should be deleted * @param purge purge instead of just deleting * @param instances_cb function to call with the * backend's return * @param instances_cb_cls closure for @a config_cb * @return the instances handle; NULL upon error */ static struct TALER_MERCHANT_ReserveDeleteHandle * reserve_delete (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, bool purge, TALER_MERCHANT_ReserveDeleteCallback cb, void *cb_cls) { struct TALER_MERCHANT_ReserveDeleteHandle *rdh; rdh = GNUNET_new (struct TALER_MERCHANT_ReserveDeleteHandle); rdh->ctx = ctx; rdh->cb = cb; rdh->cb_cls = cb_cls; { char res_str[sizeof (*reserve_pub) * 2]; char arg_str[sizeof (res_str) + 32]; char *end; end = GNUNET_STRINGS_data_to_string (reserve_pub, sizeof (*reserve_pub), res_str, sizeof (res_str)); *end = '\0'; GNUNET_snprintf (arg_str, sizeof (arg_str), "private/reserves/%s", res_str); if (purge) rdh->url = TALER_url_join (backend_url, arg_str, "purge", "yes", NULL); else rdh->url = TALER_url_join (backend_url, arg_str, NULL); } if (NULL == rdh->url) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not construct request URL.\n"); GNUNET_free (rdh); return NULL; } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Requesting URL '%s'\n", rdh->url); { CURL *eh; eh = curl_easy_init (); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_URL, rdh->url)); GNUNET_assert (CURLE_OK == curl_easy_setopt (eh, CURLOPT_CUSTOMREQUEST, MHD_HTTP_METHOD_DELETE)); rdh->job = GNUNET_CURL_job_add (ctx, eh, &handle_delete_reserve_finished, rdh); } return rdh; } /** * Issue a DELETE /reserve/$RESERVE_ID request to the backend. Only * deletes the private key of the reserve, preserves tipping data. * * @param ctx execution context * @param backend_url base URL of the merchant backend * @param reserve_pub which reserve should be queried * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ struct TALER_MERCHANT_ReserveDeleteHandle * TALER_MERCHANT_reserve_delete ( struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, TALER_MERCHANT_ReserveDeleteCallback cb, void *cb_cls) { return reserve_delete (ctx, backend_url, reserve_pub, false, cb, cb_cls); } /** * Issue a DELETE /reserve/$RESERVE_ID request to the backend. * Purges the reserve, deleting all associated data. DANGEROUS. * * @param ctx execution context * @param backend_url base URL of the merchant backend * @param reserve_pub which reserve should be queried * @param cb function to call with the result * @param cb_cls closure for @a cb * @return handle for this operation, NULL upon errors */ struct TALER_MERCHANT_ReserveDeleteHandle * TALER_MERCHANT_reserve_purge (struct GNUNET_CURL_Context *ctx, const char *backend_url, const struct TALER_ReservePublicKeyP *reserve_pub, TALER_MERCHANT_ReserveDeleteCallback cb, void *cb_cls) { return reserve_delete (ctx, backend_url, reserve_pub, true, cb, cb_cls); } /** * Cancel a DELETE (or purge) /reserve/$RESERVE_ID request. * * @param rdh handle to the request to be canceled */ void TALER_MERCHANT_reserve_delete_cancel ( struct TALER_MERCHANT_ReserveDeleteHandle *rdh) { if (NULL != rdh->job) GNUNET_CURL_job_cancel (rdh->job); GNUNET_free (rdh->url); GNUNET_free (rdh); }