Line data Source code
1 : /*
2 : This file is part of GNU Taler
3 : (C) 2021 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 :
31 :
32 : /**
33 : * We do not re-check an acceptable KYC status for
34 : * a month, as usually a KYC never expires.
35 : */
36 : #define STALE_KYC_TIMEOUT GNUNET_TIME_UNIT_MONTHS
37 :
38 : /**
39 : * How long should clients cache a KYC failure response?
40 : */
41 : #define EXPIRATION_KYC_FAILURE GNUNET_TIME_relative_multiply ( \
42 : GNUNET_TIME_UNIT_MINUTES, 5)
43 :
44 : /**
45 : * How long should clients cache a KYC success response?
46 : */
47 : #define EXPIRATION_KYC_SUCCESS GNUNET_TIME_relative_multiply ( \
48 : GNUNET_TIME_UNIT_HOURS, 1)
49 :
50 :
51 : /**
52 : * Information we keep per /kyc request.
53 : */
54 : struct KycContext;
55 :
56 :
57 : /**
58 : * Structure for tracking requests to the exchange's
59 : * ``/kyc-check`` API.
60 : */
61 : struct ExchangeKycRequest
62 : {
63 : /**
64 : * Kept in a DLL.
65 : */
66 : struct ExchangeKycRequest *next;
67 :
68 : /**
69 : * Kept in a DLL.
70 : */
71 : struct ExchangeKycRequest *prev;
72 :
73 : /**
74 : * Find operation where we connect to the respective exchange.
75 : */
76 : struct TMH_EXCHANGES_FindOperation *fo;
77 :
78 : /**
79 : * KYC request this exchange request is made for.
80 : */
81 : struct KycContext *kc;
82 :
83 : /**
84 : * Hash of the wire account (with salt) we are checking.
85 : */
86 : struct TALER_MerchantWireHashP h_wire;
87 :
88 : /**
89 : * Handle for the actual HTTP request to the exchange.
90 : */
91 : struct TALER_EXCHANGE_KycCheckHandle *kyc;
92 :
93 : /**
94 : * KYC number used by the exchange.
95 : */
96 : uint64_t exchange_kyc_serial;
97 :
98 : /**
99 : * Our account's payto URI.
100 : */
101 : char *payto_uri;
102 :
103 : /**
104 : * Base URL of the exchange.
105 : */
106 : char *exchange_url;
107 :
108 : /**
109 : * Timestamp when we last got a reply from the exchange.
110 : */
111 : struct GNUNET_TIME_Timestamp last_check;
112 :
113 : /**
114 : * Last KYC status returned by the exchange.
115 : */
116 : bool kyc_ok;
117 :
118 : };
119 :
120 :
121 : /**
122 : * Information we keep per /kyc request.
123 : */
124 : struct KycContext
125 : {
126 : /**
127 : * Stored in a DLL.
128 : */
129 : struct KycContext *next;
130 :
131 : /**
132 : * Stored in a DLL.
133 : */
134 : struct KycContext *prev;
135 :
136 : /**
137 : * Connection we are handling.
138 : */
139 : struct MHD_Connection *connection;
140 :
141 : /**
142 : * Instance we are serving.
143 : */
144 : struct TMH_MerchantInstance *mi;
145 :
146 : /**
147 : * Our handler context.
148 : */
149 : struct TMH_HandlerContext *hc;
150 :
151 : /**
152 : * Task to trigger on request timeout, or NULL.
153 : */
154 : struct GNUNET_SCHEDULER_Task *timeout_task;
155 :
156 : /**
157 : * Response to return, NULL if we don't have one yet.
158 : */
159 : struct MHD_Response *response;
160 :
161 : /**
162 : * JSON array where we are building up the array with
163 : * pending KYC operations.
164 : */
165 : json_t *pending_kycs;
166 :
167 : /**
168 : * JSON array where we are building up the array with
169 : * troubled KYC operations.
170 : */
171 : json_t *timeout_kycs;
172 :
173 : /**
174 : * Head of DLL of requests we are making to an
175 : * exchange to inquire about the latest KYC status.
176 : */
177 : struct ExchangeKycRequest *exchange_pending_head;
178 :
179 : /**
180 : * Tail of DLL of requests we are making to an
181 : * exchange to inquire about the latest KYC status.
182 : */
183 : struct ExchangeKycRequest *exchange_pending_tail;
184 :
185 : /**
186 : * Set to the exchange URL, or NULL to not filter by
187 : * exchange.
188 : */
189 : const char *exchange_url;
190 :
191 : /**
192 : * Set to the h_wire of the merchant account if
193 : * @a have_h_wire is true, used to filter by account.
194 : */
195 : struct TALER_MerchantWireHashP h_wire;
196 :
197 : /**
198 : * How long are we willing to wait for the exchange(s)?
199 : */
200 : struct GNUNET_TIME_Relative timeout;
201 :
202 : /**
203 : * HTTP status code to use for the reply, i.e 200 for "OK".
204 : * Special value UINT_MAX is used to indicate hard errors
205 : * (no reply, return #MHD_NO).
206 : */
207 : unsigned int response_code;
208 :
209 : /**
210 : * #GNUNET_NO if the @e connection was not suspended,
211 : * #GNUNET_YES if the @e connection was suspended,
212 : * #GNUNET_SYSERR if @e connection was resumed to as
213 : * part of #MH_force_pc_resume during shutdown.
214 : */
215 : enum GNUNET_GenericReturnValue suspended;
216 :
217 : /**
218 : * True if @e h_wire was given.
219 : */
220 : bool have_h_wire;
221 :
222 : /**
223 : * We're still waiting on the exchange to determine
224 : * the KYC status of our deposit(s).
225 : */
226 : bool kyc_serial_pending;
227 :
228 : };
229 :
230 :
231 : /**
232 : * Head of DLL.
233 : */
234 : static struct KycContext *kc_head;
235 :
236 : /**
237 : * Tail of DLL.
238 : */
239 : static struct KycContext *kc_tail;
240 :
241 :
242 : void
243 0 : TMH_force_kyc_resume ()
244 : {
245 0 : for (struct KycContext *kc = kc_head;
246 : NULL != kc;
247 0 : kc = kc->next)
248 : {
249 0 : if (NULL != kc->timeout_task)
250 : {
251 0 : GNUNET_SCHEDULER_cancel (kc->timeout_task);
252 0 : kc->timeout_task = NULL;
253 : }
254 0 : if (GNUNET_YES == kc->suspended)
255 : {
256 0 : kc->suspended = GNUNET_SYSERR;
257 0 : MHD_resume_connection (kc->connection);
258 : }
259 : }
260 0 : }
261 :
262 :
263 : /**
264 : * Custom cleanup routine for a `struct KycContext`.
265 : *
266 : * @param cls the `struct KycContext` to clean up.
267 : */
268 : static void
269 0 : kyc_context_cleanup (void *cls)
270 : {
271 0 : struct KycContext *kc = cls;
272 : struct ExchangeKycRequest *ekr;
273 :
274 0 : while (NULL != (ekr = kc->exchange_pending_head))
275 : {
276 0 : GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
277 : kc->exchange_pending_tail,
278 : ekr);
279 0 : if (NULL != ekr->kyc)
280 : {
281 0 : TALER_EXCHANGE_kyc_check_cancel (ekr->kyc);
282 0 : ekr->kyc = NULL;
283 : }
284 0 : if (NULL != ekr->fo)
285 : {
286 0 : TMH_EXCHANGES_find_exchange_cancel (ekr->fo);
287 0 : ekr->fo = NULL;
288 : }
289 0 : GNUNET_free (ekr->exchange_url);
290 0 : GNUNET_free (ekr->payto_uri);
291 0 : GNUNET_free (ekr);
292 : }
293 0 : if (NULL != kc->timeout_task)
294 : {
295 0 : GNUNET_SCHEDULER_cancel (kc->timeout_task);
296 0 : kc->timeout_task = NULL;
297 : }
298 0 : if (NULL != kc->response)
299 : {
300 0 : MHD_destroy_response (kc->response);
301 0 : kc->response = NULL;
302 : }
303 0 : GNUNET_CONTAINER_DLL_remove (kc_head,
304 : kc_tail,
305 : kc);
306 0 : json_decref (kc->pending_kycs);
307 0 : json_decref (kc->timeout_kycs);
308 0 : GNUNET_free (kc);
309 0 : }
310 :
311 :
312 : /**
313 : * Resume the given KYC context and send the given response.
314 : * Stores the response in the @a kc and signals MHD to resume
315 : * the connection. Also ensures MHD runs immediately.
316 : *
317 : * @param kc KYC context
318 : * @param response_code response code to use
319 : * @param response response data to send back
320 : */
321 : static void
322 0 : resume_kyc_with_response (struct KycContext *kc,
323 : unsigned int response_code,
324 : struct MHD_Response *response)
325 : {
326 : char dat[128];
327 :
328 0 : kc->response_code = response_code;
329 0 : kc->response = response;
330 0 : switch (response_code)
331 : {
332 0 : case MHD_HTTP_OK:
333 : /* KYC failed, cache briefly */
334 0 : TALER_MHD_get_date_string (GNUNET_TIME_relative_to_absolute (
335 : EXPIRATION_KYC_FAILURE),
336 : dat);
337 0 : GNUNET_break (MHD_YES ==
338 : MHD_add_response_header (response,
339 : MHD_HTTP_HEADER_EXPIRES,
340 : dat));
341 0 : GNUNET_break (MHD_YES ==
342 : MHD_add_response_header (response,
343 : MHD_HTTP_HEADER_CACHE_CONTROL,
344 : "max-age=300"));
345 0 : break;
346 0 : case MHD_HTTP_NO_CONTENT:
347 : /* KYC passed, cache for a long time! */
348 0 : TALER_MHD_get_date_string (GNUNET_TIME_relative_to_absolute (
349 : EXPIRATION_KYC_SUCCESS),
350 : dat);
351 0 : GNUNET_break (MHD_YES ==
352 : MHD_add_response_header (response,
353 : MHD_HTTP_HEADER_EXPIRES,
354 : dat));
355 0 : GNUNET_break (MHD_YES ==
356 : MHD_add_response_header (response,
357 : MHD_HTTP_HEADER_CACHE_CONTROL,
358 : "max-age=3600"));
359 0 : break;
360 0 : case MHD_HTTP_BAD_GATEWAY:
361 : case MHD_HTTP_GATEWAY_TIMEOUT:
362 0 : break; /* no caching */
363 : }
364 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
365 : "Resuming /kyc handling as exchange interaction is done (%u)\n",
366 : response_code);
367 0 : if (NULL != kc->timeout_task)
368 : {
369 0 : GNUNET_SCHEDULER_cancel (kc->timeout_task);
370 0 : kc->timeout_task = NULL;
371 : }
372 0 : GNUNET_assert (GNUNET_YES == kc->suspended);
373 0 : kc->suspended = GNUNET_NO;
374 0 : MHD_resume_connection (kc->connection);
375 0 : TALER_MHD_daemon_trigger (); /* we resumed, kick MHD */
376 0 : }
377 :
378 :
379 : /**
380 : * Handle a timeout for the processing of the kyc request.
381 : *
382 : * @param cls our `struct KycContext`
383 : */
384 : static void
385 0 : handle_kyc_timeout (void *cls)
386 : {
387 0 : struct KycContext *kc = cls;
388 : struct ExchangeKycRequest *ekr;
389 :
390 0 : kc->timeout_task = NULL;
391 0 : while (NULL != (ekr = kc->exchange_pending_head))
392 : {
393 0 : GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
394 : kc->exchange_pending_tail,
395 : ekr);
396 0 : if (NULL != ekr->kyc)
397 : {
398 0 : TALER_EXCHANGE_kyc_check_cancel (ekr->kyc);
399 0 : ekr->kyc = NULL;
400 : }
401 0 : if (NULL != ekr->fo)
402 : {
403 0 : TMH_EXCHANGES_find_exchange_cancel (ekr->fo);
404 0 : ekr->fo = NULL;
405 : }
406 0 : GNUNET_assert (
407 : 0 ==
408 : json_array_append_new (
409 : kc->timeout_kycs,
410 : GNUNET_JSON_PACK (
411 : GNUNET_JSON_pack_string ("exchange_url",
412 : ekr->exchange_url),
413 : GNUNET_JSON_pack_uint64 ("exchange_code",
414 : TALER_EC_MERCHANT_GENERIC_EXCHANGE_TIMEOUT),
415 : GNUNET_JSON_pack_uint64 ("exchange_http_status",
416 : 0))));
417 0 : GNUNET_free (ekr->exchange_url);
418 0 : GNUNET_free (ekr->payto_uri);
419 0 : GNUNET_free (ekr);
420 : }
421 0 : GNUNET_assert (GNUNET_YES == kc->suspended);
422 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 : "Resuming KYC with gateway timeout\n");
424 0 : resume_kyc_with_response (
425 : kc,
426 : MHD_HTTP_GATEWAY_TIMEOUT,
427 0 : TALER_MHD_MAKE_JSON_PACK (
428 : GNUNET_JSON_pack_array_incref ("pending_kycs",
429 : kc->pending_kycs),
430 : GNUNET_JSON_pack_array_incref ("timeout_kycs",
431 : kc->timeout_kycs)));
432 0 : }
433 :
434 :
435 : /**
436 : * We are done with the KYC request @a ekr.
437 : * Remove it from the work list and check if
438 : * we are done overall.
439 : *
440 : * @param[in] ekr key request that is done (and will be freed)
441 : */
442 : static void
443 0 : ekr_finished (struct ExchangeKycRequest *ekr)
444 : {
445 0 : struct KycContext *kc = ekr->kc;
446 :
447 0 : GNUNET_CONTAINER_DLL_remove (kc->exchange_pending_head,
448 : kc->exchange_pending_tail,
449 : ekr);
450 0 : GNUNET_free (ekr->exchange_url);
451 0 : GNUNET_free (ekr->payto_uri);
452 0 : GNUNET_free (ekr);
453 0 : if (NULL != kc->exchange_pending_head)
454 0 : return; /* wait for more */
455 : /* All exchange requests done, create final
456 : big response from cummulated replies */
457 0 : if ( (0 == json_array_size (kc->pending_kycs)) &&
458 0 : (0 == json_array_size (kc->timeout_kycs)) )
459 : {
460 : /* special case: all KYC operations did succeed
461 : after we asked at the exchanges => 204 */
462 : struct MHD_Response *response;
463 :
464 0 : response = MHD_create_response_from_buffer (0,
465 : "",
466 : MHD_RESPMEM_PERSISTENT);
467 0 : resume_kyc_with_response (kc,
468 : MHD_HTTP_NO_CONTENT,
469 : response);
470 0 : return;
471 : }
472 0 : resume_kyc_with_response (
473 : kc,
474 : kc->response_code, /* MHD_HTTP_OK or MHD_HTTP_BAD_GATEWAY */
475 0 : TALER_MHD_MAKE_JSON_PACK (
476 : GNUNET_JSON_pack_array_incref ("pending_kycs",
477 : kc->pending_kycs),
478 : GNUNET_JSON_pack_array_incref ("timeout_kycs",
479 : kc->timeout_kycs)));
480 : }
481 :
482 :
483 : /**
484 : * Function called with the result of a KYC check.
485 : *
486 : * @param cls a `struct ExchangeKycRequest *`
487 : * @param ks the account's KYC status details
488 : */
489 : static void
490 0 : exchange_check_cb (void *cls,
491 : const struct TALER_EXCHANGE_KycStatus *ks)
492 : {
493 0 : struct ExchangeKycRequest *ekr = cls;
494 0 : struct KycContext *kc = ekr->kc;
495 :
496 0 : ekr->kyc = NULL;
497 0 : switch (ks->http_status)
498 : {
499 0 : case MHD_HTTP_OK:
500 : {
501 : enum GNUNET_DB_QueryStatus qs;
502 :
503 0 : qs = TMH_db->account_kyc_set_status (TMH_db->cls,
504 0 : kc->mi->settings.id,
505 0 : &ekr->h_wire,
506 0 : ekr->exchange_url,
507 : ekr->exchange_kyc_serial,
508 : &ks->details.success.exchange_sig,
509 : &ks->details.success.exchange_pub,
510 : ks->details.success.timestamp,
511 : true);
512 0 : if (qs < 0)
513 : {
514 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
515 : "Failed to store KYC status in database!\n");
516 : }
517 : }
518 0 : break;
519 0 : case MHD_HTTP_ACCEPTED:
520 0 : GNUNET_assert (
521 : 0 ==
522 : json_array_append_new (
523 : kc->pending_kycs,
524 : GNUNET_JSON_PACK (
525 : GNUNET_JSON_pack_string ("kyc_url",
526 : ks->details.accepted.kyc_url),
527 : GNUNET_JSON_pack_string ("exchange_url",
528 : ekr->exchange_url),
529 : GNUNET_JSON_pack_string ("payto_uri",
530 : ekr->payto_uri))));
531 0 : break;
532 0 : case MHD_HTTP_NO_CONTENT:
533 : {
534 : struct GNUNET_TIME_Timestamp now;
535 : enum GNUNET_DB_QueryStatus qs;
536 :
537 0 : now = GNUNET_TIME_timestamp_get ();
538 0 : qs = TMH_db->account_kyc_set_status (TMH_db->cls,
539 0 : kc->mi->settings.id,
540 0 : &ekr->h_wire,
541 0 : ekr->exchange_url,
542 : ekr->exchange_kyc_serial,
543 : NULL,
544 : NULL,
545 : now,
546 : true);
547 0 : if (qs < 0)
548 : {
549 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
550 : "Failed to store KYC status in database!\n");
551 : }
552 : }
553 0 : break;
554 0 : default:
555 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
556 : "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
557 : ks->http_status,
558 : ks->ec);
559 0 : kc->response_code = MHD_HTTP_BAD_GATEWAY;
560 0 : GNUNET_assert (
561 : 0 ==
562 : json_array_append_new (
563 : kc->timeout_kycs,
564 : GNUNET_JSON_PACK (
565 : GNUNET_JSON_pack_string ("exchange_url",
566 : ekr->exchange_url),
567 : GNUNET_JSON_pack_uint64 ("exchange_code",
568 : ks->ec),
569 : GNUNET_JSON_pack_uint64 ("exchange_http_status",
570 : ks->http_status))));
571 : }
572 0 : ekr_finished (ekr);
573 0 : }
574 :
575 :
576 : /**
577 : * Function called with the result of a #TMH_EXCHANGES_find_exchange()
578 : * operation. Runs the KYC check against the exchange.
579 : *
580 : * @param cls closure with our `struct ExchangeKycRequest *`
581 : * @param hr HTTP response details
582 : * @param eh handle to the exchange context
583 : * @param payto_uri payto://-URI of the exchange
584 : * @param wire_fee current applicable wire fee for dealing with @a eh, NULL if not available
585 : * @param exchange_trusted true if this exchange is trusted by config
586 : */
587 : static void
588 0 : kyc_with_exchange (void *cls,
589 : const struct TALER_EXCHANGE_HttpResponse *hr,
590 : struct TALER_EXCHANGE_Handle *eh,
591 : const char *payto_uri,
592 : const struct TALER_Amount *wire_fee,
593 : bool exchange_trusted)
594 : {
595 0 : struct ExchangeKycRequest *ekr = cls;
596 0 : struct KycContext *kc = ekr->kc;
597 : struct TALER_PaytoHashP h_payto;
598 :
599 : (void) payto_uri;
600 : (void) wire_fee;
601 : (void) exchange_trusted;
602 0 : ekr->fo = NULL;
603 0 : if (MHD_HTTP_OK != hr->http_status)
604 : {
605 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
606 : "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
607 : hr->http_status,
608 : hr->ec);
609 0 : kc->response_code = MHD_HTTP_BAD_GATEWAY;
610 0 : GNUNET_assert (
611 : 0 ==
612 : json_array_append_new (
613 : kc->timeout_kycs,
614 : GNUNET_JSON_PACK (
615 : GNUNET_JSON_pack_string ("exchange_url",
616 : ekr->exchange_url),
617 : GNUNET_JSON_pack_uint64 ("exchange_code",
618 : hr->ec),
619 : GNUNET_JSON_pack_uint64 ("exchange_http_status",
620 : hr->http_status))));
621 0 : ekr_finished (ekr);
622 0 : return;
623 : }
624 0 : TALER_payto_hash (ekr->payto_uri,
625 : &h_payto);
626 0 : ekr->kyc = TALER_EXCHANGE_kyc_check (
627 : eh,
628 : ekr->exchange_kyc_serial,
629 : &h_payto,
630 : /* FIXME: get from settings! */
631 : TALER_KYCLOGIC_KYC_UT_BUSINESS,
632 : kc->timeout,
633 : &exchange_check_cb,
634 : ekr);
635 : }
636 :
637 :
638 : /**
639 : * Function called from ``account_kyc_get_status``
640 : * with KYC status information for this merchant.
641 : *
642 : * @param cls our `struct KycContext *`
643 : * @param h_wire hash of the wire account
644 : * @param exchange_kyc_serial serial number for the KYC process at the exchange, 0 if unknown
645 : * @param payto_uri payto:// URI of the merchant's bank account
646 : * @param exchange_url base URL of the exchange for which this is a status
647 : * @param last_check when did we last get an update on our KYC status from the exchange
648 : * @param kyc_ok true if we satisfied the KYC requirements
649 : */
650 : static void
651 0 : kyc_status_cb (void *cls,
652 : const struct TALER_MerchantWireHashP *h_wire,
653 : uint64_t exchange_kyc_serial,
654 : const char *payto_uri,
655 : const char *exchange_url,
656 : struct GNUNET_TIME_Timestamp last_check,
657 : bool kyc_ok)
658 : {
659 0 : struct KycContext *kc = cls;
660 : struct ExchangeKycRequest *ekr;
661 :
662 0 : if (kyc_ok &&
663 0 : (GNUNET_TIME_relative_cmp (
664 : GNUNET_TIME_absolute_get_duration (last_check.abs_time),
665 : <,
666 : STALE_KYC_TIMEOUT)) )
667 0 : return; /* KYC ok, ignore! */
668 0 : if (0 == exchange_kyc_serial)
669 : {
670 0 : kc->kyc_serial_pending = true;
671 0 : return;
672 : }
673 0 : kc->response_code = MHD_HTTP_ACCEPTED;
674 0 : ekr = GNUNET_new (struct ExchangeKycRequest);
675 0 : GNUNET_CONTAINER_DLL_insert (kc->exchange_pending_head,
676 : kc->exchange_pending_tail,
677 : ekr);
678 0 : ekr->h_wire = *h_wire;
679 0 : ekr->exchange_kyc_serial = exchange_kyc_serial;
680 0 : ekr->exchange_url = GNUNET_strdup (exchange_url);
681 0 : ekr->payto_uri = GNUNET_strdup (payto_uri);
682 0 : ekr->last_check = last_check;
683 0 : ekr->kyc_ok = kyc_ok;
684 0 : ekr->kc = kc;
685 0 : ekr->fo = TMH_EXCHANGES_find_exchange (exchange_url,
686 : NULL,
687 : GNUNET_NO,
688 : &kyc_with_exchange,
689 : ekr);
690 : }
691 :
692 :
693 : /**
694 : * Check the KYC status of an instance.
695 : *
696 : * @param mi instance to check KYC status of
697 : * @param connection the MHD connection to handle
698 : * @param[in,out] hc context with further information about the request
699 : * @return MHD result code
700 : */
701 : static MHD_RESULT
702 0 : get_instances_ID_kyc (struct TMH_MerchantInstance *mi,
703 : struct MHD_Connection *connection,
704 : struct TMH_HandlerContext *hc)
705 : {
706 0 : struct KycContext *kc = hc->ctx;
707 :
708 0 : if (NULL == kc)
709 : {
710 0 : kc = GNUNET_new (struct KycContext);
711 0 : kc->mi = mi;
712 0 : hc->ctx = kc;
713 0 : hc->cc = &kyc_context_cleanup;
714 0 : GNUNET_CONTAINER_DLL_insert (kc_head,
715 : kc_tail,
716 : kc);
717 0 : kc->connection = connection;
718 0 : kc->hc = hc;
719 0 : kc->pending_kycs = json_array ();
720 0 : GNUNET_assert (NULL != kc->pending_kycs);
721 0 : kc->timeout_kycs = json_array ();
722 0 : GNUNET_assert (NULL != kc->timeout_kycs);
723 :
724 : /* process 'timeout_ms' argument */
725 : {
726 : const char *long_poll_timeout_s;
727 :
728 : long_poll_timeout_s
729 0 : = MHD_lookup_connection_value (connection,
730 : MHD_GET_ARGUMENT_KIND,
731 : "timeout_ms");
732 0 : if (NULL != long_poll_timeout_s)
733 : {
734 : unsigned int timeout_ms;
735 : char dummy;
736 :
737 0 : if (1 != sscanf (long_poll_timeout_s,
738 : "%u%c",
739 : &timeout_ms,
740 : &dummy))
741 : {
742 0 : GNUNET_break_op (0);
743 0 : return TALER_MHD_reply_with_error (connection,
744 : MHD_HTTP_BAD_REQUEST,
745 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
746 : "timeout_ms must be non-negative number");
747 : }
748 0 : kc->timeout = GNUNET_TIME_relative_multiply (
749 : GNUNET_TIME_UNIT_MILLISECONDS,
750 : timeout_ms);
751 : kc->timeout_task
752 0 : = GNUNET_SCHEDULER_add_delayed (kc->timeout,
753 : &handle_kyc_timeout,
754 : kc);
755 : }
756 : } /* end timeout processing */
757 :
758 : /* process 'exchange_url' argument */
759 0 : kc->exchange_url = MHD_lookup_connection_value (connection,
760 : MHD_GET_ARGUMENT_KIND,
761 : "exchange_url");
762 0 : if ( (NULL != kc->exchange_url) &&
763 0 : (! TALER_url_valid_charset (kc->exchange_url) ||
764 0 : ( (0 != strncasecmp (kc->exchange_url,
765 : "http://",
766 0 : strlen ("http://"))) &&
767 0 : (0 != strncasecmp (kc->exchange_url,
768 : "https://",
769 : strlen ("https://"))) ) ) )
770 : {
771 0 : GNUNET_break_op (0);
772 0 : return TALER_MHD_reply_with_error (connection,
773 : MHD_HTTP_BAD_REQUEST,
774 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
775 : "exchange_url must be a valid HTTP(s) URL");
776 : }
777 :
778 : /* process 'h_wire' argument */
779 : {
780 : const char *h_wire_s;
781 :
782 : h_wire_s
783 0 : = MHD_lookup_connection_value (connection,
784 : MHD_GET_ARGUMENT_KIND,
785 : "h_wire");
786 0 : if (NULL != h_wire_s)
787 : {
788 0 : if (GNUNET_OK !=
789 0 : GNUNET_STRINGS_string_to_data (h_wire_s,
790 : strlen (h_wire_s),
791 0 : &kc->h_wire,
792 : sizeof (kc->h_wire)))
793 : {
794 0 : GNUNET_break_op (0);
795 0 : return TALER_MHD_reply_with_error (connection,
796 : MHD_HTTP_BAD_REQUEST,
797 : TALER_EC_GENERIC_PARAMETER_MALFORMED,
798 : "h_wire must be Crockford base32 encoded hash");
799 : }
800 0 : kc->have_h_wire = true;
801 : }
802 : } /* end of h_wire processing */
803 :
804 : /* Check our database */
805 : {
806 : enum GNUNET_DB_QueryStatus qs;
807 :
808 0 : qs = TMH_db->account_kyc_get_status (TMH_db->cls,
809 0 : mi->settings.id,
810 0 : kc->have_h_wire
811 : ? &kc->h_wire
812 : : NULL,
813 : kc->exchange_url,
814 : &kyc_status_cb,
815 : kc);
816 0 : if (qs < 0)
817 : {
818 0 : GNUNET_break (0);
819 0 : return TALER_MHD_reply_with_ec (connection,
820 : TALER_EC_GENERIC_DB_FETCH_FAILED,
821 : "account_kyc_get_status");
822 : }
823 : }
824 0 : if (kc->kyc_serial_pending)
825 : {
826 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
827 : "Exchange legitimization UUID unknown, assuming KYC pending\n");
828 0 : return TALER_MHD_REPLY_JSON_PACK (
829 : connection,
830 : MHD_HTTP_SERVICE_UNAVAILABLE,
831 : GNUNET_JSON_pack_string ("hint",
832 : "awaiting legitimization UUID"));
833 : }
834 0 : if (NULL == kc->exchange_pending_head)
835 0 : return TALER_MHD_reply_static (connection,
836 : MHD_HTTP_NO_CONTENT,
837 : NULL,
838 : NULL,
839 : 0);
840 0 : MHD_suspend_connection (connection);
841 0 : kc->suspended = GNUNET_YES;
842 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
843 : "Suspending KYC request handling while checking with the exchange(s)\n");
844 0 : return MHD_YES;
845 : }
846 0 : if (GNUNET_SYSERR == kc->suspended)
847 0 : return MHD_NO; /* during shutdown, we don't generate any more replies */
848 0 : GNUNET_assert (GNUNET_NO == kc->suspended);
849 0 : if (0 != kc->response_code)
850 : {
851 : /* We are *done* processing the request, just queue the response (!) */
852 0 : if (UINT_MAX == kc->response_code)
853 : {
854 0 : GNUNET_break (0);
855 0 : return MHD_NO; /* hard error */
856 : }
857 0 : return MHD_queue_response (connection,
858 : kc->response_code,
859 : kc->response);
860 : }
861 : /* we should never get here */
862 0 : GNUNET_break (0);
863 0 : return MHD_NO;
864 : }
865 :
866 :
867 : MHD_RESULT
868 0 : TMH_private_get_instances_ID_kyc (const struct TMH_RequestHandler *rh,
869 : struct MHD_Connection *connection,
870 : struct TMH_HandlerContext *hc)
871 : {
872 0 : struct TMH_MerchantInstance *mi = hc->instance;
873 :
874 : (void) rh;
875 0 : return get_instances_ID_kyc (mi,
876 : connection,
877 : hc);
878 : }
879 :
880 :
881 : MHD_RESULT
882 0 : TMH_private_get_instances_default_ID_kyc (const struct TMH_RequestHandler *rh,
883 : struct MHD_Connection *connection,
884 : struct TMH_HandlerContext *hc)
885 : {
886 : struct TMH_MerchantInstance *mi;
887 :
888 : (void) rh;
889 0 : mi = TMH_lookup_instance (hc->infix);
890 0 : if (NULL == mi)
891 : {
892 0 : return TALER_MHD_reply_with_error (connection,
893 : MHD_HTTP_NOT_FOUND,
894 : TALER_EC_MERCHANT_GENERIC_INSTANCE_UNKNOWN,
895 0 : hc->infix);
896 : }
897 0 : return get_instances_ID_kyc (mi,
898 : connection,
899 : hc);
900 : }
901 :
902 :
903 : /* end of taler-merchant-httpd_private-get-instances-ID-kyc.c */
|