exchange_api_post-management-partners.c (7904B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023-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-partners.c 19 * @brief functions to add a partner exchange 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-partners.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_PostManagementPartnersHandle 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_PostManagementPartnersCallback cb; 60 61 /** 62 * Closure for @a cb. 63 */ 64 TALER_EXCHANGE_POST_MANAGEMENT_PARTNERS_RESULT_CLOSURE *cb_cls; 65 66 /** 67 * Reference to the execution context. 68 */ 69 struct GNUNET_CURL_Context *ctx; 70 71 /** 72 * Offline signing key of the partner. 73 */ 74 struct TALER_MasterPublicKeyP partner_pub; 75 76 /** 77 * Validity period start. 78 */ 79 struct GNUNET_TIME_Timestamp start_date; 80 81 /** 82 * Validity period end. 83 */ 84 struct GNUNET_TIME_Timestamp end_date; 85 86 /** 87 * How often will we do wad transfers to this partner. 88 */ 89 struct GNUNET_TIME_Relative wad_frequency; 90 91 /** 92 * Wad fee to this partner. 93 */ 94 struct TALER_Amount wad_fee; 95 96 /** 97 * Base URL of the partner exchange. 98 */ 99 char *partner_base_url; 100 101 /** 102 * Signature. 103 */ 104 struct TALER_MasterSignatureP master_sig; 105 106 }; 107 108 109 /** 110 * Function called when we're done processing the 111 * HTTP POST /management/partners request. 112 * 113 * @param cls the `struct TALER_EXCHANGE_PostManagementPartnersHandle` 114 * @param response_code HTTP response code, 0 on error 115 * @param response response body, NULL if not in JSON 116 */ 117 static void 118 handle_partners_finished (void *cls, 119 long response_code, 120 const void *response) 121 { 122 struct TALER_EXCHANGE_PostManagementPartnersHandle *pmph = cls; 123 const json_t *json = response; 124 struct TALER_EXCHANGE_PostManagementPartnersResponse res = { 125 .hr.http_status = (unsigned int) response_code, 126 .hr.reply = json 127 }; 128 129 pmph->job = NULL; 130 switch (response_code) 131 { 132 case 0: 133 /* no reply */ 134 res.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 135 res.hr.hint = "server offline?"; 136 break; 137 case MHD_HTTP_NO_CONTENT: 138 break; 139 case MHD_HTTP_FORBIDDEN: 140 res.hr.ec = TALER_JSON_get_error_code (json); 141 res.hr.hint = TALER_JSON_get_error_hint (json); 142 break; 143 case MHD_HTTP_CONFLICT: 144 res.hr.ec = TALER_JSON_get_error_code (json); 145 res.hr.hint = TALER_JSON_get_error_hint (json); 146 break; 147 default: 148 /* unexpected response code */ 149 GNUNET_break_op (0); 150 res.hr.ec = TALER_JSON_get_error_code (json); 151 res.hr.hint = TALER_JSON_get_error_hint (json); 152 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 153 "Unexpected response code %u/%d for adding exchange partner\n", 154 (unsigned int) response_code, 155 (int) res.hr.ec); 156 break; 157 } 158 if (NULL != pmph->cb) 159 { 160 pmph->cb (pmph->cb_cls, 161 &res); 162 pmph->cb = NULL; 163 } 164 TALER_EXCHANGE_post_management_partners_cancel (pmph); 165 } 166 167 168 struct TALER_EXCHANGE_PostManagementPartnersHandle * 169 TALER_EXCHANGE_post_management_partners_create ( 170 struct GNUNET_CURL_Context *ctx, 171 const char *url, 172 const struct TALER_MasterPublicKeyP *partner_pub, 173 struct GNUNET_TIME_Timestamp start_date, 174 struct GNUNET_TIME_Timestamp end_date, 175 struct GNUNET_TIME_Relative wad_frequency, 176 const struct TALER_Amount *wad_fee, 177 const char *partner_base_url, 178 const struct TALER_MasterSignatureP *master_sig) 179 { 180 struct TALER_EXCHANGE_PostManagementPartnersHandle *pmph; 181 182 pmph = GNUNET_new (struct TALER_EXCHANGE_PostManagementPartnersHandle); 183 pmph->ctx = ctx; 184 pmph->base_url = GNUNET_strdup (url); 185 pmph->partner_pub = *partner_pub; 186 pmph->start_date = start_date; 187 pmph->end_date = end_date; 188 pmph->wad_frequency = wad_frequency; 189 pmph->wad_fee = *wad_fee; 190 pmph->partner_base_url = GNUNET_strdup (partner_base_url); 191 pmph->master_sig = *master_sig; 192 return pmph; 193 } 194 195 196 enum TALER_ErrorCode 197 TALER_EXCHANGE_post_management_partners_start ( 198 struct TALER_EXCHANGE_PostManagementPartnersHandle *pmph, 199 TALER_EXCHANGE_PostManagementPartnersCallback cb, 200 TALER_EXCHANGE_POST_MANAGEMENT_PARTNERS_RESULT_CLOSURE *cb_cls) 201 { 202 CURL *eh; 203 json_t *body; 204 205 pmph->cb = cb; 206 pmph->cb_cls = cb_cls; 207 pmph->url = TALER_url_join (pmph->base_url, 208 "management/partners", 209 NULL); 210 if (NULL == pmph->url) 211 { 212 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 213 "Could not construct request URL.\n"); 214 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 215 } 216 body = GNUNET_JSON_PACK ( 217 GNUNET_JSON_pack_string ("partner_base_url", 218 pmph->partner_base_url), 219 GNUNET_JSON_pack_timestamp ("start_date", 220 pmph->start_date), 221 GNUNET_JSON_pack_timestamp ("end_date", 222 pmph->end_date), 223 GNUNET_JSON_pack_time_rel ("wad_frequency", 224 pmph->wad_frequency), 225 GNUNET_JSON_pack_data_auto ("partner_pub", 226 &pmph->partner_pub), 227 GNUNET_JSON_pack_data_auto ("master_sig", 228 &pmph->master_sig), 229 TALER_JSON_pack_amount ("wad_fee", 230 &pmph->wad_fee)); 231 eh = TALER_EXCHANGE_curl_easy_get_ (pmph->url); 232 if ( (NULL == eh) || 233 (GNUNET_OK != 234 TALER_curl_easy_post (&pmph->post_ctx, 235 eh, 236 body)) ) 237 { 238 GNUNET_break (0); 239 if (NULL != eh) 240 curl_easy_cleanup (eh); 241 json_decref (body); 242 GNUNET_free (pmph->url); 243 pmph->url = NULL; 244 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 245 } 246 json_decref (body); 247 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 248 "Requesting URL '%s'\n", 249 pmph->url); 250 pmph->job = GNUNET_CURL_job_add2 (pmph->ctx, 251 eh, 252 pmph->post_ctx.headers, 253 &handle_partners_finished, 254 pmph); 255 if (NULL == pmph->job) 256 { 257 TALER_curl_easy_post_finished (&pmph->post_ctx); 258 GNUNET_free (pmph->url); 259 pmph->url = NULL; 260 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 261 } 262 return TALER_EC_NONE; 263 } 264 265 266 void 267 TALER_EXCHANGE_post_management_partners_cancel ( 268 struct TALER_EXCHANGE_PostManagementPartnersHandle *pmph) 269 { 270 if (NULL != pmph->job) 271 { 272 GNUNET_CURL_job_cancel (pmph->job); 273 pmph->job = NULL; 274 } 275 TALER_curl_easy_post_finished (&pmph->post_ctx); 276 GNUNET_free (pmph->partner_base_url); 277 GNUNET_free (pmph->url); 278 GNUNET_free (pmph->base_url); 279 GNUNET_free (pmph); 280 } 281 282 283 /* end of exchange_api_post-management-partners.c */