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