exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

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 }