LCOV - code coverage report
Current view: top level - lib - exchange_api_purse_create_with_deposit.c (source / functions) Hit Total Coverage
Test: GNU Taler exchange coverage report Lines: 0 287 0.0 %
Date: 2022-08-25 06:15:09 Functions: 0 3 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    This file is part of TALER
       3             :    Copyright (C) 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 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_purse_create_with_deposit.c
      19             :  * @brief Implementation of the client to create a purse with
      20             :  *        an initial set of deposits (and a contract)
      21             :  * @author Christian Grothoff
      22             :  */
      23             : #include "platform.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_json_lib.h>
      28             : #include <gnunet/gnunet_curl_lib.h>
      29             : #include "taler_json_lib.h"
      30             : #include "taler_exchange_service.h"
      31             : #include "exchange_api_handle.h"
      32             : #include "exchange_api_common.h"
      33             : #include "taler_signatures.h"
      34             : #include "exchange_api_curl_defaults.h"
      35             : 
      36             : 
      37             : /**
      38             :  * Information we track per deposited coin.
      39             :  */
      40             : struct Deposit
      41             : {
      42             :   /**
      43             :    * Coin's public key.
      44             :    */
      45             :   struct TALER_CoinSpendPublicKeyP coin_pub;
      46             : 
      47             :   /**
      48             :    * Signature made with the coin.
      49             :    */
      50             :   struct TALER_CoinSpendSignatureP coin_sig;
      51             : 
      52             :   /**
      53             :    * Coin's denomination.
      54             :    */
      55             :   struct TALER_DenominationHashP h_denom_pub;
      56             : 
      57             :   /**
      58             :    * Age restriction hash for the coin.
      59             :    */
      60             :   struct TALER_AgeCommitmentHash ahac;
      61             : 
      62             :   /**
      63             :    * How much did we say the coin contributed.
      64             :    */
      65             :   struct TALER_Amount contribution;
      66             : };
      67             : 
      68             : 
      69             : /**
      70             :  * @brief A purse create with deposit handle
      71             :  */
      72             : struct TALER_EXCHANGE_PurseCreateDepositHandle
      73             : {
      74             : 
      75             :   /**
      76             :    * The connection to exchange this request handle will use
      77             :    */
      78             :   struct TALER_EXCHANGE_Handle *exchange;
      79             : 
      80             :   /**
      81             :    * The url for this request.
      82             :    */
      83             :   char *url;
      84             : 
      85             :   /**
      86             :    * Context for #TEH_curl_easy_post(). Keeps the data that must
      87             :    * persist for Curl to make the upload.
      88             :    */
      89             :   struct TALER_CURL_PostContext ctx;
      90             : 
      91             :   /**
      92             :    * Handle for the request.
      93             :    */
      94             :   struct GNUNET_CURL_Job *job;
      95             : 
      96             :   /**
      97             :    * Function to call with the result.
      98             :    */
      99             :   TALER_EXCHANGE_PurseCreateDepositCallback cb;
     100             : 
     101             :   /**
     102             :    * Closure for @a cb.
     103             :    */
     104             :   void *cb_cls;
     105             : 
     106             :   /**
     107             :    * Expected value in the purse after fees.
     108             :    */
     109             :   struct TALER_Amount purse_value_after_fees;
     110             : 
     111             :   /**
     112             :    * Our encryped contract (if we had any).
     113             :    */
     114             :   struct TALER_EncryptedContract econtract;
     115             : 
     116             :   /**
     117             :    * Public key of the merge capability.
     118             :    */
     119             :   struct TALER_PurseMergePublicKeyP merge_pub;
     120             : 
     121             :   /**
     122             :    * Public key of the purse.
     123             :    */
     124             :   struct TALER_PurseContractPublicKeyP purse_pub;
     125             : 
     126             :   /**
     127             :    * Signature with the purse key on the request.
     128             :    */
     129             :   struct TALER_PurseContractSignatureP purse_sig;
     130             : 
     131             :   /**
     132             :    * Hash over the purse's contract terms.
     133             :    */
     134             :   struct TALER_PrivateContractHashP h_contract_terms;
     135             : 
     136             :   /**
     137             :    * When does the purse expire.
     138             :    */
     139             :   struct GNUNET_TIME_Timestamp purse_expiration;
     140             : 
     141             :   /**
     142             :    * Array of @e num_deposit deposits.
     143             :    */
     144             :   struct Deposit *deposits;
     145             : 
     146             :   /**
     147             :    * How many deposits did we make?
     148             :    */
     149             :   unsigned int num_deposits;
     150             : 
     151             : };
     152             : 
     153             : 
     154             : /**
     155             :  * Function called when we're done processing the
     156             :  * HTTP /deposit request.
     157             :  *
     158             :  * @param cls the `struct TALER_EXCHANGE_DepositHandle`
     159             :  * @param response_code HTTP response code, 0 on error
     160             :  * @param response parsed JSON result, NULL on error
     161             :  */
     162             : static void
     163           0 : handle_purse_create_deposit_finished (void *cls,
     164             :                                       long response_code,
     165             :                                       const void *response)
     166             : {
     167           0 :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch = cls;
     168           0 :   const json_t *j = response;
     169           0 :   struct TALER_EXCHANGE_PurseCreateDepositResponse dr = {
     170             :     .hr.reply = j,
     171           0 :     .hr.http_status = (unsigned int) response_code
     172             :   };
     173             :   const struct TALER_EXCHANGE_Keys *keys;
     174             : 
     175           0 :   pch->job = NULL;
     176           0 :   keys = TALER_EXCHANGE_get_keys (pch->exchange);
     177           0 :   switch (response_code)
     178             :   {
     179           0 :   case 0:
     180           0 :     dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     181           0 :     break;
     182           0 :   case MHD_HTTP_OK:
     183             :     {
     184             :       const struct TALER_EXCHANGE_Keys *key_state;
     185             :       struct GNUNET_TIME_Timestamp etime;
     186             :       struct TALER_Amount total_deposited;
     187             :       struct TALER_ExchangeSignatureP exchange_sig;
     188             :       struct TALER_ExchangePublicKeyP exchange_pub;
     189             :       struct GNUNET_JSON_Specification spec[] = {
     190           0 :         GNUNET_JSON_spec_fixed_auto ("exchange_sig",
     191             :                                      &exchange_sig),
     192           0 :         GNUNET_JSON_spec_fixed_auto ("exchange_pub",
     193             :                                      &exchange_pub),
     194           0 :         GNUNET_JSON_spec_timestamp ("exchange_timestamp",
     195             :                                     &etime),
     196           0 :         TALER_JSON_spec_amount ("total_deposited",
     197           0 :                                 pch->purse_value_after_fees.currency,
     198             :                                 &total_deposited),
     199           0 :         GNUNET_JSON_spec_end ()
     200             :       };
     201             : 
     202           0 :       if (GNUNET_OK !=
     203           0 :           GNUNET_JSON_parse (j,
     204             :                              spec,
     205             :                              NULL, NULL))
     206             :       {
     207           0 :         GNUNET_break_op (0);
     208           0 :         dr.hr.http_status = 0;
     209           0 :         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     210           0 :         break;
     211             :       }
     212           0 :       key_state = TALER_EXCHANGE_get_keys (pch->exchange);
     213           0 :       if (GNUNET_OK !=
     214           0 :           TALER_EXCHANGE_test_signing_key (key_state,
     215             :                                            &exchange_pub))
     216             :       {
     217           0 :         GNUNET_break_op (0);
     218           0 :         dr.hr.http_status = 0;
     219           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_CREATE_EXCHANGE_SIGNATURE_INVALID;
     220           0 :         break;
     221             :       }
     222           0 :       if (GNUNET_OK !=
     223           0 :           TALER_exchange_online_purse_created_verify (
     224             :             etime,
     225             :             pch->purse_expiration,
     226           0 :             &pch->purse_value_after_fees,
     227             :             &total_deposited,
     228           0 :             &pch->purse_pub,
     229           0 :             &pch->h_contract_terms,
     230             :             &exchange_pub,
     231             :             &exchange_sig))
     232             :       {
     233           0 :         GNUNET_break_op (0);
     234           0 :         dr.hr.http_status = 0;
     235           0 :         dr.hr.ec = TALER_EC_EXCHANGE_PURSE_CREATE_EXCHANGE_SIGNATURE_INVALID;
     236           0 :         break;
     237             :       }
     238             :     }
     239           0 :     break;
     240           0 :   case MHD_HTTP_BAD_REQUEST:
     241             :     /* This should never happen, either us or the exchange is buggy
     242             :        (or API version conflict); just pass JSON reply to the application */
     243           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     244           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     245           0 :     break;
     246           0 :   case MHD_HTTP_FORBIDDEN:
     247           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     248           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     249             :     /* Nothing really to verify, exchange says one of the signatures is
     250             :        invalid; as we checked them, this should never happen, we
     251             :        should pass the JSON reply to the application */
     252           0 :     break;
     253           0 :   case MHD_HTTP_NOT_FOUND:
     254           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     255           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     256             :     /* Nothing really to verify, this should never
     257             :        happen, we should pass the JSON reply to the application */
     258           0 :     break;
     259           0 :   case MHD_HTTP_CONFLICT:
     260             :     {
     261           0 :       dr.hr.ec = TALER_JSON_get_error_code (j);
     262           0 :       switch (dr.hr.ec)
     263             :       {
     264           0 :       case TALER_EC_EXCHANGE_PURSE_CREATE_CONFLICTING_META_DATA:
     265           0 :         if (GNUNET_OK !=
     266           0 :             TALER_EXCHANGE_check_purse_create_conflict_ (
     267           0 :               &pch->purse_sig,
     268           0 :               &pch->purse_pub,
     269             :               j))
     270             :         {
     271           0 :           GNUNET_break_op (0);
     272           0 :           dr.hr.http_status = 0;
     273           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     274           0 :           break;
     275             :         }
     276           0 :         break;
     277           0 :       case TALER_EC_EXCHANGE_GENERIC_INSUFFICIENT_FUNDS:
     278             :         {
     279             :           struct TALER_Amount left;
     280             :           struct TALER_CoinSpendPublicKeyP pcoin_pub;
     281           0 :           bool found = false;
     282             : 
     283           0 :           if (GNUNET_OK !=
     284           0 :               TALER_EXCHANGE_check_coin_amount_conflict_ (
     285             :                 keys,
     286             :                 j,
     287             :                 &pcoin_pub,
     288             :                 &left))
     289             :           {
     290           0 :             GNUNET_break_op (0);
     291           0 :             dr.hr.http_status = 0;
     292           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     293           0 :             break;
     294             :           }
     295           0 :           for (unsigned int i = 0; i<pch->num_deposits; i++)
     296             :           {
     297           0 :             struct Deposit *deposit = &pch->deposits[i];
     298             : 
     299           0 :             if (0 != GNUNET_memcmp (&pcoin_pub,
     300             :                                     &deposit->coin_pub))
     301           0 :               continue;
     302           0 :             if (-1 !=
     303           0 :                 TALER_amount_cmp (&left,
     304           0 :                                   &deposit->contribution))
     305             :             {
     306             :               /* Balance was sufficient after all; recoup MAY have still been possible */
     307           0 :               GNUNET_break_op (0);
     308           0 :               continue;
     309             :             }
     310           0 :             if (GNUNET_OK !=
     311           0 :                 TALER_EXCHANGE_check_coin_signature_conflict_ (
     312             :                   j,
     313           0 :                   &deposit->coin_sig))
     314             :             {
     315           0 :               GNUNET_break_op (0);
     316           0 :               continue;
     317             :             }
     318           0 :             found = true;
     319           0 :             break;
     320             :           }
     321           0 :           if (! found)
     322             :           {
     323             :             /* conflict is for a different coin! */
     324           0 :             GNUNET_break_op (0);
     325           0 :             dr.hr.http_status = 0;
     326           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     327           0 :             break;
     328             :           }
     329           0 :           break;
     330             :         }
     331           0 :       case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
     332             :         {
     333             :           struct TALER_Amount left;
     334             :           struct TALER_CoinSpendPublicKeyP pcoin_pub;
     335           0 :           bool found = false;
     336             : 
     337           0 :           if (GNUNET_OK !=
     338           0 :               TALER_EXCHANGE_check_coin_amount_conflict_ (
     339             :                 keys,
     340             :                 j,
     341             :                 &pcoin_pub,
     342             :                 &left))
     343             :           {
     344           0 :             GNUNET_break_op (0);
     345           0 :             dr.hr.http_status = 0;
     346           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     347           0 :             break;
     348             :           }
     349           0 :           for (unsigned int i = 0; i<pch->num_deposits; i++)
     350             :           {
     351           0 :             struct Deposit *deposit = &pch->deposits[i];
     352             : 
     353           0 :             if (0 !=
     354           0 :                 GNUNET_memcmp (&pcoin_pub,
     355             :                                &deposit->coin_pub))
     356           0 :               continue;
     357           0 :             if (GNUNET_OK !=
     358           0 :                 TALER_EXCHANGE_check_coin_denomination_conflict_ (
     359             :                   j,
     360           0 :                   &deposit->h_denom_pub))
     361             :             {
     362             :               /* Eh, same denomination, hence no conflict */
     363           0 :               GNUNET_break_op (0);
     364           0 :               continue;
     365             :             }
     366           0 :             found = true;
     367             :           }
     368           0 :           if (! found)
     369             :           {
     370             :             /* conflict is for a different coin! */
     371           0 :             GNUNET_break_op (0);
     372           0 :             dr.hr.http_status = 0;
     373           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     374           0 :             break;
     375             :           }
     376             :           /* meta data conflict is real! */
     377           0 :           break;
     378             :         }
     379           0 :       case TALER_EC_EXCHANGE_PURSE_DEPOSIT_CONFLICTING_META_DATA:
     380             :         {
     381             :           struct TALER_CoinSpendPublicKeyP coin_pub;
     382             :           struct TALER_CoinSpendSignatureP coin_sig;
     383             :           struct TALER_DenominationHashP h_denom_pub;
     384             :           struct TALER_AgeCommitmentHash phac;
     385           0 :           bool found = false;
     386             : 
     387           0 :           if (GNUNET_OK !=
     388           0 :               TALER_EXCHANGE_check_purse_coin_conflict_ (
     389           0 :                 &pch->purse_pub,
     390           0 :                 pch->exchange->url,
     391             :                 j,
     392             :                 &h_denom_pub,
     393             :                 &phac,
     394             :                 &coin_pub,
     395             :                 &coin_sig))
     396             :           {
     397           0 :             GNUNET_break_op (0);
     398           0 :             dr.hr.http_status = 0;
     399           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     400           0 :             break;
     401             :           }
     402           0 :           for (unsigned int i = 0; i<pch->num_deposits; i++)
     403             :           {
     404           0 :             struct Deposit *deposit = &pch->deposits[i];
     405             : 
     406           0 :             if (0 !=
     407           0 :                 GNUNET_memcmp (&coin_pub,
     408             :                                &deposit->coin_pub))
     409           0 :               continue;
     410           0 :             if (0 !=
     411           0 :                 GNUNET_memcmp (&deposit->h_denom_pub,
     412             :                                &h_denom_pub))
     413             :             {
     414           0 :               found = true;
     415           0 :               break;
     416             :             }
     417           0 :             if (0 !=
     418           0 :                 GNUNET_memcmp (&deposit->ahac,
     419             :                                &phac))
     420             :             {
     421           0 :               found = true;
     422           0 :               break;
     423             :             }
     424           0 :             if (0 ==
     425           0 :                 GNUNET_memcmp (&coin_sig,
     426             :                                &deposit->coin_sig))
     427             :             {
     428           0 :               GNUNET_break_op (0);
     429           0 :               continue;
     430             :             }
     431           0 :             found = true;
     432           0 :             break;
     433             :           }
     434           0 :           if (! found)
     435             :           {
     436             :             /* conflict is for a different coin! */
     437           0 :             GNUNET_break_op (0);
     438           0 :             dr.hr.http_status = 0;
     439           0 :             dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     440           0 :             break;
     441             :           }
     442             :         }
     443             :       case TALER_EC_EXCHANGE_PURSE_ECONTRACT_CONFLICTING_META_DATA:
     444           0 :         if (GNUNET_OK !=
     445           0 :             TALER_EXCHANGE_check_purse_econtract_conflict_ (
     446           0 :               &pch->econtract.econtract_sig,
     447           0 :               &pch->purse_pub,
     448             :               j))
     449             :         {
     450           0 :           GNUNET_break_op (0);
     451           0 :           dr.hr.http_status = 0;
     452           0 :           dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     453           0 :           break;
     454             :         }
     455           0 :         break;
     456           0 :       default:
     457           0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     458             :                     "Unexpected error code %d for conflcting deposit\n",
     459             :                     dr.hr.ec);
     460           0 :         GNUNET_break_op (0);
     461           0 :         dr.hr.http_status = 0;
     462           0 :         dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
     463             :       }
     464             :     }
     465           0 :     break;
     466           0 :   case MHD_HTTP_GONE:
     467             :     /* could happen if denomination was revoked */
     468             :     /* Note: one might want to check /keys for revocation
     469             :        signature here, alas tricky in case our /keys
     470             :        is outdated => left to clients */
     471           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     472           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     473           0 :     break;
     474           0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     475           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     476           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     477             :     /* Server had an internal issue; we should retry, but this API
     478             :        leaves this to the application */
     479           0 :     break;
     480           0 :   default:
     481             :     /* unexpected response code */
     482           0 :     dr.hr.ec = TALER_JSON_get_error_code (j);
     483           0 :     dr.hr.hint = TALER_JSON_get_error_hint (j);
     484           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     485             :                 "Unexpected response code %u/%d for exchange deposit\n",
     486             :                 (unsigned int) response_code,
     487             :                 dr.hr.ec);
     488           0 :     GNUNET_break_op (0);
     489           0 :     break;
     490             :   }
     491           0 :   pch->cb (pch->cb_cls,
     492             :            &dr);
     493           0 :   TALER_EXCHANGE_purse_create_with_deposit_cancel (pch);
     494           0 : }
     495             : 
     496             : 
     497             : struct TALER_EXCHANGE_PurseCreateDepositHandle *
     498           0 : TALER_EXCHANGE_purse_create_with_deposit (
     499             :   struct TALER_EXCHANGE_Handle *exchange,
     500             :   const struct TALER_PurseContractPrivateKeyP *purse_priv,
     501             :   const struct TALER_PurseMergePrivateKeyP *merge_priv,
     502             :   const struct TALER_ContractDiffiePrivateP *contract_priv,
     503             :   const json_t *contract_terms,
     504             :   unsigned int num_deposits,
     505             :   const struct TALER_EXCHANGE_PurseDeposit *deposits,
     506             :   bool upload_contract,
     507             :   TALER_EXCHANGE_PurseCreateDepositCallback cb,
     508             :   void *cb_cls)
     509             : {
     510             :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch;
     511             :   struct GNUNET_CURL_Context *ctx;
     512             :   json_t *create_obj;
     513             :   json_t *deposit_arr;
     514             :   CURL *eh;
     515             :   char arg_str[sizeof (pch->purse_pub) * 2 + 32];
     516             :   char *url;
     517           0 :   uint32_t min_age = 0;
     518             : 
     519           0 :   pch = GNUNET_new (struct TALER_EXCHANGE_PurseCreateDepositHandle);
     520           0 :   pch->exchange = exchange;
     521           0 :   pch->cb = cb;
     522           0 :   pch->cb_cls = cb_cls;
     523             :   {
     524             :     struct GNUNET_JSON_Specification spec[] = {
     525           0 :       GNUNET_JSON_spec_timestamp ("pay_deadline",
     526             :                                   &pch->purse_expiration),
     527           0 :       TALER_JSON_spec_amount_any ("amount",
     528             :                                   &pch->purse_value_after_fees),
     529           0 :       GNUNET_JSON_spec_mark_optional (
     530             :         GNUNET_JSON_spec_uint32 ("minimum_age",
     531             :                                  &min_age),
     532             :         NULL),
     533           0 :       GNUNET_JSON_spec_end ()
     534             :     };
     535             : 
     536           0 :     if (GNUNET_OK !=
     537           0 :         GNUNET_JSON_parse (contract_terms,
     538             :                            spec,
     539             :                            NULL, NULL))
     540             :     {
     541           0 :       GNUNET_break (0);
     542           0 :       return NULL;
     543             :     }
     544             :   }
     545           0 :   GNUNET_assert (GNUNET_YES ==
     546             :                  TEAH_handle_is_ready (exchange));
     547           0 :   if (GNUNET_OK !=
     548           0 :       TALER_JSON_contract_hash (contract_terms,
     549             :                                 &pch->h_contract_terms))
     550             :   {
     551           0 :     GNUNET_break (0);
     552           0 :     return NULL;
     553             :   }
     554           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv->eddsa_priv,
     555             :                                       &pch->purse_pub.eddsa_pub);
     556             :   {
     557             :     char pub_str[sizeof (pch->purse_pub) * 2];
     558             :     char *end;
     559             : 
     560           0 :     end = GNUNET_STRINGS_data_to_string (
     561           0 :       &pch->purse_pub,
     562             :       sizeof (pch->purse_pub),
     563             :       pub_str,
     564             :       sizeof (pub_str));
     565           0 :     *end = '\0';
     566           0 :     GNUNET_snprintf (arg_str,
     567             :                      sizeof (arg_str),
     568             :                      "/purses/%s/create",
     569             :                      pub_str);
     570             :   }
     571           0 :   GNUNET_CRYPTO_eddsa_key_get_public (&merge_priv->eddsa_priv,
     572             :                                       &pch->merge_pub.eddsa_pub);
     573           0 :   pch->url = TEAH_path_to_url (exchange,
     574             :                                arg_str);
     575           0 :   if (NULL == pch->url)
     576             :   {
     577           0 :     GNUNET_break (0);
     578           0 :     GNUNET_free (pch);
     579           0 :     return NULL;
     580             :   }
     581           0 :   pch->num_deposits = num_deposits;
     582           0 :   pch->deposits = GNUNET_new_array (num_deposits,
     583             :                                     struct Deposit);
     584           0 :   deposit_arr = json_array ();
     585           0 :   GNUNET_assert (NULL != deposit_arr);
     586           0 :   url = TEAH_path_to_url (exchange,
     587             :                           "/");
     588           0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     589             :               "Signing with URL `%s'\n",
     590             :               url);
     591           0 :   for (unsigned int i = 0; i<num_deposits; i++)
     592             :   {
     593           0 :     const struct TALER_EXCHANGE_PurseDeposit *deposit = &deposits[i];
     594           0 :     const struct TALER_AgeCommitmentProof *acp = deposit->age_commitment_proof;
     595           0 :     struct Deposit *d = &pch->deposits[i];
     596             :     json_t *jdeposit;
     597           0 :     struct TALER_AgeCommitmentHash *aghp = NULL;
     598             :     struct TALER_AgeAttestation attest;
     599           0 :     struct TALER_AgeAttestation *attestp = NULL;
     600             : 
     601           0 :     if (NULL != acp)
     602             :     {
     603           0 :       TALER_age_commitment_hash (&acp->commitment,
     604             :                                  &d->ahac);
     605           0 :       aghp = &d->ahac;
     606           0 :       if (GNUNET_OK !=
     607           0 :           TALER_age_commitment_attest (acp,
     608             :                                        min_age,
     609             :                                        &attest))
     610             :       {
     611           0 :         GNUNET_break (0);
     612           0 :         json_decref (deposit_arr);
     613           0 :         GNUNET_free (url);
     614           0 :         GNUNET_free (pch);
     615           0 :         return NULL;
     616             :       }
     617             :     }
     618           0 :     d->contribution = deposit->amount;
     619           0 :     d->h_denom_pub = deposit->h_denom_pub;
     620           0 :     GNUNET_CRYPTO_eddsa_key_get_public (&deposit->coin_priv.eddsa_priv,
     621             :                                         &d->coin_pub.eddsa_pub);
     622           0 :     TALER_wallet_purse_deposit_sign (
     623             :       url,
     624           0 :       &pch->purse_pub,
     625             :       &deposit->amount,
     626           0 :       &d->h_denom_pub,
     627           0 :       &d->ahac,
     628             :       &deposit->coin_priv,
     629             :       &d->coin_sig);
     630           0 :     jdeposit = GNUNET_JSON_PACK (
     631             :       GNUNET_JSON_pack_allow_null (
     632             :         GNUNET_JSON_pack_data_auto ("h_age_commitment",
     633             :                                     aghp)),
     634             :       GNUNET_JSON_pack_allow_null (
     635             :         GNUNET_JSON_pack_data_auto ("age_attestation",
     636             :                                     attestp)),
     637             :       TALER_JSON_pack_amount ("amount",
     638             :                               &deposit->amount),
     639             :       GNUNET_JSON_pack_data_auto ("denom_pub_hash",
     640             :                                   &deposit->h_denom_pub),
     641             :       TALER_JSON_pack_denom_sig ("ub_sig",
     642             :                                  &deposit->denom_sig),
     643             :       GNUNET_JSON_pack_data_auto ("coin_sig",
     644             :                                   &d->coin_sig),
     645             :       GNUNET_JSON_pack_data_auto ("coin_pub",
     646             :                                   &d->coin_pub));
     647           0 :     GNUNET_assert (0 ==
     648             :                    json_array_append_new (deposit_arr,
     649             :                                           jdeposit));
     650             :   }
     651           0 :   GNUNET_free (url);
     652           0 :   TALER_wallet_purse_create_sign (pch->purse_expiration,
     653             :                                   &pch->h_contract_terms,
     654           0 :                                   &pch->merge_pub,
     655             :                                   min_age,
     656           0 :                                   &pch->purse_value_after_fees,
     657             :                                   purse_priv,
     658             :                                   &pch->purse_sig);
     659           0 :   if (upload_contract)
     660             :   {
     661           0 :     TALER_CRYPTO_contract_encrypt_for_merge (&pch->purse_pub,
     662             :                                              contract_priv,
     663             :                                              merge_priv,
     664             :                                              contract_terms,
     665             :                                              &pch->econtract.econtract,
     666             :                                              &pch->econtract.econtract_size);
     667           0 :     GNUNET_CRYPTO_ecdhe_key_get_public (&contract_priv->ecdhe_priv,
     668             :                                         &pch->econtract.contract_pub.ecdhe_pub);
     669           0 :     TALER_wallet_econtract_upload_sign (pch->econtract.econtract,
     670             :                                         pch->econtract.econtract_size,
     671           0 :                                         &pch->econtract.contract_pub,
     672             :                                         purse_priv,
     673             :                                         &pch->econtract.econtract_sig);
     674             :   }
     675           0 :   create_obj = GNUNET_JSON_PACK (
     676             :     TALER_JSON_pack_amount ("amount",
     677             :                             &pch->purse_value_after_fees),
     678             :     GNUNET_JSON_pack_uint64 ("min_age",
     679             :                              min_age),
     680             :     GNUNET_JSON_pack_allow_null (
     681             :       TALER_JSON_pack_econtract ("econtract",
     682             :                                  upload_contract
     683             :                                  ? &pch->econtract
     684             :                                  : NULL)),
     685             :     GNUNET_JSON_pack_data_auto ("purse_sig",
     686             :                                 &pch->purse_sig),
     687             :     GNUNET_JSON_pack_data_auto ("merge_pub",
     688             :                                 &pch->merge_pub),
     689             :     GNUNET_JSON_pack_data_auto ("h_contract_terms",
     690             :                                 &pch->h_contract_terms),
     691             :     GNUNET_JSON_pack_timestamp ("purse_expiration",
     692             :                                 pch->purse_expiration),
     693             :     GNUNET_JSON_pack_array_steal ("deposits",
     694             :                                   deposit_arr));
     695           0 :   GNUNET_assert (NULL != create_obj);
     696           0 :   eh = TALER_EXCHANGE_curl_easy_get_ (pch->url);
     697           0 :   if ( (NULL == eh) ||
     698             :        (GNUNET_OK !=
     699           0 :         TALER_curl_easy_post (&pch->ctx,
     700             :                               eh,
     701             :                               create_obj)) )
     702             :   {
     703           0 :     GNUNET_break (0);
     704           0 :     if (NULL != eh)
     705           0 :       curl_easy_cleanup (eh);
     706           0 :     json_decref (create_obj);
     707           0 :     GNUNET_free (pch->econtract.econtract);
     708           0 :     GNUNET_free (pch->deposits);
     709           0 :     GNUNET_free (pch->url);
     710           0 :     GNUNET_free (pch);
     711           0 :     return NULL;
     712             :   }
     713           0 :   json_decref (create_obj);
     714           0 :   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
     715             :               "URL for purse create with deposit: `%s'\n",
     716             :               pch->url);
     717           0 :   ctx = TEAH_handle_to_context (exchange);
     718           0 :   pch->job = GNUNET_CURL_job_add2 (ctx,
     719             :                                    eh,
     720           0 :                                    pch->ctx.headers,
     721             :                                    &handle_purse_create_deposit_finished,
     722             :                                    pch);
     723           0 :   return pch;
     724             : }
     725             : 
     726             : 
     727             : void
     728           0 : TALER_EXCHANGE_purse_create_with_deposit_cancel (
     729             :   struct TALER_EXCHANGE_PurseCreateDepositHandle *pch)
     730             : {
     731           0 :   if (NULL != pch->job)
     732             :   {
     733           0 :     GNUNET_CURL_job_cancel (pch->job);
     734           0 :     pch->job = NULL;
     735             :   }
     736           0 :   GNUNET_free (pch->econtract.econtract);
     737           0 :   GNUNET_free (pch->url);
     738           0 :   GNUNET_free (pch->deposits);
     739           0 :   TALER_curl_easy_post_finished (&pch->ctx);
     740           0 :   GNUNET_free (pch);
     741           0 : }
     742             : 
     743             : 
     744             : /* end of exchange_api_purse_create_with_deposit.c */

Generated by: LCOV version 1.14