exchange_api_delete-purses-PURSE_PUB.c (7867B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022-2026 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 TALER; see the file COPYING. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file lib/exchange_api_delete-purses-PURSE_PUB.c 19 * @brief Implementation of the client to delete a purse 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <jansson.h> 24 #include <microhttpd.h> /* just for HTTP status codes */ 25 #include <gnunet/gnunet_util_lib.h> 26 #include <gnunet/gnunet_json_lib.h> 27 #include <gnunet/gnunet_curl_lib.h> 28 #include "taler/taler_json_lib.h" 29 #include "taler/taler_exchange_service.h" 30 #include "exchange_api_handle.h" 31 #include "exchange_api_common.h" 32 #include "taler/taler_signatures.h" 33 #include "exchange_api_curl_defaults.h" 34 35 36 /** 37 * @brief A purse delete handle 38 */ 39 struct TALER_EXCHANGE_DeletePursesHandle 40 { 41 42 /** 43 * The base url for this request. 44 */ 45 char *base_url; 46 47 /** 48 * The full url for this request, set during _start. 49 */ 50 char *url; 51 52 /** 53 * Handle for the request. 54 */ 55 struct GNUNET_CURL_Job *job; 56 57 /** 58 * Function to call with the result. 59 */ 60 TALER_EXCHANGE_DeletePursesCallback cb; 61 62 /** 63 * Closure for @a cb. 64 */ 65 TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls; 66 67 /** 68 * Reference to the execution context. 69 */ 70 struct GNUNET_CURL_Context *ctx; 71 72 /** 73 * Header with the purse_sig. 74 */ 75 struct curl_slist *xhdr; 76 77 /** 78 * Public key of the purse (derived from private key in _create). 79 */ 80 struct TALER_PurseContractPublicKeyP purse_pub; 81 }; 82 83 84 /** 85 * Function called when we're done processing the 86 * HTTP DELETE /purse/$PID request. 87 * 88 * @param cls the `struct TALER_EXCHANGE_DeletePursesHandle` 89 * @param response_code HTTP response code, 0 on error 90 * @param response parsed JSON result, NULL on error 91 */ 92 static void 93 handle_purse_delete_finished (void *cls, 94 long response_code, 95 const void *response) 96 { 97 struct TALER_EXCHANGE_DeletePursesHandle *dph = cls; 98 const json_t *j = response; 99 struct TALER_EXCHANGE_DeletePursesResponse dr = { 100 .hr.reply = j, 101 .hr.http_status = (unsigned int) response_code 102 }; 103 104 dph->job = NULL; 105 switch (response_code) 106 { 107 case 0: 108 dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 109 break; 110 case MHD_HTTP_NO_CONTENT: 111 break; 112 case MHD_HTTP_BAD_REQUEST: 113 /* This should never happen, either us or the exchange is buggy 114 (or API version conflict); just pass JSON reply to the application */ 115 dr.hr.ec = TALER_JSON_get_error_code (j); 116 dr.hr.hint = TALER_JSON_get_error_hint (j); 117 break; 118 case MHD_HTTP_FORBIDDEN: 119 dr.hr.ec = TALER_JSON_get_error_code (j); 120 dr.hr.hint = TALER_JSON_get_error_hint (j); 121 /* Nothing really to verify, exchange says one of the signatures is 122 invalid; as we checked them, this should never happen, we 123 should pass the JSON reply to the application */ 124 break; 125 case MHD_HTTP_NOT_FOUND: 126 dr.hr.ec = TALER_JSON_get_error_code (j); 127 dr.hr.hint = TALER_JSON_get_error_hint (j); 128 /* Nothing really to verify, this should never 129 happen, we should pass the JSON reply to the application */ 130 break; 131 case MHD_HTTP_CONFLICT: 132 dr.hr.ec = TALER_JSON_get_error_code (j); 133 dr.hr.hint = TALER_JSON_get_error_hint (j); 134 break; 135 case MHD_HTTP_INTERNAL_SERVER_ERROR: 136 dr.hr.ec = TALER_JSON_get_error_code (j); 137 dr.hr.hint = TALER_JSON_get_error_hint (j); 138 /* Server had an internal issue; we should retry, but this API 139 leaves this to the application */ 140 break; 141 default: 142 /* unexpected response code */ 143 dr.hr.ec = TALER_JSON_get_error_code (j); 144 dr.hr.hint = TALER_JSON_get_error_hint (j); 145 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 146 "Unexpected response code %u/%d for exchange purse delete\n", 147 (unsigned int) response_code, 148 dr.hr.ec); 149 GNUNET_break_op (0); 150 break; 151 } 152 dph->cb (dph->cb_cls, 153 &dr); 154 TALER_EXCHANGE_delete_purses_cancel (dph); 155 } 156 157 158 struct TALER_EXCHANGE_DeletePursesHandle * 159 TALER_EXCHANGE_delete_purses_create ( 160 struct GNUNET_CURL_Context *ctx, 161 const char *url, 162 const struct TALER_PurseContractPrivateKeyP *purse_priv) 163 { 164 struct TALER_EXCHANGE_DeletePursesHandle *dph; 165 struct TALER_PurseContractSignatureP purse_sig; 166 167 dph = GNUNET_new (struct TALER_EXCHANGE_DeletePursesHandle); 168 dph->ctx = ctx; 169 dph->base_url = GNUNET_strdup (url); 170 GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, 171 &dph->purse_pub.eddsa_pub); 172 TALER_wallet_purse_delete_sign (purse_priv, 173 &purse_sig); 174 { 175 char *delete_str; 176 char *xhdr; 177 178 delete_str = 179 GNUNET_STRINGS_data_to_string_alloc (&purse_sig, 180 sizeof (purse_sig)); 181 GNUNET_asprintf (&xhdr, 182 "Taler-Purse-Signature: %s", 183 delete_str); 184 GNUNET_free (delete_str); 185 dph->xhdr = curl_slist_append (NULL, 186 xhdr); 187 GNUNET_free (xhdr); 188 } 189 return dph; 190 } 191 192 193 enum TALER_ErrorCode 194 TALER_EXCHANGE_delete_purses_start ( 195 struct TALER_EXCHANGE_DeletePursesHandle *dph, 196 TALER_EXCHANGE_DeletePursesCallback cb, 197 TALER_EXCHANGE_DELETE_PURSES_RESULT_CLOSURE *cb_cls) 198 { 199 CURL *eh; 200 char arg_str[sizeof (dph->purse_pub) * 2 + 32]; 201 202 dph->cb = cb; 203 dph->cb_cls = cb_cls; 204 { 205 char pub_str[sizeof (dph->purse_pub) * 2]; 206 char *end; 207 208 end = GNUNET_STRINGS_data_to_string (&dph->purse_pub, 209 sizeof (dph->purse_pub), 210 pub_str, 211 sizeof (pub_str)); 212 *end = '\0'; 213 GNUNET_snprintf (arg_str, 214 sizeof (arg_str), 215 "purses/%s", 216 pub_str); 217 } 218 dph->url = TALER_url_join (dph->base_url, 219 arg_str, 220 NULL); 221 if (NULL == dph->url) 222 { 223 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 224 "Could not construct request URL.\n"); 225 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 226 } 227 eh = TALER_EXCHANGE_curl_easy_get_ (dph->url); 228 if (NULL == eh) 229 { 230 GNUNET_break (0); 231 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 232 } 233 GNUNET_assert (CURLE_OK == 234 curl_easy_setopt (eh, 235 CURLOPT_CUSTOMREQUEST, 236 MHD_HTTP_METHOD_DELETE)); 237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 238 "URL for purse delete: `%s'\n", 239 dph->url); 240 dph->job = GNUNET_CURL_job_add2 (dph->ctx, 241 eh, 242 dph->xhdr, 243 &handle_purse_delete_finished, 244 dph); 245 if (NULL == dph->job) 246 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 247 return TALER_EC_NONE; 248 } 249 250 251 void 252 TALER_EXCHANGE_delete_purses_cancel ( 253 struct TALER_EXCHANGE_DeletePursesHandle *dph) 254 { 255 if (NULL != dph->job) 256 { 257 GNUNET_CURL_job_cancel (dph->job); 258 dph->job = NULL; 259 } 260 curl_slist_free_all (dph->xhdr); 261 GNUNET_free (dph->url); 262 GNUNET_free (dph->base_url); 263 GNUNET_free (dph); 264 } 265 266 267 /* end of exchange_api_delete-purses-PURSE_PUB.c */