Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 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 Affero 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 Affero General Public License
14 : along with TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file src/backend/taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c
18 : * @brief Handle POST /private/accounts/$H_WIRE/kycauth requests
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include <jansson.h>
23 : #include <microhttpd.h>
24 : #include <gnunet/gnunet_json_lib.h>
25 : #include <taler/taler_json_lib.h>
26 : #include <taler/taler_mhd_lib.h>
27 : #include <taler/taler_bank_service.h>
28 : #include "taler-merchant-httpd.h"
29 : #include "taler-merchant-httpd_exchanges.h"
30 : #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h"
31 : #include "merchant-database/get_account.h"
32 : #include "taler/taler_util.h"
33 :
34 :
35 : /**
36 : * Processing phases for a kycauth POST request.
37 : */
38 : enum KycAuthPhase
39 : {
40 : /**
41 : * Parse the request body and URL path.
42 : */
43 : KP_PARSE = 0,
44 :
45 : /**
46 : * Fetch exchange /keys (and optionally register with bank gateway).
47 : * The connection is suspended in this phase.
48 : */
49 : KP_CHECK_EXCHANGES,
50 :
51 : /**
52 : * Return the prepared response to the client.
53 : */
54 : KP_RETURN_RESPONSE,
55 :
56 : /**
57 : * Return MHD_YES to finish handling.
58 : */
59 : KP_END_YES,
60 :
61 : /**
62 : * Return MHD_NO to close the connection.
63 : */
64 : KP_END_NO
65 : };
66 :
67 :
68 : struct ExchangeAccount
69 : {
70 :
71 : /**
72 : * Payto URI of the exchange, saved from /keys.
73 : */
74 : struct TALER_FullPayto payto;
75 :
76 : /**
77 : * Pending bank gateway registration handle, or NULL.
78 : */
79 : struct TALER_BANK_RegistrationHandle *brh;
80 :
81 : /**
82 : * Context we are operating in.
83 : */
84 : struct KycAuthContext *kac;
85 :
86 : /**
87 : * Transfer subjects to use for the account.
88 : */
89 : struct TALER_BANK_TransferSubject *subjects;
90 :
91 : /**
92 : * Length of the @e subjects array.
93 : */
94 : unsigned int num_subjects;
95 :
96 : /**
97 : * Expiration time for the given @e ts.
98 : */
99 : struct GNUNET_TIME_Timestamp expiration;
100 : };
101 :
102 :
103 : /**
104 : * Per-request context for POST /private/accounts/$H_WIRE/kycauth.
105 : */
106 : struct KycAuthContext
107 : {
108 :
109 : /**
110 : * Kept in doubly-linked list.
111 : */
112 : struct KycAuthContext *next;
113 :
114 : /**
115 : * Kept in doubly-linked list.
116 : */
117 : struct KycAuthContext *prev;
118 :
119 : /**
120 : * MHD connection we are handling.
121 : */
122 : struct MHD_Connection *connection;
123 :
124 : /**
125 : * Handler context for this request.
126 : */
127 : struct TMH_HandlerContext *hc;
128 :
129 : /**
130 : * Prepared HTTP response to return, or NULL.
131 : */
132 : struct MHD_Response *response;
133 :
134 : /**
135 : * Exchange URL from the request body.
136 : */
137 : char *exchange_url;
138 :
139 : /**
140 : * Payto URI of our merchant bank account (from DB).
141 : */
142 : struct TALER_FullPayto payto_uri;
143 :
144 : /**
145 : * Pending /keys lookup operation with the exchange.
146 : */
147 : struct TMH_EXCHANGES_KeysOperation *fo;
148 :
149 : /**
150 : * Tiny amount from exchange /keys, used as the transfer amount.
151 : */
152 : struct TALER_Amount tiny_amount;
153 :
154 : /**
155 : * Array of exchange wire account payto URIs, saved from /keys.
156 : * Length is @e exchange_accounts_len.
157 : */
158 : struct ExchangeAccount *exchange_accounts;
159 :
160 : /**
161 : * Number of entries in @e exchange_accounts.
162 : */
163 : unsigned int exchange_accounts_len;
164 :
165 : /**
166 : * Number of active registrations in @e exchange_accounts.
167 : */
168 : unsigned int active_registrations;
169 :
170 : /**
171 : * HTTP status code to send with @e response.
172 : * UINT_MAX indicates a hard error (return MHD_NO).
173 : */
174 : unsigned int response_code;
175 :
176 : /**
177 : * Current processing phase.
178 : */
179 : enum KycAuthPhase phase;
180 :
181 : /**
182 : * #GNUNET_NO if the connection is not suspended,
183 : * #GNUNET_YES if the connection is suspended,
184 : * #GNUNET_SYSERR if suspended and being force-resumed during shutdown.
185 : */
186 : enum GNUNET_GenericReturnValue suspended;
187 :
188 : };
189 :
190 :
191 : /**
192 : * Head of the doubly-linked list of active kycauth contexts.
193 : */
194 : static struct KycAuthContext *kac_head;
195 :
196 : /**
197 : * Tail of the doubly-linked list of active kycauth contexts.
198 : */
199 : static struct KycAuthContext *kac_tail;
200 :
201 :
202 : void
203 20 : TMH_force_kac_resume (void)
204 : {
205 20 : for (struct KycAuthContext *kac = kac_head;
206 20 : NULL != kac;
207 0 : kac = kac->next)
208 : {
209 0 : if (NULL != kac->fo)
210 : {
211 0 : TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
212 0 : kac->fo = NULL;
213 : }
214 0 : if (GNUNET_YES == kac->suspended)
215 : {
216 0 : kac->suspended = GNUNET_SYSERR;
217 0 : MHD_resume_connection (kac->connection);
218 : }
219 : }
220 20 : }
221 :
222 :
223 : /**
224 : * Resume processing of @a kac after an async operation completed.
225 : *
226 : * @param[in,out] kac context to resume
227 : */
228 : static void
229 1 : kac_resume (struct KycAuthContext *kac)
230 : {
231 1 : GNUNET_assert (GNUNET_YES == kac->suspended);
232 1 : kac->suspended = GNUNET_NO;
233 1 : MHD_resume_connection (kac->connection);
234 1 : TALER_MHD_daemon_trigger ();
235 1 : }
236 :
237 :
238 : /**
239 : * Clean up a kycauth context, freeing all resources.
240 : *
241 : * @param cls a `struct KycAuthContext` to clean up
242 : */
243 : static void
244 1 : kac_cleanup (void *cls)
245 : {
246 1 : struct KycAuthContext *kac = cls;
247 :
248 1 : if (NULL != kac->fo)
249 : {
250 0 : TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
251 0 : kac->fo = NULL;
252 : }
253 1 : if (NULL != kac->response)
254 : {
255 1 : MHD_destroy_response (kac->response);
256 1 : kac->response = NULL;
257 : }
258 1 : GNUNET_free (kac->exchange_url);
259 1 : GNUNET_free (kac->payto_uri.full_payto);
260 2 : for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
261 : {
262 1 : struct ExchangeAccount *acc = &kac->exchange_accounts[i];
263 :
264 1 : if (NULL != acc->brh)
265 : {
266 0 : TALER_BANK_registration_cancel (acc->brh);
267 0 : acc->brh = NULL;
268 : }
269 2 : for (unsigned int j = 0; j<acc->num_subjects; j++)
270 1 : TALER_BANK_transfer_subject_free (&acc->subjects[j]);
271 1 : GNUNET_free (acc->subjects);
272 1 : GNUNET_free (acc->payto.full_payto);
273 : }
274 1 : GNUNET_free (kac->exchange_accounts);
275 1 : GNUNET_CONTAINER_DLL_remove (kac_head,
276 : kac_tail,
277 : kac);
278 1 : GNUNET_free (kac);
279 1 : }
280 :
281 :
282 : /**
283 : * Convert a @a ts (transfer subject) to a JSON object.
284 : * The resulting object has a "type" field discriminating the format,
285 : * matching the JSON format returned by the bank gateway's /registration.
286 : *
287 : * @param acc general account details
288 : * @param ts the specific transfer subject to convert
289 : * @return freshly allocated JSON object, or NULL on error
290 : */
291 : static json_t *
292 1 : kyc_transfer_subject_to_json (const struct ExchangeAccount *acc,
293 : const struct TALER_BANK_TransferSubject *ts)
294 : {
295 1 : struct KycAuthContext *kac = acc->kac;
296 : json_t *ret;
297 :
298 1 : switch (ts->format)
299 : {
300 1 : case TALER_BANK_SUBJECT_FORMAT_SIMPLE:
301 : {
302 1 : struct GNUNET_Buffer buf = { 0 };
303 : char *subject;
304 :
305 1 : GNUNET_buffer_write_str (&buf,
306 : "KYC:");
307 1 : GNUNET_buffer_write_data_encoded (&buf,
308 1 : &kac->hc->instance->merchant_pub,
309 : sizeof (kac->hc->instance->merchant_pub));
310 1 : subject = GNUNET_buffer_reap_str (&buf);
311 1 : ret = GNUNET_JSON_PACK (
312 : GNUNET_JSON_pack_string ("type",
313 : "SIMPLE"),
314 : TALER_JSON_pack_amount ("credit_amount",
315 : &kac->tiny_amount),
316 : GNUNET_JSON_pack_string ("subject",
317 : subject));
318 1 : GNUNET_free (subject);
319 : }
320 1 : return ret;
321 0 : case TALER_BANK_SUBJECT_FORMAT_URI:
322 0 : return GNUNET_JSON_PACK (
323 : GNUNET_JSON_pack_string ("type",
324 : "URI"),
325 : TALER_JSON_pack_amount ("credit_amount",
326 : &kac->tiny_amount),
327 : GNUNET_JSON_pack_string ("uri",
328 : ts->details.uri.uri));
329 0 : case TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL:
330 0 : return GNUNET_JSON_PACK (
331 : GNUNET_JSON_pack_string ("type",
332 : "CH_QR_BILL"),
333 : TALER_JSON_pack_amount ("credit_amount",
334 : &ts->details.ch_qr_bill.credit_amount),
335 : GNUNET_JSON_pack_string ("qr_reference_number",
336 : ts->details.ch_qr_bill.qr_reference_number));
337 : }
338 0 : GNUNET_break (0);
339 0 : return NULL;
340 : }
341 :
342 :
343 : /**
344 : * Generate the final "OK" response for the request in @a kac.
345 : * Builds the wire_instructions JSON array from the saved exchange accounts
346 : * and the given transfer subject.
347 : *
348 : * @param[in,out] kac request with all the details ready to build a response
349 : */
350 : static void
351 1 : generate_ok_response (struct KycAuthContext *kac)
352 : {
353 : json_t *arr;
354 :
355 1 : arr = json_array ();
356 1 : GNUNET_assert (NULL != arr);
357 2 : for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
358 : {
359 1 : const struct ExchangeAccount *acc = &kac->exchange_accounts[i];
360 : json_t *subj;
361 : json_t *entry;
362 :
363 2 : for (unsigned int j = 0; j < acc->num_subjects; j++)
364 : {
365 1 : subj = kyc_transfer_subject_to_json (acc,
366 1 : &acc->subjects[j]);
367 1 : GNUNET_assert (NULL != subj);
368 1 : entry = GNUNET_JSON_PACK (
369 : TALER_JSON_pack_amount ("amount",
370 : &kac->tiny_amount),
371 : TALER_JSON_pack_full_payto ("target_payto",
372 : acc->payto),
373 : GNUNET_JSON_pack_object_steal ("subject",
374 : subj),
375 : GNUNET_JSON_pack_timestamp ("expiration",
376 : acc->expiration));
377 1 : GNUNET_assert (NULL != entry);
378 1 : GNUNET_assert (0 ==
379 : json_array_append_new (arr,
380 : entry));
381 : }
382 : }
383 1 : kac->response_code = MHD_HTTP_OK;
384 1 : kac->response = TALER_MHD_MAKE_JSON_PACK (
385 : GNUNET_JSON_pack_array_steal ("wire_instructions",
386 : arr));
387 1 : kac->phase = KP_RETURN_RESPONSE;
388 1 : kac_resume (kac);
389 1 : }
390 :
391 :
392 : /**
393 : * Callback invoked with the result of the bank gateway /registration request.
394 : *
395 : * @param cls our `struct KycAuthContext`
396 : * @param rr response details
397 : */
398 : static void
399 0 : registration_cb (void *cls,
400 : const struct TALER_BANK_RegistrationResponse *rr)
401 : {
402 0 : struct ExchangeAccount *acc = cls;
403 0 : struct KycAuthContext *kac = acc->kac;
404 :
405 0 : acc->brh = NULL;
406 0 : kac->active_registrations--;
407 0 : if (MHD_HTTP_OK != rr->http_status)
408 : {
409 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
410 : "Bank gateway registration failed with HTTP status %u\n",
411 : rr->http_status);
412 0 : if (NULL == kac->response)
413 : {
414 0 : kac->response_code = MHD_HTTP_BAD_GATEWAY;
415 0 : kac->response = TALER_MHD_make_error (
416 : TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_BANK_GATEWAY_UNREACHABLE,
417 : "bank gateway /registration failed");
418 0 : kac->phase = KP_RETURN_RESPONSE;
419 0 : kac_resume (kac);
420 : }
421 0 : return;
422 : }
423 0 : GNUNET_free (acc->subjects);
424 0 : acc->num_subjects = rr->details.ok.num_subjects;
425 0 : acc->subjects = GNUNET_new_array (acc->num_subjects,
426 : struct TALER_BANK_TransferSubject);
427 0 : for (unsigned int i = 0; i<acc->num_subjects; i++)
428 : {
429 0 : TALER_BANK_transfer_subject_copy (&acc->subjects[i],
430 0 : &rr->details.ok.subjects[i]);
431 : }
432 0 : acc->expiration = rr->details.ok.expiration;
433 0 : if (0 != kac->active_registrations)
434 0 : return; /* wait for more replies */
435 0 : generate_ok_response (kac);
436 : }
437 :
438 :
439 : /**
440 : * Callback invoked with the /keys of the selected exchange.
441 : *
442 : * Saves tiny_amount and exchange account payto URIs from the keys, then
443 : * either calls the bank gateway /registration (if wire_transfer_gateway is
444 : * present) or directly constructs the SIMPLE-format response.
445 : *
446 : * @param cls our `struct KycAuthContext`
447 : * @param keys the exchange's key material, or NULL on failure
448 : * @param exchange internal exchange handle (unused)
449 : */
450 : static void
451 1 : process_keys_cb (void *cls,
452 : struct TALER_EXCHANGE_Keys *keys,
453 : struct TMH_Exchange *exchange)
454 : {
455 1 : struct KycAuthContext *kac = cls;
456 1 : struct TMH_MerchantInstance *mi = kac->hc->instance;
457 :
458 : (void) exchange;
459 1 : kac->fo = NULL;
460 1 : if (NULL == keys)
461 : {
462 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
463 : "Could not get /keys from exchange `%s'\n",
464 : kac->exchange_url);
465 0 : GNUNET_assert (NULL == kac->response);
466 0 : kac->response_code = MHD_HTTP_BAD_GATEWAY;
467 0 : kac->response = TALER_MHD_make_error (
468 : TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_EXCHANGE_UNREACHABLE,
469 0 : kac->exchange_url);
470 0 : kac->phase = KP_RETURN_RESPONSE;
471 0 : kac_resume (kac);
472 0 : return;
473 : }
474 1 : if (! keys->tiny_amount_available)
475 : {
476 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
477 : "Exchange `%s' did not provide tiny_amount in /keys\n",
478 : kac->exchange_url);
479 0 : GNUNET_assert (NULL == kac->response);
480 0 : kac->response_code = MHD_HTTP_BAD_GATEWAY;
481 0 : kac->response = TALER_MHD_make_error (
482 : TALER_EC_MERCHANT_POST_ACCOUNTS_EXCHANGE_TOO_OLD,
483 : "exchange /keys missing tiny_amount");
484 0 : kac->phase = KP_RETURN_RESPONSE;
485 0 : kac_resume (kac);
486 0 : return;
487 : }
488 :
489 : /* Save tiny_amount and exchange wire accounts from keys */
490 1 : kac->tiny_amount = keys->tiny_amount;
491 1 : kac->exchange_accounts_len = keys->accounts_len;
492 1 : if (0 == keys->accounts_len)
493 : {
494 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
495 : "Exchange `%s' did not provide any wire accounts in /keys\n",
496 : kac->exchange_url);
497 0 : GNUNET_assert (NULL == kac->response);
498 0 : kac->response_code = MHD_HTTP_BAD_GATEWAY;
499 0 : kac->response = TALER_MHD_make_error (
500 : TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS,
501 : "exchange /keys missing wire accounts");
502 0 : kac->phase = KP_RETURN_RESPONSE;
503 0 : kac_resume (kac);
504 0 : return;
505 : }
506 :
507 : kac->exchange_accounts
508 1 : = GNUNET_new_array (keys->accounts_len,
509 : struct ExchangeAccount);
510 2 : for (unsigned int i = 0; i < keys->accounts_len; i++)
511 : {
512 1 : struct ExchangeAccount *acc = &kac->exchange_accounts[i];
513 : struct TALER_PreparedTransferAuthorizationPrivateKeyP apk;
514 :
515 1 : GNUNET_CRYPTO_eddsa_key_create (&apk.eddsa_priv);
516 1 : acc->kac = kac;
517 : acc->payto.full_payto
518 1 : = GNUNET_strdup (keys->accounts[i].fpayto_uri.full_payto);
519 1 : acc->subjects = GNUNET_new (struct TALER_BANK_TransferSubject);
520 1 : acc->num_subjects = 1;
521 1 : acc->subjects[0].format = TALER_BANK_SUBJECT_FORMAT_SIMPLE;
522 1 : acc->expiration = GNUNET_TIME_UNIT_FOREVER_TS;
523 1 : if (NULL == keys->accounts[i].prepared_transfer_url)
524 1 : continue;
525 0 : acc->brh = TALER_BANK_registration (
526 : TMH_curl_ctx,
527 0 : keys->accounts[i].prepared_transfer_url,
528 0 : &keys->accounts[i].fpayto_uri,
529 0 : &kac->tiny_amount,
530 : TALER_BANK_REGISTRATION_TYPE_KYC,
531 0 : (const union TALER_AccountPublicKeyP *) &mi->merchant_pub,
532 : // FIXME: turn this into an option when modernizing the BANK API...
533 : &apk,
534 : false, /* recurrent */
535 : ®istration_cb,
536 : acc);
537 0 : if (NULL == acc->brh)
538 : {
539 0 : GNUNET_break (0);
540 0 : GNUNET_assert (NULL == kac->response);
541 0 : kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
542 0 : kac->response = TALER_MHD_make_error (
543 : TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
544 : "could not start bank gateway registration");
545 0 : kac->phase = KP_RETURN_RESPONSE;
546 0 : kac_resume (kac);
547 0 : return;
548 : }
549 0 : kac->active_registrations++;
550 : }
551 1 : if (0 != kac->active_registrations)
552 0 : return;
553 1 : generate_ok_response (kac);
554 : }
555 :
556 :
557 : /**
558 : * Process the PARSE phase: validate the URL path, parse the request body,
559 : * and look up the merchant account in the database.
560 : *
561 : * @param[in,out] kac context to process
562 : */
563 : static void
564 1 : phase_parse (struct KycAuthContext *kac)
565 : {
566 1 : const char *h_wire_s = kac->hc->infix;
567 : struct TALER_MerchantWireHashP h_wire;
568 : const char *exchange_url;
569 : enum GNUNET_GenericReturnValue res;
570 : struct GNUNET_JSON_Specification spec[] = {
571 1 : TALER_JSON_spec_web_url ("exchange_url",
572 : &exchange_url),
573 1 : GNUNET_JSON_spec_end ()
574 : };
575 :
576 1 : GNUNET_assert (NULL != h_wire_s);
577 1 : if (GNUNET_OK !=
578 1 : GNUNET_STRINGS_string_to_data (h_wire_s,
579 : strlen (h_wire_s),
580 : &h_wire,
581 : sizeof (h_wire)))
582 : {
583 0 : GNUNET_break_op (0);
584 0 : kac->response_code = MHD_HTTP_BAD_REQUEST;
585 0 : kac->response = TALER_MHD_make_error (
586 : TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED,
587 : h_wire_s);
588 0 : kac->phase = KP_RETURN_RESPONSE;
589 0 : return;
590 : }
591 :
592 1 : res = TALER_MHD_parse_json_data (kac->connection,
593 1 : kac->hc->request_body,
594 : spec);
595 1 : if (GNUNET_OK != res)
596 : {
597 0 : kac->phase = (GNUNET_NO == res) ? KP_END_YES : KP_END_NO;
598 0 : return;
599 : }
600 :
601 : /* Look up the merchant account in the database */
602 : {
603 1 : struct TALER_MERCHANTDB_AccountDetails ad = { 0 };
604 : enum GNUNET_DB_QueryStatus qs;
605 :
606 1 : qs = TALER_MERCHANTDB_get_account (TMH_db,
607 1 : kac->hc->instance->settings.id,
608 : &h_wire,
609 : &ad);
610 1 : if (0 > qs)
611 : {
612 0 : GNUNET_break (0);
613 0 : GNUNET_JSON_parse_free (spec);
614 0 : kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
615 0 : kac->response = TALER_MHD_make_error (
616 : TALER_EC_GENERIC_DB_FETCH_FAILED,
617 : "get_account");
618 0 : kac->phase = KP_RETURN_RESPONSE;
619 0 : return;
620 : }
621 1 : if (0 == qs)
622 : {
623 0 : GNUNET_JSON_parse_free (spec);
624 0 : kac->response_code = MHD_HTTP_NOT_FOUND;
625 0 : kac->response = TALER_MHD_make_error (
626 : TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN,
627 : h_wire_s);
628 0 : kac->phase = KP_RETURN_RESPONSE;
629 0 : return;
630 : }
631 1 : kac->payto_uri.full_payto = GNUNET_strdup (ad.payto_uri.full_payto);
632 : /* Free fields we do not need */
633 1 : GNUNET_free (ad.payto_uri.full_payto);
634 1 : GNUNET_free (ad.credit_facade_url);
635 1 : GNUNET_free (ad.extra_wire_subject_metadata);
636 1 : json_decref (ad.credit_facade_credentials);
637 : }
638 :
639 1 : kac->exchange_url = GNUNET_strdup (exchange_url);
640 1 : GNUNET_JSON_parse_free (spec);
641 1 : kac->phase = KP_CHECK_EXCHANGES;
642 : }
643 :
644 :
645 : /**
646 : * Process the CHECK_EXCHANGES phase: start an async /keys fetch from
647 : * the requested exchange and suspend the connection.
648 : *
649 : * @param[in,out] kac context to process
650 : */
651 : static void
652 1 : phase_check_exchanges (struct KycAuthContext *kac)
653 : {
654 1 : kac->fo = TMH_EXCHANGES_keys4exchange (kac->exchange_url,
655 : false,
656 : &process_keys_cb,
657 : kac);
658 1 : if (NULL == kac->fo)
659 : {
660 0 : GNUNET_break_op (0);
661 0 : kac->response_code = MHD_HTTP_BAD_REQUEST;
662 0 : kac->response = TALER_MHD_make_error (
663 : TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
664 0 : kac->exchange_url);
665 0 : kac->phase = KP_RETURN_RESPONSE;
666 0 : return;
667 : }
668 1 : MHD_suspend_connection (kac->connection);
669 1 : kac->suspended = GNUNET_YES;
670 : }
671 :
672 :
673 : /**
674 : * Process the RETURN_RESPONSE phase: queue the prepared response into MHD.
675 : *
676 : * @param[in,out] kac context to process
677 : */
678 : static void
679 1 : phase_return_response (struct KycAuthContext *kac)
680 : {
681 : enum MHD_Result ret;
682 :
683 1 : if (UINT_MAX == kac->response_code)
684 : {
685 0 : GNUNET_break (0);
686 0 : kac->phase = KP_END_NO;
687 0 : return;
688 : }
689 1 : GNUNET_assert (0 != kac->response_code);
690 1 : ret = MHD_queue_response (kac->connection,
691 : kac->response_code,
692 : kac->response);
693 1 : kac->phase = (MHD_YES == ret) ? KP_END_YES : KP_END_NO;
694 : }
695 :
696 :
697 : enum MHD_Result
698 2 : TMH_private_post_accounts_H_WIRE_kycauth (
699 : const struct TMH_RequestHandler *rh,
700 : struct MHD_Connection *connection,
701 : struct TMH_HandlerContext *hc)
702 : {
703 2 : struct KycAuthContext *kac = hc->ctx;
704 :
705 : (void) rh;
706 2 : GNUNET_assert (NULL != hc->infix);
707 2 : if (NULL == kac)
708 : {
709 1 : kac = GNUNET_new (struct KycAuthContext);
710 1 : kac->connection = connection;
711 1 : kac->hc = hc;
712 1 : hc->ctx = kac;
713 1 : hc->cc = &kac_cleanup;
714 1 : GNUNET_CONTAINER_DLL_insert (kac_head,
715 : kac_tail,
716 : kac);
717 : }
718 :
719 : while (1)
720 : {
721 6 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
722 : "Processing POST /private/accounts/$H_WIRE/kycauth"
723 : " in phase %d\n",
724 : (int) kac->phase);
725 4 : switch (kac->phase)
726 : {
727 1 : case KP_PARSE:
728 1 : phase_parse (kac);
729 1 : break;
730 1 : case KP_CHECK_EXCHANGES:
731 1 : phase_check_exchanges (kac);
732 1 : break;
733 1 : case KP_RETURN_RESPONSE:
734 1 : phase_return_response (kac);
735 1 : break;
736 1 : case KP_END_YES:
737 1 : return MHD_YES;
738 0 : case KP_END_NO:
739 0 : return MHD_NO;
740 0 : default:
741 0 : GNUNET_assert (0);
742 : return MHD_NO;
743 : }
744 :
745 3 : switch (kac->suspended)
746 : {
747 0 : case GNUNET_SYSERR:
748 : /* Shutdown in progress */
749 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
750 : "Processing POST /private/accounts/$H_WIRE/kycauth"
751 : " ends due to shutdown in phase %d\n",
752 : (int) kac->phase);
753 0 : return MHD_NO;
754 2 : case GNUNET_NO:
755 : /* Not suspended, continue with next phase */
756 2 : break;
757 1 : case GNUNET_YES:
758 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
759 : "Processing POST /private/accounts/$H_WIRE/kycauth"
760 : " suspended in phase %d\n",
761 : (int) kac->phase);
762 1 : return MHD_YES;
763 : }
764 : }
765 : GNUNET_assert (0);
766 : return MHD_YES;
767 : }
768 :
769 :
770 : /* end of taler-merchant-httpd_private-post-accounts-H_WIRE-kycauth.c */
|