merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-httpd_exchanges.c (35229B)


      1 /*
      2   This file is part of TALER
      3   (C) 2014-2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero 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 <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file src/backend/taler-merchant-httpd_exchanges.c
     18  * @brief logic this HTTPD keeps for each exchange we interact with
     19  * @author Marcello Stanisci
     20  * @author Christian Grothoff
     21  */
     22 #include "platform.h"
     23 #include <taler/taler_json_lib.h>
     24 #include <taler/taler_dbevents.h>
     25 #include "taler-merchant-httpd_exchanges.h"
     26 #include "taler-merchant-httpd_get-private-kyc.h"
     27 #include "taler-merchant-httpd.h"
     28 #include "merchant-database/get_kyc_limits.h"
     29 #include "merchant-database/set_instance.h"
     30 #include "merchant-database/get_exchange_keys.h"
     31 #include "merchant-database/event_listen.h"
     32 #include "merchant-database/event_notify.h"
     33 
     34 
     35 /**
     36  * How often do we retry DB transactions with soft errors?
     37  */
     38 #define MAX_RETRIES 3
     39 
     40 /**
     41  * Threshold after which exponential backoff should not increase.
     42  */
     43 #define RETRY_BACKOFF_THRESHOLD GNUNET_TIME_relative_multiply ( \
     44           GNUNET_TIME_UNIT_SECONDS, 60)
     45 
     46 /**
     47  * This is how long /keys long-polls for, so we should
     48  * allow this time between requests if there is no
     49  * answer. See exchange_api_handle.c.
     50  */
     51 #define LONG_POLL_THRESHOLD GNUNET_TIME_relative_multiply ( \
     52           GNUNET_TIME_UNIT_SECONDS, 120)
     53 
     54 
     55 /**
     56  * Information we keep for a pending #MMH_EXCHANGES_keys4exchange() operation.
     57  */
     58 struct TMH_EXCHANGES_KeysOperation
     59 {
     60 
     61   /**
     62    * Kept in a DLL.
     63    */
     64   struct TMH_EXCHANGES_KeysOperation *next;
     65 
     66   /**
     67    * Kept in a DLL.
     68    */
     69   struct TMH_EXCHANGES_KeysOperation *prev;
     70 
     71   /**
     72    * Function to call with the result.
     73    */
     74   TMH_EXCHANGES_Find2Continuation fc;
     75 
     76   /**
     77    * Closure for @e fc.
     78    */
     79   void *fc_cls;
     80 
     81   /**
     82    * Exchange we wait for the /keys for.
     83    */
     84   struct TMH_Exchange *my_exchange;
     85 
     86   /**
     87    * Task scheduled to asynchronously return the result to
     88    * the find continuation.
     89    */
     90   struct GNUNET_SCHEDULER_Task *at;
     91 
     92 };
     93 
     94 
     95 /**
     96  * Information about wire transfer fees of an exchange, by wire method.
     97  */
     98 struct FeesByWireMethod
     99 {
    100 
    101   /**
    102    * Kept in a DLL.
    103    */
    104   struct FeesByWireMethod *next;
    105 
    106   /**
    107    * Kept in a DLL.
    108    */
    109   struct FeesByWireMethod *prev;
    110 
    111   /**
    112    * Wire method these fees are for.
    113    */
    114   char *wire_method;
    115 
    116   /**
    117    * Applicable fees, NULL if unknown/error.
    118    */
    119   struct TALER_EXCHANGE_WireAggregateFees *af;
    120 
    121 };
    122 
    123 
    124 /**
    125  * Internal representation for an exchange
    126  */
    127 struct TMH_Exchange
    128 {
    129 
    130   /**
    131    * Kept in a DLL.
    132    */
    133   struct TMH_Exchange *next;
    134 
    135   /**
    136    * Kept in a DLL.
    137    */
    138   struct TMH_Exchange *prev;
    139 
    140   /**
    141    * Head of FOs pending for this exchange.
    142    */
    143   struct TMH_EXCHANGES_KeysOperation *keys_head;
    144 
    145   /**
    146    * Tail of FOs pending for this exchange.
    147    */
    148   struct TMH_EXCHANGES_KeysOperation *keys_tail;
    149 
    150   /**
    151    * (base) URL of the exchange.
    152    */
    153   char *url;
    154 
    155   /**
    156    * Currency offered by the exchange according to OUR configuration.
    157    */
    158   char *currency;
    159 
    160   /**
    161    * The keys of this exchange.
    162    */
    163   struct TALER_EXCHANGE_Keys *keys;
    164 
    165   /**
    166    * Head of wire fees from /wire request.
    167    */
    168   struct FeesByWireMethod *wire_fees_head;
    169 
    170   /**
    171    * Tail of wire fees from /wire request.
    172    */
    173   struct FeesByWireMethod *wire_fees_tail;
    174 
    175   /**
    176    * Task to retry downloading /keys again.
    177    */
    178   struct GNUNET_SCHEDULER_Task *retry_task;
    179 
    180   /**
    181    * When are we willing to force downloading again?
    182    */
    183   struct GNUNET_TIME_Absolute first_retry;
    184 
    185   /**
    186    * Current exponential back-off for @e retry_task.
    187    */
    188   struct GNUNET_TIME_Relative retry_delay;
    189 
    190   /**
    191    * Master public key of the exchange.
    192    */
    193   struct TALER_MasterPublicKeyP master_pub;
    194 
    195   /**
    196    * true if this exchange is from our configuration and
    197    * explicitly trusted, false if we need to check each
    198    * key to be sure it is trusted.
    199    */
    200   bool trusted;
    201 
    202 };
    203 
    204 
    205 /**
    206  * Head of exchanges we know about.
    207  */
    208 static struct TMH_Exchange *exchange_head;
    209 
    210 /**
    211  * Tail of exchanges we know about.
    212  */
    213 static struct TMH_Exchange *exchange_tail;
    214 
    215 /**
    216  * Our event handler listening for /keys downloads
    217  * being put into the database.
    218  */
    219 static struct GNUNET_DB_EventHandler *keys_eh;
    220 
    221 /**
    222  * How many exchanges do we trust (for our configured
    223  * currency) as per our configuration? Used for a
    224  * sanity-check on startup.
    225  */
    226 static int trusted_exchange_count;
    227 
    228 
    229 const struct TALER_MasterPublicKeyP *
    230 TMH_EXCHANGES_get_master_pub (
    231   const struct TMH_Exchange *exchange)
    232 {
    233   GNUNET_break ( (exchange->trusted) ||
    234                  (NULL != exchange->keys) );
    235   return &exchange->master_pub;
    236 }
    237 
    238 
    239 const char *
    240 TMH_EXCHANGES_get_currency (
    241   const struct TMH_Exchange *exchange)
    242 {
    243   return exchange->currency;
    244 }
    245 
    246 
    247 struct TMH_Exchange *
    248 TMH_EXCHANGES_lookup_exchange (const char *exchange_url)
    249 {
    250   for (struct TMH_Exchange *exchange = exchange_head;
    251        NULL != exchange;
    252        exchange = exchange->next)
    253     if (0 == strcmp (exchange->url,
    254                      exchange_url))
    255       return exchange;
    256   return NULL;
    257 }
    258 
    259 
    260 bool
    261 TMH_EXCHANGES_check_trusted (
    262   const char *exchange_url)
    263 {
    264   struct TMH_Exchange *exchange = TMH_EXCHANGES_lookup_exchange (exchange_url);
    265 
    266   if (NULL == exchange)
    267     return false;
    268   return exchange->trusted;
    269 }
    270 
    271 
    272 /**
    273  * Check if we have any remaining pending requests for the
    274  * given @a exchange, and if we have the required data, call
    275  * the callback.
    276  *
    277  * @param exchange the exchange to check for pending find operations
    278  */
    279 static void
    280 process_find_operations (struct TMH_Exchange *exchange)
    281 {
    282   struct GNUNET_TIME_Timestamp now;
    283 
    284   now = GNUNET_TIME_timestamp_get ();
    285   for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
    286        NULL != fbw;
    287        fbw = fbw->next)
    288   {
    289     while ( (NULL != fbw->af) &&
    290             (GNUNET_TIME_timestamp_cmp (fbw->af->end_date,
    291                                         <,
    292                                         now)) )
    293     {
    294       struct TALER_EXCHANGE_WireAggregateFees *af = fbw->af;
    295 
    296       fbw->af = af->next;
    297       GNUNET_free (af);
    298     }
    299     if (NULL == fbw->af)
    300     {
    301       /* Disagreement on the current time */
    302       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    303                   "Exchange has no wire fees configured for `%s' wire method\n",
    304                   fbw->wire_method);
    305     }
    306     else if (GNUNET_TIME_timestamp_cmp (fbw->af->start_date,
    307                                         >,
    308                                         now))
    309     {
    310       /* Disagreement on the current time */
    311       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    312                   "Exchange's earliest fee is %s ahead of our time. Clock skew issue?\n",
    313                   GNUNET_TIME_relative2s (
    314                     GNUNET_TIME_absolute_get_remaining (
    315                       fbw->af->start_date.abs_time),
    316                     true));
    317     }
    318   } /* for all wire methods */
    319 
    320   {
    321     struct TMH_EXCHANGES_KeysOperation *kon;
    322 
    323     kon = NULL;
    324     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    325                 "Processing find operations for `%s'\n",
    326                 exchange->url);
    327     for (struct TMH_EXCHANGES_KeysOperation *ko = exchange->keys_head;
    328          NULL != ko;
    329          ko = kon)
    330     {
    331       kon = ko->next;
    332       ko->fc (ko->fc_cls,
    333               exchange->keys,
    334               exchange);
    335       TMH_EXCHANGES_keys4exchange_cancel (ko);
    336     }
    337   }
    338 }
    339 
    340 
    341 /**
    342  * Function called with information about the wire fees for each wire method.
    343  * Stores the wire fees within our internal data structures for later use.
    344  *
    345  * @param exchange connection to the exchange
    346  * @param master_pub public key of the exchange
    347  * @param num_methods number of wire methods supported
    348  * @param fbm wire fees by method
    349  * @return #GNUNET_OK on success
    350  */
    351 static enum GNUNET_GenericReturnValue
    352 process_wire_fees (
    353   struct TMH_Exchange *exchange,
    354   const struct TALER_MasterPublicKeyP *master_pub,
    355   unsigned int num_methods,
    356   const struct TALER_EXCHANGE_WireFeesByMethod fbm[static num_methods])
    357 {
    358   for (unsigned int i = 0; i<num_methods; i++)
    359   {
    360     const char *wire_method = fbm[i].method;
    361     const struct TALER_EXCHANGE_WireAggregateFees *fees = fbm[i].fees_head;
    362     struct FeesByWireMethod *f;
    363     struct TALER_EXCHANGE_WireAggregateFees *endp;
    364 
    365     for (f = exchange->wire_fees_head; NULL != f; f = f->next)
    366       if (0 == strcasecmp (wire_method,
    367                            f->wire_method))
    368         break;
    369     if (NULL == f)
    370     {
    371       f = GNUNET_new (struct FeesByWireMethod);
    372       f->wire_method = GNUNET_strdup (wire_method);
    373       GNUNET_CONTAINER_DLL_insert (exchange->wire_fees_head,
    374                                    exchange->wire_fees_tail,
    375                                    f);
    376     }
    377     endp = f->af;
    378     while ( (NULL != endp) &&
    379             (NULL != endp->next) )
    380       endp = endp->next;
    381     while ( (NULL != endp) &&
    382             (NULL != fees) &&
    383             (GNUNET_TIME_timestamp_cmp (fees->start_date,
    384                                         <,
    385                                         endp->end_date)) )
    386       fees = fees->next;
    387     if ( (NULL != endp) &&
    388          (NULL != fees) &&
    389          (GNUNET_TIME_timestamp_cmp (fees->start_date,
    390                                      !=,
    391                                      endp->end_date)) )
    392     {
    393       /* Hole or overlap in the fee structure, not allowed! */
    394       GNUNET_break_op (0);
    395       return GNUNET_SYSERR;
    396     }
    397     while (NULL != fees)
    398     {
    399       struct TALER_EXCHANGE_WireAggregateFees *af;
    400 
    401       af = GNUNET_new (struct TALER_EXCHANGE_WireAggregateFees);
    402       *af = *fees;
    403       af->next = NULL;
    404       if (NULL == endp)
    405         f->af = af;
    406       else
    407         endp->next = af;
    408       endp = af;
    409       fees = fees->next;
    410     } /* all fees for this method */
    411   } /* for all methods (i) */
    412   return GNUNET_OK;
    413 }
    414 
    415 
    416 /**
    417  * Retry getting keys from the given exchange in the closure.
    418  *
    419  * @param cls the `struct TMH_Exchange *`
    420  */
    421 static void
    422 retry_exchange (void *cls)
    423 {
    424   struct TMH_Exchange *exchange = cls;
    425   struct GNUNET_DB_EventHeaderP es = {
    426     .size = htons (sizeof (es)),
    427     .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_FORCE_KEYS)
    428   };
    429 
    430   exchange->retry_task = NULL;
    431   exchange->retry_delay
    432     = GNUNET_TIME_randomized_backoff (exchange->retry_delay,
    433                                       RETRY_BACKOFF_THRESHOLD);
    434   exchange->first_retry
    435     = GNUNET_TIME_relative_to_absolute (
    436         exchange->retry_delay);
    437 
    438   TALER_MERCHANTDB_event_notify (TMH_db,
    439                                  &es,
    440                                  exchange->url,
    441                                  strlen (exchange->url) + 1);
    442 }
    443 
    444 
    445 /**
    446  * Task to asynchronously return keys operation result to caller.
    447  *
    448  * @param cls a `struct TMH_EXCHANGES_KeysOperation`
    449  */
    450 static void
    451 return_keys (void *cls)
    452 {
    453   struct TMH_EXCHANGES_KeysOperation *fo = cls;
    454   struct TMH_Exchange *exchange = fo->my_exchange;
    455 
    456   fo->at = NULL;
    457   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    458               "Returning key data for %s instantly\n",
    459               exchange->url);
    460   process_find_operations (exchange);
    461 }
    462 
    463 
    464 struct TMH_EXCHANGES_KeysOperation *
    465 TMH_EXCHANGES_keys4exchange (
    466   const char *chosen_exchange,
    467   bool force_download,
    468   TMH_EXCHANGES_Find2Continuation fc,
    469   void *fc_cls)
    470 {
    471   struct TMH_Exchange *exchange;
    472   struct TMH_EXCHANGES_KeysOperation *fo;
    473 
    474   if (NULL == TMH_curl_ctx)
    475   {
    476     GNUNET_break (0);
    477     return NULL;
    478   }
    479   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    480               "Trying to find chosen exchange `%s'\n",
    481               chosen_exchange);
    482   exchange = TMH_EXCHANGES_lookup_exchange (chosen_exchange);
    483   if (NULL == exchange)
    484   {
    485     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    486                 "Exchange `%s' not configured\n",
    487                 chosen_exchange);
    488     return NULL;
    489   }
    490   if (! exchange->trusted)
    491   {
    492     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    493                 "Exchange `%s' not trusted\n",
    494                 chosen_exchange);
    495     return NULL;
    496   }
    497   fo = GNUNET_new (struct TMH_EXCHANGES_KeysOperation);
    498   fo->fc = fc;
    499   fo->fc_cls = fc_cls;
    500   fo->my_exchange = exchange;
    501   GNUNET_CONTAINER_DLL_insert (exchange->keys_head,
    502                                exchange->keys_tail,
    503                                fo);
    504   if ( (NULL == exchange->keys) &&
    505        (! force_download) )
    506   {
    507     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    508                 "Waiting for `%skeys' already, failing query instantly\n",
    509                 exchange->url);
    510     GNUNET_assert (NULL == fo->at);
    511     fo->at = GNUNET_SCHEDULER_add_now (&return_keys,
    512                                        fo);
    513     return fo;
    514   }
    515   if ( (NULL != exchange->keys) &&
    516        (! force_download) &&
    517        (GNUNET_TIME_absolute_is_future (
    518           exchange->keys->key_data_expiration.abs_time)) )
    519   {
    520     /* We have a valid reply, immediately return result */
    521     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    522                 "The exchange `%s' is ready\n",
    523                 exchange->url);
    524     GNUNET_assert (NULL == fo->at);
    525     fo->at = GNUNET_SCHEDULER_add_now (&return_keys,
    526                                        fo);
    527     return fo;
    528   }
    529   if ( (force_download) &&
    530        (GNUNET_TIME_absolute_is_future (exchange->first_retry)) &&
    531        (NULL != exchange->keys) )
    532   {
    533     /* Return results immediately. */
    534     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    535                 "Earliest retry is in the future, returning keys now\n");
    536     fo->at = GNUNET_SCHEDULER_add_now (&return_keys,
    537                                        fo);
    538     /* *no* return here, we MAY schedule a 'retry_task' in the
    539        next block if there isn't one yet */
    540   }
    541   if (NULL == exchange->retry_task)
    542     exchange->retry_task
    543       = GNUNET_SCHEDULER_add_at (exchange->first_retry,
    544                                  &retry_exchange,
    545                                  exchange);
    546   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    547               "Next %skeys request scheduled for %s\n",
    548               exchange->url,
    549               GNUNET_TIME_absolute2s (
    550                 exchange->first_retry));
    551   /* No activity to launch, we are already doing so. */
    552   return fo;
    553 }
    554 
    555 
    556 void
    557 TMH_EXCHANGES_keys4exchange_cancel (
    558   struct TMH_EXCHANGES_KeysOperation *fo)
    559 {
    560   struct TMH_Exchange *exchange = fo->my_exchange;
    561 
    562   if (NULL != fo->at)
    563   {
    564     GNUNET_SCHEDULER_cancel (fo->at);
    565     fo->at = NULL;
    566   }
    567   GNUNET_CONTAINER_DLL_remove (exchange->keys_head,
    568                                exchange->keys_tail,
    569                                fo);
    570   GNUNET_free (fo);
    571 }
    572 
    573 
    574 /**
    575  * Obtain applicable fees for @a exchange and @a wire_method.
    576  *
    577  * @param exchange the exchange to query
    578  * @param now current time
    579  * @param wire_method the wire method we want the fees for
    580  * @return NULL if we do not have fees for this method yet
    581  */
    582 static const struct FeesByWireMethod *
    583 get_wire_fees (const struct TMH_Exchange *exchange,
    584                struct GNUNET_TIME_Timestamp now,
    585                const char *wire_method)
    586 {
    587   for (struct FeesByWireMethod *fbw = exchange->wire_fees_head;
    588        NULL != fbw;
    589        fbw = fbw->next)
    590   {
    591     if (0 == strcasecmp (fbw->wire_method,
    592                          wire_method) )
    593     {
    594       struct TALER_EXCHANGE_WireAggregateFees *af;
    595 
    596       /* Advance through list up to current time */
    597       while ( (NULL != (af = fbw->af)) &&
    598               (GNUNET_TIME_timestamp_cmp (now,
    599                                           >=,
    600                                           af->end_date)) )
    601       {
    602         fbw->af = af->next;
    603         GNUNET_free (af);
    604       }
    605       return fbw;
    606     }
    607     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    608                 "Exchange supports `%s' as a wire method (but we do not use that one)\n",
    609                 fbw->wire_method);
    610   }
    611   return NULL;
    612 }
    613 
    614 
    615 /**
    616  * Free @a exchange.
    617  *
    618  * @param[in] exchange entry to free
    619  */
    620 static void
    621 free_exchange_entry (struct TMH_Exchange *exchange)
    622 {
    623   struct FeesByWireMethod *f;
    624 
    625   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    626               "Releasing %s exchange %s\n",
    627               exchange->trusted ? "trusted" : "untrusted",
    628               exchange->url);
    629   GNUNET_CONTAINER_DLL_remove (exchange_head,
    630                                exchange_tail,
    631                                exchange);
    632   while (NULL != (f = exchange->wire_fees_head))
    633   {
    634     struct TALER_EXCHANGE_WireAggregateFees *af;
    635 
    636     GNUNET_CONTAINER_DLL_remove (exchange->wire_fees_head,
    637                                  exchange->wire_fees_tail,
    638                                  f);
    639     while (NULL != (af = f->af))
    640     {
    641       f->af = af->next;
    642       GNUNET_free (af);
    643     }
    644     GNUNET_free (f->wire_method);
    645     GNUNET_free (f);
    646   }
    647   TALER_EXCHANGE_keys_decref (exchange->keys);
    648   exchange->keys = NULL;
    649   if (NULL != exchange->retry_task)
    650   {
    651     GNUNET_SCHEDULER_cancel (exchange->retry_task);
    652     exchange->retry_task = NULL;
    653   }
    654   GNUNET_assert (NULL == exchange->keys_head);
    655   GNUNET_assert (NULL == exchange->keys_tail);
    656   GNUNET_free (exchange->currency);
    657   GNUNET_free (exchange->url);
    658   GNUNET_free (exchange);
    659 }
    660 
    661 
    662 enum GNUNET_GenericReturnValue
    663 TMH_EXCHANGES_lookup_wire_fee (
    664   const struct TMH_Exchange *exchange,
    665   const char *wire_method,
    666   struct TALER_Amount *wire_fee)
    667 {
    668   const struct FeesByWireMethod *fbm;
    669   const struct TALER_EXCHANGE_WireAggregateFees *af;
    670 
    671   fbm = get_wire_fees (exchange,
    672                        GNUNET_TIME_timestamp_get (),
    673                        wire_method);
    674   if (NULL == fbm)
    675     return GNUNET_NO;
    676   af = fbm->af;
    677   if (NULL == af)
    678     return GNUNET_NO;
    679   *wire_fee = af->fees.wire;
    680   return GNUNET_OK;
    681 }
    682 
    683 
    684 enum TMH_ExchangeStatus
    685 TMH_exchange_check_debit (
    686   const char *instance_id,
    687   const struct TMH_Exchange *exchange,
    688   const struct TMH_WireMethod *wm,
    689   struct TALER_Amount *max_amount)
    690 {
    691   const struct TALER_EXCHANGE_Keys *keys = exchange->keys;
    692   bool have_kyc = false;
    693   bool no_access_token = true;
    694   enum TMH_ExchangeStatus retry_ok = 0;
    695 
    696   if (GNUNET_TIME_absolute_is_past (exchange->first_retry))
    697     retry_ok = TMH_ES_RETRY_OK;
    698 
    699   if (NULL == keys)
    700     return TMH_ES_NO_KEYS | retry_ok;
    701   if (0 != strcasecmp (keys->currency,
    702                        max_amount->currency))
    703   {
    704     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    705                 "Currency mismatch: exchange %s uses %s, we need %s\n",
    706                 exchange->url,
    707                 keys->currency,
    708                 max_amount->currency);
    709     return TMH_ES_NO_CURR | retry_ok;
    710   }
    711   {
    712     struct TALER_NormalizedPayto np;
    713     bool account_ok;
    714 
    715     np = TALER_payto_normalize (wm->payto_uri);
    716     account_ok = TALER_EXCHANGE_keys_test_account_allowed (keys,
    717                                                            false,
    718                                                            np);
    719     GNUNET_free (np.normalized_payto);
    720     if (! account_ok)
    721       return TMH_ES_NO_ACC | retry_ok;
    722   }
    723   if (! keys->kyc_enabled)
    724     return TMH_ES_OK | retry_ok;
    725 
    726   {
    727     json_t *jlimits = NULL;
    728     enum GNUNET_DB_QueryStatus qs;
    729 
    730     qs = TALER_MERCHANTDB_set_instance (
    731       TMH_db,
    732       instance_id);
    733     if (0 >= qs)
    734     {
    735       GNUNET_break (0);
    736       return TMH_ES_NO_KEYS | TMH_ES_RETRY_OK;
    737     }
    738     qs = TALER_MERCHANTDB_get_kyc_limits (TMH_db,
    739                                           wm->payto_uri,
    740                                           instance_id,
    741                                           exchange->url,
    742                                           &have_kyc,
    743                                           &no_access_token,
    744                                           &jlimits);
    745     GNUNET_break (qs >= 0);
    746     GNUNET_break (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
    747                   TALER_MERCHANTDB_set_instance (
    748                     TMH_db,
    749                     NULL));
    750     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    751                 "get_kyc_limits for %s at %s returned %s/%s\n",
    752                 wm->payto_uri.full_payto,
    753                 exchange->url,
    754                 have_kyc ? "KYC OK" : "KYC missing",
    755                 NULL == jlimits ? "default limits" : "custom limits");
    756     if ( (qs > 0) &&
    757          (NULL != jlimits) )
    758     {
    759       json_t *jlimit;
    760       size_t idx;
    761       struct TALER_Amount kyc_limit;
    762       bool unlimited = true;
    763 
    764       json_array_foreach (jlimits, idx, jlimit)
    765       {
    766         enum TALER_KYCLOGIC_KycTriggerEvent ot;
    767         struct TALER_Amount threshold;
    768         bool soft_limit = false;
    769         struct GNUNET_JSON_Specification spec[] = {
    770           TALER_JSON_spec_kycte ("operation_type",
    771                                  &ot),
    772           TALER_JSON_spec_amount_any ("threshold",
    773                                       &threshold),
    774           GNUNET_JSON_spec_mark_optional (
    775             GNUNET_JSON_spec_bool ("soft_limit",
    776                                    &soft_limit),
    777             NULL),
    778           GNUNET_JSON_spec_end ()
    779         };
    780 
    781         if (GNUNET_OK !=
    782             GNUNET_JSON_parse (jlimit,
    783                                spec,
    784                                NULL, NULL))
    785         {
    786           GNUNET_break (0);
    787           continue;
    788         }
    789         if (soft_limit)
    790           continue;
    791         if ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT != ot) &&
    792              (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION != ot) )
    793           continue;
    794         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    795                     "KYC rule %u with limit %s applies\n",
    796                     (unsigned int) idx,
    797                     TALER_amount2s (&threshold));
    798         if (unlimited)
    799         {
    800           unlimited = false;
    801           kyc_limit = threshold;
    802         }
    803         else
    804         {
    805           TALER_amount_min (&kyc_limit,
    806                             &kyc_limit,
    807                             &threshold);
    808         }
    809       }
    810       json_decref (jlimits);
    811       /* We had custom rules, do not evaluate default rules */
    812       if (! unlimited)
    813         TALER_amount_min (max_amount,
    814                           max_amount,
    815                           &kyc_limit);
    816       return TMH_ES_OK | retry_ok;
    817     } /* END of if qs > 0, NULL != jlimits */
    818   }
    819 
    820   /* Check zero limits *only* if we did no KYC process at all yet.
    821      Because if we did, there is at least a chance that those have
    822      been lifted. */
    823   if ( (no_access_token) ||
    824        ( (! have_kyc) &&
    825          (TALER_EXCHANGE_keys_evaluate_zero_limits (
    826             keys,
    827             TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    828           TALER_EXCHANGE_keys_evaluate_zero_limits (
    829             keys,
    830             TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION)) ) )
    831   {
    832     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    833                 "KYC requirements of %s not satisfied\n",
    834                 exchange->url);
    835     GNUNET_assert (GNUNET_OK ==
    836                    TALER_amount_set_zero (
    837                      max_amount->currency,
    838                      max_amount));
    839     return TMH_ES_OK | retry_ok;
    840   }
    841   /* In any case, abide by hard limits (unless we have custom rules). */
    842   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    843               "Evaluating default hard limits of %s\n",
    844               exchange->url);
    845   TALER_EXCHANGE_keys_evaluate_hard_limits (
    846     keys,
    847     TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT,
    848     max_amount);
    849   TALER_EXCHANGE_keys_evaluate_hard_limits (
    850     keys,
    851     TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION,
    852     max_amount);
    853   if (TALER_EXCHANGE_keys_evaluate_zero_limits (
    854         keys,
    855         TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT) ||
    856       TALER_EXCHANGE_keys_evaluate_zero_limits (
    857         keys,
    858         TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION))
    859   {
    860     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    861                 "Operation is zero-limited by default\n");
    862     GNUNET_assert (GNUNET_OK ==
    863                    TALER_amount_set_zero (max_amount->currency,
    864                                           max_amount));
    865   }
    866   return TMH_ES_OK | retry_ok;
    867 }
    868 
    869 
    870 void
    871 TMH_exchange_get_trusted (TMH_ExchangeCallback cb,
    872                           void *cb_cls)
    873 {
    874   for (const struct TMH_Exchange *exchange = exchange_head;
    875        NULL != exchange;
    876        exchange = exchange->next)
    877   {
    878     if (! exchange->trusted)
    879     {
    880       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    881                   "Exchange %s not trusted, skipping!\n",
    882                   exchange->url);
    883       continue;
    884     }
    885     cb (cb_cls,
    886         exchange->url,
    887         exchange);
    888   }
    889 }
    890 
    891 
    892 bool
    893 TMH_test_exchange_configured_for_currency (
    894   const char *currency)
    895 {
    896   for (const struct TMH_Exchange *exchange = exchange_head;
    897        NULL != exchange;
    898        exchange = exchange->next)
    899   {
    900     if (! exchange->trusted)
    901       continue;
    902     if (NULL == exchange->currency)
    903       continue;
    904     if (0 == strcasecmp (currency,
    905                          exchange->currency))
    906       return true;
    907   }
    908   return false;
    909 }
    910 
    911 
    912 /**
    913  * (Re)load of keys from DB.
    914  *
    915  * @param exchange exchange to reload keys of
    916  */
    917 static void
    918 reload_exchange_keys (struct TMH_Exchange *exchange)
    919 {
    920   enum GNUNET_DB_QueryStatus qs;
    921   struct TALER_EXCHANGE_Keys *keys;
    922   struct GNUNET_TIME_Absolute first_retry;
    923 
    924   qs = TALER_MERCHANTDB_get_exchange_keys (TMH_db,
    925                                            exchange->url,
    926                                            &first_retry,
    927                                            &keys);
    928   if (qs < 0)
    929   {
    930     GNUNET_break (0);
    931     return;
    932   }
    933   if ( (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) ||
    934        (NULL == keys) )
    935   {
    936     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    937                 "No keys yet for `%s'\n",
    938                 exchange->url);
    939     return;
    940   }
    941   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    942               "Loading latest keys of `%s' from database\n",
    943               exchange->url);
    944   exchange->retry_delay = GNUNET_TIME_UNIT_ZERO;
    945   exchange->first_retry = first_retry;
    946   if (NULL == exchange->currency)
    947     exchange->currency = GNUNET_strdup (keys->currency);
    948   if (0 != strcasecmp (keys->currency,
    949                        exchange->currency))
    950   {
    951     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    952                 "/keys cached in our database are for currency `%s', but we expected `%s'\n",
    953                 keys->currency,
    954                 exchange->currency);
    955     return;
    956   }
    957   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    958               "Loaded /keys from database with %u accounts, %u fees\n",
    959               keys->accounts_len,
    960               keys->fees_len);
    961   if (GNUNET_OK !=
    962       process_wire_fees (exchange,
    963                          &keys->master_pub,
    964                          keys->fees_len,
    965                          keys->fees))
    966   {
    967     /* invalid wire fee specification given */
    968     GNUNET_break_op (0);
    969     /* but: we can continue anyway, things may just not
    970        work, but probably better than to not keep going. */
    971     return;
    972   }
    973 
    974   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    975               "Reloaded /keys of %s from database\n",
    976               exchange->url);
    977   TALER_EXCHANGE_keys_decref (exchange->keys);
    978   exchange->keys = keys;
    979   if ( (exchange->trusted) &&
    980        (0 != GNUNET_memcmp (&exchange->master_pub,
    981                             &keys->master_pub)) )
    982   {
    983     /* master pub differs => do not trust the exchange (without auditor) */
    984     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    985                 "Master public key of exchange `%s' differs from our configuration. Not trusting exchange.\n",
    986                 exchange->url);
    987     exchange->trusted = false;
    988   }
    989   if (! exchange->trusted)
    990   {
    991     exchange->master_pub = keys->master_pub;
    992     for (struct TMH_Exchange *e = exchange_head;
    993          NULL != e;
    994          e = e->next)
    995     {
    996       if (e == exchange)
    997         continue;
    998       if (! e->trusted)
    999         continue;
   1000       if (0 ==
   1001           GNUNET_memcmp (&e->master_pub,
   1002                          &exchange->master_pub))
   1003         exchange->trusted = true; /* same exchange, different URL => trust applies */
   1004     }
   1005   }
   1006 
   1007   TMH_kyc_keys_changed (exchange->url);
   1008   process_find_operations (exchange);
   1009 }
   1010 
   1011 
   1012 /**
   1013  * Function called on each configuration section. Finds sections
   1014  * about exchanges, parses the entries.
   1015  *
   1016  * @param cls closure, with a `const struct GNUNET_CONFIGURATION_Handle *`
   1017  * @param section name of the section
   1018  */
   1019 static void
   1020 accept_exchanges (void *cls,
   1021                   const char *section)
   1022 {
   1023   const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
   1024   char *url;
   1025   char *mks;
   1026   struct TMH_Exchange *exchange;
   1027   char *currency;
   1028 
   1029   if (GNUNET_SYSERR == trusted_exchange_count)
   1030     return;
   1031   if (0 != strncasecmp (section,
   1032                         "merchant-exchange-",
   1033                         strlen ("merchant-exchange-")))
   1034     return;
   1035   if (GNUNET_YES ==
   1036       GNUNET_CONFIGURATION_get_value_yesno (cfg,
   1037                                             section,
   1038                                             "DISABLED"))
   1039     return;
   1040   if (GNUNET_OK !=
   1041       GNUNET_CONFIGURATION_get_value_string (cfg,
   1042                                              section,
   1043                                              "EXCHANGE_BASE_URL",
   1044                                              &url))
   1045   {
   1046     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   1047                                section,
   1048                                "EXCHANGE_BASE_URL");
   1049     return;
   1050   }
   1051   exchange = TMH_EXCHANGES_lookup_exchange (url);
   1052   if (NULL != exchange)
   1053   {
   1054     GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   1055                                section,
   1056                                "EXCHANGE_BASE_URL",
   1057                                "same base URL specified again");
   1058     GNUNET_free (url);
   1059     return;
   1060   }
   1061   if (GNUNET_OK !=
   1062       GNUNET_CONFIGURATION_get_value_string (cfg,
   1063                                              section,
   1064                                              "CURRENCY",
   1065                                              &currency))
   1066   {
   1067     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   1068                                section,
   1069                                "CURRENCY");
   1070     GNUNET_free (url);
   1071     return;
   1072   }
   1073   exchange = GNUNET_new (struct TMH_Exchange);
   1074   exchange->url = url;
   1075   exchange->currency = currency;
   1076   GNUNET_CONTAINER_DLL_insert (exchange_head,
   1077                                exchange_tail,
   1078                                exchange);
   1079   if (GNUNET_OK ==
   1080       GNUNET_CONFIGURATION_get_value_string (cfg,
   1081                                              section,
   1082                                              "MASTER_KEY",
   1083                                              &mks))
   1084   {
   1085     if (GNUNET_OK ==
   1086         GNUNET_CRYPTO_eddsa_public_key_from_string (
   1087           mks,
   1088           strlen (mks),
   1089           &exchange->master_pub.eddsa_pub))
   1090     {
   1091       exchange->trusted = true;
   1092       trusted_exchange_count++;
   1093     }
   1094     else
   1095     {
   1096       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
   1097                                  section,
   1098                                  "MASTER_KEY",
   1099                                  "malformed EdDSA key");
   1100     }
   1101     GNUNET_free (mks);
   1102   }
   1103   else
   1104   {
   1105     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1106                 "MASTER_KEY missing in section '%s', not trusting exchange\n",
   1107                 section);
   1108   }
   1109   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1110               "Setup exchange %s as %s\n",
   1111               exchange->url,
   1112               exchange->trusted ? "trusted" : "untrusted");
   1113   reload_exchange_keys (exchange);
   1114   if (NULL != exchange->retry_task)
   1115   {
   1116     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1117                 "Exchange at `%s' configured in multiple configuration sections (see `%s')!\n",
   1118                 exchange->url,
   1119                 section);
   1120     trusted_exchange_count = GNUNET_SYSERR;
   1121     return;
   1122   }
   1123   exchange->retry_task
   1124     = GNUNET_SCHEDULER_add_now (&retry_exchange,
   1125                                 exchange);
   1126 }
   1127 
   1128 
   1129 /**
   1130  * Trigger (re)loading of keys from DB.
   1131  *
   1132  * @param cls NULL
   1133  * @param extra base URL of the exchange that changed
   1134  * @param extra_len number of bytes in @a extra
   1135  */
   1136 static void
   1137 update_exchange_keys (void *cls,
   1138                       const void *extra,
   1139                       size_t extra_len)
   1140 {
   1141   const char *url = extra;
   1142   struct TMH_Exchange *exchange;
   1143 
   1144   if ( (NULL == extra) ||
   1145        (0 == extra_len) )
   1146   {
   1147     GNUNET_break (0);
   1148     return;
   1149   }
   1150   if ('\0' != url[extra_len - 1])
   1151   {
   1152     GNUNET_break (0);
   1153     return;
   1154   }
   1155   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1156               "Received keys change notification: reload `%s'\n",
   1157               url);
   1158   exchange = TMH_EXCHANGES_lookup_exchange (url);
   1159   GNUNET_break (NULL != exchange);
   1160   if (NULL != exchange)
   1161     reload_exchange_keys (exchange);
   1162 }
   1163 
   1164 
   1165 bool
   1166 TMH_EXCHANGES_is_below_limit (
   1167   const struct TALER_EXCHANGE_Keys *keys,
   1168   enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
   1169   const struct TALER_Amount *amount)
   1170 {
   1171   if (NULL == keys)
   1172   {
   1173     /* should only be called after we have keys! */
   1174     GNUNET_break (0);
   1175     return false;
   1176   }
   1177   for (unsigned int i = 0; i<keys->hard_limits_length; i++)
   1178   {
   1179     const struct TALER_EXCHANGE_AccountLimit *al
   1180       = &keys->hard_limits[i];
   1181 
   1182     if (operation_type != al->operation_type)
   1183       continue;
   1184     if (-1 ==
   1185         TALER_amount_cmp (&al->threshold,
   1186                           amount))
   1187       /* -1: threshold < amount */
   1188       return false;
   1189   }
   1190   return true;
   1191 }
   1192 
   1193 
   1194 void
   1195 TMH_EXCHANGES_get_limit (
   1196   const char *exchange_url,
   1197   enum TALER_KYCLOGIC_KycTriggerEvent operation_type,
   1198   struct TALER_Amount *amount)
   1199 {
   1200   struct TMH_Exchange *exchange;
   1201   const struct TALER_EXCHANGE_Keys *keys;
   1202 
   1203   exchange = TMH_EXCHANGES_lookup_exchange (exchange_url);
   1204   if ( (NULL == exchange) ||
   1205        (NULL == (keys = exchange->keys)) )
   1206   {
   1207     GNUNET_assert (GNUNET_OK ==
   1208                    TALER_amount_set_zero (
   1209                      amount->currency,
   1210                      amount));
   1211     return;
   1212   }
   1213   for (unsigned int i = 0; i<keys->hard_limits_length; i++)
   1214   {
   1215     const struct TALER_EXCHANGE_AccountLimit *al
   1216       = &keys->hard_limits[i];
   1217 
   1218     if (operation_type != al->operation_type)
   1219       continue;
   1220     TALER_amount_min (amount,
   1221                       amount,
   1222                       &al->threshold);
   1223   }
   1224 }
   1225 
   1226 
   1227 enum GNUNET_GenericReturnValue
   1228 TMH_EXCHANGES_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
   1229 {
   1230   /* get exchanges from the merchant configuration and try to connect to them */
   1231   {
   1232     struct GNUNET_DB_EventHeaderP es = {
   1233       .size = htons (sizeof (es)),
   1234       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
   1235     };
   1236 
   1237     GNUNET_assert (NULL == keys_eh);
   1238     keys_eh = TALER_MERCHANTDB_event_listen (TMH_db,
   1239                                              &es,
   1240                                              GNUNET_TIME_UNIT_FOREVER_REL,
   1241                                              &update_exchange_keys,
   1242                                              NULL);
   1243   }
   1244   GNUNET_CONFIGURATION_iterate_sections (cfg,
   1245                                          &accept_exchanges,
   1246                                          (void *) cfg);
   1247   /* build JSON with list of trusted exchanges (will be included in contracts) */
   1248   return trusted_exchange_count;
   1249 }
   1250 
   1251 
   1252 void
   1253 TMH_EXCHANGES_done ()
   1254 {
   1255   if (NULL != keys_eh)
   1256   {
   1257     TALER_MERCHANTDB_event_listen_cancel (keys_eh);
   1258     keys_eh = NULL;
   1259   }
   1260   while (NULL != exchange_head)
   1261     free_exchange_entry (exchange_head);
   1262 }
   1263 
   1264 
   1265 /* end of taler-merchant-httpd_get-exchanges.c */