Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2023, 2024, 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-aml-OFFICER_PUB-measures.c
19 : * @brief Implementation of the GET /aml/$OFFICER_PUB/measures 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 "taler/taler-exchange/get-aml-OFFICER_PUB-measures.h"
29 : #include "exchange_api_handle.h"
30 : #include "taler/taler_signatures.h"
31 : #include "exchange_api_curl_defaults.h"
32 :
33 :
34 : /**
35 : * Scrap buffer of temporary arrays.
36 : */
37 : struct Scrap
38 : {
39 : /**
40 : * Kept in DLL.
41 : */
42 : struct Scrap *next;
43 :
44 : /**
45 : * Kept in DLL.
46 : */
47 : struct Scrap *prev;
48 :
49 : /**
50 : * Pointer to our allocation.
51 : */
52 : const char **ptr;
53 : };
54 :
55 :
56 : /**
57 : * @brief A GET /aml/$OFFICER_PUB/measures Handle
58 : */
59 : struct TALER_EXCHANGE_GetAmlMeasuresHandle
60 : {
61 :
62 : /**
63 : * The base URL of the exchange.
64 : */
65 : char *base_url;
66 :
67 : /**
68 : * The full URL for this request, set during _start.
69 : */
70 : char *url;
71 :
72 : /**
73 : * Handle for the request.
74 : */
75 : struct GNUNET_CURL_Job *job;
76 :
77 : /**
78 : * Function to call with the result.
79 : */
80 : TALER_EXCHANGE_GetAmlMeasuresCallback cb;
81 :
82 : /**
83 : * Closure for @e cb.
84 : */
85 : TALER_EXCHANGE_GET_AML_MEASURES_RESULT_CLOSURE *cb_cls;
86 :
87 : /**
88 : * Reference to the execution context.
89 : */
90 : struct GNUNET_CURL_Context *ctx;
91 :
92 : /**
93 : * Public key of the AML officer.
94 : */
95 : struct TALER_AmlOfficerPublicKeyP officer_pub;
96 :
97 : /**
98 : * Private key of the AML officer (for signing).
99 : */
100 : struct TALER_AmlOfficerPrivateKeyP officer_priv;
101 :
102 : /**
103 : * Head of scrap list.
104 : */
105 : struct Scrap *scrap_head;
106 :
107 : /**
108 : * Tail of scrap list.
109 : */
110 : struct Scrap *scrap_tail;
111 : };
112 :
113 :
114 : /**
115 : * Create array of length @a len in scrap book.
116 : *
117 : * @param[in,out] amh context for allocations
118 : * @param len length of array
119 : * @return scrap array
120 : */
121 : static const char **
122 0 : make_scrap (
123 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
124 : unsigned int len)
125 : {
126 0 : struct Scrap *s = GNUNET_new (struct Scrap);
127 :
128 0 : s->ptr = GNUNET_new_array (len,
129 : const char *);
130 0 : GNUNET_CONTAINER_DLL_insert (amh->scrap_head,
131 : amh->scrap_tail,
132 : s);
133 0 : return s->ptr;
134 : }
135 :
136 :
137 : /**
138 : * Free all scrap space.
139 : *
140 : * @param[in,out] amh scrap context
141 : */
142 : static void
143 0 : free_scrap (struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh)
144 : {
145 : struct Scrap *s;
146 :
147 0 : while (NULL != (s = amh->scrap_head))
148 : {
149 0 : GNUNET_CONTAINER_DLL_remove (amh->scrap_head,
150 : amh->scrap_tail,
151 : s);
152 0 : GNUNET_free (s->ptr);
153 0 : GNUNET_free (s);
154 : }
155 0 : }
156 :
157 :
158 : /**
159 : * Convert JSON array of strings to string array.
160 : *
161 : * @param j JSON array to convert
162 : * @param[out] a array to initialize
163 : * @return true on success
164 : */
165 : static bool
166 0 : j_to_a (const json_t *j,
167 : const char **a)
168 : {
169 : const json_t *e;
170 : size_t idx;
171 :
172 0 : json_array_foreach ((json_t *) j, idx, e)
173 : {
174 0 : if (NULL == (a[idx] = json_string_value (e)))
175 0 : return false;
176 : }
177 0 : return true;
178 : }
179 :
180 :
181 : /**
182 : * Parse AML root measures.
183 : *
184 : * @param jroots JSON object with measure data
185 : * @param[out] roots where to write the result
186 : * @return #GNUNET_OK on success
187 : */
188 : static enum GNUNET_GenericReturnValue
189 0 : parse_aml_roots (
190 : const json_t *jroots,
191 : struct TALER_EXCHANGE_GetAmlMeasuresMeasureInfo *roots)
192 : {
193 : const json_t *obj;
194 : const char *name;
195 0 : size_t idx = 0;
196 :
197 0 : json_object_foreach ((json_t *) jroots, name, obj)
198 : {
199 0 : struct TALER_EXCHANGE_GetAmlMeasuresMeasureInfo *root = &roots[idx++];
200 : struct GNUNET_JSON_Specification spec[] = {
201 0 : GNUNET_JSON_spec_string ("check_name",
202 : &root->check_name),
203 0 : GNUNET_JSON_spec_mark_optional (
204 : GNUNET_JSON_spec_string ("prog_name",
205 : &root->prog_name),
206 : NULL),
207 0 : GNUNET_JSON_spec_mark_optional (
208 : GNUNET_JSON_spec_object_const ("context",
209 : &root->context),
210 : NULL),
211 0 : GNUNET_JSON_spec_mark_optional (
212 : GNUNET_JSON_spec_string ("operation_type",
213 : &root->operation_type),
214 : NULL),
215 0 : GNUNET_JSON_spec_mark_optional (
216 : GNUNET_JSON_spec_bool ("voluntary",
217 : &root->voluntary),
218 : NULL),
219 0 : GNUNET_JSON_spec_end ()
220 : };
221 :
222 0 : if (GNUNET_OK !=
223 0 : GNUNET_JSON_parse (obj,
224 : spec,
225 : NULL,
226 : NULL))
227 : {
228 0 : GNUNET_break_op (0);
229 0 : return GNUNET_SYSERR;
230 : }
231 0 : root->measure_name = name;
232 : }
233 0 : return GNUNET_OK;
234 : }
235 :
236 :
237 : /**
238 : * Parse AML programs.
239 : *
240 : * @param[in,out] amh context for allocations
241 : * @param jprogs JSON object with program data
242 : * @param[out] progs where to write the result
243 : * @return #GNUNET_OK on success
244 : */
245 : static enum GNUNET_GenericReturnValue
246 0 : parse_aml_programs (
247 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
248 : const json_t *jprogs,
249 : struct TALER_EXCHANGE_GetAmlMeasuresProgramRequirement *progs)
250 : {
251 : const json_t *obj;
252 : const char *name;
253 0 : size_t idx = 0;
254 :
255 0 : json_object_foreach ((json_t *) jprogs, name, obj)
256 : {
257 0 : struct TALER_EXCHANGE_GetAmlMeasuresProgramRequirement *prog = &progs[idx++]
258 : ;
259 : const json_t *jcontext;
260 : const json_t *jinputs;
261 : struct GNUNET_JSON_Specification spec[] = {
262 0 : GNUNET_JSON_spec_string ("description",
263 : &prog->description),
264 0 : GNUNET_JSON_spec_array_const ("context",
265 : &jcontext),
266 0 : GNUNET_JSON_spec_array_const ("inputs",
267 : &jinputs),
268 0 : GNUNET_JSON_spec_end ()
269 : };
270 : unsigned int len;
271 : const char **ptr;
272 :
273 0 : if (GNUNET_OK !=
274 0 : GNUNET_JSON_parse (obj,
275 : spec,
276 : NULL,
277 : NULL))
278 : {
279 0 : GNUNET_break_op (0);
280 0 : return GNUNET_SYSERR;
281 : }
282 0 : prog->prog_name = name;
283 0 : prog->contexts_length = json_array_size (jcontext);
284 0 : prog->inputs_length = json_array_size (jinputs);
285 0 : len = (unsigned int) (prog->contexts_length + prog->inputs_length);
286 0 : if ( ((size_t) len) != prog->contexts_length + prog->inputs_length)
287 : {
288 0 : GNUNET_break_op (0);
289 0 : return GNUNET_SYSERR;
290 : }
291 0 : ptr = make_scrap (amh, len);
292 0 : prog->contexts = ptr;
293 0 : if (! j_to_a (jcontext, prog->contexts))
294 : {
295 0 : GNUNET_break_op (0);
296 0 : return GNUNET_SYSERR;
297 : }
298 0 : prog->inputs = &ptr[prog->contexts_length];
299 0 : if (! j_to_a (jinputs, prog->inputs))
300 : {
301 0 : GNUNET_break_op (0);
302 0 : return GNUNET_SYSERR;
303 : }
304 : }
305 0 : return GNUNET_OK;
306 : }
307 :
308 :
309 : /**
310 : * Parse KYC checks.
311 : *
312 : * @param[in,out] amh context for allocations
313 : * @param jchecks JSON object with check data
314 : * @param[out] checks where to write the result
315 : * @return #GNUNET_OK on success
316 : */
317 : static enum GNUNET_GenericReturnValue
318 0 : parse_aml_checks (
319 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
320 : const json_t *jchecks,
321 : struct TALER_EXCHANGE_GetAmlMeasuresCheckInfo *checks)
322 : {
323 : const json_t *obj;
324 : const char *name;
325 0 : size_t idx = 0;
326 :
327 0 : json_object_foreach ((json_t *) jchecks, name, obj)
328 : {
329 0 : struct TALER_EXCHANGE_GetAmlMeasuresCheckInfo *check = &checks[idx++];
330 : const json_t *jrequires;
331 : const json_t *joutputs;
332 : struct GNUNET_JSON_Specification spec[] = {
333 0 : GNUNET_JSON_spec_string ("description",
334 : &check->description),
335 0 : GNUNET_JSON_spec_mark_optional (
336 : GNUNET_JSON_spec_object_const ("description_i18n",
337 : &check->description_i18n),
338 : NULL),
339 0 : GNUNET_JSON_spec_array_const ("requires",
340 : &jrequires),
341 0 : GNUNET_JSON_spec_array_const ("outputs",
342 : &joutputs),
343 0 : GNUNET_JSON_spec_string ("fallback",
344 : &check->fallback),
345 0 : GNUNET_JSON_spec_end ()
346 : };
347 : unsigned int len;
348 : const char **ptr;
349 :
350 0 : if (GNUNET_OK !=
351 0 : GNUNET_JSON_parse (obj,
352 : spec,
353 : NULL,
354 : NULL))
355 : {
356 0 : GNUNET_break_op (0);
357 0 : return GNUNET_SYSERR;
358 : }
359 0 : check->check_name = name;
360 0 : check->requires_length = json_array_size (jrequires);
361 0 : check->outputs_length = json_array_size (joutputs);
362 0 : len = (unsigned int) (check->requires_length + check->outputs_length);
363 0 : if ( ((size_t) len) != check->requires_length + check->outputs_length)
364 : {
365 0 : GNUNET_break_op (0);
366 0 : return GNUNET_SYSERR;
367 : }
368 0 : ptr = make_scrap (amh, len);
369 0 : check->requires = ptr;
370 0 : if (! j_to_a (jrequires, check->requires))
371 : {
372 0 : GNUNET_break_op (0);
373 0 : return GNUNET_SYSERR;
374 : }
375 0 : check->outputs = &ptr[check->requires_length];
376 0 : if (! j_to_a (joutputs, check->outputs))
377 : {
378 0 : GNUNET_break_op (0);
379 0 : return GNUNET_SYSERR;
380 : }
381 : }
382 0 : return GNUNET_OK;
383 : }
384 :
385 :
386 : /**
387 : * Parse default KYC rules from the default_rules array.
388 : *
389 : * @param[in,out] amh context for allocations
390 : * @param jrules JSON array with rule data
391 : * @param[out] rules where to write the result
392 : * @return #GNUNET_OK on success
393 : */
394 : static enum GNUNET_GenericReturnValue
395 0 : parse_default_rules (
396 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
397 : const json_t *jrules,
398 : struct TALER_EXCHANGE_GetAmlMeasuresKycRule *rules)
399 : {
400 : const json_t *obj;
401 : size_t idx;
402 :
403 0 : json_array_foreach ((json_t *) jrules, idx, obj)
404 : {
405 0 : struct TALER_EXCHANGE_GetAmlMeasuresKycRule *rule = &rules[idx];
406 : const json_t *jmeasures;
407 : struct GNUNET_JSON_Specification spec[] = {
408 0 : TALER_JSON_spec_kycte ("operation_type",
409 : &rule->operation_type),
410 0 : GNUNET_JSON_spec_mark_optional (
411 : GNUNET_JSON_spec_string ("rule_name",
412 : &rule->rule_name),
413 : NULL),
414 0 : TALER_JSON_spec_amount_any ("threshold",
415 : &rule->threshold),
416 0 : GNUNET_JSON_spec_relative_time ("timeframe",
417 : &rule->timeframe),
418 0 : GNUNET_JSON_spec_array_const ("measures",
419 : &jmeasures),
420 0 : GNUNET_JSON_spec_mark_optional (
421 : GNUNET_JSON_spec_bool ("exposed",
422 : &rule->exposed),
423 : NULL),
424 0 : GNUNET_JSON_spec_mark_optional (
425 : GNUNET_JSON_spec_bool ("is_and_combinator",
426 : &rule->is_and_combinator),
427 : NULL),
428 0 : GNUNET_JSON_spec_int64 ("display_priority",
429 : &rule->display_priority),
430 0 : GNUNET_JSON_spec_end ()
431 : };
432 :
433 0 : if (GNUNET_OK !=
434 0 : GNUNET_JSON_parse (obj,
435 : spec,
436 : NULL,
437 : NULL))
438 : {
439 0 : GNUNET_break_op (0);
440 0 : return GNUNET_SYSERR;
441 : }
442 0 : rule->measures_length = json_array_size (jmeasures);
443 : {
444 0 : const char **ptr = make_scrap (amh,
445 0 : (unsigned int) rule->measures_length);
446 :
447 0 : rule->measures = ptr;
448 0 : if (! j_to_a (jmeasures,
449 : ptr))
450 : {
451 0 : GNUNET_break_op (0);
452 0 : return GNUNET_SYSERR;
453 : }
454 : }
455 : }
456 0 : return GNUNET_OK;
457 : }
458 :
459 :
460 : /**
461 : * Parse the provided measures data from the "200 OK" response.
462 : *
463 : * @param[in,out] amh handle (callback may be zero'ed out)
464 : * @param json json reply with the data
465 : * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
466 : */
467 : static enum GNUNET_GenericReturnValue
468 0 : parse_get_aml_measures_ok (struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
469 : const json_t *json)
470 : {
471 0 : struct TALER_EXCHANGE_GetAmlMeasuresResponse lr = {
472 : .hr.reply = json,
473 : .hr.http_status = MHD_HTTP_OK
474 : };
475 : const json_t *jroots;
476 : const json_t *jprograms;
477 : const json_t *jchecks;
478 0 : const json_t *jdefault_rules = NULL;
479 : struct GNUNET_JSON_Specification spec[] = {
480 0 : GNUNET_JSON_spec_object_const ("roots",
481 : &jroots),
482 0 : GNUNET_JSON_spec_object_const ("programs",
483 : &jprograms),
484 0 : GNUNET_JSON_spec_object_const ("checks",
485 : &jchecks),
486 0 : GNUNET_JSON_spec_mark_optional (
487 : GNUNET_JSON_spec_array_const ("default_rules",
488 : &jdefault_rules),
489 : NULL),
490 0 : GNUNET_JSON_spec_end ()
491 : };
492 :
493 0 : if (GNUNET_OK !=
494 0 : GNUNET_JSON_parse (json,
495 : spec,
496 : NULL,
497 : NULL))
498 : {
499 0 : GNUNET_break_op (0);
500 0 : return GNUNET_SYSERR;
501 : }
502 :
503 0 : lr.details.ok.roots_length = json_object_size (jroots);
504 0 : lr.details.ok.programs_length = json_object_size (jprograms);
505 0 : lr.details.ok.checks_length = json_object_size (jchecks);
506 0 : lr.details.ok.default_rules_length =
507 0 : (NULL != jdefault_rules) ? json_array_size (jdefault_rules) : 0;
508 :
509 0 : {
510 0 : struct TALER_EXCHANGE_GetAmlMeasuresMeasureInfo roots[
511 0 : GNUNET_NZL (lr.details.ok.roots_length)];
512 0 : struct TALER_EXCHANGE_GetAmlMeasuresProgramRequirement progs[
513 0 : GNUNET_NZL (lr.details.ok.programs_length)];
514 0 : struct TALER_EXCHANGE_GetAmlMeasuresCheckInfo checks[
515 0 : GNUNET_NZL (lr.details.ok.checks_length)];
516 0 : struct TALER_EXCHANGE_GetAmlMeasuresKycRule drules[
517 0 : GNUNET_NZL (lr.details.ok.default_rules_length)];
518 : enum GNUNET_GenericReturnValue ret;
519 :
520 0 : memset (roots, 0, sizeof (roots));
521 0 : memset (progs, 0, sizeof (progs));
522 0 : memset (checks, 0, sizeof (checks));
523 0 : memset (drules, 0, sizeof (drules));
524 0 : lr.details.ok.roots = roots;
525 0 : lr.details.ok.programs = progs;
526 0 : lr.details.ok.checks = checks;
527 0 : lr.details.ok.default_rules = drules;
528 :
529 0 : ret = parse_aml_roots (jroots, roots);
530 0 : if (GNUNET_OK == ret)
531 0 : ret = parse_aml_programs (amh, jprograms, progs);
532 0 : if (GNUNET_OK == ret)
533 0 : ret = parse_aml_checks (amh, jchecks, checks);
534 0 : if ( (GNUNET_OK == ret) && (NULL != jdefault_rules) )
535 0 : ret = parse_default_rules (amh, jdefault_rules, drules);
536 0 : if (GNUNET_OK == ret)
537 : {
538 0 : amh->cb (amh->cb_cls,
539 : &lr);
540 0 : amh->cb = NULL;
541 : }
542 0 : free_scrap (amh);
543 0 : return ret;
544 : }
545 : }
546 :
547 :
548 : /**
549 : * Function called when we're done processing the
550 : * HTTP GET /aml/$OFFICER_PUB/measures request.
551 : *
552 : * @param cls the `struct TALER_EXCHANGE_GetAmlMeasuresHandle`
553 : * @param response_code HTTP response code, 0 on error
554 : * @param response parsed JSON result, NULL on error
555 : */
556 : static void
557 0 : handle_get_aml_measures_finished (void *cls,
558 : long response_code,
559 : const void *response)
560 : {
561 0 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh = cls;
562 0 : const json_t *j = response;
563 0 : struct TALER_EXCHANGE_GetAmlMeasuresResponse lr = {
564 : .hr.reply = j,
565 0 : .hr.http_status = (unsigned int) response_code
566 : };
567 :
568 0 : amh->job = NULL;
569 0 : switch (response_code)
570 : {
571 0 : case 0:
572 0 : lr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
573 0 : break;
574 0 : case MHD_HTTP_OK:
575 0 : if (GNUNET_OK !=
576 0 : parse_get_aml_measures_ok (amh,
577 : j))
578 : {
579 0 : GNUNET_break_op (0);
580 0 : lr.hr.http_status = 0;
581 0 : lr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
582 0 : break;
583 : }
584 0 : GNUNET_assert (NULL == amh->cb);
585 0 : TALER_EXCHANGE_get_aml_measures_cancel (amh);
586 0 : return;
587 0 : case MHD_HTTP_NO_CONTENT:
588 0 : break;
589 0 : case MHD_HTTP_BAD_REQUEST:
590 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
591 0 : lr.hr.hint = TALER_JSON_get_error_hint (j);
592 0 : break;
593 0 : case MHD_HTTP_FORBIDDEN:
594 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
595 0 : lr.hr.hint = TALER_JSON_get_error_hint (j);
596 0 : break;
597 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
598 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
599 0 : lr.hr.hint = TALER_JSON_get_error_hint (j);
600 0 : break;
601 0 : default:
602 : /* unexpected response code */
603 0 : GNUNET_break_op (0);
604 0 : lr.hr.ec = TALER_JSON_get_error_code (j);
605 0 : lr.hr.hint = TALER_JSON_get_error_hint (j);
606 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
607 : "Unexpected response code %u/%d for GET AML measures\n",
608 : (unsigned int) response_code,
609 : (int) lr.hr.ec);
610 0 : break;
611 : }
612 0 : if (NULL != amh->cb)
613 0 : amh->cb (amh->cb_cls,
614 : &lr);
615 0 : TALER_EXCHANGE_get_aml_measures_cancel (amh);
616 : }
617 :
618 :
619 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *
620 0 : TALER_EXCHANGE_get_aml_measures_create (
621 : struct GNUNET_CURL_Context *ctx,
622 : const char *url,
623 : const struct TALER_AmlOfficerPrivateKeyP *officer_priv)
624 : {
625 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh;
626 :
627 0 : amh = GNUNET_new (struct TALER_EXCHANGE_GetAmlMeasuresHandle);
628 0 : amh->ctx = ctx;
629 0 : amh->base_url = GNUNET_strdup (url);
630 0 : amh->officer_priv = *officer_priv;
631 0 : GNUNET_CRYPTO_eddsa_key_get_public (&officer_priv->eddsa_priv,
632 : &amh->officer_pub.eddsa_pub);
633 0 : return amh;
634 : }
635 :
636 :
637 : enum TALER_ErrorCode
638 0 : TALER_EXCHANGE_get_aml_measures_start (
639 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh,
640 : TALER_EXCHANGE_GetAmlMeasuresCallback cb,
641 : TALER_EXCHANGE_GET_AML_MEASURES_RESULT_CLOSURE *cb_cls)
642 : {
643 : CURL *eh;
644 : struct TALER_AmlOfficerSignatureP officer_sig;
645 : char arg_str[sizeof (struct TALER_AmlOfficerPublicKeyP) * 2 + 32];
646 0 : struct curl_slist *job_headers = NULL;
647 :
648 0 : amh->cb = cb;
649 0 : amh->cb_cls = cb_cls;
650 :
651 : /* Build AML officer signature */
652 0 : TALER_officer_aml_query_sign (&amh->officer_priv,
653 : &officer_sig);
654 :
655 : /* Build the path component: aml/{officer_pub}/measures */
656 : {
657 : char pub_str[sizeof (amh->officer_pub) * 2];
658 : char *end;
659 :
660 0 : end = GNUNET_STRINGS_data_to_string (
661 0 : &amh->officer_pub,
662 : sizeof (amh->officer_pub),
663 : pub_str,
664 : sizeof (pub_str));
665 0 : *end = '\0';
666 0 : GNUNET_snprintf (arg_str,
667 : sizeof (arg_str),
668 : "aml/%s/measures",
669 : pub_str);
670 : }
671 :
672 0 : amh->url = TALER_url_join (amh->base_url,
673 : arg_str,
674 : NULL);
675 0 : if (NULL == amh->url)
676 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
677 :
678 0 : eh = TALER_EXCHANGE_curl_easy_get_ (amh->url);
679 0 : if (NULL == eh)
680 : {
681 0 : GNUNET_break (0);
682 0 : GNUNET_free (amh->url);
683 0 : amh->url = NULL;
684 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
685 : }
686 :
687 : /* Build job headers with AML officer signature */
688 : {
689 : char *hdr;
690 : char sig_str[sizeof (officer_sig) * 2];
691 : char *end;
692 :
693 0 : end = GNUNET_STRINGS_data_to_string (
694 : &officer_sig,
695 : sizeof (officer_sig),
696 : sig_str,
697 : sizeof (sig_str));
698 0 : *end = '\0';
699 :
700 0 : GNUNET_asprintf (&hdr,
701 : "%s: %s",
702 : TALER_AML_OFFICER_SIGNATURE_HEADER,
703 : sig_str);
704 0 : job_headers = curl_slist_append (NULL,
705 : hdr);
706 0 : GNUNET_free (hdr);
707 0 : job_headers = curl_slist_append (job_headers,
708 : "Content-Type: application/json");
709 : }
710 :
711 0 : amh->job = GNUNET_CURL_job_add2 (amh->ctx,
712 : eh,
713 : job_headers,
714 : &handle_get_aml_measures_finished,
715 : amh);
716 0 : curl_slist_free_all (job_headers);
717 :
718 0 : if (NULL == amh->job)
719 : {
720 0 : GNUNET_free (amh->url);
721 0 : amh->url = NULL;
722 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
723 : }
724 0 : return TALER_EC_NONE;
725 : }
726 :
727 :
728 : void
729 0 : TALER_EXCHANGE_get_aml_measures_cancel (
730 : struct TALER_EXCHANGE_GetAmlMeasuresHandle *amh)
731 : {
732 0 : if (NULL != amh->job)
733 : {
734 0 : GNUNET_CURL_job_cancel (amh->job);
735 0 : amh->job = NULL;
736 : }
737 0 : free_scrap (amh);
738 0 : GNUNET_free (amh->url);
739 0 : GNUNET_free (amh->base_url);
740 0 : GNUNET_free (amh);
741 0 : }
742 :
743 :
744 : /* end of exchange_api_get-aml-OFFICER_PUB-measures.c */
|