LCOV - code coverage report
Current view: top level - exchange-lib - exchange_api_track_transfer.c (source / functions) Hit Total Coverage
Test: rcoverage.info Lines: 84 123 68.3 %
Date: 2017-11-25 11:31:41 Functions: 4 4 100.0 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014, 2015, 2016 GNUnet e.V.
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU 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 General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU General Public License along with
      14             :   TALER; see the file COPYING.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file exchange-lib/exchange_api_track_transfer.c
      19             :  * @brief Implementation of the /track/transfer request of the exchange's HTTP API
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <curl/curl.h>
      24             : #include <jansson.h>
      25             : #include <microhttpd.h> /* just for HTTP status codes */
      26             : #include <gnunet/gnunet_util_lib.h>
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_exchange_service.h"
      29             : #include "taler_json_lib.h"
      30             : #include "exchange_api_handle.h"
      31             : #include "taler_signatures.h"
      32             : 
      33             : 
      34             : /**
      35             :  * @brief A /track/transfer Handle
      36             :  */
      37             : struct TALER_EXCHANGE_TrackTransferHandle
      38             : {
      39             : 
      40             :   /**
      41             :    * The connection to exchange this request handle will use
      42             :    */
      43             :   struct TALER_EXCHANGE_Handle *exchange;
      44             : 
      45             :   /**
      46             :    * The url for this request.
      47             :    */
      48             :   char *url;
      49             : 
      50             :   /**
      51             :    * Handle for the request.
      52             :    */
      53             :   struct GNUNET_CURL_Job *job;
      54             : 
      55             :   /**
      56             :    * Function to call with the result.
      57             :    */
      58             :   TALER_EXCHANGE_TrackTransferCallback cb;
      59             : 
      60             :   /**
      61             :    * Closure for @a cb.
      62             :    */
      63             :   void *cb_cls;
      64             : 
      65             : };
      66             : 
      67             : 
      68             : /**
      69             :  * We got a #MHD_HTTP_OK response for the /track/transfer request.
      70             :  * Check that the response is well-formed and if it is, call the
      71             :  * callback.  If not, return an error code.
      72             :  *
      73             :  * This code is very similar to
      74             :  * merchant_api_track_transfer.c::check_track_transfer_response_ok.
      75             :  * Any changes should likely be reflected there as well.
      76             :  *
      77             :  * @param wdh handle to the operation
      78             :  * @param json response we got
      79             :  * @return #GNUNET_OK if we are done and all is well,
      80             :  *         #GNUNET_SYSERR if the response was bogus
      81             :  */
      82             : static int
      83           2 : check_track_transfer_response_ok (struct TALER_EXCHANGE_TrackTransferHandle *wdh,
      84             :                                   const json_t *json)
      85             : {
      86             :   json_t *details_j;
      87             :   struct GNUNET_HashCode h_wire;
      88             :   struct GNUNET_TIME_Absolute exec_time;
      89             :   struct TALER_Amount total_amount;
      90             :   struct TALER_Amount total_expected;
      91             :   struct TALER_Amount wire_fee;
      92             :   struct TALER_MerchantPublicKeyP merchant_pub;
      93             :   unsigned int num_details;
      94             :   struct TALER_ExchangePublicKeyP exchange_pub;
      95             :   struct TALER_ExchangeSignatureP exchange_sig;
      96           2 :   struct GNUNET_JSON_Specification spec[] = {
      97             :     TALER_JSON_spec_amount ("total", &total_amount),
      98             :     TALER_JSON_spec_amount ("wire_fee", &wire_fee),
      99             :     GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
     100             :     GNUNET_JSON_spec_fixed_auto ("H_wire", &h_wire),
     101             :     GNUNET_JSON_spec_absolute_time ("execution_time", &exec_time),
     102             :     GNUNET_JSON_spec_json ("deposits", &details_j),
     103             :     GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
     104             :     GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
     105             :     GNUNET_JSON_spec_end()
     106             :   };
     107             : 
     108           2 :   if (GNUNET_OK !=
     109           2 :       GNUNET_JSON_parse (json,
     110             :                          spec,
     111             :                          NULL, NULL))
     112             :   {
     113           0 :     GNUNET_break_op (0);
     114           0 :     return GNUNET_SYSERR;
     115             :   }
     116           2 :   if (GNUNET_OK !=
     117           2 :       TALER_amount_get_zero (total_amount.currency,
     118             :                              &total_expected))
     119             :   {
     120           0 :     GNUNET_break_op (0);
     121           0 :     return GNUNET_SYSERR;
     122             :   }
     123           2 :   num_details = json_array_size (details_j);
     124           2 :   {
     125           2 :     struct TALER_TrackTransferDetails details[num_details];
     126             :     unsigned int i;
     127             :     struct GNUNET_HashContext *hash_context;
     128             :     struct TALER_WireDepositDetailP dd;
     129             :     struct TALER_WireDepositDataPS wdp;
     130             : 
     131           2 :     hash_context = GNUNET_CRYPTO_hash_context_start ();
     132           8 :     for (i=0;i<num_details;i++)
     133             :     {
     134           2 :       struct TALER_TrackTransferDetails *detail = &details[i];
     135           2 :       struct json_t *detail_j = json_array_get (details_j, i);
     136           8 :       struct GNUNET_JSON_Specification spec_detail[] = {
     137           2 :         GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &detail->h_contract_terms),
     138           2 :         GNUNET_JSON_spec_fixed_auto ("coin_pub", &detail->coin_pub),
     139           2 :         TALER_JSON_spec_amount ("deposit_value", &detail->coin_value),
     140           2 :         TALER_JSON_spec_amount ("deposit_fee", &detail->coin_fee),
     141             :         GNUNET_JSON_spec_end()
     142             :       };
     143             : 
     144           2 :       if (GNUNET_OK !=
     145           2 :           GNUNET_JSON_parse (detail_j,
     146             :                              spec_detail,
     147             :                              NULL, NULL))
     148             :       {
     149           0 :         GNUNET_break_op (0);
     150           0 :         GNUNET_CRYPTO_hash_context_abort (hash_context);
     151           0 :         GNUNET_JSON_parse_free (spec);
     152           0 :         return GNUNET_SYSERR;
     153             :       }
     154             :       /* build up big hash for signature checking later */
     155           2 :       dd.h_contract_terms = detail->h_contract_terms;
     156           2 :       dd.execution_time = GNUNET_TIME_absolute_hton (exec_time);
     157           2 :       dd.coin_pub = detail->coin_pub;
     158           2 :       TALER_amount_hton (&dd.deposit_value,
     159           2 :                          &detail->coin_value);
     160           2 :       TALER_amount_hton (&dd.deposit_fee,
     161           2 :                          &detail->coin_fee);
     162           2 :       if ( (GNUNET_OK !=
     163           2 :             TALER_amount_add (&total_expected,
     164             :                               &total_expected,
     165           4 :                               &detail->coin_value)) ||
     166             :            (GNUNET_OK !=
     167           2 :             TALER_amount_subtract (&total_expected,
     168             :                                    &total_expected,
     169           2 :                                    &detail->coin_fee)) )
     170             :       {
     171           0 :         GNUNET_break_op (0);
     172           0 :         GNUNET_CRYPTO_hash_context_abort (hash_context);
     173           0 :         GNUNET_JSON_parse_free (spec);
     174           0 :         return GNUNET_SYSERR;
     175             :       }
     176           2 :       GNUNET_CRYPTO_hash_context_read (hash_context,
     177             :                                        &dd,
     178             :                                        sizeof (struct TALER_WireDepositDetailP));
     179             :     }
     180             :     /* Check signature */
     181           2 :     wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT);
     182           2 :     wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
     183           2 :     TALER_amount_hton (&wdp.total,
     184             :                        &total_amount);
     185           2 :     TALER_amount_hton (&wdp.wire_fee,
     186             :                        &wire_fee);
     187           2 :     wdp.merchant_pub = merchant_pub;
     188           2 :     wdp.h_wire = h_wire;
     189           2 :     GNUNET_CRYPTO_hash_context_finish (hash_context,
     190             :                                        &wdp.h_details);
     191           2 :     if (GNUNET_OK !=
     192           2 :         TALER_EXCHANGE_test_signing_key (TALER_EXCHANGE_get_keys (wdh->exchange),
     193             :                                          &exchange_pub))
     194             :     {
     195           0 :       GNUNET_break_op (0);
     196           0 :       GNUNET_JSON_parse_free (spec);
     197           0 :       return GNUNET_SYSERR;
     198             :     }
     199           2 :     if (GNUNET_OK !=
     200           2 :         TALER_EXCHANGE_test_signing_key (TALER_EXCHANGE_get_keys (wdh->exchange),
     201             :                                          &exchange_pub))
     202             :     {
     203           0 :       GNUNET_break_op (0);
     204           0 :       GNUNET_JSON_parse_free (spec);
     205           0 :       return GNUNET_SYSERR;
     206             :     }
     207           2 :     if (GNUNET_OK !=
     208           2 :         TALER_amount_subtract (&total_expected,
     209             :                                &total_expected,
     210             :                                &wire_fee))
     211             :     {
     212           0 :       GNUNET_break_op (0);
     213           0 :       GNUNET_JSON_parse_free (spec);
     214           0 :       return GNUNET_SYSERR;
     215             :     }
     216           2 :     if (0 !=
     217           2 :         TALER_amount_cmp (&total_expected,
     218             :                           &total_amount))
     219             :     {
     220           0 :       GNUNET_break_op (0);
     221           0 :       GNUNET_JSON_parse_free (spec);
     222           0 :       return GNUNET_SYSERR;
     223             :     }
     224           2 :     wdh->cb (wdh->cb_cls,
     225             :              MHD_HTTP_OK,
     226             :              TALER_EC_NONE,
     227             :              &exchange_pub,
     228             :              json,
     229             :              &h_wire,
     230             :              exec_time,
     231             :              &total_amount,
     232             :              &wire_fee,
     233             :              num_details,
     234             :              details);
     235             :   }
     236           2 :   GNUNET_JSON_parse_free (spec);
     237           2 :   TALER_EXCHANGE_track_transfer_cancel (wdh);
     238           2 :   return GNUNET_OK;
     239             : }
     240             : 
     241             : 
     242             : /**
     243             :  * Function called when we're done processing the
     244             :  * HTTP /track/transfer request.
     245             :  *
     246             :  * @param cls the `struct TALER_EXCHANGE_TrackTransferHandle`
     247             :  * @param response_code HTTP response code, 0 on error
     248             :  * @param json parsed JSON result, NULL on error
     249             :  */
     250             : static void
     251           3 : handle_track_transfer_finished (void *cls,
     252             :                                 long response_code,
     253             :                                 const json_t *json)
     254             : {
     255           3 :   struct TALER_EXCHANGE_TrackTransferHandle *wdh = cls;
     256             : 
     257           3 :   wdh->job = NULL;
     258           3 :   switch (response_code)
     259             :   {
     260             :   case 0:
     261           0 :     break;
     262             :   case MHD_HTTP_OK:
     263           2 :     if (GNUNET_OK ==
     264           2 :         check_track_transfer_response_ok (wdh,
     265             :                                           json))
     266           2 :       return;
     267           0 :     GNUNET_break_op (0);
     268           0 :     response_code = 0;
     269           0 :     break;
     270             :   case MHD_HTTP_BAD_REQUEST:
     271             :     /* This should never happen, either us or the exchange is buggy
     272             :        (or API version conflict); just pass JSON reply to the application */
     273           0 :     break;
     274             :   case MHD_HTTP_UNAUTHORIZED:
     275             :     /* Nothing really to verify, exchange says one of the signatures is
     276             :        invalid; as we checked them, this should never happen, we
     277             :        should pass the JSON reply to the application */
     278           0 :     break;
     279             :   case MHD_HTTP_NOT_FOUND:
     280             :     /* Exchange does not know about transaction;
     281             :        we should pass the reply to the application */
     282           1 :     break;
     283             :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     284             :     /* Server had an internal issue; we should retry, but this API
     285             :        leaves this to the application */
     286           0 :     break;
     287             :   default:
     288             :     /* unexpected response code */
     289           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     290             :                 "Unexpected response code %u\n",
     291             :                 (unsigned int) response_code);
     292           0 :     GNUNET_break (0);
     293           0 :     response_code = 0;
     294           0 :     break;
     295             :   }
     296           1 :   wdh->cb (wdh->cb_cls,
     297             :            response_code,
     298             :            TALER_JSON_get_error_code (json),
     299             :            NULL,
     300             :            json,
     301             :            NULL,
     302             :            GNUNET_TIME_UNIT_ZERO_ABS,
     303             :            NULL,
     304             :            NULL,
     305             :            0, NULL);
     306           1 :   TALER_EXCHANGE_track_transfer_cancel (wdh);
     307             : }
     308             : 
     309             : 
     310             : /**
     311             :  * Query the exchange about which transactions were combined
     312             :  * to create a wire transfer.
     313             :  *
     314             :  * @param exchange exchange to query
     315             :  * @param wtid raw wire transfer identifier to get information about
     316             :  * @param cb callback to call
     317             :  * @param cb_cls closure for @a cb
     318             :  * @return handle to cancel operation
     319             :  */
     320             : struct TALER_EXCHANGE_TrackTransferHandle *
     321           3 : TALER_EXCHANGE_track_transfer (struct TALER_EXCHANGE_Handle *exchange,
     322             :                                const struct TALER_WireTransferIdentifierRawP *wtid,
     323             :                                TALER_EXCHANGE_TrackTransferCallback cb,
     324             :                                void *cb_cls)
     325             : {
     326             :   struct TALER_EXCHANGE_TrackTransferHandle *wdh;
     327             :   struct GNUNET_CURL_Context *ctx;
     328             :   char *buf;
     329             :   char *path;
     330             :   CURL *eh;
     331             : 
     332           3 :   if (GNUNET_YES !=
     333           3 :       MAH_handle_is_ready (exchange))
     334             :   {
     335           0 :     GNUNET_break (0);
     336           0 :     return NULL;
     337             :   }
     338             : 
     339           3 :   wdh = GNUNET_new (struct TALER_EXCHANGE_TrackTransferHandle);
     340           3 :   wdh->exchange = exchange;
     341           3 :   wdh->cb = cb;
     342           3 :   wdh->cb_cls = cb_cls;
     343             : 
     344           3 :   buf = GNUNET_STRINGS_data_to_string_alloc (wtid,
     345             :                                              sizeof (struct TALER_WireTransferIdentifierRawP));
     346           3 :   GNUNET_asprintf (&path,
     347             :                    "/track/transfer?wtid=%s",
     348             :                    buf);
     349           3 :   wdh->url = MAH_path_to_url (wdh->exchange,
     350             :                               path);
     351           3 :   GNUNET_free (buf);
     352           3 :   GNUNET_free (path);
     353             : 
     354           3 :   eh = curl_easy_init ();
     355           3 :   GNUNET_assert (CURLE_OK ==
     356             :                  curl_easy_setopt (eh,
     357             :                                    CURLOPT_URL,
     358             :                                    wdh->url));
     359           3 :   ctx = MAH_handle_to_context (exchange);
     360           3 :   wdh->job = GNUNET_CURL_job_add (ctx,
     361             :                           eh,
     362             :                           GNUNET_YES,
     363             :                           &handle_track_transfer_finished,
     364             :                           wdh);
     365           3 :   return wdh;
     366             : }
     367             : 
     368             : 
     369             : /**
     370             :  * Cancel wire deposits request.  This function cannot be used on a request
     371             :  * handle if a response is already served for it.
     372             :  *
     373             :  * @param wdh the wire deposits request handle
     374             :  */
     375             : void
     376           3 : TALER_EXCHANGE_track_transfer_cancel (struct TALER_EXCHANGE_TrackTransferHandle *wdh)
     377             : {
     378           3 :   if (NULL != wdh->job)
     379             :   {
     380           0 :     GNUNET_CURL_job_cancel (wdh->job);
     381           0 :     wdh->job = NULL;
     382             :   }
     383           3 :   GNUNET_free (wdh->url);
     384           3 :   GNUNET_free (wdh);
     385           3 : }
     386             : 
     387             : 
     388             : /* end of exchange_api_wire_deposits.c */

Generated by: LCOV version 1.13