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