exchange_api_post-management-drain.c (7565B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2020-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_post-management-drain.c 19 * @brief functions to drain profits from an exchange account 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include "taler/taler_json_lib.h" 24 #include <gnunet/gnunet_curl_lib.h> 25 #include <microhttpd.h> 26 #include "taler/taler_exchange_service.h" 27 #include "taler/taler-exchange/post-management-drain.h" 28 #include "exchange_api_curl_defaults.h" 29 #include "taler/taler_signatures.h" 30 #include "taler/taler_curl_lib.h" 31 32 33 struct TALER_EXCHANGE_PostManagementDrainHandle 34 { 35 36 /** 37 * The base URL for this request. 38 */ 39 char *base_url; 40 41 /** 42 * The full URL for this request, set during _start. 43 */ 44 char *url; 45 46 /** 47 * Minor context that holds body and headers. 48 */ 49 struct TALER_CURL_PostContext post_ctx; 50 51 /** 52 * Handle for the request. 53 */ 54 struct GNUNET_CURL_Job *job; 55 56 /** 57 * Function to call with the result. 58 */ 59 TALER_EXCHANGE_PostManagementDrainCallback cb; 60 61 /** 62 * Closure for @a cb. 63 */ 64 TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls; 65 66 /** 67 * Reference to the execution context. 68 */ 69 struct GNUNET_CURL_Context *ctx; 70 71 /** 72 * Wire transfer identifier to use. 73 */ 74 struct TALER_WireTransferIdentifierRawP wtid; 75 76 /** 77 * Total to transfer. 78 */ 79 struct TALER_Amount amount; 80 81 /** 82 * When was the request created. 83 */ 84 struct GNUNET_TIME_Timestamp date; 85 86 /** 87 * Configuration section identifying account to debit. 88 */ 89 char *account_section; 90 91 /** 92 * Payto URI of the account to credit. 93 */ 94 char *payto_uri_str; 95 96 /** 97 * Signature affirming the operation. 98 */ 99 struct TALER_MasterSignatureP master_sig; 100 101 }; 102 103 104 /** 105 * Function called when we're done processing the 106 * HTTP POST /management/drain request. 107 * 108 * @param cls the `struct TALER_EXCHANGE_PostManagementDrainHandle` 109 * @param response_code HTTP response code, 0 on error 110 * @param response response body, NULL if not in JSON 111 */ 112 static void 113 handle_drain_finished (void *cls, 114 long response_code, 115 const void *response) 116 { 117 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh = cls; 118 const json_t *json = response; 119 struct TALER_EXCHANGE_PostManagementDrainResponse res = { 120 .hr.http_status = (unsigned int) response_code, 121 .hr.reply = json 122 }; 123 124 pmdh->job = NULL; 125 switch (response_code) 126 { 127 case MHD_HTTP_NO_CONTENT: 128 break; 129 case MHD_HTTP_FORBIDDEN: 130 res.hr.ec = TALER_JSON_get_error_code (json); 131 res.hr.hint = TALER_JSON_get_error_hint (json); 132 break; 133 case MHD_HTTP_INTERNAL_SERVER_ERROR: 134 res.hr.ec = TALER_JSON_get_error_code (json); 135 res.hr.hint = TALER_JSON_get_error_hint (json); 136 break; 137 default: 138 /* unexpected response code */ 139 GNUNET_break_op (0); 140 res.hr.ec = TALER_JSON_get_error_code (json); 141 res.hr.hint = TALER_JSON_get_error_hint (json); 142 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 143 "Unexpected response code %u/%d for exchange management drain profits\n", 144 (unsigned int) response_code, 145 (int) res.hr.ec); 146 break; 147 } 148 if (NULL != pmdh->cb) 149 { 150 pmdh->cb (pmdh->cb_cls, 151 &res); 152 pmdh->cb = NULL; 153 } 154 TALER_EXCHANGE_post_management_drain_cancel (pmdh); 155 } 156 157 158 struct TALER_EXCHANGE_PostManagementDrainHandle * 159 TALER_EXCHANGE_post_management_drain_create ( 160 struct GNUNET_CURL_Context *ctx, 161 const char *url, 162 const struct TALER_WireTransferIdentifierRawP *wtid, 163 const struct TALER_Amount *amount, 164 struct GNUNET_TIME_Timestamp date, 165 const char *account_section, 166 const struct TALER_FullPayto payto_uri, 167 const struct TALER_MasterSignatureP *master_sig) 168 { 169 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh; 170 171 pmdh = GNUNET_new (struct TALER_EXCHANGE_PostManagementDrainHandle); 172 pmdh->ctx = ctx; 173 pmdh->base_url = GNUNET_strdup (url); 174 pmdh->wtid = *wtid; 175 pmdh->amount = *amount; 176 pmdh->date = date; 177 pmdh->account_section = GNUNET_strdup (account_section); 178 pmdh->payto_uri_str = GNUNET_strdup (payto_uri.full_payto); 179 pmdh->master_sig = *master_sig; 180 return pmdh; 181 } 182 183 184 enum TALER_ErrorCode 185 TALER_EXCHANGE_post_management_drain_start ( 186 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh, 187 TALER_EXCHANGE_PostManagementDrainCallback cb, 188 TALER_EXCHANGE_POST_MANAGEMENT_DRAIN_RESULT_CLOSURE *cb_cls) 189 { 190 CURL *eh; 191 json_t *body; 192 struct TALER_FullPayto payto_uri = { 193 .full_payto = pmdh->payto_uri_str 194 }; 195 196 pmdh->cb = cb; 197 pmdh->cb_cls = cb_cls; 198 pmdh->url = TALER_url_join (pmdh->base_url, 199 "management/drain", 200 NULL); 201 if (NULL == pmdh->url) 202 { 203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 204 "Could not construct request URL.\n"); 205 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 206 } 207 body = GNUNET_JSON_PACK ( 208 GNUNET_JSON_pack_string ("debit_account_section", 209 pmdh->account_section), 210 TALER_JSON_pack_full_payto ("credit_payto_uri", 211 payto_uri), 212 GNUNET_JSON_pack_data_auto ("wtid", 213 &pmdh->wtid), 214 GNUNET_JSON_pack_data_auto ("master_sig", 215 &pmdh->master_sig), 216 GNUNET_JSON_pack_timestamp ("date", 217 pmdh->date), 218 TALER_JSON_pack_amount ("amount", 219 &pmdh->amount)); 220 eh = TALER_EXCHANGE_curl_easy_get_ (pmdh->url); 221 if ( (NULL == eh) || 222 (GNUNET_OK != 223 TALER_curl_easy_post (&pmdh->post_ctx, 224 eh, 225 body)) ) 226 { 227 GNUNET_break (0); 228 if (NULL != eh) 229 curl_easy_cleanup (eh); 230 json_decref (body); 231 GNUNET_free (pmdh->url); 232 pmdh->url = NULL; 233 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 234 } 235 json_decref (body); 236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 237 "Requesting URL '%s'\n", 238 pmdh->url); 239 pmdh->job = GNUNET_CURL_job_add2 (pmdh->ctx, 240 eh, 241 pmdh->post_ctx.headers, 242 &handle_drain_finished, 243 pmdh); 244 if (NULL == pmdh->job) 245 { 246 TALER_curl_easy_post_finished (&pmdh->post_ctx); 247 GNUNET_free (pmdh->url); 248 pmdh->url = NULL; 249 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 250 } 251 return TALER_EC_NONE; 252 } 253 254 255 void 256 TALER_EXCHANGE_post_management_drain_cancel ( 257 struct TALER_EXCHANGE_PostManagementDrainHandle *pmdh) 258 { 259 if (NULL != pmdh->job) 260 { 261 GNUNET_CURL_job_cancel (pmdh->job); 262 pmdh->job = NULL; 263 } 264 TALER_curl_easy_post_finished (&pmdh->post_ctx); 265 GNUNET_free (pmdh->account_section); 266 GNUNET_free (pmdh->payto_uri_str); 267 GNUNET_free (pmdh->url); 268 GNUNET_free (pmdh->base_url); 269 GNUNET_free (pmdh); 270 } 271 272 273 /* end of exchange_api_post-management-drain.c */