taler-merchant-httpd_post-challenge-ID-confirm.c (4872B)
1 /* 2 This file is part of TALER 3 (C) 2025 Taler Systems SA 4 5 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 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 src/backend/taler-merchant-httpd_post-challenge-ID-confirm.c 22 * @brief endpoint to solve MFA challenge 23 * @author Christian Grothoff 24 */ 25 #include "platform.h" 26 #include "taler-merchant-httpd.h" 27 #include "taler-merchant-httpd_mfa.h" 28 #include "taler-merchant-httpd_post-challenge-ID-confirm.h" 29 #include "merchant-database/solve_mfa_challenge.h" 30 31 32 enum MHD_Result 33 TMH_post_challenge_ID_confirm (const struct TMH_RequestHandler *rh, 34 struct MHD_Connection *connection, 35 struct TMH_HandlerContext *hc) 36 { 37 uint64_t challenge_serial; 38 struct TALER_MERCHANT_MFA_BodyHash h_body; 39 const char *tan; 40 struct GNUNET_JSON_Specification spec[] = { 41 GNUNET_JSON_spec_string ("tan", 42 &tan), 43 GNUNET_JSON_spec_end () 44 }; 45 enum GNUNET_DB_QueryStatus qs; 46 bool solved; 47 uint32_t retry_counter; 48 enum GNUNET_GenericReturnValue ret; 49 char *xtan = NULL; 50 51 ret = TMH_mfa_parse_challenge_id (hc, 52 hc->infix, 53 &challenge_serial, 54 &h_body); 55 if (GNUNET_OK != ret) 56 return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES; 57 { 58 enum GNUNET_GenericReturnValue res; 59 60 res = TALER_MHD_parse_json_data (hc->connection, 61 hc->request_body, 62 spec); 63 if (GNUNET_OK != res) 64 { 65 GNUNET_break_op (0); 66 return (GNUNET_NO == res) 67 ? MHD_YES 68 : MHD_NO; 69 } 70 } 71 { 72 /* User may have submitted the entire challenge as a single 73 8-digit number instead of (4-digits)-"-"-(4-digits) which 74 is the new format generated by taler-merchant-httpd_mfa.c. 75 Thus, in this case, we convert the format to the string 76 with the dash and use that. */ 77 unsigned long long challenge_num; 78 char dummy; 79 80 if (1 == 81 sscanf (tan, 82 "%llu%c", 83 &challenge_num, 84 &dummy)) 85 { 86 /* inject hyphen */ 87 GNUNET_asprintf (&xtan, 88 "%04llu-%04llu", 89 challenge_num / 10000, 90 challenge_num % 10000); 91 92 } 93 } 94 qs = TALER_MERCHANTDB_solve_mfa_challenge (TMH_db, 95 challenge_serial, 96 &h_body, 97 (NULL == xtan) 98 ? tan 99 : xtan, 100 &solved, 101 &retry_counter); 102 GNUNET_free (xtan); 103 switch (qs) 104 { 105 case GNUNET_DB_STATUS_HARD_ERROR: 106 GNUNET_break (0); 107 return TALER_MHD_reply_with_error ( 108 hc->connection, 109 110 MHD_HTTP_INTERNAL_SERVER_ERROR, 111 TALER_EC_GENERIC_DB_COMMIT_FAILED, 112 "solve_mfa_challenge"); 113 case GNUNET_DB_STATUS_SOFT_ERROR: 114 GNUNET_break (0); 115 return TALER_MHD_reply_with_error ( 116 hc->connection, 117 MHD_HTTP_INTERNAL_SERVER_ERROR, 118 TALER_EC_GENERIC_DB_SOFT_FAILURE, 119 "solve_mfa_challenge"); 120 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 121 GNUNET_break_op (0); 122 return TALER_MHD_reply_with_error ( 123 hc->connection, 124 MHD_HTTP_NOT_FOUND, 125 TALER_EC_MERCHANT_TAN_CHALLENGE_UNKNOWN, 126 hc->infix); 127 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 128 break; 129 } 130 if (0 == retry_counter) 131 { 132 return TALER_MHD_reply_with_error ( 133 hc->connection, 134 MHD_HTTP_TOO_MANY_REQUESTS, 135 TALER_EC_MERCHANT_TAN_TOO_MANY_ATTEMPTS, 136 NULL); 137 } 138 if (! solved) 139 { 140 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 141 "Generating JSON response with code %d\n", 142 (int) TALER_EC_MERCHANT_TAN_CHALLENGE_FAILED); 143 return TALER_MHD_REPLY_JSON_PACK ( 144 hc->connection, 145 MHD_HTTP_CONFLICT, 146 TALER_MHD_PACK_EC (TALER_EC_MERCHANT_TAN_CHALLENGE_FAILED), 147 GNUNET_JSON_pack_uint64 ("retry_counter", 148 retry_counter)); 149 } 150 return TALER_MHD_reply_static ( 151 hc->connection, 152 MHD_HTTP_NO_CONTENT, 153 NULL, 154 NULL, 155 0); 156 }