exchange_api_get-reserves-RESERVE_PUB-attest.c (8480B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2014-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_get-reserves-RESERVE_PUB-attest.c 19 * @brief Implementation of the GET /reserves/$RESERVE_PUB/attest request 20 * @author Christian Grothoff 21 */ 22 #include <jansson.h> 23 #include <microhttpd.h> /* just for HTTP status codes */ 24 #include <gnunet/gnunet_util_lib.h> 25 #include <gnunet/gnunet_json_lib.h> 26 #include <gnunet/gnunet_curl_lib.h> 27 #include "taler/taler_json_lib.h" 28 #include "exchange_api_handle.h" 29 #include "taler/taler_signatures.h" 30 #include "exchange_api_curl_defaults.h" 31 32 33 /** 34 * @brief A GET /reserves/$RESERVE_PUB/attest Handle 35 */ 36 struct TALER_EXCHANGE_GetReservesAttestHandle 37 { 38 39 /** 40 * Base URL of the exchange. 41 */ 42 char *base_url; 43 44 /** 45 * The url for this request. 46 */ 47 char *url; 48 49 /** 50 * CURL context to use. 51 */ 52 struct GNUNET_CURL_Context *ctx; 53 54 /** 55 * Handle for the request. 56 */ 57 struct GNUNET_CURL_Job *job; 58 59 /** 60 * Function to call with the result. 61 */ 62 TALER_EXCHANGE_GetReservesAttestCallback cb; 63 64 /** 65 * Closure for @e cb. 66 */ 67 TALER_EXCHANGE_GET_RESERVES_ATTEST_RESULT_CLOSURE *cb_cls; 68 69 /** 70 * Public key of the reserve we are querying. 71 */ 72 struct TALER_ReservePublicKeyP reserve_pub; 73 74 }; 75 76 77 /** 78 * We received an #MHD_HTTP_OK status code. Handle the JSON response. 79 * 80 * @param grah handle of the request 81 * @param j JSON response 82 * @return #GNUNET_OK on success 83 */ 84 static enum GNUNET_GenericReturnValue 85 handle_reserves_get_attestable_ok ( 86 struct TALER_EXCHANGE_GetReservesAttestHandle *grah, 87 const json_t *j) 88 { 89 struct TALER_EXCHANGE_GetReservesAttestResponse rs = { 90 .hr.reply = j, 91 .hr.http_status = MHD_HTTP_OK 92 }; 93 const json_t *details; 94 struct GNUNET_JSON_Specification spec[] = { 95 GNUNET_JSON_spec_array_const ("details", 96 &details), 97 GNUNET_JSON_spec_end () 98 }; 99 100 if (GNUNET_OK != 101 GNUNET_JSON_parse (j, 102 spec, 103 NULL, 104 NULL)) 105 { 106 GNUNET_break_op (0); 107 return GNUNET_SYSERR; 108 } 109 { 110 size_t dlen = json_array_size (details); 111 const char **attributes; 112 113 if (dlen > GNUNET_MAX_MALLOC_CHECKED / sizeof (*attributes)) 114 { 115 GNUNET_break_op (0); 116 return GNUNET_SYSERR; 117 } 118 attributes = GNUNET_new_array (GNUNET_NZL (dlen), 119 const char *); 120 for (unsigned int i = 0; i < dlen; i++) 121 { 122 json_t *detail = json_array_get (details, 123 i); 124 attributes[i] = json_string_value (detail); 125 if (NULL == attributes[i]) 126 { 127 GNUNET_break_op (0); 128 GNUNET_free (attributes); 129 return GNUNET_SYSERR; 130 } 131 } 132 rs.details.ok.attributes_length = dlen; 133 rs.details.ok.attributes = attributes; 134 grah->cb (grah->cb_cls, 135 &rs); 136 grah->cb = NULL; 137 GNUNET_free (attributes); 138 } 139 return GNUNET_OK; 140 } 141 142 143 /** 144 * Function called when we're done processing the 145 * HTTP GET /reserves/$RESERVE_PUB/attest request. 146 * 147 * @param cls the `struct TALER_EXCHANGE_GetReservesAttestHandle` 148 * @param response_code HTTP response code, 0 on error 149 * @param response parsed JSON result, NULL on error 150 */ 151 static void 152 handle_reserves_get_attestable_finished (void *cls, 153 long response_code, 154 const void *response) 155 { 156 struct TALER_EXCHANGE_GetReservesAttestHandle *grah = cls; 157 const json_t *j = response; 158 struct TALER_EXCHANGE_GetReservesAttestResponse rs = { 159 .hr.reply = j, 160 .hr.http_status = (unsigned int) response_code 161 }; 162 163 grah->job = NULL; 164 switch (response_code) 165 { 166 case 0: 167 rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 168 break; 169 case MHD_HTTP_OK: 170 if (GNUNET_OK != 171 handle_reserves_get_attestable_ok (grah, 172 j)) 173 { 174 rs.hr.http_status = 0; 175 rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 176 } 177 break; 178 case MHD_HTTP_BAD_REQUEST: 179 /* This should never happen, either us or the exchange is buggy 180 (or API version conflict); just pass JSON reply to the application */ 181 rs.hr.ec = TALER_JSON_get_error_code (j); 182 rs.hr.hint = TALER_JSON_get_error_hint (j); 183 break; 184 case MHD_HTTP_NOT_FOUND: 185 /* Nothing really to verify, this should never 186 happen, we should pass the JSON reply to the application */ 187 rs.hr.ec = TALER_JSON_get_error_code (j); 188 rs.hr.hint = TALER_JSON_get_error_hint (j); 189 break; 190 case MHD_HTTP_CONFLICT: 191 /* Nothing really to verify, this should never 192 happen, we should pass the JSON reply to the application */ 193 rs.hr.ec = TALER_JSON_get_error_code (j); 194 rs.hr.hint = TALER_JSON_get_error_hint (j); 195 break; 196 case MHD_HTTP_INTERNAL_SERVER_ERROR: 197 /* Server had an internal issue; we should retry, but this API 198 leaves this to the application */ 199 rs.hr.ec = TALER_JSON_get_error_code (j); 200 rs.hr.hint = TALER_JSON_get_error_hint (j); 201 break; 202 default: 203 /* unexpected response code */ 204 GNUNET_break_op (0); 205 rs.hr.ec = TALER_JSON_get_error_code (j); 206 rs.hr.hint = TALER_JSON_get_error_hint (j); 207 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 208 "Unexpected response code %u/%d for reserves get_attestable\n", 209 (unsigned int) response_code, 210 (int) rs.hr.ec); 211 break; 212 } 213 if (NULL != grah->cb) 214 { 215 grah->cb (grah->cb_cls, 216 &rs); 217 grah->cb = NULL; 218 } 219 TALER_EXCHANGE_get_reserves_attest_cancel (grah); 220 } 221 222 223 struct TALER_EXCHANGE_GetReservesAttestHandle * 224 TALER_EXCHANGE_get_reserves_attest_create ( 225 struct GNUNET_CURL_Context *ctx, 226 const char *url, 227 const struct TALER_ReservePublicKeyP *reserve_pub) 228 { 229 struct TALER_EXCHANGE_GetReservesAttestHandle *grah; 230 231 grah = GNUNET_new (struct TALER_EXCHANGE_GetReservesAttestHandle); 232 grah->ctx = ctx; 233 grah->base_url = GNUNET_strdup (url); 234 grah->reserve_pub = *reserve_pub; 235 return grah; 236 } 237 238 239 enum TALER_ErrorCode 240 TALER_EXCHANGE_get_reserves_attest_start ( 241 struct TALER_EXCHANGE_GetReservesAttestHandle *grah, 242 TALER_EXCHANGE_GetReservesAttestCallback cb, 243 TALER_EXCHANGE_GET_RESERVES_ATTEST_RESULT_CLOSURE *cb_cls) 244 { 245 char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; 246 CURL *eh; 247 248 if (NULL != grah->job) 249 { 250 GNUNET_break (0); 251 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 252 } 253 grah->cb = cb; 254 grah->cb_cls = cb_cls; 255 { 256 char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; 257 char *end; 258 259 end = GNUNET_STRINGS_data_to_string ( 260 &grah->reserve_pub, 261 sizeof (grah->reserve_pub), 262 pub_str, 263 sizeof (pub_str)); 264 *end = '\0'; 265 GNUNET_snprintf (arg_str, 266 sizeof (arg_str), 267 "reserves/%s/attest", 268 pub_str); 269 } 270 grah->url = TALER_url_join (grah->base_url, 271 arg_str, 272 NULL); 273 if (NULL == grah->url) 274 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 275 eh = TALER_EXCHANGE_curl_easy_get_ (grah->url); 276 if (NULL == eh) 277 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 278 grah->job = GNUNET_CURL_job_add (grah->ctx, 279 eh, 280 &handle_reserves_get_attestable_finished, 281 grah); 282 if (NULL == grah->job) 283 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 284 return TALER_EC_NONE; 285 } 286 287 288 void 289 TALER_EXCHANGE_get_reserves_attest_cancel ( 290 struct TALER_EXCHANGE_GetReservesAttestHandle *grah) 291 { 292 if (NULL != grah->job) 293 { 294 GNUNET_CURL_job_cancel (grah->job); 295 grah->job = NULL; 296 } 297 GNUNET_free (grah->url); 298 GNUNET_free (grah->base_url); 299 GNUNET_free (grah); 300 } 301 302 303 /* end of exchange_api_get-reserves-RESERVE_PUB-attest.c */