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

Generated by: LCOV version 1.13