Line data Source code
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 "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_exchange_service.h"
27 : #include "taler_json_lib.h"
28 : #include "exchange_api_handle.h"
29 : #include "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 0 : parse_stats_ok (
76 : struct TALER_EXCHANGE_KycGetStatisticsHandle *lh,
77 : const json_t *json)
78 : {
79 0 : 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 0 : GNUNET_JSON_spec_uint64 ("counter",
86 : &cnt),
87 0 : GNUNET_JSON_spec_end ()
88 : };
89 :
90 0 : if (GNUNET_OK !=
91 0 : GNUNET_JSON_parse (json,
92 : spec,
93 : NULL,
94 : NULL))
95 : {
96 0 : GNUNET_break_op (0);
97 0 : return GNUNET_SYSERR;
98 : }
99 0 : lr.details.ok.counter = (unsigned long long) cnt;
100 0 : lh->stats_cb (lh->stats_cb_cls,
101 : &lr);
102 0 : lh->stats_cb = NULL;
103 0 : 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 0 : handle_lookup_finished (void *cls,
117 : long response_code,
118 : const void *response)
119 : {
120 0 : struct TALER_EXCHANGE_KycGetStatisticsHandle *lh = cls;
121 0 : const json_t *j = response;
122 0 : struct TALER_EXCHANGE_KycGetStatisticsResponse lr = {
123 : .hr.reply = j,
124 0 : .hr.http_status = (unsigned int) response_code
125 : };
126 :
127 0 : lh->job = NULL;
128 0 : switch (response_code)
129 : {
130 0 : case 0:
131 0 : lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
132 0 : break;
133 0 : case MHD_HTTP_OK:
134 0 : if (GNUNET_OK !=
135 0 : parse_stats_ok (lh,
136 : j))
137 : {
138 0 : GNUNET_break_op (0);
139 0 : lr.hr.http_status = 0;
140 0 : lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
141 0 : break;
142 : }
143 0 : GNUNET_assert (NULL == lh->stats_cb);
144 0 : TALER_EXCHANGE_kyc_get_statistics_cancel (lh);
145 0 : return;
146 0 : case MHD_HTTP_NO_CONTENT:
147 0 : break;
148 0 : case MHD_HTTP_BAD_REQUEST:
149 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
150 0 : 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 0 : break;
154 0 : case MHD_HTTP_FORBIDDEN:
155 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
156 0 : 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 0 : break;
160 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
161 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
162 0 : 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 0 : break;
166 0 : default:
167 : /* unexpected response code */
168 0 : GNUNET_break_op (0);
169 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
170 0 : lr.hr.hint = TALER_JSON_get_error_hint (j);
171 0 : 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 0 : break;
176 : }
177 0 : if (NULL != lh->stats_cb)
178 0 : lh->stats_cb (lh->stats_cb_cls,
179 : &lr);
180 0 : TALER_EXCHANGE_kyc_get_statistics_cancel (lh);
181 : }
182 :
183 :
184 : struct TALER_EXCHANGE_KycGetStatisticsHandle *
185 0 : 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 0 : const char *sd = NULL;
204 0 : const char *ed = NULL;
205 :
206 0 : if (! GNUNET_TIME_absolute_is_zero (start_date.abs_time))
207 : {
208 : unsigned long long sec;
209 :
210 0 : sec = (unsigned long long) GNUNET_TIME_timestamp_to_s (start_date);
211 0 : GNUNET_snprintf (sd_str,
212 : sizeof (sd_str),
213 : "%llu",
214 : sec);
215 0 : sd = sd_str;
216 : }
217 0 : if (! GNUNET_TIME_absolute_is_never (end_date.abs_time))
218 : {
219 : unsigned long long sec;
220 :
221 0 : sec = (unsigned long long) GNUNET_TIME_timestamp_to_s (end_date);
222 0 : GNUNET_snprintf (ed_str,
223 : sizeof (ed_str),
224 : "%llu",
225 : sec);
226 0 : ed = ed_str;
227 : }
228 0 : GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
229 : &officer_pub.eddsa_pub);
230 0 : TALER_officer_aml_query_sign (officer_priv,
231 : &officer_sig);
232 : {
233 : char pub_str[sizeof (officer_pub) * 2];
234 : char *end;
235 :
236 0 : end = GNUNET_STRINGS_data_to_string (
237 : &officer_pub,
238 : sizeof (officer_pub),
239 : pub_str,
240 : sizeof (pub_str));
241 0 : *end = '\0';
242 0 : GNUNET_snprintf (arg_str,
243 : sizeof (arg_str),
244 : "aml/%s/kyc-statistics/%s",
245 : pub_str,
246 : name);
247 : }
248 0 : lh = GNUNET_new (struct TALER_EXCHANGE_KycGetStatisticsHandle);
249 0 : lh->stats_cb = cb;
250 0 : lh->stats_cb_cls = cb_cls;
251 0 : lh->url = TALER_url_join (exchange_url,
252 : arg_str,
253 : "start_date",
254 : sd,
255 : "end_date",
256 : ed,
257 : NULL);
258 0 : if (NULL == lh->url)
259 : {
260 0 : GNUNET_free (lh);
261 0 : return NULL;
262 : }
263 0 : eh = TALER_EXCHANGE_curl_easy_get_ (lh->url);
264 0 : if (NULL == eh)
265 : {
266 0 : GNUNET_break (0);
267 0 : GNUNET_free (lh->url);
268 0 : GNUNET_free (lh);
269 0 : return NULL;
270 : }
271 : {
272 : char *hdr;
273 : char sig_str[sizeof (officer_sig) * 2];
274 : char *end;
275 :
276 0 : end = GNUNET_STRINGS_data_to_string (
277 : &officer_sig,
278 : sizeof (officer_sig),
279 : sig_str,
280 : sizeof (sig_str));
281 0 : *end = '\0';
282 :
283 0 : GNUNET_asprintf (&hdr,
284 : "%s: %s",
285 : TALER_AML_OFFICER_SIGNATURE_HEADER,
286 : sig_str);
287 0 : lh->job_headers = curl_slist_append (NULL,
288 : hdr);
289 0 : GNUNET_free (hdr);
290 0 : lh->job_headers = curl_slist_append (lh->job_headers,
291 : "Content-type: application/json");
292 0 : lh->job = GNUNET_CURL_job_add2 (ctx,
293 : eh,
294 0 : lh->job_headers,
295 : &handle_lookup_finished,
296 : lh);
297 : }
298 0 : return lh;
299 : }
300 :
301 :
302 : void
303 0 : TALER_EXCHANGE_kyc_get_statistics_cancel (
304 : struct TALER_EXCHANGE_KycGetStatisticsHandle *lh)
305 : {
306 0 : if (NULL != lh->job)
307 : {
308 0 : GNUNET_CURL_job_cancel (lh->job);
309 0 : lh->job = NULL;
310 : }
311 0 : curl_slist_free_all (lh->job_headers);
312 0 : GNUNET_free (lh->url);
313 0 : GNUNET_free (lh);
314 0 : }
315 :
316 :
317 : /* end of exchange_api_get_kyc_statistics.c */
|