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 (11443B)


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