taler-merchant-httpd_post-challenge-ID-confirm.c (4920B)
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/do_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 75 taler-merchant-httpd_post-challenge-ID.c. 76 Thus, in this case, we convert the format to the string 77 with the dash and use that. */ 78 unsigned long long challenge_num; 79 char dummy; 80 81 if (1 == 82 sscanf (tan, 83 "%llu%c", 84 &challenge_num, 85 &dummy)) 86 { 87 /* inject hyphen */ 88 GNUNET_asprintf (&xtan, 89 "%04llu-%04llu", 90 challenge_num / 10000, 91 challenge_num % 10000); 92 93 } 94 } 95 qs = TALER_MERCHANTDB_do_solve_mfa_challenge (TMH_db, 96 challenge_serial, 97 &h_body, 98 (NULL == xtan) 99 ? tan 100 : xtan, 101 &solved, 102 &retry_counter); 103 GNUNET_free (xtan); 104 switch (qs) 105 { 106 case GNUNET_DB_STATUS_HARD_ERROR: 107 GNUNET_break (0); 108 return TALER_MHD_reply_with_error ( 109 hc->connection, 110 111 MHD_HTTP_INTERNAL_SERVER_ERROR, 112 TALER_EC_GENERIC_DB_COMMIT_FAILED, 113 "do_solve_mfa_challenge"); 114 case GNUNET_DB_STATUS_SOFT_ERROR: 115 GNUNET_break (0); 116 return TALER_MHD_reply_with_error ( 117 hc->connection, 118 MHD_HTTP_INTERNAL_SERVER_ERROR, 119 TALER_EC_GENERIC_DB_SOFT_FAILURE, 120 "do_solve_mfa_challenge"); 121 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 122 GNUNET_break_op (0); 123 return TALER_MHD_reply_with_error ( 124 hc->connection, 125 MHD_HTTP_NOT_FOUND, 126 TALER_EC_MERCHANT_TAN_CHALLENGE_UNKNOWN, 127 hc->infix); 128 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 129 break; 130 } 131 if (0 == retry_counter) 132 { 133 return TALER_MHD_reply_with_error ( 134 hc->connection, 135 MHD_HTTP_TOO_MANY_REQUESTS, 136 TALER_EC_MERCHANT_TAN_TOO_MANY_ATTEMPTS, 137 NULL); 138 } 139 if (! solved) 140 { 141 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 142 "Generating JSON response with code %d\n", 143 (int) TALER_EC_MERCHANT_TAN_CHALLENGE_FAILED); 144 return TALER_MHD_REPLY_JSON_PACK ( 145 hc->connection, 146 MHD_HTTP_CONFLICT, 147 TALER_MHD_PACK_EC (TALER_EC_MERCHANT_TAN_CHALLENGE_FAILED), 148 GNUNET_JSON_pack_uint64 ("retry_counter", 149 retry_counter)); 150 } 151 return TALER_MHD_reply_static ( 152 hc->connection, 153 MHD_HTTP_NO_CONTENT, 154 NULL, 155 NULL, 156 0); 157 }