LCOV - code coverage report
Current view: top level - lib - merchant_api_tip_pickup.c (source / functions) Hit Total Coverage
Test: GNU Taler merchant coverage report Lines: 0 150 0.0 %
Date: 2022-08-25 06:17:04 Functions: 0 6 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2014-2022 Taler Systems SA
       4             : 
       5             :   TALER is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser General Public License as published by the Free Software
       7             :   Foundation; either version 2.1, 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 Lesser General Public License for more details.
      12             : 
      13             :   You should have received a copy of the GNU Lesser General Public License along with
      14             :   TALER; see the file COPYING.LGPL.  If not, see
      15             :   <http://www.gnu.org/licenses/>
      16             : */
      17             : /**
      18             :  * @file merchant_api_tip_pickup.c
      19             :  * @brief Implementation of the /tip-pickup request of the merchant's HTTP API
      20             :  * @author Marcello Stanisci
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.h"
      24             : #include <curl/curl.h>
      25             : #include <jansson.h>
      26             : #include <microhttpd.h> /* just for HTTP status codes */
      27             : #include <gnunet/gnunet_util_lib.h>
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_merchant_service.h"
      30             : #include <taler/taler_json_lib.h>
      31             : #include <taler/taler_signatures.h>
      32             : #include <taler/taler_curl_lib.h>
      33             : 
      34             : 
      35             : /**
      36             :  * Data we keep per planchet.
      37             :  */
      38             : struct PlanchetData
      39             : {
      40             :   /**
      41             :    * Secrets of the planchet.
      42             :    */
      43             :   struct TALER_PlanchetMasterSecretP ps;
      44             : 
      45             :   /**
      46             :    * Denomination key we are withdrawing.
      47             :    */
      48             :   struct TALER_EXCHANGE_DenomPublicKey pk;
      49             : 
      50             :   /**
      51             :    * Hash of the public key of the coin we are signing.
      52             :    */
      53             :   struct TALER_CoinPubHashP c_hash;
      54             : 
      55             :   /**
      56             :    * Nonce used for @e csr request, if any.
      57             :    */
      58             :   struct TALER_CsNonce nonce;
      59             : 
      60             :   /**
      61             :    * Handle for a /csr request we may optionally need
      62             :    * to trigger.
      63             :    */
      64             :   struct TALER_EXCHANGE_CsRWithdrawHandle *csr;
      65             : 
      66             :   /**
      67             :    * Handle for the /tip-pickup operation we are part of.
      68             :    */
      69             :   struct TALER_MERCHANT_TipPickupHandle *tp;
      70             : 
      71             :   /**
      72             :    * Offset of this entry in the array.
      73             :    */
      74             :   unsigned int off;
      75             : };
      76             : 
      77             : 
      78             : /**
      79             :  * Handle for a /tip-pickup operation.
      80             :  */
      81             : struct TALER_MERCHANT_TipPickupHandle
      82             : {
      83             : 
      84             :   /**
      85             :    * Function to call with the result.
      86             :    */
      87             :   TALER_MERCHANT_TipPickupCallback cb;
      88             : 
      89             :   /**
      90             :    * Closure for @a cb.
      91             :    */
      92             :   void *cb_cls;
      93             : 
      94             :   /**
      95             :    * Handle for the actual (internal) withdraw operation.
      96             :    */
      97             :   struct TALER_MERCHANT_TipPickup2Handle *tpo2;
      98             : 
      99             :   /**
     100             :    * Array of length @e num_planchets.
     101             :    */
     102             :   struct PlanchetData *planchets;
     103             : 
     104             :   /**
     105             :    * Array of length @e num_planchets.
     106             :    */
     107             :   struct TALER_EXCHANGE_PrivateCoinDetails *pcds;
     108             : 
     109             :   /**
     110             :    * Context for making HTTP requests.
     111             :    */
     112             :   struct GNUNET_CURL_Context *ctx;
     113             : 
     114             :   /**
     115             :    * URL of the merchant backend.
     116             :    */
     117             :   char *backend_url;
     118             : 
     119             :   /**
     120             :    * ID of the tip we are picking up.
     121             :    */
     122             :   struct TALER_TipIdentifierP tip_id;
     123             : 
     124             :   /**
     125             :    * Number of planchets/coins used for this operation.
     126             :    */
     127             :   unsigned int num_planchets;
     128             : 
     129             :   /**
     130             :    * Number of remaining active /csr-withdraw requests.
     131             :    */
     132             :   unsigned int csr_active;
     133             : };
     134             : 
     135             : 
     136             : /**
     137             :  * Fail the pickup operation @a tp, returning @a ec.
     138             :  * Also cancels @a tp.
     139             :  *
     140             :  * @param[in] tp operation to fail
     141             :  * @param ec reason for the failure
     142             :  */
     143             : static void
     144           0 : fail_pickup (struct TALER_MERCHANT_TipPickupHandle *tp,
     145             :              enum TALER_ErrorCode ec)
     146             : {
     147           0 :   struct TALER_MERCHANT_PickupDetails pd = {
     148             :     .hr.ec = ec
     149             :   };
     150             : 
     151           0 :   tp->cb (tp->cb_cls,
     152             :           &pd);
     153           0 :   TALER_MERCHANT_tip_pickup_cancel (tp);
     154           0 : }
     155             : 
     156             : 
     157             : /**
     158             :  * Callback for a /tip-pickup request.  Returns the result of the operation.
     159             :  * Note that the client MUST still do the unblinding of the @a blind_sigs.
     160             :  *
     161             :  * @param cls closure, a `struct TALER_MERCHANT_TipPickupHandle *`
     162             :  * @param hr HTTP response details
     163             :  * @param num_blind_sigs length of the @a reserve_sigs array, 0 on error
     164             :  * @param blind_sigs array of blind signatures over the planchets, NULL on error
     165             :  */
     166             : static void
     167           0 : pickup_done_cb (void *cls,
     168             :                 const struct TALER_MERCHANT_HttpResponse *hr,
     169             :                 unsigned int num_blind_sigs,
     170             :                 const struct TALER_BlindedDenominationSignature *blind_sigs)
     171             : {
     172           0 :   struct TALER_MERCHANT_TipPickupHandle *tp = cls;
     173           0 :   struct TALER_MERCHANT_PickupDetails pd = {
     174             :     .hr = *hr
     175             :   };
     176             : 
     177           0 :   tp->tpo2 = NULL;
     178           0 :   if (NULL == blind_sigs)
     179             :   {
     180           0 :     tp->cb (tp->cb_cls,
     181             :             &pd);
     182           0 :     TALER_MERCHANT_tip_pickup_cancel (tp);
     183           0 :     return;
     184             :   }
     185             :   {
     186           0 :     enum GNUNET_GenericReturnValue ok = GNUNET_OK;
     187             : 
     188           0 :     for (unsigned int i = 0; i<num_blind_sigs; i++)
     189             :     {
     190           0 :       struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
     191             :       struct TALER_FreshCoin fc;
     192             : 
     193           0 :       if (GNUNET_OK !=
     194           0 :           TALER_planchet_to_coin (&tp->planchets[i].pk.key,
     195           0 :                                   &blind_sigs[i],
     196           0 :                                   &pcd->bks,
     197           0 :                                   &pcd->coin_priv,
     198             :                                   NULL,
     199           0 :                                   &tp->planchets[i].c_hash,
     200           0 :                                   &pcd->exchange_vals,
     201             :                                   &fc))
     202             :       {
     203           0 :         ok = GNUNET_SYSERR;
     204           0 :         break;
     205             :       }
     206           0 :       pcd->sig = fc.sig;
     207             :     }
     208           0 :     if (GNUNET_OK != ok)
     209             :     {
     210           0 :       struct TALER_MERCHANT_HttpResponse hrx = {
     211           0 :         .reply = hr->reply,
     212             :         .ec = TALER_EC_MERCHANT_TIP_PICKUP_UNBLIND_FAILURE
     213             :       };
     214             : 
     215           0 :       pd.hr = hrx;
     216           0 :       tp->cb (tp->cb_cls,
     217             :               &pd);
     218             :     }
     219             :     else
     220             :     {
     221           0 :       pd.details.success.num_sigs = num_blind_sigs;
     222           0 :       pd.details.success.pcds = tp->pcds;
     223           0 :       tp->cb (tp->cb_cls,
     224             :               &pd);
     225             :     }
     226             :   }
     227           0 :   TALER_MERCHANT_tip_pickup_cancel (tp);
     228             : }
     229             : 
     230             : 
     231             : /**
     232             :  * We have obtained all of the exchange inputs. Continue the pickup.
     233             :  *
     234             :  * @param[in,out] tp operation to continue
     235             :  */
     236             : static void
     237           0 : pickup_post_csr (struct TALER_MERCHANT_TipPickupHandle *tp)
     238           0 : {
     239           0 :   struct TALER_PlanchetDetail details[tp->num_planchets];
     240             : 
     241           0 :   for (unsigned int i = 0; i<tp->num_planchets; i++)
     242             :   {
     243           0 :     const struct PlanchetData *pd = &tp->planchets[i];
     244           0 :     struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
     245             : 
     246           0 :     TALER_planchet_setup_coin_priv (&pd->ps,
     247           0 :                                     &pcd->exchange_vals,
     248             :                                     &pcd->coin_priv);
     249           0 :     TALER_planchet_blinding_secret_create (&pd->ps,
     250           0 :                                            &pcd->exchange_vals,
     251             :                                            &pcd->bks);
     252           0 :     if (TALER_DENOMINATION_CS == pcd->exchange_vals.cipher)
     253             :     {
     254             :       details[i].blinded_planchet.details.cs_blinded_planchet.nonce
     255           0 :         = pd->nonce;
     256             :     }
     257           0 :     if (GNUNET_OK !=
     258           0 :         TALER_planchet_prepare (&pd->pk.key,
     259           0 :                                 &pcd->exchange_vals,
     260           0 :                                 &pcd->bks,
     261           0 :                                 &pcd->coin_priv,
     262             :                                 NULL,
     263           0 :                                 &tp->planchets[i].c_hash,
     264             :                                 &details[i]))
     265             :     {
     266           0 :       GNUNET_break (0);
     267           0 :       for (unsigned int j = 0; j<i; j++)
     268           0 :         TALER_planchet_detail_free (&details[j]);
     269           0 :       fail_pickup (tp,
     270             :                    TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
     271           0 :       return;
     272             :     }
     273             :   }
     274           0 :   tp->tpo2 = TALER_MERCHANT_tip_pickup2 (tp->ctx,
     275           0 :                                          tp->backend_url,
     276           0 :                                          &tp->tip_id,
     277             :                                          tp->num_planchets,
     278             :                                          details,
     279             :                                          &pickup_done_cb,
     280             :                                          tp);
     281           0 :   for (unsigned int j = 0; j<tp->num_planchets; j++)
     282           0 :     TALER_planchet_detail_free (&details[j]);
     283           0 :   if (NULL == tp->tpo2)
     284             :   {
     285           0 :     GNUNET_break (0);
     286           0 :     fail_pickup (tp,
     287             :                  TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
     288           0 :     return;
     289             :   }
     290             : }
     291             : 
     292             : 
     293             : /**
     294             :  * Callbacks of this type are used to serve the result of submitting a
     295             :  * CS R request to a exchange.
     296             :  *
     297             :  * @param cls a `struct TALER_MERCHANT_TipPickupHandle`
     298             :  * @param csrr response details
     299             :  */
     300             : static void
     301           0 : csr_cb (void *cls,
     302             :         const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr)
     303             : {
     304           0 :   struct PlanchetData *pd = cls;
     305           0 :   struct TALER_MERCHANT_TipPickupHandle *tp = pd->tp;
     306             : 
     307           0 :   pd->csr = NULL;
     308           0 :   tp->csr_active--;
     309           0 :   switch (csrr->hr.http_status)
     310             :   {
     311           0 :   case MHD_HTTP_OK:
     312             :     {
     313           0 :       struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[pd->off];
     314             : 
     315           0 :       pcd->exchange_vals = csrr->details.success.alg_values;
     316             :     }
     317           0 :     if (0 != tp->csr_active)
     318           0 :       return;
     319           0 :     pickup_post_csr (tp);
     320           0 :     return;
     321           0 :   default:
     322             :     {
     323           0 :       struct TALER_MERCHANT_PickupDetails pd = {
     324             :         .hr.hint = "/csr-withdraw failed",
     325           0 :         .hr.exchange_http_status = csrr->hr.http_status
     326             :       };
     327             : 
     328           0 :       tp->cb (tp->cb_cls,
     329             :               &pd);
     330           0 :       TALER_MERCHANT_tip_pickup_cancel (tp);
     331           0 :       return;
     332             :     }
     333             :   }
     334             : }
     335             : 
     336             : 
     337             : struct TALER_MERCHANT_TipPickupHandle *
     338           0 : TALER_MERCHANT_tip_pickup (struct GNUNET_CURL_Context *ctx,
     339             :                            struct TALER_EXCHANGE_Handle *exchange,
     340             :                            const char *backend_url,
     341             :                            const struct TALER_TipIdentifierP *tip_id,
     342             :                            unsigned int num_planchets,
     343             :                            const struct TALER_MERCHANT_PlanchetData *pds,
     344             :                            TALER_MERCHANT_TipPickupCallback pickup_cb,
     345             :                            void *pickup_cb_cls)
     346             : {
     347             :   struct TALER_MERCHANT_TipPickupHandle *tp;
     348             : 
     349           0 :   if (0 == num_planchets)
     350             :   {
     351           0 :     GNUNET_break (0);
     352           0 :     return NULL;
     353             :   }
     354           0 :   tp = GNUNET_new (struct TALER_MERCHANT_TipPickupHandle);
     355           0 :   tp->cb = pickup_cb;
     356           0 :   tp->cb_cls = pickup_cb_cls;
     357           0 :   tp->ctx = ctx;
     358           0 :   tp->backend_url = GNUNET_strdup (backend_url);
     359           0 :   tp->tip_id = *tip_id;
     360           0 :   tp->num_planchets = num_planchets;
     361           0 :   tp->planchets = GNUNET_new_array (num_planchets,
     362             :                                     struct PlanchetData);
     363           0 :   tp->pcds = GNUNET_new_array (num_planchets,
     364             :                                struct TALER_EXCHANGE_PrivateCoinDetails);
     365           0 :   for (unsigned int i = 0; i<num_planchets; i++)
     366             :   {
     367           0 :     const struct TALER_MERCHANT_PlanchetData *mpd = &pds[i];
     368           0 :     const struct TALER_EXCHANGE_DenomPublicKey *pk = mpd->pk;
     369           0 :     struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
     370           0 :     struct PlanchetData *pd = &tp->planchets[i];
     371             : 
     372           0 :     pd->off = i;
     373           0 :     pd->tp = tp;
     374           0 :     tp->planchets[i].ps = mpd->ps;
     375           0 :     tp->planchets[i].pk = *pds[i].pk;
     376           0 :     TALER_denom_pub_deep_copy (&tp->planchets[i].pk.key,
     377           0 :                                &pds[i].pk->key);
     378           0 :     switch (pk->key.cipher)
     379             :     {
     380           0 :     case TALER_DENOMINATION_RSA:
     381           0 :       pcd->exchange_vals.cipher = TALER_DENOMINATION_RSA;
     382           0 :       break;
     383           0 :     case TALER_DENOMINATION_CS:
     384             :       {
     385           0 :         TALER_cs_withdraw_nonce_derive (&pd->ps,
     386             :                                         &pd->nonce);
     387           0 :         pd->csr = TALER_EXCHANGE_csr_withdraw (exchange,
     388           0 :                                                &pd->pk,
     389           0 :                                                &pd->nonce,
     390             :                                                &csr_cb,
     391             :                                                pd);
     392           0 :         if (NULL == pd->csr)
     393             :         {
     394           0 :           GNUNET_break (0);
     395           0 :           TALER_MERCHANT_tip_pickup_cancel (tp);
     396           0 :           return NULL;
     397             :         }
     398           0 :         tp->csr_active++;
     399           0 :         break;
     400             :       }
     401           0 :     default:
     402           0 :       GNUNET_break (0);
     403           0 :       TALER_MERCHANT_tip_pickup_cancel (tp);
     404           0 :       return NULL;
     405             :     }
     406             :   }
     407           0 :   if (0 == tp->csr_active)
     408             :   {
     409           0 :     pickup_post_csr (tp);
     410           0 :     return tp;
     411             :   }
     412           0 :   return tp;
     413             : }
     414             : 
     415             : 
     416             : void
     417           0 : TALER_MERCHANT_tip_pickup_cancel (struct TALER_MERCHANT_TipPickupHandle *tp)
     418             : {
     419           0 :   for (unsigned int i = 0; i<tp->num_planchets; i++)
     420             :   {
     421           0 :     struct TALER_EXCHANGE_PrivateCoinDetails *pcd = &tp->pcds[i];
     422           0 :     struct PlanchetData *pd = &tp->planchets[i];
     423             : 
     424           0 :     TALER_denom_sig_free (&pcd->sig);
     425           0 :     TALER_denom_pub_free (&tp->planchets[i].pk.key);
     426           0 :     if (NULL != pd->csr)
     427             :     {
     428           0 :       TALER_EXCHANGE_csr_withdraw_cancel (pd->csr);
     429           0 :       pd->csr = NULL;
     430             :     }
     431             :   }
     432           0 :   GNUNET_array_grow (tp->planchets,
     433             :                      tp->num_planchets,
     434             :                      0);
     435           0 :   if (NULL != tp->tpo2)
     436             :   {
     437           0 :     TALER_MERCHANT_tip_pickup2_cancel (tp->tpo2);
     438           0 :     tp->tpo2 = NULL;
     439             :   }
     440           0 :   GNUNET_free (tp->backend_url);
     441           0 :   GNUNET_free (tp->pcds);
     442           0 :   GNUNET_free (tp);
     443           0 : }
     444             : 
     445             : 
     446             : /* end of merchant_api_tip_pickup.c */

Generated by: LCOV version 1.14