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 (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 }