fakebank_tbi_post_withdrawal_operation.c (9334B)
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 enum 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 ( 70 connection, 71 MHD_HTTP_NOT_FOUND, 72 TALER_EC_BANK_TRANSACTION_NOT_FOUND, 73 wopid); 74 } 75 if (wo->aborted) 76 { 77 GNUNET_assert (0 == 78 pthread_mutex_unlock (&h->big_lock)); 79 return TALER_MHD_reply_with_error ( 80 connection, 81 MHD_HTTP_CONFLICT, 82 TALER_EC_BANK_UPDATE_ABORT_CONFLICT, 83 wopid); 84 } 85 if ( (wo->selection_done) && 86 (0 != GNUNET_memcmp (&wo->reserve_pub, 87 reserve_pub)) ) 88 { 89 GNUNET_assert (0 == 90 pthread_mutex_unlock (&h->big_lock)); 91 return TALER_MHD_reply_with_error ( 92 connection, 93 MHD_HTTP_CONFLICT, 94 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 95 "reserve public key changed"); 96 } 97 { 98 /* check if reserve_pub is already in use */ 99 const struct GNUNET_PeerIdentity *pid; 100 bool duplicate; 101 102 pid = (const struct GNUNET_PeerIdentity *) reserve_pub; 103 GNUNET_assert (0 == pthread_mutex_lock (&h->rpubs_lock)); 104 duplicate = GNUNET_CONTAINER_multipeermap_contains (h->rpubs, 105 pid); 106 GNUNET_assert (0 == pthread_mutex_unlock (&h->rpubs_lock)); 107 if (duplicate) 108 { 109 GNUNET_assert (0 == 110 pthread_mutex_unlock (&h->big_lock)); 111 return TALER_MHD_reply_with_error (connection, 112 MHD_HTTP_CONFLICT, 113 TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT, 114 NULL); 115 } 116 } 117 credit_name = TALER_xtalerbank_account_from_payto (exchange_payto_uri); 118 if (NULL == credit_name) 119 { 120 GNUNET_break_op (0); 121 GNUNET_assert (0 == 122 pthread_mutex_unlock (&h->big_lock)); 123 return TALER_MHD_reply_with_error (connection, 124 MHD_HTTP_BAD_REQUEST, 125 TALER_EC_GENERIC_PAYTO_URI_MALFORMED, 126 NULL); 127 } 128 credit_account = TALER_FAKEBANK_lookup_account_ (h, 129 credit_name, 130 NULL); 131 if (NULL == credit_account) 132 { 133 enum MHD_Result res; 134 135 GNUNET_break_op (0); 136 GNUNET_assert (0 == 137 pthread_mutex_unlock (&h->big_lock)); 138 res = TALER_MHD_reply_with_error (connection, 139 MHD_HTTP_NOT_FOUND, 140 TALER_EC_BANK_UNKNOWN_ACCOUNT, 141 credit_name); 142 GNUNET_free (credit_name); 143 return res; 144 } 145 GNUNET_free (credit_name); 146 if ( (NULL != wo->exchange_account) && 147 (credit_account != wo->exchange_account) ) 148 { 149 GNUNET_assert (0 == 150 pthread_mutex_unlock (&h->big_lock)); 151 return TALER_MHD_reply_with_error ( 152 connection, 153 MHD_HTTP_CONFLICT, 154 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 155 "exchange account changed"); 156 } 157 if ( (NULL != wo->amount) && 158 (NULL != amount) && 159 (0 != TALER_amount_cmp (wo->amount, 160 amount)) ) 161 { 162 GNUNET_assert (0 == 163 pthread_mutex_unlock (&h->big_lock)); 164 return TALER_MHD_reply_with_error ( 165 connection, 166 MHD_HTTP_CONFLICT, 167 TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, 168 "amount changed"); 169 } 170 if (NULL == wo->amount) 171 { 172 if (NULL == amount) 173 { 174 GNUNET_assert (0 == 175 pthread_mutex_unlock (&h->big_lock)); 176 return TALER_MHD_reply_with_error ( 177 connection, 178 MHD_HTTP_BAD_REQUEST, 179 TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED, 180 "amount missing"); 181 } 182 else 183 { 184 wo->amount = GNUNET_new (struct TALER_Amount); 185 *wo->amount = *amount; 186 } 187 } 188 GNUNET_assert (NULL != wo->amount); 189 wo->exchange_account = credit_account; 190 wo->reserve_pub = *reserve_pub; 191 wo->selection_done = true; 192 GNUNET_assert (0 == 193 pthread_mutex_unlock (&h->big_lock)); 194 if (wo->aborted) 195 status_string = "aborted"; 196 else if (wo->confirmation_done) 197 status_string = "confirmed"; 198 else 199 status_string = "selected"; 200 return TALER_MHD_REPLY_JSON_PACK ( 201 connection, 202 MHD_HTTP_OK, 203 // FIXME: Deprecated field, should be deleted in the future. 204 GNUNET_JSON_pack_bool ("transfer_done", 205 wo->confirmation_done), 206 GNUNET_JSON_pack_string ("status", 207 status_string)); 208 } 209 210 211 enum MHD_Result 212 TALER_FAKEBANK_tbi_post_withdrawal ( 213 struct TALER_FAKEBANK_Handle *h, 214 struct MHD_Connection *connection, 215 const char *wopid, 216 const void *upload_data, 217 size_t *upload_data_size, 218 void **con_cls) 219 { 220 struct ConnectionContext *cc = *con_cls; 221 enum GNUNET_MHD_PostResult pr; 222 json_t *json; 223 enum MHD_Result res; 224 225 if (NULL == cc) 226 { 227 cc = GNUNET_new (struct ConnectionContext); 228 cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup; 229 *con_cls = cc; 230 } 231 pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX, 232 connection, 233 &cc->ctx, 234 upload_data, 235 upload_data_size, 236 &json); 237 switch (pr) 238 { 239 case GNUNET_MHD_PR_OUT_OF_MEMORY: 240 GNUNET_break (0); 241 return MHD_NO; 242 case GNUNET_MHD_PR_CONTINUE: 243 return MHD_YES; 244 case GNUNET_MHD_PR_REQUEST_TOO_LARGE: 245 GNUNET_break (0); 246 return MHD_NO; 247 case GNUNET_MHD_PR_JSON_INVALID: 248 GNUNET_break (0); 249 return MHD_NO; 250 case GNUNET_MHD_PR_SUCCESS: 251 break; 252 } 253 254 { 255 struct TALER_ReservePublicKeyP reserve_pub; 256 struct TALER_FullPayto exchange_payto_url; 257 enum GNUNET_GenericReturnValue ret; 258 struct TALER_Amount amount; 259 bool amount_missing; 260 struct TALER_Amount *amount_ptr; 261 struct GNUNET_JSON_Specification spec[] = { 262 GNUNET_JSON_spec_fixed_auto ("reserve_pub", 263 &reserve_pub), 264 TALER_JSON_spec_full_payto_uri ("selected_exchange", 265 &exchange_payto_url), 266 GNUNET_JSON_spec_mark_optional ( 267 TALER_JSON_spec_amount ("amount", 268 h->currency, 269 &amount), 270 &amount_missing), 271 GNUNET_JSON_spec_end () 272 }; 273 274 if (GNUNET_OK != 275 (ret = TALER_MHD_parse_json_data (connection, 276 json, 277 spec))) 278 { 279 GNUNET_break_op (0); 280 json_decref (json); 281 return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; 282 } 283 284 amount_ptr = amount_missing ? NULL : &amount; 285 286 res = do_post_withdrawal (h, 287 connection, 288 wopid, 289 &reserve_pub, 290 exchange_payto_url, 291 amount_ptr); 292 } 293 json_decref (json); 294 return res; 295 }