LCOV - code coverage report
Current view: top level - exchange - taler-exchange-httpd_track_transaction.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 64 78 82.1 %
Date: 2017-11-25 11:31:41 Functions: 6 6 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2017 GNUnet e.V.
       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_track_transaction.c
      18             :  * @brief Handle wire transfer 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_signatures.h"
      27             : #include "taler-exchange-httpd_parsing.h"
      28             : #include "taler-exchange-httpd_keystate.h"
      29             : #include "taler-exchange-httpd_track_transaction.h"
      30             : #include "taler-exchange-httpd_responses.h"
      31             : 
      32             : 
      33             : /**
      34             :  * A merchant asked for details about a deposit, but
      35             :  * we did not execute the deposit yet. Generate a 202 reply.
      36             :  *
      37             :  * @param connection connection to the client
      38             :  * @param planned_exec_time planned execution time
      39             :  * @return MHD result code
      40             :  */
      41             : static int
      42           1 : reply_transfer_pending (struct MHD_Connection *connection,
      43             :                         struct GNUNET_TIME_Absolute planned_exec_time)
      44             : {
      45           1 :   return TEH_RESPONSE_reply_json_pack (connection,
      46             :                                        MHD_HTTP_ACCEPTED,
      47             :                                        "{s:o}",
      48             :                                        "execution_time", GNUNET_JSON_from_time_abs (planned_exec_time));
      49             : }
      50             : 
      51             : 
      52             : /**
      53             :  * A merchant asked for details about a deposit.  Provide
      54             :  * them. Generates the 200 reply.
      55             :  *
      56             :  * @param connection connection to the client
      57             :  * @param h_contract_terms hash of the contract
      58             :  * @param h_wire hash of wire account details
      59             :  * @param coin_pub public key of the coin
      60             :  * @param coin_contribution how much did the coin we asked about
      61             :  *        contribute to the total transfer value? (deposit value minus fee)
      62             :  * @param wtid raw wire transfer identifier
      63             :  * @param exec_time execution time of the wire transfer
      64             :  * @return MHD result code
      65             :  */
      66             : static int
      67           1 : reply_track_transaction (struct MHD_Connection *connection,
      68             :                          const struct GNUNET_HashCode *h_contract_terms,
      69             :                          const struct GNUNET_HashCode *h_wire,
      70             :                          const struct TALER_CoinSpendPublicKeyP *coin_pub,
      71             :                          const struct TALER_Amount *coin_contribution,
      72             :                          const struct TALER_WireTransferIdentifierRawP *wtid,
      73             :                          struct GNUNET_TIME_Absolute exec_time)
      74             : {
      75             :   struct TALER_ConfirmWirePS cw;
      76             :   struct TALER_ExchangePublicKeyP pub;
      77             :   struct TALER_ExchangeSignatureP sig;
      78             : 
      79           1 :   cw.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE);
      80           1 :   cw.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
      81           1 :   cw.h_wire = *h_wire;
      82           1 :   cw.h_contract_terms = *h_contract_terms;
      83           1 :   cw.wtid = *wtid;
      84           1 :   cw.coin_pub = *coin_pub;
      85           1 :   cw.execution_time = GNUNET_TIME_absolute_hton (exec_time);
      86           1 :   TALER_amount_hton (&cw.coin_contribution,
      87             :                      coin_contribution);
      88           1 :   if (GNUNET_OK !=
      89           1 :       TEH_KS_sign (&cw.purpose,
      90             :                    &pub,
      91             :                    &sig))
      92             :   {
      93           0 :     return TEH_RESPONSE_reply_internal_error (connection,
      94             :                                               TALER_EC_EXCHANGE_BAD_CONFIGURATION,
      95             :                                               "no keys");
      96             :   }
      97           1 :   return TEH_RESPONSE_reply_json_pack (connection,
      98             :                                        MHD_HTTP_OK,
      99             :                                        "{s:o, s:o, s:o, s:o, s:o}",
     100             :                                        "wtid", GNUNET_JSON_from_data_auto (wtid),
     101             :                                        "execution_time", GNUNET_JSON_from_time_abs (exec_time),
     102             :                                        "coin_contribution", TALER_JSON_from_amount (coin_contribution),
     103             :                                        "exchange_sig", GNUNET_JSON_from_data_auto (&sig),
     104             :                                        "exchange_pub", GNUNET_JSON_from_data_auto (&pub));
     105             : }
     106             : 
     107             : 
     108             : /**
     109             :  * Closure for #handle_wtid_data.
     110             :  */
     111             : struct DepositWtidContext
     112             : {
     113             : 
     114             :   /**
     115             :    * Deposit details.
     116             :    */
     117             :   const struct TALER_DepositTrackPS *tps;
     118             : 
     119             :   /**
     120             :    * Public key of the merchant.
     121             :    */
     122             :   const struct TALER_MerchantPublicKeyP *merchant_pub;
     123             :   
     124             :   /**
     125             :    * Set by #handle_wtid data to the wire transfer ID.
     126             :    */ 
     127             :   struct TALER_WireTransferIdentifierRawP wtid;
     128             :   
     129             :   /**
     130             :    * Set by #handle_wtid data to the coin's contribution to the wire transfer.
     131             :    */ 
     132             :   struct TALER_Amount coin_contribution;
     133             :   
     134             :   /**
     135             :    * Set by #handle_wtid data to the fee charged to the coin.
     136             :    */ 
     137             :   struct TALER_Amount coin_fee;
     138             : 
     139             :   /**
     140             :    * Set by #handle_wtid data to the wire transfer execution time.
     141             :    */ 
     142             :   struct GNUNET_TIME_Absolute execution_time;
     143             : 
     144             :   /**
     145             :    * Set by #handle_wtid to the coin contribution to the transaction
     146             :    * (that is, @e coin_contribution minus @e coin_fee).
     147             :    */
     148             :   struct TALER_Amount coin_delta;
     149             : 
     150             :   /**
     151             :    * Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
     152             :    * (and the above were not set).
     153             :    * Set to #GNUNET_SYSERR if there was a serious error.
     154             :    */
     155             :   int pending;
     156             : };
     157             : 
     158             : 
     159             : /**
     160             :  * Function called with the results of the lookup of the
     161             :  * wire transfer identifier information.
     162             :  *
     163             :  * @param cls our context for transmission
     164             :  * @param wtid raw wire transfer identifier, NULL
     165             :  *         if the transaction was not yet done
     166             :  * @param coin_contribution how much did the coin we asked about
     167             :  *        contribute to the total transfer value? (deposit value including fee)
     168             :  * @param coin_fee how much did the exchange charge for the deposit fee
     169             :  * @param execution_time when was the transaction done, or
     170             :  *         when we expect it to be done (if @a wtid was NULL);
     171             :  *         #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
     172             :  *         to the exchange
     173             :  */
     174             : static void
     175           2 : handle_wtid_data (void *cls,
     176             :                   const struct TALER_WireTransferIdentifierRawP *wtid,
     177             :                   const struct TALER_Amount *coin_contribution,
     178             :                   const struct TALER_Amount *coin_fee,
     179             :                   struct GNUNET_TIME_Absolute execution_time)
     180             : {
     181           2 :   struct DepositWtidContext *ctx = cls;
     182             : 
     183           2 :   if (NULL == wtid)
     184             :   {
     185           1 :     ctx->pending = GNUNET_YES;
     186           1 :     ctx->execution_time = execution_time;
     187           1 :     return;
     188             :   }
     189           1 :   if (GNUNET_SYSERR ==
     190           1 :       TALER_amount_subtract (&ctx->coin_delta,
     191             :                              coin_contribution,
     192             :                              coin_fee))
     193             :   {
     194           0 :     GNUNET_break (0);
     195           0 :     ctx->pending = GNUNET_SYSERR;
     196           0 :     return;
     197             :   }
     198           1 :   ctx->wtid = *wtid;
     199           1 :   ctx->execution_time = execution_time;
     200           1 :   ctx->coin_contribution = *coin_contribution;
     201           1 :   ctx->coin_fee = *coin_fee;
     202             : }
     203             : 
     204             : 
     205             : /**
     206             :  * Execute a "/track/transaction".  Returns the transfer information
     207             :  * associated with the given deposit.
     208             :  *
     209             :  * If it returns a non-error code, the transaction logic MUST
     210             :  * NOT queue a MHD response.  IF it returns an hard error, the
     211             :  * transaction logic MUST queue a MHD response and set @a mhd_ret.  IF
     212             :  * it returns the soft error code, the function MAY be called again to
     213             :  * retry and MUST not queue a MHD response.
     214             :  *
     215             :  * @param cls closure of type `struct DepositWtidContext *`
     216             :  * @param connection MHD request which triggered the transaction
     217             :  * @param session database session to use
     218             :  * @param[out] mhd_ret set to MHD response status for @a connection,
     219             :  *             if transaction failed (!)
     220             :  * @return transaction status
     221             :  */
     222             : static enum GNUNET_DB_QueryStatus
     223           3 : track_transaction_transaction (void *cls,
     224             :                                struct MHD_Connection *connection,
     225             :                                struct TALER_EXCHANGEDB_Session *session,
     226             :                                int *mhd_ret)
     227             : {
     228           3 :   struct DepositWtidContext *ctx = cls;
     229             :   enum GNUNET_DB_QueryStatus qs;
     230             : 
     231          12 :   qs = TEH_plugin->wire_lookup_deposit_wtid (TEH_plugin->cls,
     232             :                                              session,
     233           3 :                                              &ctx->tps->h_contract_terms,
     234           3 :                                              &ctx->tps->h_wire,
     235           3 :                                              &ctx->tps->coin_pub,
     236             :                                              ctx->merchant_pub,
     237             :                                              &handle_wtid_data,
     238             :                                              ctx);
     239           3 :   if (0 > qs)
     240             :   {
     241           0 :     if (GNUNET_DB_STATUS_HARD_ERROR == qs)
     242             :     {
     243           0 :       GNUNET_break (0);
     244           0 :       *mhd_ret = TEH_RESPONSE_reply_internal_db_error (connection,
     245             :                                                        TALER_EC_TRACK_TRANSACTION_DB_FETCH_FAILED);
     246             :     }
     247           0 :     return qs;
     248             :   }
     249           3 :   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
     250             :   {
     251           1 :     *mhd_ret = TEH_RESPONSE_reply_transaction_unknown (connection,
     252             :                                                        TALER_EC_TRACK_TRANSACTION_NOT_FOUND);
     253           1 :     return GNUNET_DB_STATUS_HARD_ERROR;
     254             :   }
     255           2 :   return qs;
     256             : }
     257             : 
     258             : 
     259             : /**
     260             :  * Check the merchant signature, and if it is valid,
     261             :  * return the wire transfer identifier.
     262             :  *
     263             :  * @param connection the MHD connection to handle
     264             :  * @param tps signed request to execute
     265             :  * @param merchant_pub public key from the merchant
     266             :  * @param merchant_sig signature from the merchant (to be checked)
     267             :  * @return MHD result code
     268             :  */
     269             : static int
     270           3 : check_and_handle_track_transaction_request (struct MHD_Connection *connection,
     271             :                                             const struct TALER_DepositTrackPS *tps,
     272             :                                             const struct TALER_MerchantPublicKeyP *merchant_pub,
     273             :                                             const struct TALER_MerchantSignatureP *merchant_sig)
     274             : {
     275             :   struct DepositWtidContext ctx;
     276             :   int mhd_ret;
     277             : 
     278           3 :   if (GNUNET_OK !=
     279           3 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION,
     280             :                                   &tps->purpose,
     281             :                                   &merchant_sig->eddsa_sig,
     282             :                                   &merchant_pub->eddsa_pub))
     283             :   {
     284           0 :     GNUNET_break_op (0);
     285           0 :     return TEH_RESPONSE_reply_signature_invalid (connection,
     286             :                                                  TALER_EC_TRACK_TRANSACTION_MERCHANT_SIGNATURE_INVALID,
     287             :                                                  "merchant_sig");
     288             :   }
     289           3 :   ctx.pending = GNUNET_NO;
     290           3 :   ctx.tps = tps;
     291           3 :   ctx.merchant_pub = merchant_pub;
     292             :   
     293           3 :   if (GNUNET_OK !=
     294           3 :       TEH_DB_run_transaction (connection,
     295             :                               &mhd_ret,
     296             :                               &track_transaction_transaction,
     297             :                               &ctx))
     298           1 :     return mhd_ret;
     299           2 :   if (GNUNET_YES == ctx.pending)
     300           1 :     return reply_transfer_pending (connection,
     301             :                                    ctx.execution_time);
     302           1 :   if (GNUNET_SYSERR == ctx.pending)
     303           0 :     return TEH_RESPONSE_reply_internal_db_error (connection,
     304             :                                                  TALER_EC_TRACK_TRANSACTION_DB_FEE_INCONSISTENT);
     305           1 :   return reply_track_transaction (connection,
     306             :                                   &tps->h_contract_terms,
     307             :                                   &tps->h_wire,
     308             :                                   &tps->coin_pub,
     309             :                                   &ctx.coin_delta,
     310             :                                   &ctx.wtid,
     311             :                                   ctx.execution_time);
     312             : }
     313             : 
     314             : 
     315             : /**
     316             :  * Handle a "/track/transaction" request.
     317             :  *
     318             :  * @param rh context of the handler
     319             :  * @param connection the MHD connection to handle
     320             :  * @param[in,out] connection_cls the connection's closure (can be updated)
     321             :  * @param upload_data upload data
     322             :  * @param[in,out] upload_data_size number of bytes (left) in @a upload_data
     323             :  * @return MHD result code
     324             :  */
     325             : int
     326           9 : TEH_TRACKING_handler_track_transaction (struct TEH_RequestHandler *rh,
     327             :                                         struct MHD_Connection *connection,
     328             :                                         void **connection_cls,
     329             :                                         const char *upload_data,
     330             :                                         size_t *upload_data_size)
     331             : {
     332             :   int res;
     333             :   json_t *json;
     334             :   struct TALER_DepositTrackPS tps;
     335             :   struct TALER_MerchantSignatureP merchant_sig;
     336           9 :   struct GNUNET_JSON_Specification spec[] = {
     337             :     GNUNET_JSON_spec_fixed_auto ("H_wire", &tps.h_wire),
     338             :     GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &tps.h_contract_terms),
     339             :     GNUNET_JSON_spec_fixed_auto ("coin_pub", &tps.coin_pub),
     340             :     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &tps.merchant),
     341             :     GNUNET_JSON_spec_fixed_auto ("merchant_sig", &merchant_sig),
     342             :     GNUNET_JSON_spec_end ()
     343             :   };
     344             : 
     345           9 :   res = TEH_PARSE_post_json (connection,
     346             :                              connection_cls,
     347             :                              upload_data,
     348             :                              upload_data_size,
     349             :                              &json);
     350           9 :   if (GNUNET_SYSERR == res)
     351           0 :     return MHD_NO;
     352           9 :   if ( (GNUNET_NO == res) || (NULL == json) )
     353           6 :     return MHD_YES;
     354           3 :   res = TEH_PARSE_json_data (connection,
     355             :                              json,
     356             :                              spec);
     357           3 :   if (GNUNET_OK != res)
     358             :   {
     359           0 :     json_decref (json);
     360           0 :     return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
     361             :   }
     362           3 :   tps.purpose.size = htonl (sizeof (struct TALER_DepositTrackPS));
     363           3 :   tps.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION);
     364           3 :   res = check_and_handle_track_transaction_request (connection,
     365             :                                                     &tps,
     366             :                                                     &tps.merchant,
     367             :                                                     &merchant_sig);
     368           3 :   GNUNET_JSON_parse_free (spec);
     369           3 :   json_decref (json);
     370           3 :   return res;
     371             : }
     372             : 
     373             : 
     374             : /* end of taler-exchange-httpd_track_transaction.c */

Generated by: LCOV version 1.13