LCOV - code coverage report
Current view: top level - lib - exchange_api_common.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 127 260 48.8 %
Date: 2025-06-05 21:03:14 Functions: 8 13 61.5 %

          Line data    Source code
       1             : /*
       2             :   This file is part of TALER
       3             :   Copyright (C) 2015-2023 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_common.c
      19             :  * @brief common functions for the exchange API
      20             :  * @author Christian Grothoff
      21             :  */
      22             : #include "platform.h"
      23             : #include "taler_json_lib.h"
      24             : #include <gnunet/gnunet_curl_lib.h>
      25             : #include "exchange_api_common.h"
      26             : #include "exchange_api_handle.h"
      27             : #include "taler_signatures.h"
      28             : 
      29             : 
      30             : const struct TALER_EXCHANGE_SigningPublicKey *
      31          10 : TALER_EXCHANGE_get_signing_key_info (
      32             :   const struct TALER_EXCHANGE_Keys *keys,
      33             :   const struct TALER_ExchangePublicKeyP *exchange_pub)
      34             : {
      35          42 :   for (unsigned int i = 0; i<keys->num_sign_keys; i++)
      36             :   {
      37          42 :     const struct TALER_EXCHANGE_SigningPublicKey *spk
      38          42 :       = &keys->sign_keys[i];
      39             : 
      40          42 :     if (0 == GNUNET_memcmp (exchange_pub,
      41             :                             &spk->key))
      42          10 :       return spk;
      43             :   }
      44           0 :   return NULL;
      45             : }
      46             : 
      47             : 
      48             : enum GNUNET_GenericReturnValue
      49           0 : TALER_EXCHANGE_check_purse_create_conflict_ (
      50             :   const struct TALER_PurseContractSignatureP *cpurse_sig,
      51             :   const struct TALER_PurseContractPublicKeyP *purse_pub,
      52             :   const json_t *proof)
      53             : {
      54             :   struct TALER_Amount amount;
      55             :   uint32_t min_age;
      56             :   struct GNUNET_TIME_Timestamp purse_expiration;
      57             :   struct TALER_PurseContractSignatureP purse_sig;
      58             :   struct TALER_PrivateContractHashP h_contract_terms;
      59             :   struct TALER_PurseMergePublicKeyP merge_pub;
      60             :   struct GNUNET_JSON_Specification spec[] = {
      61           0 :     TALER_JSON_spec_amount_any ("amount",
      62             :                                 &amount),
      63           0 :     GNUNET_JSON_spec_uint32 ("min_age",
      64             :                              &min_age),
      65           0 :     GNUNET_JSON_spec_timestamp ("purse_expiration",
      66             :                                 &purse_expiration),
      67           0 :     GNUNET_JSON_spec_fixed_auto ("purse_sig",
      68             :                                  &purse_sig),
      69           0 :     GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
      70             :                                  &h_contract_terms),
      71           0 :     GNUNET_JSON_spec_fixed_auto ("merge_pub",
      72             :                                  &merge_pub),
      73           0 :     GNUNET_JSON_spec_end ()
      74             :   };
      75             : 
      76           0 :   if (GNUNET_OK !=
      77           0 :       GNUNET_JSON_parse (proof,
      78             :                          spec,
      79             :                          NULL, NULL))
      80             :   {
      81           0 :     GNUNET_break_op (0);
      82           0 :     return GNUNET_SYSERR;
      83             :   }
      84           0 :   if (GNUNET_OK !=
      85           0 :       TALER_wallet_purse_create_verify (purse_expiration,
      86             :                                         &h_contract_terms,
      87             :                                         &merge_pub,
      88             :                                         min_age,
      89             :                                         &amount,
      90             :                                         purse_pub,
      91             :                                         &purse_sig))
      92             :   {
      93           0 :     GNUNET_break_op (0);
      94           0 :     return GNUNET_SYSERR;
      95             :   }
      96           0 :   if (0 ==
      97           0 :       GNUNET_memcmp (&purse_sig,
      98             :                      cpurse_sig))
      99             :   {
     100             :     /* Must be the SAME data, not a conflict! */
     101           0 :     GNUNET_break_op (0);
     102           0 :     return GNUNET_SYSERR;
     103             :   }
     104           0 :   return GNUNET_OK;
     105             : }
     106             : 
     107             : 
     108             : enum GNUNET_GenericReturnValue
     109           2 : TALER_EXCHANGE_check_purse_merge_conflict_ (
     110             :   const struct TALER_PurseMergeSignatureP *cmerge_sig,
     111             :   const struct TALER_PurseMergePublicKeyP *merge_pub,
     112             :   const struct TALER_PurseContractPublicKeyP *purse_pub,
     113             :   const char *exchange_url,
     114             :   const json_t *proof)
     115             : {
     116             :   struct TALER_PurseMergeSignatureP merge_sig;
     117             :   struct GNUNET_TIME_Timestamp merge_timestamp;
     118           2 :   const char *partner_url = NULL;
     119             :   struct TALER_ReservePublicKeyP reserve_pub;
     120             :   struct GNUNET_JSON_Specification spec[] = {
     121           2 :     GNUNET_JSON_spec_mark_optional (
     122             :       TALER_JSON_spec_web_url ("partner_url",
     123             :                                &partner_url),
     124             :       NULL),
     125           2 :     GNUNET_JSON_spec_timestamp ("merge_timestamp",
     126             :                                 &merge_timestamp),
     127           2 :     GNUNET_JSON_spec_fixed_auto ("merge_sig",
     128             :                                  &merge_sig),
     129           2 :     GNUNET_JSON_spec_fixed_auto ("reserve_pub",
     130             :                                  &reserve_pub),
     131           2 :     GNUNET_JSON_spec_end ()
     132             :   };
     133             :   struct TALER_NormalizedPayto payto_uri;
     134             : 
     135           2 :   if (GNUNET_OK !=
     136           2 :       GNUNET_JSON_parse (proof,
     137             :                          spec,
     138             :                          NULL, NULL))
     139             :   {
     140           0 :     GNUNET_break_op (0);
     141           0 :     return GNUNET_SYSERR;
     142             :   }
     143           2 :   if (NULL == partner_url)
     144           2 :     partner_url = exchange_url;
     145           2 :   payto_uri = TALER_reserve_make_payto (partner_url,
     146             :                                         &reserve_pub);
     147           2 :   if (GNUNET_OK !=
     148           2 :       TALER_wallet_purse_merge_verify (
     149             :         payto_uri,
     150             :         merge_timestamp,
     151             :         purse_pub,
     152             :         merge_pub,
     153             :         &merge_sig))
     154             :   {
     155           0 :     GNUNET_break_op (0);
     156           0 :     GNUNET_free (payto_uri.normalized_payto);
     157           0 :     return GNUNET_SYSERR;
     158             :   }
     159           2 :   GNUNET_free (payto_uri.normalized_payto);
     160           2 :   if (0 ==
     161           2 :       GNUNET_memcmp (&merge_sig,
     162             :                      cmerge_sig))
     163             :   {
     164             :     /* Must be the SAME data, not a conflict! */
     165           0 :     GNUNET_break_op (0);
     166           0 :     return GNUNET_SYSERR;
     167             :   }
     168           2 :   return GNUNET_OK;
     169             : }
     170             : 
     171             : 
     172             : enum GNUNET_GenericReturnValue
     173           0 : TALER_EXCHANGE_check_purse_coin_conflict_ (
     174             :   const struct TALER_PurseContractPublicKeyP *purse_pub,
     175             :   const char *exchange_url,
     176             :   const json_t *proof,
     177             :   struct TALER_DenominationHashP *h_denom_pub,
     178             :   struct TALER_AgeCommitmentHash *phac,
     179             :   struct TALER_CoinSpendPublicKeyP *coin_pub,
     180             :   struct TALER_CoinSpendSignatureP *coin_sig)
     181             : {
     182           0 :   const char *partner_url = NULL;
     183             :   struct TALER_Amount amount;
     184             :   struct GNUNET_JSON_Specification spec[] = {
     185           0 :     GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     186             :                                  h_denom_pub),
     187           0 :     GNUNET_JSON_spec_fixed_auto ("h_age_commitment",
     188             :                                  phac),
     189           0 :     GNUNET_JSON_spec_fixed_auto ("coin_sig",
     190             :                                  coin_sig),
     191           0 :     GNUNET_JSON_spec_fixed_auto ("coin_pub",
     192             :                                  coin_pub),
     193           0 :     GNUNET_JSON_spec_mark_optional (
     194             :       TALER_JSON_spec_web_url ("partner_url",
     195             :                                &partner_url),
     196             :       NULL),
     197           0 :     TALER_JSON_spec_amount_any ("amount",
     198             :                                 &amount),
     199           0 :     GNUNET_JSON_spec_end ()
     200             :   };
     201             : 
     202           0 :   if (GNUNET_OK !=
     203           0 :       GNUNET_JSON_parse (proof,
     204             :                          spec,
     205             :                          NULL, NULL))
     206             :   {
     207           0 :     GNUNET_break_op (0);
     208           0 :     return GNUNET_SYSERR;
     209             :   }
     210           0 :   if (NULL == partner_url)
     211           0 :     partner_url = exchange_url;
     212           0 :   if (GNUNET_OK !=
     213           0 :       TALER_wallet_purse_deposit_verify (
     214             :         partner_url,
     215             :         purse_pub,
     216             :         &amount,
     217             :         h_denom_pub,
     218             :         phac,
     219             :         coin_pub,
     220             :         coin_sig))
     221             :   {
     222           0 :     GNUNET_break_op (0);
     223           0 :     return GNUNET_SYSERR;
     224             :   }
     225           0 :   return GNUNET_OK;
     226             : }
     227             : 
     228             : 
     229             : enum GNUNET_GenericReturnValue
     230           0 : TALER_EXCHANGE_check_purse_econtract_conflict_ (
     231             :   const struct TALER_PurseContractSignatureP *ccontract_sig,
     232             :   const struct TALER_PurseContractPublicKeyP *purse_pub,
     233             :   const json_t *proof)
     234             : {
     235             :   struct TALER_ContractDiffiePublicP contract_pub;
     236             :   struct TALER_PurseContractSignatureP contract_sig;
     237             :   struct GNUNET_HashCode h_econtract;
     238             :   struct GNUNET_JSON_Specification spec[] = {
     239           0 :     GNUNET_JSON_spec_fixed_auto ("h_econtract",
     240             :                                  &h_econtract),
     241           0 :     GNUNET_JSON_spec_fixed_auto ("econtract_sig",
     242             :                                  &contract_sig),
     243           0 :     GNUNET_JSON_spec_fixed_auto ("contract_pub",
     244             :                                  &contract_pub),
     245           0 :     GNUNET_JSON_spec_end ()
     246             :   };
     247             : 
     248           0 :   if (GNUNET_OK !=
     249           0 :       GNUNET_JSON_parse (proof,
     250             :                          spec,
     251             :                          NULL, NULL))
     252             :   {
     253           0 :     GNUNET_break_op (0);
     254           0 :     return GNUNET_SYSERR;
     255             :   }
     256           0 :   if (GNUNET_OK !=
     257           0 :       TALER_wallet_econtract_upload_verify2 (
     258             :         &h_econtract,
     259             :         &contract_pub,
     260             :         purse_pub,
     261             :         &contract_sig))
     262             :   {
     263           0 :     GNUNET_break_op (0);
     264           0 :     return GNUNET_SYSERR;
     265             :   }
     266           0 :   if (0 ==
     267           0 :       GNUNET_memcmp (&contract_sig,
     268             :                      ccontract_sig))
     269             :   {
     270             :     /* Must be the SAME data, not a conflict! */
     271           0 :     GNUNET_break_op (0);
     272           0 :     return GNUNET_SYSERR;
     273             :   }
     274           0 :   return GNUNET_OK;
     275             : }
     276             : 
     277             : 
     278             : // FIXME: should be used... - #9422
     279             : enum GNUNET_GenericReturnValue
     280           0 : TALER_EXCHANGE_check_coin_denomination_conflict_ (
     281             :   const json_t *proof,
     282             :   const struct TALER_DenominationHashP *ch_denom_pub)
     283             : {
     284             :   struct TALER_DenominationHashP h_denom_pub;
     285             :   struct GNUNET_JSON_Specification spec[] = {
     286           0 :     GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
     287             :                                  &h_denom_pub),
     288           0 :     GNUNET_JSON_spec_end ()
     289             :   };
     290             : 
     291           0 :   if (GNUNET_OK !=
     292           0 :       GNUNET_JSON_parse (proof,
     293             :                          spec,
     294             :                          NULL, NULL))
     295             :   {
     296           0 :     GNUNET_break_op (0);
     297           0 :     return GNUNET_SYSERR;
     298             :   }
     299           0 :   if (0 ==
     300           0 :       GNUNET_memcmp (ch_denom_pub,
     301             :                      &h_denom_pub))
     302             :   {
     303           0 :     GNUNET_break_op (0);
     304           0 :     return GNUNET_OK;
     305             :   }
     306             :   /* indeed, proof with different denomination key provided */
     307           0 :   return GNUNET_OK;
     308             : }
     309             : 
     310             : 
     311             : enum GNUNET_GenericReturnValue
     312           0 : TALER_EXCHANGE_get_min_denomination_ (
     313             :   const struct TALER_EXCHANGE_Keys *keys,
     314             :   struct TALER_Amount *min)
     315             : {
     316           0 :   bool have_min = false;
     317           0 :   for (unsigned int i = 0; i<keys->num_denom_keys; i++)
     318             :   {
     319           0 :     const struct TALER_EXCHANGE_DenomPublicKey *dk = &keys->denom_keys[i];
     320             : 
     321           0 :     if (! have_min)
     322             :     {
     323           0 :       *min = dk->value;
     324           0 :       have_min = true;
     325           0 :       continue;
     326             :     }
     327           0 :     if (1 != TALER_amount_cmp (min,
     328             :                                &dk->value))
     329           0 :       continue;
     330           0 :     *min = dk->value;
     331             :   }
     332           0 :   if (! have_min)
     333             :   {
     334           0 :     GNUNET_break (0);
     335           0 :     return GNUNET_SYSERR;
     336             :   }
     337           0 :   return GNUNET_OK;
     338             : }
     339             : 
     340             : 
     341             : enum GNUNET_GenericReturnValue
     342         106 : TALER_EXCHANGE_verify_deposit_signature_ (
     343             :   const struct TALER_EXCHANGE_DepositContractDetail *dcd,
     344             :   const struct TALER_ExtensionPolicyHashP *ech,
     345             :   const struct TALER_MerchantWireHashP *h_wire,
     346             :   const struct TALER_EXCHANGE_CoinDepositDetail *cdd,
     347             :   const struct TALER_EXCHANGE_DenomPublicKey *dki)
     348             : {
     349         106 :   if (GNUNET_OK !=
     350         106 :       TALER_wallet_deposit_verify (&cdd->amount,
     351             :                                    &dki->fees.deposit,
     352             :                                    h_wire,
     353             :                                    &dcd->h_contract_terms,
     354             :                                    &dcd->wallet_data_hash,
     355             :                                    &cdd->h_age_commitment,
     356             :                                    ech,
     357             :                                    &cdd->h_denom_pub,
     358             :                                    dcd->wallet_timestamp,
     359             :                                    &dcd->merchant_pub,
     360             :                                    dcd->refund_deadline,
     361             :                                    &cdd->coin_pub,
     362             :                                    &cdd->coin_sig))
     363             :   {
     364           0 :     GNUNET_break_op (0);
     365           0 :     TALER_LOG_WARNING ("Invalid coin signature on /deposit request!\n");
     366           0 :     TALER_LOG_DEBUG ("... amount_with_fee was %s\n",
     367             :                      TALER_amount2s (&cdd->amount));
     368           0 :     TALER_LOG_DEBUG ("... deposit_fee was %s\n",
     369             :                      TALER_amount2s (&dki->fees.deposit));
     370           0 :     return GNUNET_SYSERR;
     371             :   }
     372             : 
     373             :   /* check coin signature */
     374             :   {
     375         106 :     struct TALER_CoinPublicInfo coin_info = {
     376             :       .coin_pub = cdd->coin_pub,
     377             :       .denom_pub_hash = cdd->h_denom_pub,
     378             :       .denom_sig = cdd->denom_sig,
     379             :       .h_age_commitment = cdd->h_age_commitment,
     380             :     };
     381             : 
     382         106 :     if (GNUNET_YES !=
     383         106 :         TALER_test_coin_valid (&coin_info,
     384             :                                &dki->key))
     385             :     {
     386           0 :       GNUNET_break_op (0);
     387           0 :       TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
     388           0 :       return GNUNET_SYSERR;
     389             :     }
     390             :   }
     391             : 
     392             :   /* Check coin does make a contribution */
     393         106 :   if (0 < TALER_amount_cmp (&dki->fees.deposit,
     394             :                             &cdd->amount))
     395             :   {
     396           0 :     GNUNET_break_op (0);
     397           0 :     TALER_LOG_WARNING ("Deposit amount smaller than fee\n");
     398           0 :     return GNUNET_SYSERR;
     399             :   }
     400         106 :   return GNUNET_OK;
     401             : }
     402             : 
     403             : 
     404             : /**
     405             :  * Parse account restriction in @a jrest into @a rest.
     406             :  *
     407             :  * @param jresta array of account restrictions in JSON
     408             :  * @param[out] resta_len set to length of @a resta
     409             :  * @param[out] resta account restriction array to set
     410             :  * @return #GNUNET_OK on success
     411             :  */
     412             : static enum GNUNET_GenericReturnValue
     413         132 : parse_restrictions (const json_t *jresta,
     414             :                     unsigned int *resta_len,
     415             :                     struct TALER_EXCHANGE_AccountRestriction **resta)
     416             : {
     417             :   size_t alen;
     418             : 
     419         132 :   if (! json_is_array (jresta))
     420             :   {
     421           0 :     GNUNET_break_op (0);
     422           0 :     return GNUNET_SYSERR;
     423             :   }
     424         132 :   alen = json_array_size (jresta);
     425         132 :   if (0 == alen)
     426             :   {
     427             :     /* no restrictions, perfectly OK */
     428         120 :     *resta = NULL;
     429         120 :     return GNUNET_OK;
     430             :   }
     431          12 :   *resta_len = (unsigned int) alen;
     432          12 :   GNUNET_assert (alen == *resta_len);
     433          12 :   *resta = GNUNET_new_array (*resta_len,
     434             :                              struct TALER_EXCHANGE_AccountRestriction);
     435          24 :   for (unsigned int i = 0; i<*resta_len; i++)
     436             :   {
     437          12 :     const json_t *jr = json_array_get (jresta,
     438             :                                        i);
     439          12 :     struct TALER_EXCHANGE_AccountRestriction *ar = &(*resta)[i];
     440          12 :     const char *type = json_string_value (json_object_get (jr,
     441             :                                                            "type"));
     442             : 
     443          12 :     if (NULL == type)
     444             :     {
     445           0 :       GNUNET_break (0);
     446           0 :       goto fail;
     447             :     }
     448          12 :     if (0 == strcmp (type,
     449             :                      "deny"))
     450             :     {
     451           0 :       ar->type = TALER_EXCHANGE_AR_DENY;
     452           0 :       continue;
     453             :     }
     454          12 :     if (0 == strcmp (type,
     455             :                      "regex"))
     456          12 :     {
     457             :       const char *regex;
     458             :       const char *hint;
     459             :       struct GNUNET_JSON_Specification spec[] = {
     460          12 :         GNUNET_JSON_spec_string (
     461             :           "payto_regex",
     462             :           &regex),
     463          12 :         GNUNET_JSON_spec_string (
     464             :           "human_hint",
     465             :           &hint),
     466          12 :         GNUNET_JSON_spec_mark_optional (
     467             :           GNUNET_JSON_spec_json (
     468             :             "human_hint_i18n",
     469             :             &ar->details.regex.human_hint_i18n),
     470             :           NULL),
     471          12 :         GNUNET_JSON_spec_end ()
     472             :       };
     473             : 
     474          12 :       if (GNUNET_OK !=
     475          12 :           GNUNET_JSON_parse (jr,
     476             :                              spec,
     477             :                              NULL, NULL))
     478             :       {
     479             :         /* bogus reply */
     480           0 :         GNUNET_break_op (0);
     481           0 :         goto fail;
     482             :       }
     483          12 :       ar->type = TALER_EXCHANGE_AR_REGEX;
     484          12 :       ar->details.regex.posix_egrep = GNUNET_strdup (regex);
     485          12 :       ar->details.regex.human_hint = GNUNET_strdup (hint);
     486          12 :       continue;
     487             :     }
     488             :     /* unsupported type */
     489           0 :     GNUNET_break (0);
     490           0 :     return GNUNET_SYSERR;
     491             :   }
     492          12 :   return GNUNET_OK;
     493           0 : fail:
     494           0 :   GNUNET_free (*resta);
     495           0 :   *resta_len = 0;
     496           0 :   return GNUNET_SYSERR;
     497             : }
     498             : 
     499             : 
     500             : enum GNUNET_GenericReturnValue
     501          62 : TALER_EXCHANGE_parse_accounts (
     502             :   const struct TALER_MasterPublicKeyP *master_pub,
     503             :   const json_t *accounts,
     504             :   unsigned int was_length,
     505             :   struct TALER_EXCHANGE_WireAccount was[static was_length])
     506          62 : {
     507          62 :   memset (was,
     508             :           0,
     509             :           sizeof (struct TALER_EXCHANGE_WireAccount) * was_length);
     510          62 :   GNUNET_assert (was_length ==
     511             :                  json_array_size (accounts));
     512          62 :   for (unsigned int i = 0;
     513         128 :        i<was_length;
     514          66 :        i++)
     515             :   {
     516          66 :     struct TALER_EXCHANGE_WireAccount *wa = &was[i];
     517             :     struct TALER_FullPayto payto_uri;
     518          66 :     const char *conversion_url = NULL;
     519          66 :     const char *bank_label = NULL;
     520          66 :     int64_t priority = 0;
     521             :     const json_t *credit_restrictions;
     522             :     const json_t *debit_restrictions;
     523             :     struct GNUNET_JSON_Specification spec_account[] = {
     524          66 :       TALER_JSON_spec_full_payto_uri ("payto_uri",
     525             :                                       &payto_uri),
     526          66 :       GNUNET_JSON_spec_mark_optional (
     527             :         TALER_JSON_spec_web_url ("conversion_url",
     528             :                                  &conversion_url),
     529             :         NULL),
     530          66 :       GNUNET_JSON_spec_mark_optional (
     531             :         GNUNET_JSON_spec_int64 ("priority",
     532             :                                 &priority),
     533             :         NULL),
     534          66 :       GNUNET_JSON_spec_mark_optional (
     535             :         GNUNET_JSON_spec_string ("bank_label",
     536             :                                  &bank_label),
     537             :         NULL),
     538          66 :       GNUNET_JSON_spec_array_const ("credit_restrictions",
     539             :                                     &credit_restrictions),
     540          66 :       GNUNET_JSON_spec_array_const ("debit_restrictions",
     541             :                                     &debit_restrictions),
     542          66 :       GNUNET_JSON_spec_fixed_auto ("master_sig",
     543             :                                    &wa->master_sig),
     544          66 :       GNUNET_JSON_spec_end ()
     545             :     };
     546             :     json_t *account;
     547             : 
     548          66 :     account = json_array_get (accounts,
     549             :                               i);
     550          66 :     if (GNUNET_OK !=
     551          66 :         GNUNET_JSON_parse (account,
     552             :                            spec_account,
     553             :                            NULL, NULL))
     554             :     {
     555             :       /* bogus reply */
     556           0 :       GNUNET_break_op (0);
     557           0 :       return GNUNET_SYSERR;
     558             :     }
     559         132 :     if ( (NULL != master_pub) &&
     560             :          (GNUNET_OK !=
     561          66 :           TALER_exchange_wire_signature_check (
     562             :             payto_uri,
     563             :             conversion_url,
     564             :             debit_restrictions,
     565             :             credit_restrictions,
     566             :             master_pub,
     567          66 :             &wa->master_sig)) )
     568             :     {
     569             :       /* bogus reply */
     570           0 :       GNUNET_break_op (0);
     571           0 :       return GNUNET_SYSERR;
     572             :     }
     573          66 :     if ( (GNUNET_OK !=
     574          66 :           parse_restrictions (credit_restrictions,
     575             :                               &wa->credit_restrictions_length,
     576          66 :                               &wa->credit_restrictions)) ||
     577             :          (GNUNET_OK !=
     578          66 :           parse_restrictions (debit_restrictions,
     579             :                               &wa->debit_restrictions_length,
     580             :                               &wa->debit_restrictions)) )
     581             :     {
     582             :       /* bogus reply */
     583           0 :       GNUNET_break_op (0);
     584           0 :       return GNUNET_SYSERR;
     585             :     }
     586             :     wa->fpayto_uri.full_payto
     587          66 :       = GNUNET_strdup (payto_uri.full_payto);
     588          66 :     wa->priority = priority;
     589          66 :     if (NULL != conversion_url)
     590           0 :       wa->conversion_url = GNUNET_strdup (conversion_url);
     591          66 :     if (NULL != bank_label)
     592           0 :       wa->bank_label = GNUNET_strdup (bank_label);
     593             :   }       /* end 'for all accounts */
     594          62 :   return GNUNET_OK;
     595             : }
     596             : 
     597             : 
     598             : /**
     599             :  * Free array of account restrictions.
     600             :  *
     601             :  * @param ar_len length of @a ar
     602             :  * @param[in] ar array to free contents of (but not @a ar itself)
     603             :  */
     604             : static void
     605         132 : free_restrictions (unsigned int ar_len,
     606             :                    struct TALER_EXCHANGE_AccountRestriction ar[static ar_len])
     607         132 : {
     608         144 :   for (unsigned int i = 0; i<ar_len; i++)
     609             :   {
     610          12 :     struct TALER_EXCHANGE_AccountRestriction *a = &ar[i];
     611          12 :     switch (a->type)
     612             :     {
     613           0 :     case TALER_EXCHANGE_AR_INVALID:
     614           0 :       GNUNET_break (0);
     615           0 :       break;
     616           0 :     case TALER_EXCHANGE_AR_DENY:
     617           0 :       break;
     618          12 :     case TALER_EXCHANGE_AR_REGEX:
     619          12 :       GNUNET_free (ar->details.regex.posix_egrep);
     620          12 :       GNUNET_free (ar->details.regex.human_hint);
     621          12 :       json_decref (ar->details.regex.human_hint_i18n);
     622          12 :       break;
     623             :     }
     624             :   }
     625         132 : }
     626             : 
     627             : 
     628             : void
     629          62 : TALER_EXCHANGE_free_accounts (
     630             :   unsigned int was_len,
     631             :   struct TALER_EXCHANGE_WireAccount was[static was_len])
     632          62 : {
     633         128 :   for (unsigned int i = 0; i<was_len; i++)
     634             :   {
     635          66 :     struct TALER_EXCHANGE_WireAccount *wa = &was[i];
     636             : 
     637          66 :     GNUNET_free (wa->fpayto_uri.full_payto);
     638          66 :     GNUNET_free (wa->conversion_url);
     639          66 :     GNUNET_free (wa->bank_label);
     640          66 :     free_restrictions (wa->credit_restrictions_length,
     641             :                        wa->credit_restrictions);
     642          66 :     GNUNET_array_grow (wa->credit_restrictions,
     643             :                        wa->credit_restrictions_length,
     644             :                        0);
     645          66 :     free_restrictions (wa->debit_restrictions_length,
     646             :                        wa->debit_restrictions);
     647          66 :     GNUNET_array_grow (wa->debit_restrictions,
     648             :                        wa->debit_restrictions_length,
     649             :                        0);
     650             :   }
     651          62 : }
     652             : 
     653             : 
     654             : enum GNUNET_GenericReturnValue
     655          18 : TALER_EXCHANGE_keys_test_account_allowed (
     656             :   const struct TALER_EXCHANGE_Keys *keys,
     657             :   bool check_credit,
     658             :   const struct TALER_NormalizedPayto payto_uri)
     659             : {
     660             :   /* For all accounts of the exchange */
     661          22 :   for (unsigned int i = 0; i<keys->accounts_len; i++)
     662             :   {
     663          18 :     const struct TALER_EXCHANGE_WireAccount *account
     664          18 :       = &keys->accounts[i];
     665             : 
     666             :     /* KYC auth transfers are never supported with conversion */
     667          18 :     if (NULL != account->conversion_url)
     668           0 :       continue;
     669             :     /* filter by source account by credit_restrictions */
     670          18 :     if (GNUNET_YES !=
     671          18 :         TALER_EXCHANGE_test_account_allowed (account,
     672             :                                              check_credit,
     673             :                                              payto_uri))
     674           4 :       continue;
     675             :     /* exchange account is allowed, add it */
     676          14 :     return true;
     677             :   }
     678           4 :   return false;
     679             : }
     680             : 
     681             : 
     682             : /* end of exchange_api_common.c */

Generated by: LCOV version 1.16