/* This file is part of TALER (C) 2016-2023 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, see */ /** * @file bank-lib/fakebank_tbi_post_withdrawal_operation.c * @brief library that fakes being a Taler bank for testcases * @author Christian Grothoff */ #include "platform.h" #include #include "taler_fakebank_lib.h" #include "taler_bank_service.h" #include "taler_mhd_lib.h" #include #include "fakebank.h" #include "fakebank_common_lookup.h" #include "fakebank_tbi_post_withdrawal_operation.h" /** * Execute POST /withdrawal-operation/ request. * * @param h our handle * @param connection the connection * @param wopid the withdrawal operation identifier * @param reserve_pub public key of the reserve * @param exchange_payto_uri payto://-URI of the exchange * @return MHD result code */ static MHD_RESULT do_post_withdrawal ( struct TALER_FAKEBANK_Handle *h, struct MHD_Connection *connection, const char *wopid, const struct TALER_ReservePublicKeyP *reserve_pub, const char *exchange_payto_uri) { struct WithdrawalOperation *wo; char *credit_name; struct Account *credit_account; const char *status_string; GNUNET_assert (0 == pthread_mutex_lock (&h->big_lock)); wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h, wopid); if (NULL == wo) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return TALER_MHD_reply_with_error (connection, MHD_HTTP_NOT_FOUND, TALER_EC_BANK_TRANSACTION_NOT_FOUND, wopid); } if ( (wo->selection_done) && (0 != GNUNET_memcmp (&wo->reserve_pub, reserve_pub)) ) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return TALER_MHD_reply_with_error (connection, MHD_HTTP_CONFLICT, TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, "reserve public key changed"); } { /* check if reserve_pub is already in use */ const struct GNUNET_PeerIdentity *pid; pid = (const struct GNUNET_PeerIdentity *) &wo->reserve_pub; if (GNUNET_CONTAINER_multipeermap_contains (h->rpubs, pid)) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return TALER_MHD_reply_with_error (connection, MHD_HTTP_CONFLICT, TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT, NULL); } } credit_name = TALER_xtalerbank_account_from_payto (exchange_payto_uri); if (NULL == credit_name) { GNUNET_break_op (0); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return TALER_MHD_reply_with_error (connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PAYTO_URI_MALFORMED, NULL); } credit_account = TALER_FAKEBANK_lookup_account_ (h, credit_name, NULL); if (NULL == credit_account) { MHD_RESULT res; GNUNET_break_op (0); GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); res = TALER_MHD_reply_with_error (connection, MHD_HTTP_NOT_FOUND, TALER_EC_BANK_UNKNOWN_ACCOUNT, credit_name); GNUNET_free (credit_name); return res; } GNUNET_free (credit_name); if ( (NULL != wo->exchange_account) && (credit_account != wo->exchange_account) ) { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); return TALER_MHD_reply_with_error (connection, MHD_HTTP_CONFLICT, TALER_EC_BANK_WITHDRAWAL_OPERATION_RESERVE_SELECTION_CONFLICT, "exchange account changed"); } wo->exchange_account = credit_account; wo->reserve_pub = *reserve_pub; wo->selection_done = true; GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); if (wo->aborted) status_string = "aborted"; else if (wo->confirmation_done) status_string = "confirmed"; else status_string = "selected"; return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, // FIXME: Deprecated field, should be deleted in the future. GNUNET_JSON_pack_bool ("transfer_done", wo->confirmation_done), GNUNET_JSON_pack_string ("status", status_string)); } MHD_RESULT TALER_FAKEBANK_tbi_post_withdrawal ( struct TALER_FAKEBANK_Handle *h, struct MHD_Connection *connection, const char *wopid, const void *upload_data, size_t *upload_data_size, void **con_cls) { struct ConnectionContext *cc = *con_cls; enum GNUNET_JSON_PostResult pr; json_t *json; MHD_RESULT res; if (NULL == cc) { cc = GNUNET_new (struct ConnectionContext); cc->ctx_cleaner = &GNUNET_JSON_post_parser_cleanup; *con_cls = cc; } pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, connection, &cc->ctx, upload_data, upload_data_size, &json); switch (pr) { case GNUNET_JSON_PR_OUT_OF_MEMORY: GNUNET_break (0); return MHD_NO; case GNUNET_JSON_PR_CONTINUE: return MHD_YES; case GNUNET_JSON_PR_REQUEST_TOO_LARGE: GNUNET_break (0); return MHD_NO; case GNUNET_JSON_PR_JSON_INVALID: GNUNET_break (0); return MHD_NO; case GNUNET_JSON_PR_SUCCESS: break; } { struct TALER_ReservePublicKeyP reserve_pub; const char *exchange_payto_url; enum GNUNET_GenericReturnValue ret; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("reserve_pub", &reserve_pub), GNUNET_JSON_spec_string ("selected_exchange", &exchange_payto_url), GNUNET_JSON_spec_end () }; if (GNUNET_OK != (ret = TALER_MHD_parse_json_data (connection, json, spec))) { GNUNET_break_op (0); json_decref (json); return (GNUNET_NO == ret) ? MHD_YES : MHD_NO; } res = do_post_withdrawal (h, connection, wopid, &reserve_pub, exchange_payto_url); } json_decref (json); return res; }