Line data Source code
1 : /*
2 : This file is part of GNU Taler
3 : (C) 2021-2024 Taler Systems SA
4 :
5 : GNU Taler is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Affero General Public License as
7 : published by the Free Software Foundation; either version 3,
8 : or (at your option) any later version.
9 :
10 : GNU Taler is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not,
17 : see <http://www.gnu.org/licenses/>
18 : */
19 :
20 : /**
21 : * @file taler-merchant-httpd_private-get-instances-ID-kyc.c
22 : * @brief implementing GET /instances/$ID/kyc request handling
23 : * @author Christian Grothoff
24 : */
25 : #include "platform.h"
26 : #include "taler-merchant-httpd_private-get-instances-ID-kyc.h"
27 : #include "taler-merchant-httpd_helper.h"
28 : #include "taler-merchant-httpd_exchanges.h"
29 : #include <taler/taler_json_lib.h>
30 : #include <taler/taler_dbevents.h>
31 : #include <regex.h>
32 :
33 : /**
34 : * Information we keep per /kyc request.
35 : */
36 : struct KycContext;
37 :
38 :
39 : /**
40 : * Structure for tracking requests to the exchange's
41 : * ``/kyc-check`` API.
42 : */
43 : struct ExchangeKycRequest
44 : {
45 : /**
46 : * Kept in a DLL.
47 : */
48 : struct ExchangeKycRequest *next;
49 :
50 : /**
51 : * Kept in a DLL.
52 : */
53 : struct ExchangeKycRequest *prev;
54 :
55 : /**
56 : * Find operation where we connect to the respective exchange.
57 : */
58 : struct TMH_EXCHANGES_KeysOperation *fo;
59 :
60 : /**
61 : * JSON array of payto-URIs with KYC auth wire transfer
62 : * instructions. Provided if @e auth_ok is false and
63 : * @e kyc_auth_conflict is false.
64 : */
65 : json_t *pkaa;
66 :
67 : /**
68 : * The keys of the exchange.
69 : */
70 : struct TALER_EXCHANGE_Keys *keys;
71 :
72 : /**
73 : * KYC request this exchange request is made for.
74 : */
75 : struct KycContext *kc;
76 :
77 : /**
78 : * JSON array of AccountLimits that apply, NULL if
79 : * unknown (and likely defaults apply).
80 : */
81 : json_t *jlimits;
82 :
83 : /**
84 : * Our account's payto URI.
85 : */
86 : struct TALER_FullPayto payto_uri;
87 :
88 : /**
89 : * Base URL of the exchange.
90 : */
91 : char *exchange_url;
92 :
93 : /**
94 : * Hash of the wire account (with salt) we are checking.
95 : */
96 : struct TALER_MerchantWireHashP h_wire;
97 :
98 : /**
99 : * Current access token for the KYC SPA. Only set
100 : * if @e auth_ok is true.
101 : */
102 : struct TALER_AccountAccessTokenP access_token;
103 :
104 : /**
105 : * Timestamp when we last got a reply from the exchange.
106 : */
107 : struct GNUNET_TIME_Timestamp last_check;
108 :
109 : /**
110 : * Last HTTP status code obtained via /kyc-check from
111 : * the exchange.
112 : */
113 : unsigned int last_http_status;
114 :
115 : /**
116 : * Last Taler error code returned from /kyc-check.
117 : */
118 : enum TALER_ErrorCode last_ec;
119 :
120 : /**
121 : * True if this account
122 : * cannot work at this exchange because KYC auth is
123 : * impossible.
124 : */
125 : bool kyc_auth_conflict;
126 :
127 : /**
128 : * We could not get /keys from the exchange.
129 : */
130 : bool no_keys;
131 :
132 : /**
133 : * True if @e access_token is available.
134 : */
135 : bool auth_ok;
136 :
137 : /**
138 : * True if we believe no KYC is currently required
139 : * for this account at this exchange.
140 : */
141 : bool kyc_ok;
142 :
143 : /**
144 : * True if the exchange exposed to us that the account
145 : * is currently under AML review.
146 : */
147 : bool in_aml_review;
148 :
149 :
150 : };
151 :
152 :
153 : /**
154 : * Information we keep per /kyc request.
155 : */
156 : struct KycContext
157 : {
158 : /**
159 : * Stored in a DLL.
160 : */
161 : struct KycContext *next;
162 :
163 : /**
164 : * Stored in a DLL.
165 : */
166 : struct KycContext *prev;
167 :
168 : /**
169 : * Connection we are handling.
170 : */
171 : struct MHD_Connection *connection;
172 :
173 : /**
174 : * Instance we are serving.
175 : */
176 : struct TMH_MerchantInstance *mi;
177 :
178 : /**
179 : * Our handler context.
180 : */
181 : struct TMH_HandlerContext *hc;
182 :
183 : /**
184 : * Response to return, NULL if we don't have one yet.
185 : */
186 : struct MHD_Response *response;
187 :
188 : /**
189 : * JSON array where we are building up the array with
190 : * pending KYC operations.
191 : */
192 : json_t *kycs_data;
193 :
194 : /**
195 : * Head of DLL of requests we are making to an
196 : * exchange to inquire about the latest KYC status.
197 : */
198 : struct ExchangeKycRequest *exchange_pending_head;
199 :
200 : /**
201 : * Tail of DLL of requests we are making to an
202 : * exchange to inquire about the latest KYC status.
203 : */
204 : struct ExchangeKycRequest *exchange_pending_tail;
205 :
206 : /**
207 : * Set to the exchange URL, or NULL to not filter by
208 : * exchange.
209 : */
210 : const char *exchange_url;
211 :
212 : /**
213 : * Notification handler from database on changes
214 : * to the KYC status.
215 : */
216 : struct GNUNET_DB_EventHandler *eh;
217 :
218 : /**
219 : * Set to the h_wire of the merchant account if
220 : * @a have_h_wire is true, used to filter by account.
221 : */
222 : struct TALER_MerchantWireHashP h_wire;
223 :
224 : /**
225 : * How long are we willing to wait for the exchange(s)?
226 : */
227 : struct GNUNET_TIME_Absolute timeout;
228 :
229 : /**
230 : * HTTP status code to use for the reply, i.e 200 for "OK".
231 : * Special value UINT_MAX is used to indicate hard errors
232 : * (no reply, return #MHD_NO).
233 : */
234 : unsigned int response_code;
235 :
236 : /**
237 : * #GNUNET_NO if the @e connection was not suspended,
238 : * #GNUNET_YES if the @e connection was suspended,
239 : * #GNUNET_SYSERR if @e connection was resumed to as
240 : * part of #MH_force_pc_resume during shutdown.
241 : */
242 : enum GNUNET_GenericReturnValue suspended;
243 :
244 : /**
245 : * What state are we long-polling for?
246 : */
247 : enum TALER_EXCHANGE_KycLongPollTarget lpt;
248 :
249 : /**
250 : * True if @e h_wire was given.
251 : */
252 : bool have_h_wire;
253 :
254 : /**
255 : * We're still waiting on the exchange to determine
256 : * the KYC status of our deposit(s).
257 : */
258 : bool return_immediately;
259 :
260 : };
261 :
262 :
263 : /**
264 : * Head of DLL.
265 : */
266 : static struct KycContext *kc_head;
267 :
268 : /**
269 : * Tail of DLL.
270 : */
271 : static struct KycContext *kc_tail;
272 :
273 :
274 : void
275 15 : TMH_force_kyc_resume ()
276 : {
277 15 : for (struct KycContext *kc = kc_head;
278 15 : NULL != kc;
279 0 : kc = kc->next)
280 : {
281 0 : if (GNUNET_YES == kc->suspended)
282 : {
283 0 : kc->suspended = GNUNET_SYSERR;
284 0 : MHD_resume_connection (kc->connection);
285 : }
286 : }
287 15 : }
288 :
289 :
290 : /**
291 : * Custom cleanup routine for a `struct KycContext`.
292 : *
293 : * @param cls the `struct KycContext` to clean up.
294 : */
295 : static void
296 9 : kyc_context_cleanup (void *cls)
297 : {
298 9 : struct KycContext *kc = cls;
299 : struct ExchangeKycRequest *ekr;
300 :
301 9 : while (NULL != (ekr = kc->exchange_pending_head))
302 : {
303 0 : GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
304 : kc->exchange_pending_tail,
305 : ekr);
306 0 : if (NULL != ekr->fo)
307 : {
308 0 : TMH_EXCHANGES_keys4exchange_cancel (ekr->fo);
309 0 : ekr->fo = NULL;
310 : }
311 0 : json_decref (ekr->pkaa);
312 0 : json_decref (ekr->jlimits);
313 0 : if (NULL != ekr->keys)
314 0 : TALER_EXCHANGE_keys_decref (ekr->keys);
315 0 : GNUNET_free (ekr->exchange_url);
316 0 : GNUNET_free (ekr->payto_uri.full_payto);
317 0 : GNUNET_free (ekr);
318 : }
319 9 : if (NULL != kc->eh)
320 : {
321 4 : TMH_db->event_listen_cancel (kc->eh);
322 4 : kc->eh = NULL;
323 : }
324 9 : if (NULL != kc->response)
325 : {
326 7 : MHD_destroy_response (kc->response);
327 7 : kc->response = NULL;
328 : }
329 9 : GNUNET_CONTAINER_DLL_remove (kc_head,
330 : kc_tail,
331 : kc);
332 9 : json_decref (kc->kycs_data);
333 9 : GNUNET_free (kc);
334 9 : }
335 :
336 :
337 : /**
338 : * Resume the given KYC context and send the final response. Stores the
339 : * response in the @a kc and signals MHD to resume the connection. Also
340 : * ensures MHD runs immediately.
341 : *
342 : * @param kc KYC context
343 : */
344 : static void
345 7 : resume_kyc_with_response (struct KycContext *kc)
346 : {
347 7 : kc->response_code = MHD_HTTP_OK;
348 7 : kc->response = TALER_MHD_MAKE_JSON_PACK (
349 : GNUNET_JSON_pack_array_incref ("kyc_data",
350 : kc->kycs_data));
351 7 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
352 : "Resuming /kyc handling as exchange interaction is done (%u)\n",
353 : MHD_HTTP_OK);
354 7 : if (GNUNET_YES == kc->suspended)
355 : {
356 3 : kc->suspended = GNUNET_NO;
357 3 : MHD_resume_connection (kc->connection);
358 3 : TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
359 : }
360 7 : }
361 :
362 :
363 : /**
364 : * Handle a DB event about an update relevant
365 : * for the processing of the kyc request.
366 : *
367 : * @param cls our `struct KycContext`
368 : * @param extra additional event data provided
369 : * @param extra_size number of bytes in @a extra
370 : */
371 : static void
372 1 : kyc_change_cb (void *cls,
373 : const void *extra,
374 : size_t extra_size)
375 : {
376 1 : struct KycContext *kc = cls;
377 :
378 1 : if (GNUNET_YES == kc->suspended)
379 : {
380 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 : "Resuming KYC with gateway timeout\n");
382 1 : kc->suspended = GNUNET_NO;
383 1 : MHD_resume_connection (kc->connection);
384 1 : TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
385 : }
386 1 : }
387 :
388 :
389 : /**
390 : * Pack the given @a limit into the JSON @a limits array.
391 : *
392 : * @param limit account limit to pack
393 : * @param[in,out] limits JSON array to extend
394 : */
395 : static void
396 0 : pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
397 : json_t *limits)
398 : {
399 : json_t *jl;
400 :
401 0 : jl = GNUNET_JSON_PACK (
402 : TALER_JSON_pack_kycte ("operation_type",
403 : limit->operation_type),
404 : GNUNET_JSON_pack_time_rel ("timeframe",
405 : limit->timeframe),
406 : TALER_JSON_pack_amount ("threshold",
407 : &limit->threshold),
408 : GNUNET_JSON_pack_bool ("soft_limit",
409 : limit->soft_limit)
410 : );
411 0 : GNUNET_assert (0 ==
412 : json_array_append_new (limits,
413 : jl));
414 0 : }
415 :
416 :
417 : /**
418 : * Return JSON array with AccountLimit objects giving
419 : * the current limits for this exchange.
420 : *
421 : * @param[in,out] ekr overall request context
422 : */
423 : static json_t *
424 9 : get_exchange_limits (
425 : struct ExchangeKycRequest *ekr)
426 : {
427 9 : const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
428 : json_t *limits;
429 :
430 9 : if (NULL != ekr->jlimits)
431 : {
432 4 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
433 : "Returning custom KYC limits\n");
434 4 : return json_incref (ekr->jlimits);
435 : }
436 5 : if (NULL == keys)
437 : {
438 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
439 : "No keys, thus no default KYC limits known\n");
440 0 : return NULL;
441 : }
442 5 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
443 : "Returning default KYC limits (%u/%u)\n",
444 : keys->hard_limits_length,
445 : keys->zero_limits_length);
446 5 : limits = json_array ();
447 5 : GNUNET_assert (NULL != limits);
448 5 : for (unsigned int i = 0; i<keys->hard_limits_length; i++)
449 : {
450 0 : const struct TALER_EXCHANGE_AccountLimit *limit
451 0 : = &keys->hard_limits[i];
452 :
453 0 : pack_limit (limit,
454 : limits);
455 : }
456 7 : for (unsigned int i = 0; i<keys->zero_limits_length; i++)
457 : {
458 2 : const struct TALER_EXCHANGE_ZeroLimitedOperation *zlimit
459 2 : = &keys->zero_limits[i];
460 : json_t *jl;
461 : struct TALER_Amount zero;
462 :
463 2 : GNUNET_assert (GNUNET_OK ==
464 : TALER_amount_set_zero (keys->currency,
465 : &zero));
466 2 : jl = GNUNET_JSON_PACK (
467 : TALER_JSON_pack_kycte ("operation_type",
468 : zlimit->operation_type),
469 : GNUNET_JSON_pack_time_rel ("timeframe",
470 : GNUNET_TIME_UNIT_ZERO),
471 : TALER_JSON_pack_amount ("threshold",
472 : &zero),
473 : GNUNET_JSON_pack_bool ("soft_limit",
474 : true)
475 : );
476 2 : GNUNET_assert (0 ==
477 : json_array_append_new (limits,
478 : jl));
479 : }
480 5 : return limits;
481 : }
482 :
483 :
484 : /**
485 : * Maps @a ekr to a status code for clients to interpret the
486 : * overall result.
487 : *
488 : * @param ekr request summary
489 : * @return status of the KYC state as a string
490 : */
491 : static const char *
492 9 : map_to_status (const struct ExchangeKycRequest *ekr)
493 : {
494 9 : if (ekr->no_keys)
495 : {
496 0 : return "no-exchange-keys";
497 : }
498 9 : if (ekr->kyc_ok)
499 : {
500 7 : if (NULL != ekr->jlimits)
501 : {
502 : size_t off;
503 : json_t *limit;
504 4 : json_array_foreach (ekr->jlimits, off, limit)
505 : {
506 : struct TALER_Amount threshold;
507 : enum TALER_KYCLOGIC_KycTriggerEvent operation_type;
508 4 : bool soft = false;
509 : struct GNUNET_JSON_Specification spec[] = {
510 4 : TALER_JSON_spec_kycte ("operation_type",
511 : &operation_type),
512 4 : TALER_JSON_spec_amount_any ("threshold",
513 : &threshold),
514 4 : GNUNET_JSON_spec_mark_optional (
515 : GNUNET_JSON_spec_bool ("soft_limit",
516 : &soft),
517 : NULL),
518 4 : GNUNET_JSON_spec_end ()
519 : };
520 :
521 4 : if (GNUNET_OK !=
522 4 : GNUNET_JSON_parse (limit,
523 : spec,
524 : NULL, NULL))
525 : {
526 0 : GNUNET_break (0);
527 4 : return "merchant-internal-error";
528 : }
529 4 : if (! TALER_amount_is_zero (&threshold))
530 0 : continue; /* only care about zero-limits */
531 4 : if (! soft)
532 0 : continue; /* only care about soft limits */
533 4 : if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
534 4 : (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
535 0 : (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
536 : {
537 4 : if (! ekr->auth_ok)
538 : {
539 0 : if (ekr->kyc_auth_conflict)
540 0 : return "kyc-wire-impossible";
541 0 : return "kyc-wire-required";
542 : }
543 4 : return "kyc-required";
544 : }
545 : }
546 : }
547 3 : if (NULL == ekr->jlimits)
548 : {
549 : /* check default limits */
550 3 : const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
551 :
552 3 : for (unsigned int i = 0; i < keys->zero_limits_length; i++)
553 : {
554 0 : enum TALER_KYCLOGIC_KycTriggerEvent operation_type
555 0 : = keys->zero_limits[i].operation_type;
556 :
557 0 : if ( (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
558 0 : (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE) ||
559 : (operation_type == TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION) )
560 : {
561 0 : if (! ekr->auth_ok)
562 : {
563 0 : if (ekr->kyc_auth_conflict)
564 0 : return "kyc-wire-impossible";
565 0 : return "kyc-wire-required";
566 : }
567 0 : return "kyc-required";
568 : }
569 : }
570 : }
571 3 : return "ready";
572 : }
573 2 : if (! ekr->auth_ok)
574 : {
575 2 : if (ekr->kyc_auth_conflict)
576 0 : return "kyc-wire-impossible";
577 2 : return "kyc-wire-required";
578 : }
579 0 : if (ekr->in_aml_review)
580 0 : return "awaiting-aml-review";
581 0 : switch (ekr->last_http_status)
582 : {
583 0 : case 0:
584 0 : return "exchange-unreachable";
585 0 : case MHD_HTTP_OK:
586 : /* then we should have kyc_ok */
587 0 : GNUNET_break (0);
588 0 : return NULL;
589 0 : case MHD_HTTP_ACCEPTED:
590 : /* Then KYC is really what is needed */
591 0 : return "kyc-required";
592 0 : case MHD_HTTP_NO_CONTENT:
593 : /* then we should have had kyc_ok! */
594 0 : GNUNET_break (0);
595 0 : return NULL;
596 0 : case MHD_HTTP_FORBIDDEN:
597 : /* then we should have had ! auth_ok */
598 0 : GNUNET_break (0);
599 0 : return NULL;
600 0 : case MHD_HTTP_NOT_FOUND:
601 : /* then we should have had ! auth_ok */
602 0 : GNUNET_break (0);
603 0 : return NULL;
604 0 : case MHD_HTTP_CONFLICT:
605 : /* then we should have had ! auth_ok */
606 0 : GNUNET_break (0);
607 0 : return NULL;
608 0 : case MHD_HTTP_INTERNAL_SERVER_ERROR:
609 0 : return "exchange-internal-error";
610 0 : case MHD_HTTP_GATEWAY_TIMEOUT:
611 0 : return "exchange-gateway-timeout";
612 0 : default:
613 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
614 : "Exchange responded with unexpected HTTP status %u to /kyc-check request!\n",
615 : ekr->last_http_status);
616 0 : break;
617 : }
618 0 : return "exchange-status-invalid";
619 : }
620 :
621 :
622 : /**
623 : * Take data from @a ekr to expand our response.
624 : *
625 : * @param ekr exchange we are done inspecting
626 : */
627 : static void
628 9 : ekr_expand_response (struct ExchangeKycRequest *ekr)
629 : {
630 : const char *status;
631 :
632 9 : status = map_to_status (ekr);
633 9 : if (NULL == status)
634 : {
635 0 : GNUNET_break (0);
636 0 : status = "logic-bug";
637 : }
638 9 : GNUNET_assert (
639 : 0 ==
640 : json_array_append_new (
641 : ekr->kc->kycs_data,
642 : GNUNET_JSON_PACK (
643 : TALER_JSON_pack_full_payto (
644 : "payto_uri",
645 : ekr->payto_uri),
646 : GNUNET_JSON_pack_data_auto (
647 : "h_wire",
648 : &ekr->h_wire),
649 : GNUNET_JSON_pack_string (
650 : "status",
651 : status),
652 : GNUNET_JSON_pack_string (
653 : "exchange_url",
654 : ekr->exchange_url),
655 : GNUNET_JSON_pack_bool ("no_keys",
656 : ekr->no_keys),
657 : GNUNET_JSON_pack_bool ("auth_conflict",
658 : ekr->kyc_auth_conflict),
659 : GNUNET_JSON_pack_uint64 ("exchange_http_status",
660 : ekr->last_http_status),
661 : (TALER_EC_NONE == ekr->last_ec)
662 : ? GNUNET_JSON_pack_allow_null (
663 : GNUNET_JSON_pack_string (
664 : "dummy",
665 : NULL))
666 : : GNUNET_JSON_pack_uint64 ("exchange_code",
667 : ekr->last_ec),
668 : ekr->auth_ok
669 : ? GNUNET_JSON_pack_data_auto (
670 : "access_token",
671 : &ekr->access_token)
672 : : GNUNET_JSON_pack_allow_null (
673 : GNUNET_JSON_pack_string (
674 : "dummy",
675 : NULL)),
676 : GNUNET_JSON_pack_allow_null (
677 : GNUNET_JSON_pack_array_steal (
678 : "limits",
679 : get_exchange_limits (ekr))),
680 : GNUNET_JSON_pack_allow_null (
681 : GNUNET_JSON_pack_array_incref ("payto_kycauths",
682 : ekr->pkaa))
683 : )));
684 9 : }
685 :
686 :
687 : /**
688 : * We are done with asynchronous processing, generate the
689 : * response for the @e kc.
690 : *
691 : * @param[in,out] kc KYC context to respond for
692 : */
693 : static void
694 8 : kc_respond (struct KycContext *kc)
695 : {
696 8 : if ( (! kc->return_immediately) &&
697 1 : (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
698 : {
699 1 : if (GNUNET_NO == kc->suspended)
700 : {
701 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
702 : "Suspending: long poll target %d not reached\n",
703 : kc->lpt);
704 0 : MHD_suspend_connection (kc->connection);
705 0 : kc->suspended = GNUNET_YES;
706 : }
707 : else
708 : {
709 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
710 : "Remaining suspended: long poll target %d not reached\n",
711 : kc->lpt);
712 : }
713 1 : return;
714 : }
715 : /* All exchange requests done, create final
716 : big response from cumulated replies */
717 7 : resume_kyc_with_response (kc);
718 : }
719 :
720 :
721 : /**
722 : * We are done with the KYC request @a ekr. Remove it from the work list and
723 : * check if we are done overall.
724 : *
725 : * @param[in] ekr key request that is done (and will be freed)
726 : */
727 : static void
728 9 : ekr_finished (struct ExchangeKycRequest *ekr)
729 : {
730 9 : struct KycContext *kc = ekr->kc;
731 :
732 9 : ekr_expand_response (ekr);
733 9 : GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
734 : kc->exchange_pending_tail,
735 : ekr);
736 9 : json_decref (ekr->jlimits);
737 9 : json_decref (ekr->pkaa);
738 9 : if (NULL != ekr->keys)
739 5 : TALER_EXCHANGE_keys_decref (ekr->keys);
740 9 : GNUNET_free (ekr->exchange_url);
741 9 : GNUNET_free (ekr->payto_uri.full_payto);
742 9 : GNUNET_free (ekr);
743 :
744 9 : if (NULL != kc->exchange_pending_head)
745 1 : return; /* wait for more */
746 8 : kc_respond (kc);
747 : }
748 :
749 :
750 : /**
751 : * Figure out which exchange accounts from @a keys could
752 : * be used for a KYC auth wire transfer from the account
753 : * that @a ekr is checking. Will set the "pkaa" array
754 : * in @a ekr.
755 : *
756 : * @param[in,out] ekr request we are processing
757 : */
758 : static void
759 5 : determine_eligible_accounts (
760 : struct ExchangeKycRequest *ekr)
761 : {
762 5 : struct KycContext *kc = ekr->kc;
763 5 : const struct TALER_EXCHANGE_Keys *keys = ekr->keys;
764 : struct TALER_Amount kyc_amount;
765 : char *merchant_pub_str;
766 : struct TALER_NormalizedPayto np;
767 :
768 5 : ekr->pkaa = json_array ();
769 5 : GNUNET_assert (NULL != ekr->pkaa);
770 : {
771 : const struct TALER_EXCHANGE_GlobalFee *gf;
772 :
773 5 : gf = TALER_EXCHANGE_get_global_fee (keys,
774 : GNUNET_TIME_timestamp_get ());
775 5 : if (NULL == gf)
776 : {
777 0 : GNUNET_assert (GNUNET_OK ==
778 : TALER_amount_set_zero (keys->currency,
779 : &kyc_amount));
780 : }
781 : else
782 : {
783 : /* FIXME-#9427: history fee should be globally renamed to KYC fee... */
784 5 : kyc_amount = gf->fees.history;
785 : }
786 : }
787 :
788 : merchant_pub_str
789 5 : = GNUNET_STRINGS_data_to_string_alloc (
790 5 : &kc->mi->merchant_pub,
791 : sizeof (kc->mi->merchant_pub));
792 : /* For all accounts of the exchange */
793 5 : np = TALER_payto_normalize (ekr->payto_uri);
794 10 : for (unsigned int i = 0; i<keys->accounts_len; i++)
795 : {
796 5 : const struct TALER_EXCHANGE_WireAccount *account
797 5 : = &keys->accounts[i];
798 :
799 : /* KYC auth transfers are never supported with conversion */
800 5 : if (NULL != account->conversion_url)
801 0 : continue;
802 : /* filter by source account by credit_restrictions */
803 5 : if (GNUNET_YES !=
804 5 : TALER_EXCHANGE_test_account_allowed (account,
805 : true, /* credit */
806 : np))
807 0 : continue;
808 : /* exchange account is allowed, add it */
809 : {
810 5 : const char *exchange_account_payto
811 : = account->fpayto_uri.full_payto;
812 : char *payto_kycauth;
813 :
814 5 : if (TALER_amount_is_zero (&kyc_amount))
815 0 : GNUNET_asprintf (&payto_kycauth,
816 : "%s%cmessage=KYC:%s",
817 : exchange_account_payto,
818 0 : (NULL == strchr (exchange_account_payto,
819 : '?'))
820 : ? '?'
821 : : '&',
822 : merchant_pub_str);
823 : else
824 10 : GNUNET_asprintf (&payto_kycauth,
825 : "%s%camount=%s&message=KYC:%s",
826 : exchange_account_payto,
827 5 : (NULL == strchr (exchange_account_payto,
828 : '?'))
829 : ? '?'
830 : : '&',
831 : TALER_amount2s (&kyc_amount),
832 : merchant_pub_str);
833 5 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
834 : "Found account %s where KYC auth is possible\n",
835 : payto_kycauth);
836 5 : GNUNET_assert (0 ==
837 : json_array_append_new (ekr->pkaa,
838 : json_string (payto_kycauth)));
839 5 : GNUNET_free (payto_kycauth);
840 : }
841 : }
842 5 : GNUNET_free (np.normalized_payto);
843 5 : GNUNET_free (merchant_pub_str);
844 5 : }
845 :
846 :
847 : /**
848 : * Function called with the result of a #TMH_EXCHANGES_keys4exchange()
849 : * operation. Runs the KYC check against the exchange.
850 : *
851 : * @param cls closure with our `struct ExchangeKycRequest *`
852 : * @param keys keys of the exchange context
853 : * @param exchange representation of the exchange
854 : */
855 : static void
856 5 : kyc_with_exchange (void *cls,
857 : struct TALER_EXCHANGE_Keys *keys,
858 : struct TMH_Exchange *exchange)
859 : {
860 5 : struct ExchangeKycRequest *ekr = cls;
861 :
862 : (void) exchange;
863 5 : ekr->fo = NULL;
864 5 : if (NULL == keys)
865 : {
866 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
867 : "Failed to download `%skeys`\n",
868 : ekr->exchange_url);
869 0 : ekr->no_keys = true;
870 0 : ekr_finished (ekr);
871 0 : return;
872 : }
873 5 : ekr->keys = TALER_EXCHANGE_keys_incref (keys);
874 5 : if (! ekr->auth_ok)
875 : {
876 5 : determine_eligible_accounts (ekr);
877 5 : if (0 == json_array_size (ekr->pkaa))
878 : {
879 : /* No KYC auth wire transfers are possible to this exchange from
880 : our merchant bank account, so we cannot use this account with
881 : this exchange if it has any KYC requirements! */
882 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
883 : "KYC auth to `%s' impossible for merchant account `%s'\n",
884 : ekr->exchange_url,
885 : ekr->payto_uri.full_payto);
886 0 : ekr->kyc_auth_conflict = true;
887 : }
888 : }
889 5 : ekr_finished (ekr);
890 : }
891 :
892 :
893 : /**
894 : * Closure for add_unreachable_status().
895 : */
896 : struct UnreachableContext
897 : {
898 : /**
899 : * Where we are building the response.
900 : */
901 : struct KycContext *kc;
902 :
903 : /**
904 : * Pointer to our account hash.
905 : */
906 : const struct TALER_MerchantWireHashP *h_wire;
907 :
908 : /**
909 : * Bank account for which we have no status from any exchange.
910 : */
911 : struct TALER_FullPayto payto_uri;
912 :
913 : };
914 :
915 : /**
916 : * Add all trusted exchanges with "unknown" status for the
917 : * bank account given in the context.
918 : *
919 : * @param cls a `struct UnreachableContext`
920 : * @param url base URL of the exchange
921 : * @param exchange internal handle for the exchange
922 : */
923 : static void
924 0 : add_unreachable_status (void *cls,
925 : const char *url,
926 : const struct TMH_Exchange *exchange)
927 : {
928 0 : struct UnreachableContext *uc = cls;
929 0 : struct KycContext *kc = uc->kc;
930 :
931 0 : GNUNET_assert (
932 : 0 ==
933 : json_array_append_new (
934 : kc->kycs_data,
935 : GNUNET_JSON_PACK (
936 : TALER_JSON_pack_full_payto (
937 : "payto_uri",
938 : uc->payto_uri),
939 : GNUNET_JSON_pack_data_auto (
940 : "h_wire",
941 : uc->h_wire),
942 : GNUNET_JSON_pack_string (
943 : "status",
944 : "exchange-unreachable"),
945 : GNUNET_JSON_pack_string (
946 : "exchange_url",
947 : url),
948 : GNUNET_JSON_pack_bool ("no_keys",
949 : true),
950 : GNUNET_JSON_pack_bool ("auth_conflict",
951 : false),
952 : GNUNET_JSON_pack_uint64 ("exchange_http_status",
953 : 0)
954 : )));
955 :
956 0 : }
957 :
958 :
959 : /**
960 : * Function called from account_kyc_get_status() with KYC status information
961 : * for this merchant.
962 : *
963 : * @param cls our `struct KycContext *`
964 : * @param h_wire hash of the wire account
965 : * @param payto_uri payto:// URI of the merchant's bank account
966 : * @param exchange_url base URL of the exchange for which this is a status
967 : * @param last_check when did we last get an update on our KYC status from the exchange
968 : * @param kyc_ok true if we satisfied the KYC requirements
969 : * @param access_token access token for the KYC SPA, NULL if we cannot access it yet (need KYC auth wire transfer)
970 : * @param last_http_status last HTTP status from /kyc-check
971 : * @param last_ec last Taler error code from /kyc-check
972 : * @param in_aml_review true if the account is pending review
973 : * @param jlimits JSON array of applicable AccountLimits, or NULL if unknown (like defaults apply)
974 : */
975 : static void
976 9 : kyc_status_cb (
977 : void *cls,
978 : const struct TALER_MerchantWireHashP *h_wire,
979 : struct TALER_FullPayto payto_uri,
980 : const char *exchange_url,
981 : struct GNUNET_TIME_Timestamp last_check,
982 : bool kyc_ok,
983 : const struct TALER_AccountAccessTokenP *access_token,
984 : unsigned int last_http_status,
985 : enum TALER_ErrorCode last_ec,
986 : bool in_aml_review,
987 : const json_t *jlimits)
988 : {
989 9 : struct KycContext *kc = cls;
990 : struct ExchangeKycRequest *ekr;
991 :
992 9 : if (NULL == exchange_url)
993 : {
994 0 : struct UnreachableContext uc = {
995 : .kc = kc,
996 : .h_wire = h_wire,
997 : .payto_uri = payto_uri
998 : };
999 :
1000 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1001 : "Account has unknown KYC status for all exchanges.\n");
1002 0 : TMH_exchange_get_trusted (&add_unreachable_status,
1003 : &uc);
1004 0 : kc_respond (kc);
1005 0 : return;
1006 : }
1007 9 : if (! TMH_EXCHANGES_check_trusted (exchange_url))
1008 : {
1009 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1010 : "Skipping exchange `%s': not trusted\n",
1011 : exchange_url);
1012 0 : return;
1013 : }
1014 9 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1015 : "KYC status for `%s' at `%s' is %u/%s/%s/%s\n",
1016 : payto_uri.full_payto,
1017 : exchange_url,
1018 : last_http_status,
1019 : kyc_ok ? "KYC OK" : "KYC NEEDED",
1020 : in_aml_review ? "IN AML REVIEW" : "NO AML REVIEW",
1021 : NULL == jlimits ? "DEFAULT LIMITS" : "CUSTOM LIMITS");
1022 9 : switch (kc->lpt)
1023 : {
1024 4 : case TALER_EXCHANGE_KLPT_NONE:
1025 4 : break;
1026 4 : case TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER:
1027 4 : if (NULL != access_token)
1028 3 : kc->return_immediately = true;
1029 4 : break;
1030 0 : case TALER_EXCHANGE_KLPT_INVESTIGATION_DONE:
1031 0 : if (! in_aml_review)
1032 0 : kc->return_immediately = true;
1033 0 : break;
1034 1 : case TALER_EXCHANGE_KLPT_KYC_OK:
1035 1 : if (kyc_ok)
1036 1 : kc->return_immediately = true;
1037 1 : break;
1038 : }
1039 9 : ekr = GNUNET_new (struct ExchangeKycRequest);
1040 9 : GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
1041 : kc->exchange_pending_tail,
1042 : ekr);
1043 9 : ekr->last_http_status = last_http_status;
1044 9 : ekr->last_ec = last_ec;
1045 9 : if (NULL != jlimits)
1046 4 : ekr->jlimits = json_incref ((json_t *) jlimits);
1047 9 : ekr->h_wire = *h_wire;
1048 9 : ekr->exchange_url = GNUNET_strdup (exchange_url);
1049 : ekr->payto_uri.full_payto
1050 9 : = GNUNET_strdup (payto_uri.full_payto);
1051 9 : ekr->last_check = last_check;
1052 9 : ekr->kyc_ok = kyc_ok;
1053 9 : ekr->kc = kc;
1054 9 : ekr->in_aml_review = in_aml_review;
1055 9 : ekr->auth_ok = (NULL != access_token);
1056 9 : if ( (! ekr->auth_ok) ||
1057 4 : (NULL == ekr->jlimits) )
1058 : {
1059 : /* Figure out wire transfer instructions */
1060 5 : if (GNUNET_NO == kc->suspended)
1061 : {
1062 4 : MHD_suspend_connection (kc->connection);
1063 4 : kc->suspended = GNUNET_YES;
1064 : }
1065 5 : ekr->fo = TMH_EXCHANGES_keys4exchange (
1066 : exchange_url,
1067 : false,
1068 : &kyc_with_exchange,
1069 : ekr);
1070 5 : if (NULL == ekr->fo)
1071 : {
1072 0 : GNUNET_break (0);
1073 0 : ekr_finished (ekr);
1074 0 : return;
1075 : }
1076 5 : return;
1077 : }
1078 4 : ekr->access_token = *access_token;
1079 4 : ekr_finished (ekr);
1080 : }
1081 :
1082 :
1083 : /**
1084 : * Check the KYC status of an instance.
1085 : *
1086 : * @param mi instance to check KYC status of
1087 : * @param connection the MHD connection to handle
1088 : * @param[in,out] hc context with further information about the request
1089 : * @return MHD result code
1090 : */
1091 : static MHD_RESULT
1092 13 : get_instances_ID_kyc (
1093 : struct TMH_MerchantInstance *mi,
1094 : struct MHD_Connection *connection,
1095 : struct TMH_HandlerContext *hc)
1096 : {
1097 13 : struct KycContext *kc = hc->ctx;
1098 :
1099 13 : if (NULL == kc)
1100 : {
1101 9 : kc = GNUNET_new (struct KycContext);
1102 9 : kc->mi = mi;
1103 9 : hc->ctx = kc;
1104 9 : hc->cc = &kyc_context_cleanup;
1105 9 : GNUNET_CONTAINER_DLL_insert (kc_head,
1106 : kc_tail,
1107 : kc);
1108 9 : kc->connection = connection;
1109 9 : kc->hc = hc;
1110 9 : kc->kycs_data = json_array ();
1111 9 : GNUNET_assert (NULL != kc->kycs_data);
1112 9 : TALER_MHD_parse_request_timeout (connection,
1113 : &kc->timeout);
1114 : {
1115 9 : uint64_t num = 0;
1116 : int val;
1117 :
1118 9 : TALER_MHD_parse_request_number (connection,
1119 : "lpt",
1120 : &num);
1121 9 : val = (int) num;
1122 9 : if ( (val < 0) ||
1123 : (val > TALER_EXCHANGE_KLPT_MAX) )
1124 : {
1125 : /* Protocol violation, but we can be graceful and
1126 : just ignore the long polling! */
1127 0 : GNUNET_break_op (0);
1128 0 : val = TALER_EXCHANGE_KLPT_NONE;
1129 : }
1130 9 : kc->lpt = (enum TALER_EXCHANGE_KycLongPollTarget) val;
1131 : }
1132 : kc->return_immediately
1133 9 : = (TALER_EXCHANGE_KLPT_NONE == kc->lpt);
1134 : /* process 'exchange_url' argument */
1135 9 : kc->exchange_url = MHD_lookup_connection_value (
1136 : connection,
1137 : MHD_GET_ARGUMENT_KIND,
1138 : "exchange_url");
1139 9 : if ( (NULL != kc->exchange_url) &&
1140 7 : ( (! TALER_url_valid_charset (kc->exchange_url)) ||
1141 7 : (! TALER_is_web_url (kc->exchange_url)) ) )
1142 : {
1143 0 : GNUNET_break_op (0);
1144 0 : return TALER_MHD_reply_with_error (
1145 : connection,
1146 : MHD_HTTP_BAD_REQUEST,
1147 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
1148 : "exchange_url must be a valid HTTP(s) URL");
1149 : }
1150 :
1151 9 : TALER_MHD_parse_request_arg_auto (connection,
1152 : "h_wire",
1153 : &kc->h_wire,
1154 : kc->have_h_wire);
1155 :
1156 9 : if ( (TALER_EXCHANGE_KLPT_NONE != kc->lpt) &&
1157 4 : (! GNUNET_TIME_absolute_is_past (kc->timeout)) )
1158 : {
1159 4 : if (kc->have_h_wire)
1160 : {
1161 2 : struct TALER_MERCHANTDB_MerchantKycStatusChangeEventP ev = {
1162 2 : .header.size = htons (sizeof (ev)),
1163 2 : .header.type = htons (
1164 : TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_STATUS_CHANGED
1165 : ),
1166 : .h_wire = kc->h_wire
1167 : };
1168 :
1169 4 : kc->eh = TMH_db->event_listen (
1170 2 : TMH_db->cls,
1171 : &ev.header,
1172 : GNUNET_TIME_absolute_get_remaining (kc->timeout),
1173 : &kyc_change_cb,
1174 : kc);
1175 : }
1176 : else
1177 : {
1178 2 : struct GNUNET_DB_EventHeaderP hdr = {
1179 2 : .size = htons (sizeof (hdr)),
1180 2 : .type = htons (TALER_DBEVENT_MERCHANT_KYC_STATUS_CHANGED)
1181 : };
1182 :
1183 4 : kc->eh = TMH_db->event_listen (
1184 2 : TMH_db->cls,
1185 : &hdr,
1186 : GNUNET_TIME_absolute_get_remaining (kc->timeout),
1187 : &kyc_change_cb,
1188 : kc);
1189 : }
1190 : } /* end register LISTEN hooks */
1191 : } /* end 1st time initialization */
1192 :
1193 13 : if (GNUNET_SYSERR == kc->suspended)
1194 0 : return MHD_NO; /* during shutdown, we don't generate any more replies */
1195 13 : GNUNET_assert (GNUNET_NO == kc->suspended);
1196 :
1197 13 : if (NULL != kc->response)
1198 3 : return MHD_queue_response (connection,
1199 : kc->response_code,
1200 : kc->response);
1201 :
1202 : /* Check our database */
1203 : {
1204 : enum GNUNET_DB_QueryStatus qs;
1205 :
1206 10 : GNUNET_break (0 ==
1207 : json_array_clear (kc->kycs_data));
1208 10 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1209 : "Checking KYC status for %s (%d/%s)\n",
1210 : mi->settings.id,
1211 : kc->have_h_wire,
1212 : kc->exchange_url);
1213 10 : qs = TMH_db->account_kyc_get_status (
1214 10 : TMH_db->cls,
1215 10 : mi->settings.id,
1216 10 : kc->have_h_wire
1217 : ? &kc->h_wire
1218 : : NULL,
1219 : kc->exchange_url,
1220 : &kyc_status_cb,
1221 : kc);
1222 10 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1223 : "account_kyc_get_status returned %d records\n",
1224 : (int) qs);
1225 10 : if (qs < 0)
1226 : {
1227 : /* Database error */
1228 0 : GNUNET_break (0);
1229 0 : if (GNUNET_YES == kc->suspended)
1230 : {
1231 : /* must have suspended before DB error, resume! */
1232 0 : MHD_resume_connection (connection);
1233 0 : kc->suspended = GNUNET_NO;
1234 : }
1235 0 : return TALER_MHD_reply_with_ec (
1236 : connection,
1237 : TALER_EC_GENERIC_DB_FETCH_FAILED,
1238 : "account_kyc_get_status");
1239 : }
1240 10 : if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
1241 : {
1242 : /* no matching accounts, could not have suspended */
1243 2 : GNUNET_assert (GNUNET_NO == kc->suspended);
1244 2 : return TALER_MHD_reply_static (connection,
1245 : MHD_HTTP_NO_CONTENT,
1246 : NULL,
1247 : NULL,
1248 : 0);
1249 : }
1250 : }
1251 8 : if (GNUNET_YES == kc->suspended)
1252 4 : return MHD_YES;
1253 : /* Should have generated a response */
1254 4 : GNUNET_break (NULL != kc->response);
1255 4 : return MHD_queue_response (connection,
1256 : kc->response_code,
1257 : kc->response);
1258 : }
1259 :
1260 :
1261 : MHD_RESULT
1262 13 : TMH_private_get_instances_ID_kyc (
1263 : const struct TMH_RequestHandler *rh,
1264 : struct MHD_Connection *connection,
1265 : struct TMH_HandlerContext *hc)
1266 : {
1267 13 : struct TMH_MerchantInstance *mi = hc->instance;
1268 :
1269 : (void) rh;
1270 13 : return get_instances_ID_kyc (mi,
1271 : connection,
1272 : hc);
1273 : }
1274 :
1275 :
1276 : MHD_RESULT
1277 0 : TMH_private_get_instances_default_ID_kyc (
1278 : const struct TMH_RequestHandler *rh,
1279 : struct MHD_Connection *connection,
1280 : struct TMH_HandlerContext *hc)
1281 : {
1282 : struct TMH_MerchantInstance *mi;
1283 :
1284 : (void) rh;
1285 0 : mi = TMH_lookup_instance (hc->infix);
1286 0 : if (NULL == mi)
1287 : {
1288 0 : return TALER_MHD_reply_with_error (
1289 : connection,
1290 : MHD_HTTP_NOT_FOUND,
1291 : TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
1292 0 : hc->infix);
1293 : }
1294 0 : return get_instances_ID_kyc (mi,
1295 : connection,
1296 : hc);
1297 : }
1298 :
1299 :
1300 : /* end of taler-merchant-httpd_private-get-instances-ID-kyc.c */
|