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