LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_deposit.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 113 164 68.9 %
Date: 2021-08-30 06:43:37 Functions: 4 4 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2020 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Affero General Public License as published by the Free Software
       7             :   Foundation; either version 3, or (at your option) any later version.
       8             : 
       9             :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10             :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11             :   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Affero General Public License along with
      14             :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15             : */
      16             : /**
      17             :  * @file taler-exchange-httpd_deposit.c
      18             :  * @brief Handle /deposit requests; parses the POST and JSON and
      19             :  *        verifies the coin signature before handing things off
      20             :  *        to the database.
      21             :  * @author Florian Dold
      22             :  * @author Benedikt Mueller
      23             :  * @author Christian Grothoff
      24             :  */
      25             : #include "platform.h"
      26             : #include <gnunet/gnunet_util_lib.h>
      27             : #include <gnunet/gnunet_json_lib.h>
      28             : #include <jansson.h>
      29             : #include <microhttpd.h>
      30             : #include <pthread.h>
      31             : #include "taler_json_lib.h"
      32             : #include "taler_mhd_lib.h"
      33             : #include "taler-exchange-httpd_deposit.h"
      34             : #include "taler-exchange-httpd_responses.h"
      35             : #include "taler_exchangedb_lib.h"
      36             : #include "taler-exchange-httpd_keys.h"
      37             : 
      38             : 
      39             : /**
      40             :  * Send confirmation of deposit success to client.  This function
      41             :  * will create a signed message affirming the given information
      42             :  * and return it to the client.  By this, the exchange affirms that
      43             :  * the coin had sufficient (residual) value for the specified
      44             :  * transaction and that it will execute the requested deposit
      45             :  * operation with the given wiring details.
      46             :  *
      47             :  * @param connection connection to the client
      48             :  * @param coin_pub public key of the coin
      49             :  * @param h_wire hash of wire details
      50             :  * @param h_contract_terms hash of contract details
      51             :  * @param exchange_timestamp exchange's timestamp
      52             :  * @param refund_deadline until when this deposit be refunded
      53             :  * @param merchant merchant public key
      54             :  * @param amount_without_fee fraction of coin value to deposit, without the fee
      55             :  * @return MHD result code
      56             :  */
      57             : static MHD_RESULT
      58          33 : reply_deposit_success (struct MHD_Connection *connection,
      59             :                        const struct TALER_CoinSpendPublicKeyP *coin_pub,
      60             :                        const struct GNUNET_HashCode *h_wire,
      61             :                        const struct GNUNET_HashCode *h_contract_terms,
      62             :                        struct GNUNET_TIME_Absolute exchange_timestamp,
      63             :                        struct GNUNET_TIME_Absolute refund_deadline,
      64             :                        const struct TALER_MerchantPublicKeyP *merchant,
      65             :                        const struct TALER_Amount *amount_without_fee)
      66             : {
      67             :   struct TALER_ExchangePublicKeyP pub;
      68             :   struct TALER_ExchangeSignatureP sig;
      69          66 :   struct TALER_DepositConfirmationPS dc = {
      70          33 :     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT),
      71          33 :     .purpose.size = htonl (sizeof (dc)),
      72             :     .h_contract_terms = *h_contract_terms,
      73             :     .h_wire = *h_wire,
      74          33 :     .exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp),
      75          33 :     .refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
      76             :     .coin_pub = *coin_pub,
      77             :     .merchant = *merchant
      78             :   };
      79             :   enum TALER_ErrorCode ec;
      80             : 
      81          33 :   TALER_amount_hton (&dc.amount_without_fee,
      82             :                      amount_without_fee);
      83          33 :   if (TALER_EC_NONE !=
      84          33 :       (ec = TEH_keys_exchange_sign (&dc,
      85             :                                     &pub,
      86             :                                     &sig)))
      87             :   {
      88           0 :     return TALER_MHD_reply_with_ec (connection,
      89             :                                     ec,
      90             :                                     NULL);
      91             :   }
      92          33 :   return TALER_MHD_REPLY_JSON_PACK (
      93             :     connection,
      94             :     MHD_HTTP_OK,
      95             :     GNUNET_JSON_pack_time_abs ("exchange_timestamp",
      96             :                                exchange_timestamp),
      97             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
      98             :                                 &sig),
      99             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
     100             :                                 &pub));
     101             : }
     102             : 
     103             : 
     104             : /**
     105             :  * Closure for #deposit_transaction.
     106             :  */
     107             : struct DepositContext
     108             : {
     109             :   /**
     110             :    * Information about the deposit request.
     111             :    */
     112             :   const struct TALER_EXCHANGEDB_Deposit *deposit;
     113             : 
     114             :   /**
     115             :    * Our timestamp (when we received the request).
     116             :    */
     117             :   struct GNUNET_TIME_Absolute exchange_timestamp;
     118             : 
     119             :   /**
     120             :    * Value of the coin.
     121             :    */
     122             :   struct TALER_Amount value;
     123             : 
     124             : };
     125             : 
     126             : 
     127             : /**
     128             :  * Check if /deposit is already in the database.  IF it returns a non-error
     129             :  * code, the transaction logic MUST NOT queue a MHD response.  IF it returns
     130             :  * an hard error, the transaction logic MUST queue a MHD response and set @a
     131             :  * mhd_ret.  We do return a "hard" error also if we found the deposit in the
     132             :  * database and generated a regular response.
     133             :  *
     134             :  * @param cls a `struct DepositContext`
     135             :  * @param connection MHD request context
     136             :  * @param[out] mhd_ret set to MHD status on error
     137             :  * @return transaction status
     138             :  */
     139             : static enum GNUNET_DB_QueryStatus
     140          78 : deposit_precheck (void *cls,
     141             :                   struct MHD_Connection *connection,
     142             :                   MHD_RESULT *mhd_ret)
     143             : {
     144          78 :   struct DepositContext *dc = cls;
     145          78 :   const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
     146             :   struct TALER_Amount deposit_fee;
     147             :   enum GNUNET_DB_QueryStatus qs;
     148             : 
     149          78 :   qs = TEH_plugin->have_deposit (TEH_plugin->cls,
     150             :                                  deposit,
     151             :                                  GNUNET_YES /* check refund deadline */,
     152             :                                  &deposit_fee,
     153             :                                  &dc->exchange_timestamp);
     154          78 :   if (qs < 0)
     155             :   {
     156           0 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     157             :     {
     158           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     159             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     160             :                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
     161             :                                              NULL);
     162           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     163             :     }
     164           0 :     return qs;
     165             :   }
     166          78 :   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
     167             :   {
     168             :     struct TALER_Amount amount_without_fee;
     169             : 
     170           1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     171             :                 "/deposit replay, accepting again!\n");
     172           1 :     GNUNET_assert (0 <=
     173             :                    TALER_amount_subtract (&amount_without_fee,
     174             :                                           &deposit->amount_with_fee,
     175             :                                           &deposit_fee));
     176           1 :     *mhd_ret = reply_deposit_success (connection,
     177             :                                       &deposit->coin.coin_pub,
     178             :                                       &deposit->h_wire,
     179             :                                       &deposit->h_contract_terms,
     180             :                                       dc->exchange_timestamp,
     181             :                                       deposit->refund_deadline,
     182             :                                       &deposit->merchant_pub,
     183             :                                       &amount_without_fee);
     184             :     /* Treat as 'hard' DB error as we want to rollback and
     185             :        never try again. */
     186           1 :     return GNUNET_DB_STATUS_HARD_ERROR;
     187             :   }
     188          77 :   return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
     189             : }
     190             : 
     191             : 
     192             : /**
     193             :  * Execute database transaction for /deposit.  Runs the transaction
     194             :  * logic; IF it returns a non-error code, the transaction logic MUST
     195             :  * NOT queue a MHD response.  IF it returns an hard error, the
     196             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     197             :  * it returns the soft error code, the function MAY be called again to
     198             :  * retry and MUST not queue a MHD response.
     199             :  *
     200             :  * @param cls a `struct DepositContext`
     201             :  * @param connection MHD request context
     202             :  * @param[out] mhd_ret set to MHD status on error
     203             :  * @return transaction status
     204             :  */
     205             : static enum GNUNET_DB_QueryStatus
     206          38 : deposit_transaction (void *cls,
     207             :                      struct MHD_Connection *connection,
     208             :                      MHD_RESULT *mhd_ret)
     209             : {
     210          38 :   struct DepositContext *dc = cls;
     211          38 :   const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
     212             :   struct TALER_Amount spent;
     213             :   enum GNUNET_DB_QueryStatus qs;
     214             : 
     215             :   /* make sure coin is 'known' in database */
     216          38 :   qs = TEH_make_coin_known (&deposit->coin,
     217             :                             connection,
     218             :                             mhd_ret);
     219          38 :   if (qs < 0)
     220           1 :     return qs;
     221             : 
     222             :   /* Theoretically, someone other threat may have received
     223             :      and committed the deposit in the meantime. Check now
     224             :      that we are in the transaction scope. */
     225          37 :   qs = deposit_precheck (cls,
     226             :                          connection,
     227             :                          mhd_ret);
     228          37 :   if (qs < 0)
     229           0 :     return qs;
     230             : 
     231             :   /* Start with fee for THIS transaction */
     232          37 :   spent = deposit->amount_with_fee;
     233             :   /* add cost of all previous transactions; skip RECOUP as revoked
     234             :      denominations are not eligible for deposit, and if we are the old coin
     235             :      pub of a revoked coin (aka a zombie), then ONLY refresh is allowed. */
     236             :   {
     237             :     struct TALER_EXCHANGEDB_TransactionList *tl;
     238             : 
     239          37 :     qs = TEH_plugin->get_coin_transactions (TEH_plugin->cls,
     240             :                                             &deposit->coin.coin_pub,
     241             :                                             GNUNET_NO,
     242             :                                             &tl);
     243          37 :     if (0 > qs)
     244             :     {
     245           0 :       if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     246           0 :         *mhd_ret = TALER_MHD_reply_with_error (
     247             :           connection,
     248             :           MHD_HTTP_INTERNAL_SERVER_ERROR,
     249             :           TALER_EC_GENERIC_DB_FETCH_FAILED,
     250             :           NULL);
     251           5 :       return qs;
     252             :     }
     253          37 :     if (GNUNET_OK !=
     254          37 :         TALER_EXCHANGEDB_calculate_transaction_list_totals (tl,
     255             :                                                             &spent, /* starting offset */
     256             :                                                             &spent /* result */))
     257             :     {
     258           0 :       TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
     259             :                                               tl);
     260           0 :       *mhd_ret = TALER_MHD_reply_with_error (
     261             :         connection,
     262             :         MHD_HTTP_INTERNAL_SERVER_ERROR,
     263             :         TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
     264             :         NULL);
     265           0 :       return GNUNET_DB_STATUS_HARD_ERROR;
     266             :     }
     267             :     /* Check that cost of all transactions (including the current one) is
     268             :        smaller (or equal) than the value of the coin. */
     269          37 :     if (0 < TALER_amount_cmp (&spent,
     270          37 :                               &dc->value))
     271             :     {
     272           5 :       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     273             :                   "Deposited coin has insufficient funds left!\n");
     274           5 :       *mhd_ret = TEH_RESPONSE_reply_coin_insufficient_funds (connection,
     275             :                                                              TALER_EC_EXCHANGE_DEPOSIT_INSUFFICIENT_FUNDS,
     276             :                                                              &deposit->coin.
     277             :                                                              coin_pub,
     278             :                                                              tl);
     279           5 :       TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
     280             :                                               tl);
     281           5 :       return GNUNET_DB_STATUS_HARD_ERROR;
     282             :     }
     283          32 :     TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
     284             :                                             tl);
     285             :   }
     286          32 :   qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
     287             :                                    dc->exchange_timestamp,
     288             :                                    deposit);
     289          32 :   if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     290             :   {
     291           0 :     TALER_LOG_WARNING ("Failed to store /deposit information in database\n");
     292           0 :     *mhd_ret = TALER_MHD_reply_with_error (connection,
     293             :                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
     294             :                                            TALER_EC_GENERIC_DB_STORE_FAILED,
     295             :                                            NULL);
     296             :   }
     297          32 :   return qs;
     298             : }
     299             : 
     300             : 
     301             : /**
     302             :  * Handle a "/coins/$COIN_PUB/deposit" request.  Parses the JSON, and, if
     303             :  * successful, passes the JSON data to #deposit_transaction() to
     304             :  * further check the details of the operation specified.  If everything checks
     305             :  * out, this will ultimately lead to the "/deposit" being executed, or
     306             :  * rejected.
     307             :  *
     308             :  * @param connection the MHD connection to handle
     309             :  * @param coin_pub public key of the coin
     310             :  * @param root uploaded JSON data
     311             :  * @return MHD result code
     312             :   */
     313             : MHD_RESULT
     314          41 : TEH_handler_deposit (struct MHD_Connection *connection,
     315             :                      const struct TALER_CoinSpendPublicKeyP *coin_pub,
     316             :                      const json_t *root)
     317             : {
     318             :   json_t *wire;
     319             :   struct DepositContext dc;
     320             :   struct TALER_EXCHANGEDB_Deposit deposit;
     321             :   struct GNUNET_HashCode my_h_wire;
     322             :   struct GNUNET_JSON_Specification spec[] = {
     323          41 :     GNUNET_JSON_spec_json ("wire", &wire),
     324          41 :     TALER_JSON_spec_amount ("contribution",
     325             :                             TEH_currency,
     326             :                             &deposit.amount_with_fee),
     327          41 :     GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
     328             :                                  &deposit.coin.denom_pub_hash),
     329          41 :     TALER_JSON_spec_denomination_signature ("ub_sig",
     330             :                                             &deposit.coin.denom_sig),
     331          41 :     GNUNET_JSON_spec_fixed_auto ("merchant_pub",
     332             :                                  &deposit.merchant_pub),
     333          41 :     GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
     334             :                                  &deposit.h_contract_terms),
     335          41 :     GNUNET_JSON_spec_fixed_auto ("h_wire",
     336             :                                  &deposit.h_wire),
     337          41 :     GNUNET_JSON_spec_fixed_auto ("coin_sig",
     338             :                                  &deposit.csig),
     339          41 :     TALER_JSON_spec_absolute_time ("timestamp",
     340             :                                    &deposit.timestamp),
     341          41 :     GNUNET_JSON_spec_mark_optional (
     342             :       TALER_JSON_spec_absolute_time ("refund_deadline",
     343             :                                      &deposit.refund_deadline)),
     344          41 :     TALER_JSON_spec_absolute_time ("wire_transfer_deadline",
     345             :                                    &deposit.wire_deadline),
     346          41 :     GNUNET_JSON_spec_end ()
     347             :   };
     348             : 
     349          41 :   memset (&deposit,
     350             :           0,
     351             :           sizeof (deposit));
     352          41 :   deposit.coin.coin_pub = *coin_pub;
     353             :   {
     354             :     int res;
     355             : 
     356          41 :     res = TALER_MHD_parse_json_data (connection,
     357             :                                      root,
     358             :                                      spec);
     359          41 :     if (GNUNET_SYSERR == res)
     360             :     {
     361           0 :       GNUNET_break (0);
     362           0 :       return MHD_NO; /* hard failure */
     363             :     }
     364          41 :     if (GNUNET_NO == res)
     365             :     {
     366           0 :       GNUNET_break_op (0);
     367           0 :       return MHD_YES; /* failure */
     368             :     }
     369             :   }
     370             :   /* validate merchant's wire details (as far as we can) */
     371             :   {
     372             :     char *payto;
     373             :     char *emsg;
     374             : 
     375          41 :     payto = TALER_JSON_wire_to_payto (wire);
     376          41 :     if (NULL == payto)
     377             :     {
     378           0 :       GNUNET_break_op (0);
     379           0 :       GNUNET_JSON_parse_free (spec);
     380           0 :       return TALER_MHD_reply_with_error (connection,
     381             :                                          MHD_HTTP_BAD_REQUEST,
     382             :                                          TALER_EC_GENERIC_PARAMETER_MALFORMED,
     383             :                                          "wire");
     384             :     }
     385          41 :     emsg = TALER_payto_validate (payto);
     386          41 :     GNUNET_free (payto);
     387          41 :     if (NULL != emsg)
     388             :     {
     389             :       MHD_RESULT ret;
     390             : 
     391           0 :       GNUNET_break_op (0);
     392           0 :       GNUNET_JSON_parse_free (spec);
     393           0 :       ret = TALER_MHD_reply_with_error (connection,
     394             :                                         MHD_HTTP_BAD_REQUEST,
     395             :                                         TALER_EC_GENERIC_PARAMETER_MALFORMED,
     396             :                                         emsg);
     397           0 :       GNUNET_free (emsg);
     398           0 :       return ret;
     399             :     }
     400             :   }
     401          41 :   deposit.receiver_wire_account = wire;
     402          41 :   if (deposit.refund_deadline.abs_value_us > deposit.wire_deadline.abs_value_us)
     403             :   {
     404           0 :     GNUNET_break_op (0);
     405           0 :     GNUNET_JSON_parse_free (spec);
     406           0 :     return TALER_MHD_reply_with_error (connection,
     407             :                                        MHD_HTTP_BAD_REQUEST,
     408             :                                        TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
     409             :                                        NULL);
     410             :   }
     411          41 :   if (GNUNET_OK !=
     412          41 :       TALER_JSON_merchant_wire_signature_hash (wire,
     413             :                                                &my_h_wire))
     414             :   {
     415           0 :     TALER_LOG_WARNING (
     416             :       "Failed to parse JSON wire format specification for /deposit request\n");
     417           0 :     GNUNET_JSON_parse_free (spec);
     418           0 :     return TALER_MHD_reply_with_error (connection,
     419             :                                        MHD_HTTP_BAD_REQUEST,
     420             :                                        TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
     421             :                                        NULL);
     422             :   }
     423          41 :   if (0 != GNUNET_memcmp (&deposit.h_wire,
     424             :                           &my_h_wire))
     425             :   {
     426             :     /* Client hashed wire details differently than we did, reject */
     427           0 :     GNUNET_JSON_parse_free (spec);
     428           0 :     return TALER_MHD_reply_with_error (connection,
     429             :                                        MHD_HTTP_BAD_REQUEST,
     430             :                                        TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT,
     431             :                                        NULL);
     432             :   }
     433             : 
     434             :   /* Check for idempotency: did we get this request before? */
     435          41 :   dc.deposit = &deposit;
     436             :   {
     437             :     MHD_RESULT mhd_ret;
     438             : 
     439          41 :     if (GNUNET_OK !=
     440          41 :         TEH_DB_run_transaction (connection,
     441             :                                 "precheck deposit",
     442             :                                 &mhd_ret,
     443             :                                 &deposit_precheck,
     444             :                                 &dc))
     445             :     {
     446           1 :       GNUNET_JSON_parse_free (spec);
     447           1 :       return mhd_ret;
     448             :     }
     449             :   }
     450             : 
     451             :   /* new deposit */
     452          40 :   dc.exchange_timestamp = GNUNET_TIME_absolute_get ();
     453          40 :   (void) GNUNET_TIME_round_abs (&dc.exchange_timestamp);
     454             :   /* check denomination exists and is valid */
     455             :   {
     456             :     struct TEH_DenominationKey *dk;
     457             :     MHD_RESULT mret;
     458             : 
     459          40 :     dk = TEH_keys_denomination_by_hash (&deposit.coin.denom_pub_hash,
     460             :                                         connection,
     461             :                                         &mret);
     462          40 :     if (NULL == dk)
     463             :     {
     464           0 :       GNUNET_JSON_parse_free (spec);
     465           2 :       return mret;
     466             :     }
     467          40 :     if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit))
     468             :     {
     469             :       /* This denomination is past the expiration time for deposits */
     470             :       struct GNUNET_TIME_Absolute now;
     471             : 
     472           0 :       now = GNUNET_TIME_absolute_get ();
     473           0 :       (void) GNUNET_TIME_round_abs (&now);
     474           0 :       GNUNET_JSON_parse_free (spec);
     475           0 :       return TEH_RESPONSE_reply_expired_denom_pub_hash (
     476             :         connection,
     477             :         &deposit.coin.denom_pub_hash,
     478             :         now,
     479             :         TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
     480             :         "DEPOSIT");
     481             :     }
     482          40 :     if (GNUNET_TIME_absolute_is_future (dk->meta.start))
     483             :     {
     484             :       /* This denomination is not yet valid */
     485             :       struct GNUNET_TIME_Absolute now;
     486             : 
     487           0 :       now = GNUNET_TIME_absolute_get ();
     488           0 :       (void) GNUNET_TIME_round_abs (&now);
     489           0 :       GNUNET_JSON_parse_free (spec);
     490           0 :       return TEH_RESPONSE_reply_expired_denom_pub_hash (
     491             :         connection,
     492             :         &deposit.coin.denom_pub_hash,
     493             :         now,
     494             :         TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
     495             :         "DEPOSIT");
     496             :     }
     497          40 :     if (dk->recoup_possible)
     498             :     {
     499             :       struct GNUNET_TIME_Absolute now;
     500             : 
     501           2 :       now = GNUNET_TIME_absolute_get ();
     502           2 :       (void) GNUNET_TIME_round_abs (&now);
     503             :       /* This denomination has been revoked */
     504           2 :       GNUNET_JSON_parse_free (spec);
     505           2 :       return TEH_RESPONSE_reply_expired_denom_pub_hash (
     506             :         connection,
     507             :         &deposit.coin.denom_pub_hash,
     508             :         now,
     509             :         TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
     510             :         "DEPOSIT");
     511             :     }
     512             : 
     513          38 :     deposit.deposit_fee = dk->meta.fee_deposit;
     514             :     /* check coin signature */
     515          38 :     if (GNUNET_YES !=
     516          38 :         TALER_test_coin_valid (&deposit.coin,
     517          38 :                                &dk->denom_pub))
     518             :     {
     519           0 :       TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
     520           0 :       GNUNET_JSON_parse_free (spec);
     521           0 :       return TALER_MHD_reply_with_error (connection,
     522             :                                          MHD_HTTP_UNAUTHORIZED,
     523             :                                          TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
     524             :                                          NULL);
     525             :     }
     526          38 :     dc.value = dk->meta.value;
     527             :   }
     528          38 :   if (0 < TALER_amount_cmp (&deposit.deposit_fee,
     529             :                             &deposit.amount_with_fee))
     530             :   {
     531           0 :     GNUNET_break_op (0);
     532           0 :     GNUNET_JSON_parse_free (spec);
     533           0 :     return TALER_MHD_reply_with_error (connection,
     534             :                                        MHD_HTTP_BAD_REQUEST,
     535             :                                        TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
     536             :                                        NULL);
     537             :   }
     538             : 
     539             :   /* check deposit signature */
     540             :   {
     541          76 :     struct TALER_DepositRequestPS dr = {
     542          38 :       .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
     543          38 :       .purpose.size = htonl (sizeof (dr)),
     544             :       .h_contract_terms = deposit.h_contract_terms,
     545             :       .h_wire = deposit.h_wire,
     546             :       .h_denom_pub = deposit.coin.denom_pub_hash,
     547          38 :       .wallet_timestamp = GNUNET_TIME_absolute_hton (deposit.timestamp),
     548          38 :       .refund_deadline = GNUNET_TIME_absolute_hton (deposit.refund_deadline),
     549             :       .merchant = deposit.merchant_pub,
     550             :       .coin_pub = deposit.coin.coin_pub
     551             :     };
     552             : 
     553          38 :     TALER_amount_hton (&dr.amount_with_fee,
     554             :                        &deposit.amount_with_fee);
     555          38 :     TALER_amount_hton (&dr.deposit_fee,
     556             :                        &deposit.deposit_fee);
     557          38 :     if (GNUNET_OK !=
     558          38 :         GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
     559             :                                     &dr,
     560             :                                     &deposit.csig.eddsa_signature,
     561             :                                     &deposit.coin.coin_pub.eddsa_pub))
     562             :     {
     563           0 :       TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
     564           0 :       GNUNET_JSON_parse_free (spec);
     565           0 :       return TALER_MHD_reply_with_error (connection,
     566             :                                          MHD_HTTP_UNAUTHORIZED,
     567             :                                          TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID,
     568             :                                          NULL);
     569             :     }
     570             :   }
     571             : 
     572             :   /* execute transaction */
     573             :   {
     574             :     MHD_RESULT mhd_ret;
     575             : 
     576          38 :     if (GNUNET_OK !=
     577          38 :         TEH_DB_run_transaction (connection,
     578             :                                 "execute deposit",
     579             :                                 &mhd_ret,
     580             :                                 &deposit_transaction,
     581             :                                 &dc))
     582             :     {
     583           6 :       GNUNET_JSON_parse_free (spec);
     584           6 :       return mhd_ret;
     585             :     }
     586             :   }
     587             : 
     588             :   /* generate regular response */
     589             :   {
     590             :     struct TALER_Amount amount_without_fee;
     591             :     MHD_RESULT res;
     592             : 
     593          32 :     GNUNET_assert (0 <=
     594             :                    TALER_amount_subtract (&amount_without_fee,
     595             :                                           &deposit.amount_with_fee,
     596             :                                           &deposit.deposit_fee));
     597          32 :     res = reply_deposit_success (connection,
     598             :                                  &deposit.coin.coin_pub,
     599             :                                  &deposit.h_wire,
     600             :                                  &deposit.h_contract_terms,
     601             :                                  dc.exchange_timestamp,
     602             :                                  deposit.refund_deadline,
     603             :                                  &deposit.merchant_pub,
     604             :                                  &amount_without_fee);
     605          32 :     GNUNET_JSON_parse_free (spec);
     606          32 :     return res;
     607             :   }
     608             : }
     609             : 
     610             : 
     611             : /* end of taler-exchange-httpd_deposit.c */

Generated by: LCOV version 1.14