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