LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_deposits_get.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 62 86 72.1 %
Date: 2021-08-30 06:43:37 Functions: 5 5 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017, 2021 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_deposits_get.c
      18             :  * @brief Handle wire deposit tracking-related requests
      19             :  * @author Christian Grothoff
      20             :  */
      21             : #include "platform.h"
      22             : #include <gnunet/gnunet_util_lib.h>
      23             : #include <jansson.h>
      24             : #include <microhttpd.h>
      25             : #include <pthread.h>
      26             : #include "taler_json_lib.h"
      27             : #include "taler_mhd_lib.h"
      28             : #include "taler_signatures.h"
      29             : #include "taler-exchange-httpd_keys.h"
      30             : #include "taler-exchange-httpd_deposits_get.h"
      31             : #include "taler-exchange-httpd_responses.h"
      32             : 
      33             : 
      34             : /**
      35             :  * A merchant asked for details about a deposit.  Provide
      36             :  * them. Generates the 200 reply.
      37             :  *
      38             :  * @param connection connection to the client
      39             :  * @param h_contract_terms hash of the contract
      40             :  * @param h_wire hash of wire account details
      41             :  * @param coin_pub public key of the coin
      42             :  * @param coin_contribution how much did the coin we asked about
      43             :  *        contribute to the total transfer value? (deposit value minus fee)
      44             :  * @param wtid raw wire transfer identifier
      45             :  * @param exec_time execution time of the wire transfer
      46             :  * @return MHD result code
      47             :  */
      48             : static MHD_RESULT
      49           1 : reply_deposit_details (struct MHD_Connection *connection,
      50             :                        const struct GNUNET_HashCode *h_contract_terms,
      51             :                        const struct GNUNET_HashCode *h_wire,
      52             :                        const struct TALER_CoinSpendPublicKeyP *coin_pub,
      53             :                        const struct TALER_Amount *coin_contribution,
      54             :                        const struct TALER_WireTransferIdentifierRawP *wtid,
      55             :                        struct GNUNET_TIME_Absolute exec_time)
      56             : {
      57             :   struct TALER_ExchangePublicKeyP pub;
      58             :   struct TALER_ExchangeSignatureP sig;
      59           1 :   struct TALER_ConfirmWirePS cw = {
      60           1 :     .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE),
      61           1 :     .purpose.size = htonl (sizeof (cw)),
      62             :     .h_wire = *h_wire,
      63             :     .h_contract_terms = *h_contract_terms,
      64             :     .wtid = *wtid,
      65             :     .coin_pub = *coin_pub,
      66           1 :     .execution_time = GNUNET_TIME_absolute_hton (exec_time)
      67             :   };
      68             :   enum TALER_ErrorCode ec;
      69             : 
      70           1 :   TALER_amount_hton (&cw.coin_contribution,
      71             :                      coin_contribution);
      72           1 :   if (TALER_EC_NONE !=
      73           1 :       (ec = TEH_keys_exchange_sign (&cw,
      74             :                                     &pub,
      75             :                                     &sig)))
      76             :   {
      77           0 :     return TALER_MHD_reply_with_ec (connection,
      78             :                                     ec,
      79             :                                     NULL);
      80             :   }
      81           1 :   return TALER_MHD_REPLY_JSON_PACK (
      82             :     connection,
      83             :     MHD_HTTP_OK,
      84             :     GNUNET_JSON_pack_data_auto ("wtid",
      85             :                                 wtid),
      86             :     GNUNET_JSON_pack_time_abs ("execution_time",
      87             :                                exec_time),
      88             :     TALER_JSON_pack_amount ("coin_contribution",
      89             :                             coin_contribution),
      90             :     GNUNET_JSON_pack_data_auto ("exchange_sig",
      91             :                                 &sig),
      92             :     GNUNET_JSON_pack_data_auto ("exchange_pub",
      93             :                                 &pub));
      94             : }
      95             : 
      96             : 
      97             : /**
      98             :  * Closure for #handle_wtid_data.
      99             :  */
     100             : struct DepositWtidContext
     101             : {
     102             : 
     103             :   /**
     104             :    * Deposit details.
     105             :    */
     106             :   const struct TALER_DepositTrackPS *tps;
     107             : 
     108             :   /**
     109             :    * Public key of the merchant.
     110             :    */
     111             :   const struct TALER_MerchantPublicKeyP *merchant_pub;
     112             : 
     113             :   /**
     114             :    * Set by #handle_wtid data to the wire transfer ID.
     115             :    */
     116             :   struct TALER_WireTransferIdentifierRawP wtid;
     117             : 
     118             :   /**
     119             :    * Set by #handle_wtid data to the coin's contribution to the wire transfer.
     120             :    */
     121             :   struct TALER_Amount coin_contribution;
     122             : 
     123             :   /**
     124             :    * Set by #handle_wtid data to the fee charged to the coin.
     125             :    */
     126             :   struct TALER_Amount coin_fee;
     127             : 
     128             :   /**
     129             :    * Set by #handle_wtid data to the wire transfer execution time.
     130             :    */
     131             :   struct GNUNET_TIME_Absolute execution_time;
     132             : 
     133             :   /**
     134             :    * Set by #handle_wtid to the coin contribution to the transaction
     135             :    * (that is, @e coin_contribution minus @e coin_fee).
     136             :    */
     137             :   struct TALER_Amount coin_delta;
     138             : 
     139             :   /**
     140             :    * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
     141             :    * (and the above were not set).
     142             :    * Set to #GNUNET_SYSERR if there was a serious error.
     143             :    */
     144             :   int pending;
     145             : };
     146             : 
     147             : 
     148             : /**
     149             :  * Function called with the results of the lookup of the
     150             :  * wire transfer identifier information.
     151             :  *
     152             :  * @param cls our context for transmission, a `struct DepositWtidContext *`
     153             :  * @param wtid raw wire transfer identifier, NULL
     154             :  *         if the transaction was not yet done
     155             :  * @param coin_contribution how much did the coin we asked about
     156             :  *        contribute to the total transfer value? (deposit value including fee)
     157             :  * @param coin_fee how much did the exchange charge for the deposit fee
     158             :  * @param execution_time when was the transaction done, or
     159             :  *         when we expect it to be done (if @a wtid was NULL);
     160             :  *         #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
     161             :  *         to the exchange
     162             :  */
     163             : static void
     164           2 : handle_wtid_data (void *cls,
     165             :                   const struct TALER_WireTransferIdentifierRawP *wtid,
     166             :                   const struct TALER_Amount *coin_contribution,
     167             :                   const struct TALER_Amount *coin_fee,
     168             :                   struct GNUNET_TIME_Absolute execution_time)
     169             : {
     170           2 :   struct DepositWtidContext *ctx = cls;
     171             : 
     172           2 :   if (NULL == wtid)
     173             :   {
     174           1 :     ctx->pending = GNUNET_YES;
     175           1 :     ctx->execution_time = execution_time;
     176           1 :     return;
     177             :   }
     178           1 :   if (0 >
     179           1 :       TALER_amount_subtract (&ctx->coin_delta,
     180             :                              coin_contribution,
     181             :                              coin_fee))
     182             :   {
     183           0 :     GNUNET_break (0);
     184           0 :     ctx->pending = GNUNET_SYSERR;
     185           0 :     return;
     186             :   }
     187           1 :   ctx->wtid = *wtid;
     188           1 :   ctx->execution_time = execution_time;
     189           1 :   ctx->coin_contribution = *coin_contribution;
     190           1 :   ctx->coin_fee = *coin_fee;
     191             : }
     192             : 
     193             : 
     194             : /**
     195             :  * Execute a "deposits" GET.  Returns the transfer information
     196             :  * associated with the given deposit.
     197             :  *
     198             :  * If it returns a non-error code, the transaction logic MUST
     199             :  * NOT queue a MHD response.  IF it returns an hard error, the
     200             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     201             :  * it returns the soft error code, the function MAY be called again to
     202             :  * retry and MUST NOT queue a MHD response.
     203             :  *
     204             :  * @param cls closure of type `struct DepositWtidContext *`
     205             :  * @param connection MHD request which triggered the transaction
     206             :  * @param[out] mhd_ret set to MHD response status for @a connection,
     207             :  *             if transaction failed (!)
     208             :  * @return transaction status
     209             :  */
     210             : static enum GNUNET_DB_QueryStatus
     211           3 : deposits_get_transaction (void *cls,
     212             :                           struct MHD_Connection *connection,
     213             :                           MHD_RESULT *mhd_ret)
     214             : {
     215           3 :   struct DepositWtidContext *ctx = cls;
     216             :   enum GNUNET_DB_QueryStatus qs;
     217             : 
     218           3 :   qs = TEH_plugin->lookup_transfer_by_deposit (TEH_plugin->cls,
     219           3 :                                                &ctx->tps->h_contract_terms,
     220           3 :                                                &ctx->tps->h_wire,
     221           3 :                                                &ctx->tps->coin_pub,
     222             :                                                ctx->merchant_pub,
     223             :                                                &handle_wtid_data,
     224             :                                                ctx);
     225           3 :   if (0 > qs)
     226             :   {
     227           0 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     228             :     {
     229           0 :       GNUNET_break (0);
     230           0 :       *mhd_ret = TALER_MHD_reply_with_error (connection,
     231             :                                              MHD_HTTP_INTERNAL_SERVER_ERROR,
     232             :                                              TALER_EC_GENERIC_DB_FETCH_FAILED,
     233             :                                              NULL);
     234             :     }
     235           0 :     return qs;
     236             :   }
     237           3 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     238             :   {
     239           1 :     *mhd_ret = TALER_MHD_reply_with_error (connection,
     240             :                                            MHD_HTTP_NOT_FOUND,
     241             :                                            TALER_EC_EXCHANGE_DEPOSITS_GET_NOT_FOUND,
     242             :                                            NULL);
     243           1 :     return GNUNET_DB_STATUS_HARD_ERROR;
     244             :   }
     245           2 :   return qs;
     246             : }
     247             : 
     248             : 
     249             : /**
     250             :  * Lookup and return the wire transfer identifier.
     251             :  *
     252             :  * @param connection the MHD connection to handle
     253             :  * @param tps signed request to execute
     254             :  * @param merchant_pub public key from the merchant
     255             :  * @return MHD result code
     256             :  */
     257             : static MHD_RESULT
     258           3 : handle_track_transaction_request (
     259             :   struct MHD_Connection *connection,
     260             :   const struct TALER_DepositTrackPS *tps,
     261             :   const struct TALER_MerchantPublicKeyP *merchant_pub)
     262             : {
     263             :   MHD_RESULT mhd_ret;
     264           3 :   struct DepositWtidContext ctx = {
     265             :     .pending = GNUNET_NO,
     266             :     .tps = tps,
     267             :     .merchant_pub = merchant_pub
     268             :   };
     269             : 
     270           3 :   if (GNUNET_OK !=
     271           3 :       TEH_DB_run_transaction (connection,
     272             :                               "handle deposits GET",
     273             :                               &mhd_ret,
     274             :                               &deposits_get_transaction,
     275             :                               &ctx))
     276           1 :     return mhd_ret;
     277           2 :   if (GNUNET_YES == ctx.pending)
     278           1 :     return TALER_MHD_REPLY_JSON_PACK (
     279             :       connection,
     280             :       MHD_HTTP_ACCEPTED,
     281             :       GNUNET_JSON_pack_time_abs ("execution_time",
     282             :                                  ctx.execution_time));
     283           1 :   if (GNUNET_SYSERR == ctx.pending)
     284           0 :     return TALER_MHD_reply_with_error (connection,
     285             :                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
     286             :                                        TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
     287             :                                        "wire fees exceed aggregate in database");
     288           1 :   return reply_deposit_details (connection,
     289             :                                 &tps->h_contract_terms,
     290             :                                 &tps->h_wire,
     291             :                                 &tps->coin_pub,
     292             :                                 &ctx.coin_delta,
     293             :                                 &ctx.wtid,
     294             :                                 ctx.execution_time);
     295             : }
     296             : 
     297             : 
     298             : MHD_RESULT
     299           3 : TEH_handler_deposits_get (struct TEH_RequestContext *rc,
     300             :                           const char *const args[4])
     301             : {
     302             :   enum GNUNET_GenericReturnValue res;
     303             :   struct TALER_MerchantSignatureP merchant_sig;
     304           3 :   struct TALER_DepositTrackPS tps = {
     305           3 :     .purpose.size = htonl (sizeof (tps)),
     306           3 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION)
     307             :   };
     308             : 
     309           3 :   if (GNUNET_OK !=
     310           3 :       GNUNET_STRINGS_string_to_data (args[0],
     311             :                                      strlen (args[0]),
     312             :                                      &tps.h_wire,
     313             :                                      sizeof (tps.h_wire)))
     314             :   {
     315           0 :     GNUNET_break_op (0);
     316           0 :     return TALER_MHD_reply_with_error (rc->connection,
     317             :                                        MHD_HTTP_BAD_REQUEST,
     318             :                                        TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_WIRE,
     319             :                                        args[0]);
     320             :   }
     321           3 :   if (GNUNET_OK !=
     322           3 :       GNUNET_STRINGS_string_to_data (args[1],
     323           3 :                                      strlen (args[1]),
     324             :                                      &tps.merchant,
     325             :                                      sizeof (tps.merchant)))
     326             :   {
     327           0 :     GNUNET_break_op (0);
     328           0 :     return TALER_MHD_reply_with_error (rc->connection,
     329             :                                        MHD_HTTP_BAD_REQUEST,
     330             :                                        TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_MERCHANT_PUB,
     331           0 :                                        args[1]);
     332             :   }
     333           3 :   if (GNUNET_OK !=
     334           3 :       GNUNET_STRINGS_string_to_data (args[2],
     335           3 :                                      strlen (args[2]),
     336             :                                      &tps.h_contract_terms,
     337             :                                      sizeof (tps.h_contract_terms)))
     338             :   {
     339           0 :     GNUNET_break_op (0);
     340           0 :     return TALER_MHD_reply_with_error (rc->connection,
     341             :                                        MHD_HTTP_BAD_REQUEST,
     342             :                                        TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_H_CONTRACT_TERMS,
     343           0 :                                        args[2]);
     344             :   }
     345           3 :   if (GNUNET_OK !=
     346           3 :       GNUNET_STRINGS_string_to_data (args[3],
     347           3 :                                      strlen (args[3]),
     348             :                                      &tps.coin_pub,
     349             :                                      sizeof (tps.coin_pub)))
     350             :   {
     351           0 :     GNUNET_break_op (0);
     352           0 :     return TALER_MHD_reply_with_error (rc->connection,
     353             :                                        MHD_HTTP_BAD_REQUEST,
     354             :                                        TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_COIN_PUB,
     355           0 :                                        args[3]);
     356             :   }
     357           3 :   res = TALER_MHD_parse_request_arg_data (rc->connection,
     358             :                                           "merchant_sig",
     359             :                                           &merchant_sig,
     360             :                                           sizeof (merchant_sig));
     361           3 :   if (GNUNET_SYSERR == res)
     362           0 :     return MHD_NO; /* internal error */
     363           3 :   if (GNUNET_NO == res)
     364           0 :     return MHD_YES; /* parse error */
     365           3 :   if (GNUNET_OK !=
     366           3 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION,
     367             :                                   &tps,
     368             :                                   &merchant_sig.eddsa_sig,
     369             :                                   &tps.merchant.eddsa_pub))
     370             :   {
     371           0 :     GNUNET_break_op (0);
     372           0 :     return TALER_MHD_reply_with_error (rc->connection,
     373             :                                        MHD_HTTP_FORBIDDEN,
     374             :                                        TALER_EC_EXCHANGE_DEPOSITS_GET_MERCHANT_SIGNATURE_INVALID,
     375             :                                        NULL);
     376             :   }
     377             : 
     378           3 :   return handle_track_transaction_request (rc->connection,
     379             :                                            &tps,
     380             :                                            &tps.merchant);
     381             : }
     382             : 
     383             : 
     384             : /* end of taler-exchange-httpd_deposits_get.c */

Generated by: LCOV version 1.14