LCOV - code coverage report
Current view: top level - lib - exchange_api_deposits_get.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 89 136 65.4 %
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 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 lib/exchange_api_deposits_get.c
      19             :  * @brief Implementation of the /deposits/ GET request
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include <jansson.h>
      24             : #include <microhttpd.h> /* just for HTTP status codes */
      25             : #include <gnunet/gnunet_util_lib.h>
      26             : #include <gnunet/gnunet_json_lib.h>
      27             : #include <gnunet/gnunet_curl_lib.h>
      28             : #include "taler_json_lib.h"
      29             : #include "taler_exchange_service.h"
      30             : #include "exchange_api_handle.h"
      31             : #include "taler_signatures.h"
      32             : #include "exchange_api_curl_defaults.h"
      33             : 
      34             : 
      35             : /**
      36             :  * @brief A Deposit Get Handle
      37             :  */
      38             : struct TALER_EXCHANGE_DepositGetHandle
      39             : {
      40             : 
      41             :   /**
      42             :    * The connection to exchange this request handle will use
      43             :    */
      44             :   struct TALER_EXCHANGE_Handle *exchange;
      45             : 
      46             :   /**
      47             :    * The url for this request.
      48             :    */
      49             :   char *url;
      50             : 
      51             :   /**
      52             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      53             :    * persist for Curl to make the upload.
      54             :    */
      55             :   struct TALER_CURL_PostContext ctx;
      56             : 
      57             :   /**
      58             :    * Handle for the request.
      59             :    */
      60             :   struct GNUNET_CURL_Job *job;
      61             : 
      62             :   /**
      63             :    * Function to call with the result.
      64             :    */
      65             :   TALER_EXCHANGE_DepositGetCallback cb;
      66             : 
      67             :   /**
      68             :    * Closure for @a cb.
      69             :    */
      70             :   void *cb_cls;
      71             : 
      72             :   /**
      73             :    * Information the exchange should sign in response.
      74             :    * (with pre-filled fields from the request).
      75             :    */
      76             :   struct TALER_ConfirmWirePS depconf;
      77             : 
      78             : };
      79             : 
      80             : 
      81             : /**
      82             :  * Verify that the signature on the "200 OK" response
      83             :  * from the exchange is valid.
      84             :  *
      85             :  * @param dwh deposit wtid handle
      86             :  * @param json json reply with the signature
      87             :  * @param exchange_pub the exchange's public key
      88             :  * @param exchange_sig the exchange's signature
      89             :  * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
      90             :  */
      91             : static int
      92           1 : verify_deposit_wtid_signature_ok (
      93             :   const struct TALER_EXCHANGE_DepositGetHandle *dwh,
      94             :   const json_t *json,
      95             :   const struct TALER_ExchangePublicKeyP *exchange_pub,
      96             :   const struct TALER_ExchangeSignatureP *exchange_sig)
      97             : {
      98             :   const struct TALER_EXCHANGE_Keys *key_state;
      99             : 
     100           1 :   key_state = TALER_EXCHANGE_get_keys (dwh->exchange);
     101           1 :   if (GNUNET_OK !=
     102           1 :       TALER_EXCHANGE_test_signing_key (key_state,
     103             :                                        exchange_pub))
     104             :   {
     105           0 :     GNUNET_break_op (0);
     106           0 :     return GNUNET_SYSERR;
     107             :   }
     108           1 :   if (GNUNET_OK !=
     109           1 :       GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE,
     110             :                                   &dwh->depconf,
     111             :                                   &exchange_sig->eddsa_signature,
     112             :                                   &exchange_pub->eddsa_pub))
     113             :   {
     114           0 :     GNUNET_break_op (0);
     115           0 :     return GNUNET_SYSERR;
     116             :   }
     117           1 :   return GNUNET_OK;
     118             : }
     119             : 
     120             : 
     121             : /**
     122             :  * Function called when we're done processing the
     123             :  * HTTP /track/transaction request.
     124             :  *
     125             :  * @param cls the `struct TALER_EXCHANGE_DepositGetHandle`
     126             :  * @param response_code HTTP response code, 0 on error
     127             :  * @param response parsed JSON result, NULL on error
     128             :  */
     129             : static void
     130           3 : handle_deposit_wtid_finished (void *cls,
     131             :                               long response_code,
     132             :                               const void *response)
     133             : {
     134           3 :   struct TALER_EXCHANGE_DepositGetHandle *dwh = cls;
     135           3 :   const json_t *j = response;
     136           3 :   struct TALER_EXCHANGE_HttpResponse hr = {
     137             :     .reply = j,
     138           3 :     .http_status = (unsigned int) response_code
     139             :   };
     140             : 
     141           3 :   dwh->job = NULL;
     142           3 :   switch (response_code)
     143             :   {
     144           0 :   case 0:
     145           0 :     hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     146           0 :     break;
     147           1 :   case MHD_HTTP_OK:
     148             :     {
     149             :       struct TALER_EXCHANGE_DepositData dd;
     150             :       struct GNUNET_JSON_Specification spec[] = {
     151           1 :         GNUNET_JSON_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
     152           1 :         TALER_JSON_spec_absolute_time ("execution_time", &dd.execution_time),
     153           1 :         TALER_JSON_spec_amount_any ("coin_contribution", &dd.coin_contribution),
     154           1 :         GNUNET_JSON_spec_fixed_auto ("exchange_sig", &dd.exchange_sig),
     155           1 :         GNUNET_JSON_spec_fixed_auto ("exchange_pub", &dd.exchange_pub),
     156           1 :         GNUNET_JSON_spec_end ()
     157             :       };
     158             : 
     159           1 :       if (GNUNET_OK !=
     160           1 :           GNUNET_JSON_parse (j,
     161             :                              spec,
     162             :                              NULL, NULL))
     163             :       {
     164           0 :         GNUNET_break_op (0);
     165           0 :         hr.http_status = 0;
     166           0 :         hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     167           0 :         break;
     168             :       }
     169           1 :       dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (
     170             :         dd.execution_time);
     171           1 :       TALER_amount_hton (&dwh->depconf.coin_contribution,
     172             :                          &dd.coin_contribution);
     173           1 :       if (GNUNET_OK !=
     174           1 :           verify_deposit_wtid_signature_ok (dwh,
     175             :                                             j,
     176             :                                             &dd.exchange_pub,
     177             :                                             &dd.exchange_sig))
     178             :       {
     179           0 :         GNUNET_break_op (0);
     180           0 :         hr.http_status = 0;
     181           0 :         hr.ec = TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_SIGNATURE_BY_EXCHANGE;
     182             :       }
     183             :       else
     184             :       {
     185           1 :         dd.wtid = dwh->depconf.wtid;
     186           1 :         dwh->cb (dwh->cb_cls,
     187             :                  &hr,
     188             :                  &dd);
     189           1 :         TALER_EXCHANGE_deposits_get_cancel (dwh);
     190           1 :         return;
     191             :       }
     192             :     }
     193           0 :     break;
     194           1 :   case MHD_HTTP_ACCEPTED:
     195             :     {
     196             :       /* Transaction known, but not executed yet */
     197             :       struct GNUNET_TIME_Absolute execution_time;
     198             :       struct GNUNET_JSON_Specification spec[] = {
     199           1 :         TALER_JSON_spec_absolute_time ("execution_time", &execution_time),
     200           1 :         GNUNET_JSON_spec_end ()
     201             :       };
     202             : 
     203           1 :       if (GNUNET_OK !=
     204           1 :           GNUNET_JSON_parse (j,
     205             :                              spec,
     206             :                              NULL, NULL))
     207             :       {
     208           0 :         GNUNET_break_op (0);
     209           0 :         hr.http_status = 0;
     210           0 :         hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     211           0 :         break;
     212             :       }
     213             :       else
     214             :       {
     215           1 :         struct TALER_EXCHANGE_DepositData dd = {
     216             :           .execution_time = execution_time
     217             :         };
     218             : 
     219           1 :         dwh->cb (dwh->cb_cls,
     220             :                  &hr,
     221             :                  &dd);
     222           1 :         TALER_EXCHANGE_deposits_get_cancel (dwh);
     223           1 :         return;
     224             :       }
     225             :     }
     226             :     break;
     227           0 :   case MHD_HTTP_BAD_REQUEST:
     228           0 :     hr.ec = TALER_JSON_get_error_code (j);
     229           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     230             :     /* This should never happen, either us or the exchange is buggy
     231             :        (or API version conflict); just pass JSON reply to the application */
     232           0 :     break;
     233           0 :   case MHD_HTTP_FORBIDDEN:
     234           0 :     hr.ec = TALER_JSON_get_error_code (j);
     235           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     236             :     /* Nothing really to verify, exchange says one of the signatures is
     237             :        invalid; as we checked them, this should never happen, we
     238             :        should pass the JSON reply to the application */
     239           0 :     break;
     240           1 :   case MHD_HTTP_NOT_FOUND:
     241           1 :     hr.ec = TALER_JSON_get_error_code (j);
     242           1 :     hr.hint = TALER_JSON_get_error_hint (j);
     243             :     /* Exchange does not know about transaction;
     244             :        we should pass the reply to the application */
     245           1 :     break;
     246           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     247           0 :     hr.ec = TALER_JSON_get_error_code (j);
     248           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     249             :     /* Server had an internal issue; we should retry, but this API
     250             :        leaves this to the application */
     251           0 :     break;
     252           0 :   default:
     253             :     /* unexpected response code */
     254           0 :     hr.ec = TALER_JSON_get_error_code (j);
     255           0 :     hr.hint = TALER_JSON_get_error_hint (j);
     256           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     257             :                 "Unexpected response code %u/%d for exchange GET deposits\n",
     258             :                 (unsigned int) response_code,
     259             :                 (int) hr.ec);
     260           0 :     GNUNET_break_op (0);
     261           0 :     break;
     262             :   }
     263           1 :   dwh->cb (dwh->cb_cls,
     264             :            &hr,
     265             :            NULL);
     266           1 :   TALER_EXCHANGE_deposits_get_cancel (dwh);
     267             : }
     268             : 
     269             : 
     270             : /**
     271             :  * Obtain wire transfer details about an existing deposit operation.
     272             :  *
     273             :  * @param exchange the exchange to query
     274             :  * @param merchant_priv the merchant's private key
     275             :  * @param h_wire hash of merchant's wire transfer details
     276             :  * @param h_contract_terms hash of the proposal data from the contract
     277             :  *                        between merchant and customer
     278             :  * @param coin_pub public key of the coin
     279             :  * @param cb function to call with the result
     280             :  * @param cb_cls closure for @a cb
     281             :  * @return handle to abort request
     282             :  */
     283             : struct TALER_EXCHANGE_DepositGetHandle *
     284           3 : TALER_EXCHANGE_deposits_get (
     285             :   struct TALER_EXCHANGE_Handle *exchange,
     286             :   const struct TALER_MerchantPrivateKeyP *merchant_priv,
     287             :   const struct GNUNET_HashCode *h_wire,
     288             :   const struct GNUNET_HashCode *h_contract_terms,
     289             :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
     290             :   TALER_EXCHANGE_DepositGetCallback cb,
     291             :   void *cb_cls)
     292             : {
     293             :   struct TALER_DepositTrackPS dtp;
     294             :   struct TALER_MerchantSignatureP merchant_sig;
     295             :   struct TALER_EXCHANGE_DepositGetHandle *dwh;
     296             :   struct GNUNET_CURL_Context *ctx;
     297             :   CURL *eh;
     298             :   char arg_str[(sizeof (struct TALER_CoinSpendPublicKeyP)
     299             :                 + sizeof (struct GNUNET_HashCode)
     300             :                 + sizeof (struct TALER_MerchantPublicKeyP)
     301             :                 + sizeof (struct GNUNET_HashCode)
     302             :                 + sizeof (struct TALER_MerchantSignatureP)) * 2 + 48];
     303             : 
     304           3 :   if (GNUNET_YES !=
     305           3 :       TEAH_handle_is_ready (exchange))
     306             :   {
     307           0 :     GNUNET_break (0);
     308           0 :     return NULL;
     309             :   }
     310           3 :   dtp.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION);
     311           3 :   dtp.purpose.size = htonl (sizeof (dtp));
     312           3 :   dtp.h_contract_terms = *h_contract_terms;
     313           3 :   dtp.h_wire = *h_wire;
     314           3 :   GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv,
     315             :                                       &dtp.merchant.eddsa_pub);
     316             : 
     317           3 :   dtp.coin_pub = *coin_pub;
     318           3 :   GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
     319             :                             &dtp,
     320             :                             &merchant_sig.eddsa_sig);
     321             :   {
     322             :     char cpub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
     323             :     char mpub_str[sizeof (struct TALER_MerchantPublicKeyP) * 2];
     324             :     char msig_str[sizeof (struct TALER_MerchantSignatureP) * 2];
     325             :     char chash_str[sizeof (struct GNUNET_HashCode) * 2];
     326             :     char whash_str[sizeof (struct GNUNET_HashCode) * 2];
     327             :     char *end;
     328             : 
     329           3 :     end = GNUNET_STRINGS_data_to_string (h_wire,
     330             :                                          sizeof (struct
     331             :                                                  GNUNET_HashCode),
     332             :                                          whash_str,
     333             :                                          sizeof (whash_str));
     334           3 :     *end = '\0';
     335           3 :     end = GNUNET_STRINGS_data_to_string (&dtp.merchant,
     336             :                                          sizeof (struct
     337             :                                                  TALER_MerchantPublicKeyP),
     338             :                                          mpub_str,
     339             :                                          sizeof (mpub_str));
     340           3 :     *end = '\0';
     341           3 :     end = GNUNET_STRINGS_data_to_string (h_contract_terms,
     342             :                                          sizeof (struct
     343             :                                                  GNUNET_HashCode),
     344             :                                          chash_str,
     345             :                                          sizeof (chash_str));
     346           3 :     *end = '\0';
     347           3 :     end = GNUNET_STRINGS_data_to_string (coin_pub,
     348             :                                          sizeof (struct
     349             :                                                  TALER_CoinSpendPublicKeyP),
     350             :                                          cpub_str,
     351             :                                          sizeof (cpub_str));
     352           3 :     *end = '\0';
     353           3 :     end = GNUNET_STRINGS_data_to_string (&merchant_sig,
     354             :                                          sizeof (struct
     355             :                                                  TALER_MerchantSignatureP),
     356             :                                          msig_str,
     357             :                                          sizeof (msig_str));
     358           3 :     *end = '\0';
     359             : 
     360           3 :     GNUNET_snprintf (arg_str,
     361             :                      sizeof (arg_str),
     362             :                      "/deposits/%s/%s/%s/%s?merchant_sig=%s",
     363             :                      whash_str,
     364             :                      mpub_str,
     365             :                      chash_str,
     366             :                      cpub_str,
     367             :                      msig_str);
     368             :   }
     369             : 
     370           3 :   dwh = GNUNET_new (struct TALER_EXCHANGE_DepositGetHandle);
     371           3 :   dwh->exchange = exchange;
     372           3 :   dwh->cb = cb;
     373           3 :   dwh->cb_cls = cb_cls;
     374           3 :   dwh->url = TEAH_path_to_url (exchange,
     375             :                                arg_str);
     376           3 :   if (NULL == dwh->url)
     377             :   {
     378           0 :     GNUNET_free (dwh);
     379           0 :     return NULL;
     380             :   }
     381           3 :   dwh->depconf.purpose.size = htonl (sizeof (struct TALER_ConfirmWirePS));
     382           3 :   dwh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE);
     383           3 :   dwh->depconf.h_wire = *h_wire;
     384           3 :   dwh->depconf.h_contract_terms = *h_contract_terms;
     385           3 :   dwh->depconf.coin_pub = *coin_pub;
     386             : 
     387           3 :   eh = TALER_EXCHANGE_curl_easy_get_ (dwh->url);
     388           3 :   if (NULL == eh)
     389             :   {
     390           0 :     GNUNET_break (0);
     391           0 :     GNUNET_free (dwh->url);
     392           0 :     GNUNET_free (dwh);
     393           0 :     return NULL;
     394             :   }
     395           3 :   ctx = TEAH_handle_to_context (exchange);
     396           3 :   dwh->job = GNUNET_CURL_job_add (ctx,
     397             :                                   eh,
     398             :                                   &handle_deposit_wtid_finished,
     399             :                                   dwh);
     400           3 :   return dwh;
     401             : }
     402             : 
     403             : 
     404             : /**
     405             :  * Cancel /deposits/$WTID request.  This function cannot be used on a request
     406             :  * handle if a response is already served for it.
     407             :  *
     408             :  * @param dwh the wire deposits request handle
     409             :  */
     410             : void
     411           3 : TALER_EXCHANGE_deposits_get_cancel (struct TALER_EXCHANGE_DepositGetHandle *dwh)
     412             : {
     413           3 :   if (NULL != dwh->job)
     414             :   {
     415           0 :     GNUNET_CURL_job_cancel (dwh->job);
     416           0 :     dwh->job = NULL;
     417             :   }
     418           3 :   GNUNET_free (dwh->url);
     419           3 :   TALER_curl_easy_post_finished (&dwh->ctx);
     420           3 :   GNUNET_free (dwh);
     421           3 : }
     422             : 
     423             : 
     424             : /* end of exchange_api_deposits_get.c */

Generated by: LCOV version 1.14