exchange_api_get_kyc_statistics.c (8915B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2023, 2024 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_kyc_statistics.c 19 * @brief Implementation of the /aml/$OFFICER_PUB/kyc-statistics/$NAME request 20 * @author Christian Grothoff 21 */ 22 #include "taler/platform.h" 23 #include <microhttpd.h> /* just for HTTP status codes */ 24 #include <gnunet/gnunet_util_lib.h> 25 #include <gnunet/gnunet_curl_lib.h> 26 #include "taler/taler_exchange_service.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 /aml/$OFFICER_PUB/kyc-statistics/$NAME Handle 35 */ 36 struct TALER_EXCHANGE_KycGetStatisticsHandle 37 { 38 39 /** 40 * The url for this request. 41 */ 42 char *url; 43 44 /** 45 * Handle for the request. 46 */ 47 struct GNUNET_CURL_Job *job; 48 49 /** 50 * Function to call with the result. 51 */ 52 TALER_EXCHANGE_KycStatisticsCallback stats_cb; 53 54 /** 55 * Closure for @e cb. 56 */ 57 void *stats_cb_cls; 58 59 /** 60 * HTTP headers for the job. 61 */ 62 struct curl_slist *job_headers; 63 64 }; 65 66 67 /** 68 * Parse the provided decision data from the "200 OK" response. 69 * 70 * @param[in,out] lh handle (callback may be zero'ed out) 71 * @param json json reply with the data for one coin 72 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error 73 */ 74 static enum GNUNET_GenericReturnValue 75 parse_stats_ok ( 76 struct TALER_EXCHANGE_KycGetStatisticsHandle *lh, 77 const json_t *json) 78 { 79 struct TALER_EXCHANGE_KycGetStatisticsResponse lr = { 80 .hr.reply = json, 81 .hr.http_status = MHD_HTTP_OK 82 }; 83 uint64_t cnt; 84 struct GNUNET_JSON_Specification spec[] = { 85 GNUNET_JSON_spec_uint64 ("counter", 86 &cnt), 87 GNUNET_JSON_spec_end () 88 }; 89 90 if (GNUNET_OK != 91 GNUNET_JSON_parse (json, 92 spec, 93 NULL, 94 NULL)) 95 { 96 GNUNET_break_op (0); 97 return GNUNET_SYSERR; 98 } 99 lr.details.ok.counter = (unsigned long long) cnt; 100 lh->stats_cb (lh->stats_cb_cls, 101 &lr); 102 lh->stats_cb = NULL; 103 return GNUNET_OK; 104 } 105 106 107 /** 108 * Function called when we're done processing the 109 * HTTP /aml/$OFFICER_PUB/kyc-statistics/$NAME request. 110 * 111 * @param cls the `struct TALER_EXCHANGE_KycGetStatisticsHandle` 112 * @param response_code HTTP response code, 0 on error 113 * @param response parsed JSON result, NULL on error 114 */ 115 static void 116 handle_lookup_finished (void *cls, 117 long response_code, 118 const void *response) 119 { 120 struct TALER_EXCHANGE_KycGetStatisticsHandle *lh = cls; 121 const json_t *j = response; 122 struct TALER_EXCHANGE_KycGetStatisticsResponse lr = { 123 .hr.reply = j, 124 .hr.http_status = (unsigned int) response_code 125 }; 126 127 lh->job = NULL; 128 switch (response_code) 129 { 130 case 0: 131 lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 132 break; 133 case MHD_HTTP_OK: 134 if (GNUNET_OK != 135 parse_stats_ok (lh, 136 j)) 137 { 138 GNUNET_break_op (0); 139 lr.hr.http_status = 0; 140 lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; 141 break; 142 } 143 GNUNET_assert (NULL == lh->stats_cb); 144 TALER_EXCHANGE_kyc_get_statistics_cancel (lh); 145 return; 146 case MHD_HTTP_NO_CONTENT: 147 break; 148 case MHD_HTTP_BAD_REQUEST: 149 lr.hr.ec = TALER_JSON_get_error_code (j); 150 lr.hr.hint = TALER_JSON_get_error_hint (j); 151 /* This should never happen, either us or the exchange is buggy 152 (or API version conflict); just pass JSON reply to the application */ 153 break; 154 case MHD_HTTP_FORBIDDEN: 155 lr.hr.ec = TALER_JSON_get_error_code (j); 156 lr.hr.hint = TALER_JSON_get_error_hint (j); 157 /* Nothing really to verify, exchange says this coin was not melted; we 158 should pass the JSON reply to the application */ 159 break; 160 case MHD_HTTP_INTERNAL_SERVER_ERROR: 161 lr.hr.ec = TALER_JSON_get_error_code (j); 162 lr.hr.hint = TALER_JSON_get_error_hint (j); 163 /* Server had an internal issue; we should retry, but this API 164 leaves this to the application */ 165 break; 166 default: 167 /* unexpected response code */ 168 GNUNET_break_op (0); 169 lr.hr.ec = TALER_JSON_get_error_code (j); 170 lr.hr.hint = TALER_JSON_get_error_hint (j); 171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 172 "Unexpected response code %u/%d for GET KYC statistics\n", 173 (unsigned int) response_code, 174 (int) lr.hr.ec); 175 break; 176 } 177 if (NULL != lh->stats_cb) 178 lh->stats_cb (lh->stats_cb_cls, 179 &lr); 180 TALER_EXCHANGE_kyc_get_statistics_cancel (lh); 181 } 182 183 184 struct TALER_EXCHANGE_KycGetStatisticsHandle * 185 TALER_EXCHANGE_kyc_get_statistics ( 186 struct GNUNET_CURL_Context *ctx, 187 const char *exchange_url, 188 const char *name, 189 struct GNUNET_TIME_Timestamp start_date, 190 struct GNUNET_TIME_Timestamp end_date, 191 const struct TALER_AmlOfficerPrivateKeyP *officer_priv, 192 TALER_EXCHANGE_KycStatisticsCallback cb, 193 void *cb_cls) 194 { 195 struct TALER_EXCHANGE_KycGetStatisticsHandle *lh; 196 CURL *eh; 197 struct TALER_AmlOfficerPublicKeyP officer_pub; 198 struct TALER_AmlOfficerSignatureP officer_sig; 199 char arg_str[sizeof (struct TALER_AmlOfficerPublicKeyP) * 2 200 + 32]; 201 char sd_str[32]; 202 char ed_str[32]; 203 const char *sd = NULL; 204 const char *ed = NULL; 205 206 if (! GNUNET_TIME_absolute_is_zero (start_date.abs_time)) 207 { 208 unsigned long long sec; 209 210 sec = (unsigned long long) GNUNET_TIME_timestamp_to_s (start_date); 211 GNUNET_snprintf (sd_str, 212 sizeof (sd_str), 213 "%llu", 214 sec); 215 sd = sd_str; 216 } 217 if (! GNUNET_TIME_absolute_is_never (end_date.abs_time)) 218 { 219 unsigned long long sec; 220 221 sec = (unsigned long long) GNUNET_TIME_timestamp_to_s (end_date); 222 GNUNET_snprintf (ed_str, 223 sizeof (ed_str), 224 "%llu", 225 sec); 226 ed = ed_str; 227 } 228 GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv, 229 &officer_pub.eddsa_pub); 230 TALER_officer_aml_query_sign (officer_priv, 231 &officer_sig); 232 { 233 char pub_str[sizeof (officer_pub) * 2]; 234 char *end; 235 236 end = GNUNET_STRINGS_data_to_string ( 237 &officer_pub, 238 sizeof (officer_pub), 239 pub_str, 240 sizeof (pub_str)); 241 *end = '\0'; 242 GNUNET_snprintf (arg_str, 243 sizeof (arg_str), 244 "aml/%s/kyc-statistics/%s", 245 pub_str, 246 name); 247 } 248 lh = GNUNET_new (struct TALER_EXCHANGE_KycGetStatisticsHandle); 249 lh->stats_cb = cb; 250 lh->stats_cb_cls = cb_cls; 251 lh->url = TALER_url_join (exchange_url, 252 arg_str, 253 "start_date", 254 sd, 255 "end_date", 256 ed, 257 NULL); 258 if (NULL == lh->url) 259 { 260 GNUNET_free (lh); 261 return NULL; 262 } 263 eh = TALER_EXCHANGE_curl_easy_get_ (lh->url); 264 if (NULL == eh) 265 { 266 GNUNET_break (0); 267 GNUNET_free (lh->url); 268 GNUNET_free (lh); 269 return NULL; 270 } 271 { 272 char *hdr; 273 char sig_str[sizeof (officer_sig) * 2]; 274 char *end; 275 276 end = GNUNET_STRINGS_data_to_string ( 277 &officer_sig, 278 sizeof (officer_sig), 279 sig_str, 280 sizeof (sig_str)); 281 *end = '\0'; 282 283 GNUNET_asprintf (&hdr, 284 "%s: %s", 285 TALER_AML_OFFICER_SIGNATURE_HEADER, 286 sig_str); 287 lh->job_headers = curl_slist_append (NULL, 288 hdr); 289 GNUNET_free (hdr); 290 lh->job_headers = curl_slist_append (lh->job_headers, 291 "Content-type: application/json"); 292 lh->job = GNUNET_CURL_job_add2 (ctx, 293 eh, 294 lh->job_headers, 295 &handle_lookup_finished, 296 lh); 297 } 298 return lh; 299 } 300 301 302 void 303 TALER_EXCHANGE_kyc_get_statistics_cancel ( 304 struct TALER_EXCHANGE_KycGetStatisticsHandle *lh) 305 { 306 if (NULL != lh->job) 307 { 308 GNUNET_CURL_job_cancel (lh->job); 309 lh->job = NULL; 310 } 311 curl_slist_free_all (lh->job_headers); 312 GNUNET_free (lh->url); 313 GNUNET_free (lh); 314 } 315 316 317 /* end of exchange_api_get_kyc_statistics.c */