taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c (21502B)
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 TMH_force_kac_resume (void) 204 { 205 for (struct KycAuthContext *kac = kac_head; 206 NULL != kac; 207 kac = kac->next) 208 { 209 if (NULL != kac->fo) 210 { 211 TMH_EXCHANGES_keys4exchange_cancel (kac->fo); 212 kac->fo = NULL; 213 } 214 if (GNUNET_YES == kac->suspended) 215 { 216 kac->suspended = GNUNET_SYSERR; 217 MHD_resume_connection (kac->connection); 218 } 219 } 220 } 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 kac_resume (struct KycAuthContext *kac) 230 { 231 GNUNET_assert (GNUNET_YES == kac->suspended); 232 kac->suspended = GNUNET_NO; 233 MHD_resume_connection (kac->connection); 234 TALER_MHD_daemon_trigger (); 235 } 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 kac_cleanup (void *cls) 245 { 246 struct KycAuthContext *kac = cls; 247 248 if (NULL != kac->fo) 249 { 250 TMH_EXCHANGES_keys4exchange_cancel (kac->fo); 251 kac->fo = NULL; 252 } 253 if (NULL != kac->response) 254 { 255 MHD_destroy_response (kac->response); 256 kac->response = NULL; 257 } 258 GNUNET_free (kac->exchange_url); 259 GNUNET_free (kac->payto_uri.full_payto); 260 for (unsigned int i = 0; i < kac->exchange_accounts_len; i++) 261 { 262 struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 263 264 if (NULL != acc->brh) 265 { 266 TALER_BANK_registration_cancel (acc->brh); 267 acc->brh = NULL; 268 } 269 for (unsigned int j = 0; j<acc->num_subjects; j++) 270 TALER_BANK_transfer_subject_free (&acc->subjects[j]); 271 GNUNET_free (acc->subjects); 272 GNUNET_free (acc->payto.full_payto); 273 } 274 GNUNET_free (kac->exchange_accounts); 275 GNUNET_CONTAINER_DLL_remove (kac_head, 276 kac_tail, 277 kac); 278 GNUNET_free (kac); 279 } 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 kyc_transfer_subject_to_json (const struct ExchangeAccount *acc, 293 const struct TALER_BANK_TransferSubject *ts) 294 { 295 struct KycAuthContext *kac = acc->kac; 296 json_t *ret; 297 298 switch (ts->format) 299 { 300 case TALER_BANK_SUBJECT_FORMAT_SIMPLE: 301 { 302 struct GNUNET_Buffer buf = { 0 }; 303 char *subject; 304 305 GNUNET_buffer_write_str (&buf, 306 "KYC:"); 307 GNUNET_buffer_write_data_encoded (&buf, 308 &kac->hc->instance->merchant_pub, 309 sizeof (kac->hc->instance->merchant_pub)); 310 subject = GNUNET_buffer_reap_str (&buf); 311 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 GNUNET_free (subject); 319 } 320 return ret; 321 case TALER_BANK_SUBJECT_FORMAT_URI: 322 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 case TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL: 330 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 GNUNET_break (0); 339 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 generate_ok_response (struct KycAuthContext *kac) 352 { 353 json_t *arr; 354 355 arr = json_array (); 356 GNUNET_assert (NULL != arr); 357 for (unsigned int i = 0; i < kac->exchange_accounts_len; i++) 358 { 359 const struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 360 json_t *subj; 361 json_t *entry; 362 363 for (unsigned int j = 0; j < acc->num_subjects; j++) 364 { 365 subj = kyc_transfer_subject_to_json (acc, 366 &acc->subjects[j]); 367 GNUNET_assert (NULL != subj); 368 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 GNUNET_assert (NULL != entry); 378 GNUNET_assert (0 == 379 json_array_append_new (arr, 380 entry)); 381 } 382 } 383 kac->response_code = MHD_HTTP_OK; 384 kac->response = TALER_MHD_MAKE_JSON_PACK ( 385 GNUNET_JSON_pack_array_steal ("wire_instructions", 386 arr)); 387 kac->phase = KP_RETURN_RESPONSE; 388 kac_resume (kac); 389 } 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 registration_cb (void *cls, 400 const struct TALER_BANK_RegistrationResponse *rr) 401 { 402 struct ExchangeAccount *acc = cls; 403 struct KycAuthContext *kac = acc->kac; 404 405 acc->brh = NULL; 406 kac->active_registrations--; 407 if (MHD_HTTP_OK != rr->http_status) 408 { 409 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 410 "Bank gateway registration failed with HTTP status %u\n", 411 rr->http_status); 412 if (NULL == kac->response) 413 { 414 kac->response_code = MHD_HTTP_BAD_GATEWAY; 415 kac->response = TALER_MHD_make_error ( 416 TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_BANK_GATEWAY_UNREACHABLE, 417 "bank gateway /registration failed"); 418 kac->phase = KP_RETURN_RESPONSE; 419 kac_resume (kac); 420 } 421 return; 422 } 423 GNUNET_free (acc->subjects); 424 acc->num_subjects = rr->details.ok.num_subjects; 425 acc->subjects = GNUNET_new_array (acc->num_subjects, 426 struct TALER_BANK_TransferSubject); 427 for (unsigned int i = 0; i<acc->num_subjects; i++) 428 { 429 TALER_BANK_transfer_subject_copy (&acc->subjects[i], 430 &rr->details.ok.subjects[i]); 431 } 432 acc->expiration = rr->details.ok.expiration; 433 if (0 != kac->active_registrations) 434 return; /* wait for more replies */ 435 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 process_keys_cb (void *cls, 452 struct TALER_EXCHANGE_Keys *keys, 453 struct TMH_Exchange *exchange) 454 { 455 struct KycAuthContext *kac = cls; 456 struct TMH_MerchantInstance *mi = kac->hc->instance; 457 458 (void) exchange; 459 kac->fo = NULL; 460 if (NULL == keys) 461 { 462 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 463 "Could not get /keys from exchange `%s'\n", 464 kac->exchange_url); 465 GNUNET_assert (NULL == kac->response); 466 kac->response_code = MHD_HTTP_BAD_GATEWAY; 467 kac->response = TALER_MHD_make_error ( 468 TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_EXCHANGE_UNREACHABLE, 469 kac->exchange_url); 470 kac->phase = KP_RETURN_RESPONSE; 471 kac_resume (kac); 472 return; 473 } 474 if (! keys->tiny_amount_available) 475 { 476 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 477 "Exchange `%s' did not provide tiny_amount in /keys\n", 478 kac->exchange_url); 479 GNUNET_assert (NULL == kac->response); 480 kac->response_code = MHD_HTTP_BAD_GATEWAY; 481 kac->response = TALER_MHD_make_error ( 482 TALER_EC_MERCHANT_POST_ACCOUNTS_EXCHANGE_TOO_OLD, 483 "exchange /keys missing tiny_amount"); 484 kac->phase = KP_RETURN_RESPONSE; 485 kac_resume (kac); 486 return; 487 } 488 489 /* Save tiny_amount and exchange wire accounts from keys */ 490 kac->tiny_amount = keys->tiny_amount; 491 kac->exchange_accounts_len = keys->accounts_len; 492 if (0 == keys->accounts_len) 493 { 494 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 495 "Exchange `%s' did not provide any wire accounts in /keys\n", 496 kac->exchange_url); 497 GNUNET_assert (NULL == kac->response); 498 kac->response_code = MHD_HTTP_BAD_GATEWAY; 499 kac->response = TALER_MHD_make_error ( 500 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS, 501 "exchange /keys missing wire accounts"); 502 kac->phase = KP_RETURN_RESPONSE; 503 kac_resume (kac); 504 return; 505 } 506 507 kac->exchange_accounts 508 = GNUNET_new_array (keys->accounts_len, 509 struct ExchangeAccount); 510 for (unsigned int i = 0; i < keys->accounts_len; i++) 511 { 512 struct ExchangeAccount *acc = &kac->exchange_accounts[i]; 513 struct TALER_PreparedTransferAuthorizationPrivateKeyP apk; 514 515 GNUNET_CRYPTO_eddsa_key_create (&apk.eddsa_priv); 516 acc->kac = kac; 517 acc->payto.full_payto 518 = GNUNET_strdup (keys->accounts[i].fpayto_uri.full_payto); 519 acc->subjects = GNUNET_new (struct TALER_BANK_TransferSubject); 520 acc->num_subjects = 1; 521 acc->subjects[0].format = TALER_BANK_SUBJECT_FORMAT_SIMPLE; 522 acc->expiration = GNUNET_TIME_UNIT_FOREVER_TS; 523 if (NULL == keys->accounts[i].prepared_transfer_url) 524 continue; 525 acc->brh = TALER_BANK_registration ( 526 TMH_curl_ctx, 527 keys->accounts[i].prepared_transfer_url, 528 &keys->accounts[i].fpayto_uri, 529 &kac->tiny_amount, 530 TALER_BANK_REGISTRATION_TYPE_KYC, 531 (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 if (NULL == acc->brh) 538 { 539 GNUNET_break (0); 540 GNUNET_assert (NULL == kac->response); 541 kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 542 kac->response = TALER_MHD_make_error ( 543 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 544 "could not start bank gateway registration"); 545 kac->phase = KP_RETURN_RESPONSE; 546 kac_resume (kac); 547 return; 548 } 549 kac->active_registrations++; 550 } 551 if (0 != kac->active_registrations) 552 return; 553 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 phase_parse (struct KycAuthContext *kac) 565 { 566 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 GNUNET_JSON_spec_string ("exchange_url", 572 &exchange_url), 573 GNUNET_JSON_spec_end () 574 }; 575 576 GNUNET_assert (NULL != h_wire_s); 577 if (GNUNET_OK != 578 GNUNET_STRINGS_string_to_data (h_wire_s, 579 strlen (h_wire_s), 580 &h_wire, 581 sizeof (h_wire))) 582 { 583 GNUNET_break_op (0); 584 kac->response_code = MHD_HTTP_BAD_REQUEST; 585 kac->response = TALER_MHD_make_error ( 586 TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED, 587 h_wire_s); 588 kac->phase = KP_RETURN_RESPONSE; 589 return; 590 } 591 592 res = TALER_MHD_parse_json_data (kac->connection, 593 kac->hc->request_body, 594 spec); 595 if (GNUNET_OK != res) 596 { 597 kac->phase = (GNUNET_NO == res) ? KP_END_YES : KP_END_NO; 598 return; 599 } 600 601 /* Look up the merchant account in the database */ 602 { 603 struct TALER_MERCHANTDB_AccountDetails ad = { 0 }; 604 enum GNUNET_DB_QueryStatus qs; 605 606 qs = TALER_MERCHANTDB_get_account (TMH_db, 607 kac->hc->instance->settings.id, 608 &h_wire, 609 &ad); 610 if (0 > qs) 611 { 612 GNUNET_break (0); 613 GNUNET_JSON_parse_free (spec); 614 kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR; 615 kac->response = TALER_MHD_make_error ( 616 TALER_EC_GENERIC_DB_FETCH_FAILED, 617 "get_account"); 618 kac->phase = KP_RETURN_RESPONSE; 619 return; 620 } 621 if (0 == qs) 622 { 623 GNUNET_JSON_parse_free (spec); 624 kac->response_code = MHD_HTTP_NOT_FOUND; 625 kac->response = TALER_MHD_make_error ( 626 TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN, 627 h_wire_s); 628 kac->phase = KP_RETURN_RESPONSE; 629 return; 630 } 631 kac->payto_uri.full_payto = GNUNET_strdup (ad.payto_uri.full_payto); 632 /* Free fields we do not need */ 633 GNUNET_free (ad.payto_uri.full_payto); 634 GNUNET_free (ad.credit_facade_url); 635 GNUNET_free (ad.extra_wire_subject_metadata); 636 json_decref (ad.credit_facade_credentials); 637 } 638 639 kac->exchange_url = GNUNET_strdup (exchange_url); 640 GNUNET_JSON_parse_free (spec); 641 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 phase_check_exchanges (struct KycAuthContext *kac) 653 { 654 kac->fo = TMH_EXCHANGES_keys4exchange (kac->exchange_url, 655 false, 656 &process_keys_cb, 657 kac); 658 if (NULL == kac->fo) 659 { 660 GNUNET_break_op (0); 661 kac->response_code = MHD_HTTP_BAD_REQUEST; 662 kac->response = TALER_MHD_make_error ( 663 TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED, 664 kac->exchange_url); 665 kac->phase = KP_RETURN_RESPONSE; 666 return; 667 } 668 MHD_suspend_connection (kac->connection); 669 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 phase_return_response (struct KycAuthContext *kac) 680 { 681 enum MHD_Result ret; 682 683 if (UINT_MAX == kac->response_code) 684 { 685 GNUNET_break (0); 686 kac->phase = KP_END_NO; 687 return; 688 } 689 GNUNET_assert (0 != kac->response_code); 690 ret = MHD_queue_response (kac->connection, 691 kac->response_code, 692 kac->response); 693 kac->phase = (MHD_YES == ret) ? KP_END_YES : KP_END_NO; 694 } 695 696 697 enum MHD_Result 698 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 struct KycAuthContext *kac = hc->ctx; 704 705 (void) rh; 706 GNUNET_assert (NULL != hc->infix); 707 if (NULL == kac) 708 { 709 kac = GNUNET_new (struct KycAuthContext); 710 kac->connection = connection; 711 kac->hc = hc; 712 hc->ctx = kac; 713 hc->cc = &kac_cleanup; 714 GNUNET_CONTAINER_DLL_insert (kac_head, 715 kac_tail, 716 kac); 717 } 718 719 while (1) 720 { 721 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 722 "Processing POST /private/accounts/$H_WIRE/kycauth" 723 " in phase %d\n", 724 (int) kac->phase); 725 switch (kac->phase) 726 { 727 case KP_PARSE: 728 phase_parse (kac); 729 break; 730 case KP_CHECK_EXCHANGES: 731 phase_check_exchanges (kac); 732 break; 733 case KP_RETURN_RESPONSE: 734 phase_return_response (kac); 735 break; 736 case KP_END_YES: 737 return MHD_YES; 738 case KP_END_NO: 739 return MHD_NO; 740 default: 741 GNUNET_assert (0); 742 return MHD_NO; 743 } 744 745 switch (kac->suspended) 746 { 747 case GNUNET_SYSERR: 748 /* Shutdown in progress */ 749 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 return MHD_NO; 754 case GNUNET_NO: 755 /* Not suspended, continue with next phase */ 756 break; 757 case GNUNET_YES: 758 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 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 */