exchange

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

fakebank_bank_post_withdrawals_id_op.c (11415B)


      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_bank_post_withdrawals_id_op.c
     21  * @brief implement bank API POST /accounts/$ACCOUNT/withdrawals/$WID/$OP endpoint(s)
     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_bank_post_withdrawals_id_op.h"
     32 #include "fakebank_common_lookup.h"
     33 #include "fakebank_common_lp.h"
     34 #include "fakebank_common_make_admin_transfer.h"
     35 
     36 
     37 /**
     38  * Handle POST /accounts/$ACC/withdrawals/{withdrawal_id}/confirm request.
     39  *
     40  * @param h our fakebank handle
     41  * @param connection the connection
     42  * @param account name of the account
     43  * @param withdrawal_id the withdrawal operation identifier
     44  * @param body uploaded JSON body, NULL if none
     45  * @return MHD result code
     46  */
     47 static MHD_RESULT
     48 bank_withdrawals_confirm (
     49   struct TALER_FAKEBANK_Handle *h,
     50   struct MHD_Connection *connection,
     51   const char *account,
     52   const char *withdrawal_id,
     53   const json_t *body)
     54 {
     55   const struct Account *acc;
     56   struct WithdrawalOperation *wo;
     57   struct TALER_Amount amount;
     58   bool amount_missing = true;
     59   struct GNUNET_JSON_Specification spec[] = {
     60     GNUNET_JSON_spec_mark_optional (
     61       TALER_JSON_spec_amount ("amount",
     62                               h->currency,
     63                               &amount),
     64       &amount_missing),
     65     GNUNET_JSON_spec_end ()
     66   };
     67   enum GNUNET_GenericReturnValue ret;
     68 
     69   if ( (NULL != body) &&
     70        (GNUNET_OK !=
     71         (ret = TALER_MHD_parse_json_data (connection,
     72                                           body,
     73                                           spec))) )
     74   {
     75     GNUNET_break_op (0);
     76     return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
     77   }
     78 
     79   GNUNET_assert (0 ==
     80                  pthread_mutex_lock (&h->big_lock));
     81   acc = TALER_FAKEBANK_lookup_account_ (h,
     82                                         account,
     83                                         NULL);
     84   if (NULL == acc)
     85   {
     86     GNUNET_assert (0 ==
     87                    pthread_mutex_unlock (&h->big_lock));
     88     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     89                 "Account %s is unknown\n",
     90                 account);
     91     return TALER_MHD_reply_with_error (connection,
     92                                        MHD_HTTP_NOT_FOUND,
     93                                        TALER_EC_BANK_UNKNOWN_ACCOUNT,
     94                                        account);
     95   }
     96   wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h,
     97                                                     withdrawal_id);
     98   if ( (NULL == wo) ||
     99        (acc != wo->debit_account) )
    100   {
    101     GNUNET_assert (0 ==
    102                    pthread_mutex_unlock (&h->big_lock));
    103     return TALER_MHD_reply_with_error (connection,
    104                                        MHD_HTTP_NOT_FOUND,
    105                                        TALER_EC_BANK_TRANSACTION_NOT_FOUND,
    106                                        withdrawal_id);
    107   }
    108   if (NULL == wo->exchange_account)
    109   {
    110     GNUNET_assert (0 ==
    111                    pthread_mutex_unlock (&h->big_lock));
    112     return TALER_MHD_reply_with_error (connection,
    113                                        MHD_HTTP_BAD_REQUEST,
    114                                        TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED,
    115                                        NULL);
    116   }
    117   if ( (NULL != wo->amount) &&
    118        (! amount_missing) &&
    119        (0 != TALER_amount_cmp (&amount,
    120                                wo->amount)) )
    121   {
    122     GNUNET_assert (0 ==
    123                    pthread_mutex_unlock (&h->big_lock));
    124     return TALER_MHD_reply_with_error (connection,
    125                                        MHD_HTTP_CONFLICT,
    126                                        TALER_EC_BANK_CONFIRM_ABORT_CONFLICT,
    127                                        "amount inconsistent");
    128   }
    129   if ( (NULL == wo->amount) &&
    130        (amount_missing) )
    131   {
    132     GNUNET_assert (0 ==
    133                    pthread_mutex_unlock (&h->big_lock));
    134     return TALER_MHD_reply_with_error (connection,
    135                                        MHD_HTTP_CONFLICT,
    136                                        TALER_EC_BANK_CONFIRM_ABORT_CONFLICT,
    137                                        "amount required");
    138   }
    139   if (NULL == wo->amount)
    140   {
    141     GNUNET_assert (! amount_missing);
    142     wo->amount = GNUNET_new (struct TALER_Amount);
    143     *wo->amount = amount;
    144   }
    145   if (wo->aborted)
    146   {
    147     GNUNET_assert (0 ==
    148                    pthread_mutex_unlock (&h->big_lock));
    149     return TALER_MHD_reply_with_error (connection,
    150                                        MHD_HTTP_CONFLICT,
    151                                        TALER_EC_BANK_CONFIRM_ABORT_CONFLICT,
    152                                        withdrawal_id);
    153   }
    154   GNUNET_assert (0 ==
    155                  pthread_mutex_unlock (&h->big_lock));
    156   if (GNUNET_OK !=
    157       TALER_FAKEBANK_make_admin_transfer_ (
    158         h,
    159         wo->debit_account->account_name,
    160         wo->exchange_account->account_name,
    161         wo->amount,
    162         &wo->reserve_pub,
    163         &wo->row_id,
    164         &wo->timestamp))
    165   {
    166     return TALER_MHD_reply_with_error (connection,
    167                                        MHD_HTTP_CONFLICT,
    168                                        TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT,
    169                                        NULL);
    170   }
    171   /* Re-acquiring the lock and continuing to operate on 'wo'
    172      is currently (!) acceptable because we NEVER free 'wo'
    173      until shutdown. We may want to revise this if keeping
    174      all withdraw operations in RAM becomes an issue... */
    175   GNUNET_assert (0 ==
    176                  pthread_mutex_lock (&h->big_lock));
    177   wo->confirmation_done = true;
    178   TALER_FAKEBANK_notify_withdrawal_ (h,
    179                                      wo);
    180   GNUNET_assert (0 ==
    181                  pthread_mutex_unlock (&h->big_lock));
    182   return TALER_MHD_reply_static (connection,
    183                                  MHD_HTTP_NO_CONTENT,
    184                                  NULL,
    185                                  NULL,
    186                                  0);
    187 }
    188 
    189 
    190 /**
    191  * Handle POST /accounts/$ACC/withdrawals/{withdrawal_id}/abort request.
    192  *
    193  * @param h our fakebank handle
    194  * @param connection the connection
    195  * @param account name of the account
    196  * @param withdrawal_id the withdrawal operation identifier
    197  * @param body uploaded JSON body, NULL if none
    198  * @return MHD result code
    199  */
    200 static MHD_RESULT
    201 bank_withdrawals_abort (
    202   struct TALER_FAKEBANK_Handle *h,
    203   struct MHD_Connection *connection,
    204   const char *account,
    205   const char *withdrawal_id,
    206   const json_t *body)
    207 {
    208   struct WithdrawalOperation *wo;
    209   const struct Account *acc;
    210 
    211   GNUNET_assert (0 ==
    212                  pthread_mutex_lock (&h->big_lock));
    213   acc = TALER_FAKEBANK_lookup_account_ (h,
    214                                         account,
    215                                         NULL);
    216   if (NULL == acc)
    217   {
    218     GNUNET_assert (0 ==
    219                    pthread_mutex_unlock (&h->big_lock));
    220     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    221                 "Account %s is unknown\n",
    222                 account);
    223     return TALER_MHD_reply_with_error (connection,
    224                                        MHD_HTTP_NOT_FOUND,
    225                                        TALER_EC_BANK_UNKNOWN_ACCOUNT,
    226                                        account);
    227   }
    228   wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h,
    229                                                     withdrawal_id);
    230   if ( (NULL == wo) ||
    231        (acc != wo->debit_account) )
    232   {
    233     GNUNET_assert (0 ==
    234                    pthread_mutex_unlock (&h->big_lock));
    235     return TALER_MHD_reply_with_error (connection,
    236                                        MHD_HTTP_NOT_FOUND,
    237                                        TALER_EC_BANK_TRANSACTION_NOT_FOUND,
    238                                        withdrawal_id);
    239   }
    240   if (wo->confirmation_done)
    241   {
    242     GNUNET_assert (0 ==
    243                    pthread_mutex_unlock (&h->big_lock));
    244     return TALER_MHD_reply_with_error (connection,
    245                                        MHD_HTTP_CONFLICT,
    246                                        TALER_EC_BANK_ABORT_CONFIRM_CONFLICT,
    247                                        withdrawal_id);
    248   }
    249   wo->aborted = true;
    250   TALER_FAKEBANK_notify_withdrawal_ (h,
    251                                      wo);
    252   GNUNET_assert (0 ==
    253                  pthread_mutex_unlock (&h->big_lock));
    254   return TALER_MHD_reply_static (connection,
    255                                  MHD_HTTP_NO_CONTENT,
    256                                  NULL,
    257                                  NULL,
    258                                  0);
    259 }
    260 
    261 
    262 MHD_RESULT
    263 TALER_FAKEBANK_bank_withdrawals_id_op_ (
    264   struct TALER_FAKEBANK_Handle *h,
    265   struct MHD_Connection *connection,
    266   const char *account,
    267   const char *withdrawal_id,
    268   const char *op,
    269   const char *upload_data,
    270   size_t *upload_data_size,
    271   void **con_cls)
    272 {
    273   struct ConnectionContext *cc = *con_cls;
    274   json_t *json = NULL;
    275 
    276   if (NULL == cc)
    277   {
    278     cc = GNUNET_new (struct ConnectionContext);
    279     cc->ctx_cleaner = &GNUNET_MHD_post_parser_cleanup;
    280     *con_cls = cc;
    281   }
    282   if (0 != *upload_data_size)
    283   {
    284     enum GNUNET_MHD_PostResult pr;
    285 
    286     pr = GNUNET_MHD_post_parser (REQUEST_BUFFER_MAX,
    287                                  connection,
    288                                  &cc->ctx,
    289                                  upload_data,
    290                                  upload_data_size,
    291                                  &json);
    292     switch (pr)
    293     {
    294     case GNUNET_MHD_PR_OUT_OF_MEMORY:
    295       GNUNET_break (0);
    296       return MHD_NO;
    297     case GNUNET_MHD_PR_CONTINUE:
    298       return MHD_YES;
    299     case GNUNET_MHD_PR_REQUEST_TOO_LARGE:
    300       GNUNET_break (0);
    301       return MHD_NO;
    302     case GNUNET_MHD_PR_JSON_INVALID:
    303       GNUNET_break (0);
    304       return MHD_NO;
    305     case GNUNET_MHD_PR_SUCCESS:
    306       break;
    307     }
    308   }
    309 
    310   if (0 == strcmp (op,
    311                    "/confirm"))
    312   {
    313     MHD_RESULT res;
    314 
    315     res = bank_withdrawals_confirm (h,
    316                                     connection,
    317                                     account,
    318                                     withdrawal_id,
    319                                     json);
    320     json_decref (json);
    321     return res;
    322   }
    323   if (0 == strcmp (op,
    324                    "/abort"))
    325   {
    326     MHD_RESULT res;
    327 
    328     res = bank_withdrawals_abort (h,
    329                                   connection,
    330                                   account,
    331                                   withdrawal_id,
    332                                   json);
    333     json_decref (json);
    334     return res;
    335   }
    336   GNUNET_break_op (0);
    337   json_decref (json);
    338   return TALER_MHD_reply_with_error (connection,
    339                                      MHD_HTTP_NOT_FOUND,
    340                                      TALER_EC_GENERIC_ENDPOINT_UNKNOWN,
    341                                      op);
    342 }