exchange_api_purse_delete.c (7133B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2022 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_purse_delete.c 19 * @brief Implementation of the client to delete a purse 20 * into an account 21 * @author Christian Grothoff 22 */ 23 #include "taler/platform.h" 24 #include <jansson.h> 25 #include <microhttpd.h> /* just for HTTP status codes */ 26 #include <gnunet/gnunet_util_lib.h> 27 #include <gnunet/gnunet_json_lib.h> 28 #include <gnunet/gnunet_curl_lib.h> 29 #include "taler/taler_json_lib.h" 30 #include "taler/taler_exchange_service.h" 31 #include "exchange_api_handle.h" 32 #include "exchange_api_common.h" 33 #include "taler/taler_signatures.h" 34 #include "exchange_api_curl_defaults.h" 35 36 37 /** 38 * @brief A purse delete with deposit handle 39 */ 40 struct TALER_EXCHANGE_PurseDeleteHandle 41 { 42 43 /** 44 * The url for this request. 45 */ 46 char *url; 47 48 /** 49 * Handle for the request. 50 */ 51 struct GNUNET_CURL_Job *job; 52 53 /** 54 * Function to call with the result. 55 */ 56 TALER_EXCHANGE_PurseDeleteCallback cb; 57 58 /** 59 * Closure for @a cb. 60 */ 61 void *cb_cls; 62 63 /** 64 * Header with the purse_sig. 65 */ 66 struct curl_slist *xhdr; 67 }; 68 69 70 /** 71 * Function called when we're done processing the 72 * HTTP DELETE /purse/$PID request. 73 * 74 * @param cls the `struct TALER_EXCHANGE_PurseDeleteHandle` 75 * @param response_code HTTP response code, 0 on error 76 * @param response parsed JSON result, NULL on error 77 */ 78 static void 79 handle_purse_delete_finished (void *cls, 80 long response_code, 81 const void *response) 82 { 83 struct TALER_EXCHANGE_PurseDeleteHandle *pdh = cls; 84 const json_t *j = response; 85 struct TALER_EXCHANGE_PurseDeleteResponse dr = { 86 .hr.reply = j, 87 .hr.http_status = (unsigned int) response_code 88 }; 89 90 pdh->job = NULL; 91 switch (response_code) 92 { 93 case 0: 94 dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 95 break; 96 case MHD_HTTP_NO_CONTENT: 97 break; 98 case MHD_HTTP_BAD_REQUEST: 99 /* This should never happen, either us or the exchange is buggy 100 (or API version conflict); just pass JSON reply to the application */ 101 dr.hr.ec = TALER_JSON_get_error_code (j); 102 dr.hr.hint = TALER_JSON_get_error_hint (j); 103 break; 104 case MHD_HTTP_FORBIDDEN: 105 dr.hr.ec = TALER_JSON_get_error_code (j); 106 dr.hr.hint = TALER_JSON_get_error_hint (j); 107 /* Nothing really to verify, exchange says one of the signatures is 108 invalid; as we checked them, this should never happen, we 109 should pass the JSON reply to the application */ 110 break; 111 case MHD_HTTP_NOT_FOUND: 112 dr.hr.ec = TALER_JSON_get_error_code (j); 113 dr.hr.hint = TALER_JSON_get_error_hint (j); 114 /* Nothing really to verify, this should never 115 happen, we should pass the JSON reply to the application */ 116 break; 117 case MHD_HTTP_CONFLICT: 118 dr.hr.ec = TALER_JSON_get_error_code (j); 119 dr.hr.hint = TALER_JSON_get_error_hint (j); 120 break; 121 case MHD_HTTP_INTERNAL_SERVER_ERROR: 122 dr.hr.ec = TALER_JSON_get_error_code (j); 123 dr.hr.hint = TALER_JSON_get_error_hint (j); 124 /* Server had an internal issue; we should retry, but this API 125 leaves this to the application */ 126 break; 127 default: 128 /* unexpected response code */ 129 dr.hr.ec = TALER_JSON_get_error_code (j); 130 dr.hr.hint = TALER_JSON_get_error_hint (j); 131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 132 "Unexpected response code %u/%d for exchange deposit\n", 133 (unsigned int) response_code, 134 dr.hr.ec); 135 GNUNET_break_op (0); 136 break; 137 } 138 pdh->cb (pdh->cb_cls, 139 &dr); 140 TALER_EXCHANGE_purse_delete_cancel (pdh); 141 } 142 143 144 struct TALER_EXCHANGE_PurseDeleteHandle * 145 TALER_EXCHANGE_purse_delete ( 146 struct GNUNET_CURL_Context *ctx, 147 const char *url, 148 const struct TALER_PurseContractPrivateKeyP *purse_priv, 149 TALER_EXCHANGE_PurseDeleteCallback cb, 150 void *cb_cls) 151 { 152 struct TALER_EXCHANGE_PurseDeleteHandle *pdh; 153 CURL *eh; 154 struct TALER_PurseContractPublicKeyP purse_pub; 155 struct TALER_PurseContractSignatureP purse_sig; 156 char arg_str[sizeof (purse_pub) * 2 + 32]; 157 158 pdh = GNUNET_new (struct TALER_EXCHANGE_PurseDeleteHandle); 159 pdh->cb = cb; 160 pdh->cb_cls = cb_cls; 161 GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv, 162 &purse_pub.eddsa_pub); 163 { 164 char pub_str[sizeof (purse_pub) * 2]; 165 char *end; 166 167 end = GNUNET_STRINGS_data_to_string (&purse_pub, 168 sizeof (purse_pub), 169 pub_str, 170 sizeof (pub_str)); 171 *end = '\0'; 172 GNUNET_snprintf (arg_str, 173 sizeof (arg_str), 174 "purses/%s", 175 pub_str); 176 } 177 pdh->url = TALER_url_join (url, 178 arg_str, 179 NULL); 180 if (NULL == pdh->url) 181 { 182 GNUNET_break (0); 183 GNUNET_free (pdh); 184 return NULL; 185 } 186 TALER_wallet_purse_delete_sign (purse_priv, 187 &purse_sig); 188 { 189 char *delete_str; 190 char *xhdr; 191 192 delete_str = 193 GNUNET_STRINGS_data_to_string_alloc (&purse_sig, 194 sizeof (purse_sig)); 195 GNUNET_asprintf (&xhdr, 196 "Taler-Purse-Signature: %s", 197 delete_str); 198 GNUNET_free (delete_str); 199 pdh->xhdr = curl_slist_append (NULL, 200 xhdr); 201 GNUNET_free (xhdr); 202 } 203 eh = TALER_EXCHANGE_curl_easy_get_ (pdh->url); 204 if (NULL == eh) 205 { 206 GNUNET_break (0); 207 curl_slist_free_all (pdh->xhdr); 208 GNUNET_free (pdh->url); 209 GNUNET_free (pdh); 210 return NULL; 211 } 212 GNUNET_assert (CURLE_OK == 213 curl_easy_setopt (eh, 214 CURLOPT_CUSTOMREQUEST, 215 MHD_HTTP_METHOD_DELETE)); 216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 217 "URL for purse delete: `%s'\n", 218 pdh->url); 219 pdh->job = GNUNET_CURL_job_add2 (ctx, 220 eh, 221 pdh->xhdr, 222 &handle_purse_delete_finished, 223 pdh); 224 return pdh; 225 } 226 227 228 void 229 TALER_EXCHANGE_purse_delete_cancel ( 230 struct TALER_EXCHANGE_PurseDeleteHandle *pdh) 231 { 232 if (NULL != pdh->job) 233 { 234 GNUNET_CURL_job_cancel (pdh->job); 235 pdh->job = NULL; 236 } 237 curl_slist_free_all (pdh->xhdr); 238 GNUNET_free (pdh->url); 239 GNUNET_free (pdh); 240 } 241 242 243 /* end of exchange_api_purse_delete.c */