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