fakebank_tbi_post_withdrawal_operation.c (9794B)
1 /* 2 This file is part of TALER 3 (C) 2016-2024 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or 6 modify it under the terms of the GNU General Public License 7 as 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, 11 but 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 * @file bank-lib/fakebank_tbi_post_withdrawal_operation.c 21 * @brief library that fakes being a Taler bank for testcases 22 * @author Christian Grothoff <christian@grothoff.org> 23 */ 24 #include <pthread.h> 25 #include "taler/taler_fakebank_lib.h" 26 #include "taler/taler_bank_service.h" 27 #include "taler/taler_mhd_lib.h" 28 #include <gnunet/gnunet_mhd_compat.h> 29 #include <gnunet/gnunet_mhd_lib.h> 30 #include "fakebank.h" 31 #include "fakebank_common_lookup.h" 32 #include "fakebank_tbi_post_withdrawal_operation.h" 33 34 35 /** 36 * Execute POST /withdrawal-operation/ request. 37 * 38 * @param h our handle 39 * @param connection the connection 40 * @param wopid the withdrawal operation identifier 41 * @param reserve_pub public key of the reserve 42 * @param exchange_payto_uri payto://-URI of the exchange 43 * @param amount chosen by the client, or NULL to use the 44 * pre-determined amount 45 * @return MHD result code 46 */ 47 static MHD_RESULT 48 do_post_withdrawal ( 49 struct TALER_FAKEBANK_Handle *h, 50 struct MHD_Connection *connection, 51 const char *wopid, 52 const struct TALER_ReservePublicKeyP *reserve_pub, 53 const struct TALER_FullPayto exchange_payto_uri, 54 const struct TALER_Amount *amount) 55 { 56 struct WithdrawalOperation *wo; 57 char *credit_name; 58 struct Account *credit_account; 59 const char *status_string; 60 61 GNUNET_assert (0 == 62 pthread_mutex_lock (&h->big_lock)); 63 wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h, 64 wopid); 65 if (NULL == wo) 66 { 67 GNUNET_assert (0 == 68 pthread_mutex_unlock (&h->big_lock)); 69 return TALER_MHD_reply_with_error (connection, 70 MHD_HTTP_NOT_FOUND, 71 TALER_EC_BANK_TRANSACTION_NOT_FOUND, 72 wopid); 73 } 74 if (wo->aborted) 75 { 76 GNUNET_assert (0 == 77 pthread_mutex_unlock (&h->big_lock)); 78 return TALER_MHD_reply_with_error (connection, 79 MHD_HTTP_CONFLICT, 80 TALER_EC_BANK_UPDATE_ABORT_CONFLICT, 81 wopid); 82 } 83 if ( (wo->selection_done) && 84 (0 != GNUNET_memcmp (&wo->reserve_pub, 85 reserve_pub)) ) 86 { 87 GNUNET_assert (0 == 88 pthread_mutex_unlock (&h->big_lock)); 89 return TALER_MHD_reply_with_error (connection, 90 MHD_HTTP_CONFLICT, 91 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 92 "reserve public key changed"); 93 } 94 { 95 /* check if reserve_pub is already in use */ 96 const struct GNUNET_PeerIdentity *pid; 97 98 pid = (const struct GNUNET_PeerIdentity *) &wo->reserve_pub; 99 if (GNUNET_CONTAINER_multipeermap_contains (h->rpubs, 100 pid)) 101 { 102 GNUNET_assert (0 == 103 pthread_mutex_unlock (&h->big_lock)); 104 return TALER_MHD_reply_with_error (connection, 105 MHD_HTTP_CONFLICT, 106 TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT, 107 NULL); 108 } 109 } 110 credit_name = TALER_xtalerbank_account_from_payto (exchange_payto_uri); 111 if (NULL == credit_name) 112 { 113 GNUNET_break_op (0); 114 GNUNET_assert (0 == 115 pthread_mutex_unlock (&h->big_lock)); 116 return TALER_MHD_reply_with_error (connection, 117 MHD_HTTP_BAD_REQUEST, 118 TALER_EC_GENERIC_PAYTO_URI_MALFORMED, 119 NULL); 120 } 121 credit_account = TALER_FAKEBANK_lookup_account_ (h, 122 credit_name, 123 NULL); 124 if (NULL == credit_account) 125 { 126 MHD_RESULT res; 127 128 GNUNET_break_op (0); 129 GNUNET_assert (0 == 130 pthread_mutex_unlock (&h->big_lock)); 131 res = TALER_MHD_reply_with_error (connection, 132 MHD_HTTP_NOT_FOUND, 133 TALER_EC_BANK_UNKNOWN_ACCOUNT, 134 credit_name); 135 GNUNET_free (credit_name); 136 return res; 137 } 138 GNUNET_free (credit_name); 139 if ( (NULL != wo->exchange_account) && 140 (credit_account != wo->exchange_account) ) 141 { 142 GNUNET_assert (0 == 143 pthread_mutex_unlock (&h->big_lock)); 144 return TALER_MHD_reply_with_error (connection, 145 MHD_HTTP_CONFLICT, 146 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 147 "exchange account changed"); 148 } 149 if ( (NULL != wo->amount) && (NULL != amount) && (0 != TALER_amount_cmp (wo-> 150 amount, 151 amount)) ) 152 { 153 GNUNET_assert (0 == 154 pthread_mutex_unlock (&h->big_lock)); 155 return TALER_MHD_reply_with_error (connection, 156 MHD_HTTP_CONFLICT, 157 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 158 "amount changed"); 159 } 160 if (NULL == wo->amount) 161 { 162 if (NULL == amount) 163 { 164 GNUNET_assert (0 == 165 pthread_mutex_unlock (&h->big_lock)); 166 return TALER_MHD_reply_with_error (connection, 167 MHD_HTTP_BAD_REQUEST, 168 TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED, 169 "amount missing"); 170 } 171 else 172 { 173 wo->amount = GNUNET_new (struct TALER_Amount); 174 *wo->amount = *amount; 175 } 176 } 177 GNUNET_assert (NULL != wo->amount); 178 wo->exchange_account = credit_account; 179 wo->reserve_pub = *reserve_pub; 180 wo->selection_done = true; 181 GNUNET_assert (0 == 182 pthread_mutex_unlock (&h->big_lock)); 183 if (wo->aborted) 184 status_string = "aborted"; 185 else if (wo->confirmation_done) 186 status_string = "confirmed"; 187 else 188 status_string = "selected"; 189 return TALER_MHD_REPLY_JSON_PACK ( 190 connection, 191 MHD_HTTP_OK, 192 // FIXME: Deprecated field, should be deleted in the future. 193 GNUNET_JSON_pack_bool ("transfer_done", 194 wo->confirmation_done), 195 GNUNET_JSON_pack_string ("status", 196 status_string)); 197 } 198 199 200 MHD_RESULT 201 TALER_FAKEBANK_tbi_post_withdrawal ( 202 struct TALER_FAKEBANK_Handle *h, 203 struct MHD_Connection *connection, 204 const char *wopid, 205 const void *upload_data, 206 size_t *upload_data_size, 207 void **con_cls) 208 { 209 struct ConnectionContext *cc = *con_cls; 210 enum GNUNET_MHD_PostResult pr; 211 json_t *json; 212 MHD_RESULT res; 213 214 if (NULL == cc) 215 { 216 cc = GNUNET_new (struct ConnectionContext); 217 cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup; 218 *con_cls = cc; 219 } 220 pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX, 221 connection, 222 &cc->ctx, 223 upload_data, 224 upload_data_size, 225 &json); 226 switch (pr) 227 { 228 case GNUNET_MHD_PR_OUT_OF_MEMORY: 229 GNUNET_break (0); 230 return MHD_NO; 231 case GNUNET_MHD_PR_CONTINUE: 232 return MHD_YES; 233 case GNUNET_MHD_PR_REQUEST_TOO_LARGE: 234 GNUNET_break (0); 235 return MHD_NO; 236 case GNUNET_MHD_PR_JSON_INVALID: 237 GNUNET_break (0); 238 return MHD_NO; 239 case GNUNET_MHD_PR_SUCCESS: 240 break; 241 } 242 243 { 244 struct TALER_ReservePublicKeyP reserve_pub; 245 struct TALER_FullPayto exchange_payto_url; 246 enum GNUNET_GenericReturnValue ret; 247 struct TALER_Amount amount; 248 bool amount_missing; 249 struct TALER_Amount *amount_ptr; 250 struct GNUNET_JSON_Specification spec[] = { 251 GNUNET_JSON_spec_fixed_auto ("reserve_pub", 252 &reserve_pub), 253 TALER_JSON_spec_full_payto_uri ("selected_exchange", 254 &exchange_payto_url), 255 GNUNET_JSON_spec_mark_optional ( 256 TALER_JSON_spec_amount ("amount", 257 h->currency, 258 &amount), 259 &amount_missing), 260 GNUNET_JSON_spec_end () 261 }; 262 263 if (GNUNET_OK != 264 (ret = TALER_MHD_parse_json_data (connection, 265 json, 266 spec))) 267 { 268 GNUNET_break_op (0); 269 json_decref (json); 270 return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; 271 } 272 273 amount_ptr = amount_missing ? NULL : &amount; 274 275 res = do_post_withdrawal (h, 276 connection, 277 wopid, 278 &reserve_pub, 279 exchange_payto_url, 280 amount_ptr); 281 } 282 json_decref (json); 283 return res; 284 }