diff options
66 files changed, 3771 insertions, 6524 deletions
| diff --git a/configure.ac b/configure.ac index 95e590bf..35813210 100644 --- a/configure.ac +++ b/configure.ac @@ -558,6 +558,5 @@ AC_CONFIG_FILES([Makefile                   src/util/Makefile                   src/util/taler-config                   src/wire/Makefile -                 src/wire-plugins/Makefile                   ])  AC_OUTPUT diff --git a/src/Makefile.am b/src/Makefile.am index 761b9c33..cc749e27 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,7 +22,7 @@ pkgcfg_DATA = \  EXTRA_DIST = \    taler.conf -SUBDIRS = include util wire json curl $(PQ_DIR) mhd $(BANK_LIB) wire-plugins exchangedb exchange exchange-tools auditordb auditor +SUBDIRS = include util wire json curl $(PQ_DIR) mhd $(BANK_LIB) exchangedb exchange exchange-tools auditordb auditor  if HAVE_LIBCURL   SUBDIRS += lib benchmark  else diff --git a/src/auditor/Makefile.am b/src/auditor/Makefile.am index b942076f..d5d7669b 100644 --- a/src/auditor/Makefile.am +++ b/src/auditor/Makefile.am @@ -73,10 +73,12 @@ taler_wire_auditor_LDADD = \    $(top_builddir)/src/util/libtalerutil.la \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/wire/libtalerwire.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/exchangedb/libtalerexchangedb.la \    $(top_builddir)/src/auditordb/libtalerauditordb.la \    -ljansson \    -lgnunetjson \ +  -lgnunetcurl \    -lgnunetutil  taler_auditor_sign_SOURCES = \ diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c index 0cc2868f..bb769fd6 100644 --- a/src/auditor/taler-auditor.c +++ b/src/auditor/taler-auditor.c @@ -1010,8 +1010,7 @@ struct ReserveContext   * @param reserve_pub public key of the reserve (also the WTID)   * @param credit amount that was received   * @param sender_account_details information about the sender's bank account - * @param wire_reference unique reference identifying the wire transfer (binary blob) - * @param wire_reference_size number of bytes in @a wire_reference + * @param wire_reference unique reference identifying the wire transfer   * @param execution_date when did we receive the funds   * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop   */ @@ -1021,8 +1020,7 @@ handle_reserve_in (void *cls,                     const struct TALER_ReservePublicKeyP *reserve_pub,                     const struct TALER_Amount *credit,                     const char *sender_account_details, -                   const void *wire_reference, -                   size_t wire_reference_size, +                   uint64_t wire_reference,                     struct GNUNET_TIME_Absolute execution_date)  {    struct ReserveContext *rc = cls; @@ -2032,35 +2030,6 @@ analyze_reserves (void *cls)  /** - * Information we keep per loaded wire plugin. - */ -struct WirePlugin -{ - -  /** -   * Kept in a DLL. -   */ -  struct WirePlugin *next; - -  /** -   * Kept in a DLL. -   */ -  struct WirePlugin *prev; - -  /** -   * Name of the wire method. -   */ -  char *type; - -  /** -   * Handle to the wire plugin. -   */ -  struct TALER_WIRE_Plugin *plugin; - -}; - - -/**   * Information about wire fees charged by the exchange.   */  struct WireFeeInfo @@ -2106,16 +2075,6 @@ struct AggregationContext  {    /** -   * DLL of wire plugins encountered. -   */ -  struct WirePlugin *wire_head; - -  /** -   * DLL of wire plugins encountered. -   */ -  struct WirePlugin *wire_tail; - -  /**     * DLL of wire fees charged by the exchange.     */    struct WireFeeInfo *fee_head; @@ -2133,46 +2092,6 @@ struct AggregationContext  /** - * Find the relevant wire plugin. - * - * @param ac context to search - * @param type type of the wire plugin to load; it - *  will be used _as is_ from the dynamic loader. - * @return NULL on error - */ -static struct TALER_WIRE_Plugin * -get_wire_plugin (struct AggregationContext *ac, -                 const char *type) -{ -  struct WirePlugin *wp; -  struct TALER_WIRE_Plugin *plugin; - -  for (wp = ac->wire_head; NULL != wp; wp = wp->next) -    if (0 == strcmp (type, -                     wp->type)) -      return wp->plugin; - -  /* Wants the exact *plugin name* (!= method)  */ -  plugin = TALER_WIRE_plugin_load (cfg, -                                   type); -  if (NULL == plugin) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Failed to locate wire plugin for `%s'\n", -                type); -    return NULL; -  } -  wp = GNUNET_new (struct WirePlugin); -  wp->type = GNUNET_strdup (type); -  wp->plugin = plugin; -  GNUNET_CONTAINER_DLL_insert (ac->wire_head, -                               ac->wire_tail, -                               wp); -  return plugin; -} - - -/**   * Closure for #wire_transfer_information_cb.   */  struct WireCheckContext @@ -2884,7 +2803,6 @@ check_wire_out_cb  {    struct AggregationContext *ac = cls;    struct WireCheckContext wcc; -  struct TALER_WIRE_Plugin *plugin;    struct TALER_Amount final_amount;    struct TALER_Amount exchange_gain;    enum GNUNET_DB_QueryStatus qs; @@ -2976,19 +2894,7 @@ check_wire_out_cb    }    /* Round down to amount supported by wire method */ -  plugin = get_wire_plugin -             (ac, -             TALER_WIRE_get_plugin_from_method (method)); -  if (NULL == plugin) -  { -    GNUNET_break (0); -    GNUNET_free (method); -    return GNUNET_SYSERR; -  } -  GNUNET_free (method); -  GNUNET_break (GNUNET_SYSERR != -                plugin->amount_round (plugin->cls, -                                      &final_amount)); +  GNUNET_break (TALER_WIRE_amount_round (&final_amount));    /* Calculate the exchange's gain as the fees plus rounding differences! */    if (GNUNET_OK != @@ -3071,7 +2977,6 @@ static enum GNUNET_DB_QueryStatus  analyze_aggregations (void *cls)  {    struct AggregationContext ac; -  struct WirePlugin *wc;    struct WireFeeInfo *wfi;    enum GNUNET_DB_QueryStatus qsx;    enum GNUNET_DB_QueryStatus qs; @@ -3125,15 +3030,6 @@ analyze_aggregations (void *cls)      GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);      ac.qs = qs;    } -  while (NULL != (wc = ac.wire_head)) -  { -    GNUNET_CONTAINER_DLL_remove (ac.wire_head, -                                 ac.wire_tail, -                                 wc); -    TALER_WIRE_plugin_unload (wc->plugin); -    GNUNET_free (wc->type); -    GNUNET_free (wc); -  }    while (NULL != (wfi = ac.fee_head))    {      GNUNET_CONTAINER_DLL_remove (ac.fee_head, diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c index e66834a1..bd961746 100644 --- a/src/auditor/taler-wire-auditor.c +++ b/src/auditor/taler-wire-auditor.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2017-2019 Taler Systems SA +  Copyright (C) 2017-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -27,9 +27,11 @@   */  #include "platform.h"  #include <gnunet/gnunet_util_lib.h> +#include <gnunet/gnunet_curl_lib.h>  #include "taler_auditordb_plugin.h"  #include "taler_exchangedb_plugin.h"  #include "taler_json_lib.h" +#include "taler_bank_service.h"  #include "taler_wire_lib.h"  #include "taler_signatures.h" @@ -65,9 +67,14 @@ struct WireAccount    struct WireAccount *prev;    /** -   * Handle to the plugin. +   * Authentication data for the account.     */ -  struct TALER_WIRE_Plugin *wire_plugin; +  struct TALER_BANK_AuthenticationData auth; + +  /** +   * Our bank account number. +   */ +  struct TALER_Account account;    /**     * Name of the section that configures this account. @@ -77,7 +84,12 @@ struct WireAccount    /**     * Active wire request for the transaction history.     */ -  struct TALER_WIRE_HistoryHandle *hh; +  struct TALER_BANK_CreditHistoryHandle *chh; + +  /** +   * Active wire request for the transaction history. +   */ +  struct TALER_BANK_DebitHistoryHandle *dhh;    /**     * Progress point for this account. @@ -92,17 +104,12 @@ struct WireAccount    /**     * Where we are in the inbound (CREDIT) transaction history.     */ -  void *in_wire_off; +  uint64_t in_wire_off;    /**     * Where we are in the inbound (DEBIT) transaction history.     */ -  void *out_wire_off; - -  /** -   * Number of bytes in #in_wire_off and #out_wire_off. -   */ -  size_t wire_off_size; +  uint64_t out_wire_off;    /**     * We should check for inbound transactions to this account. @@ -341,6 +348,16 @@ static struct TALER_Amount total_wire_format_amount;   */  static struct TALER_Amount zero; +/** + * Handle to the context for interacting with the bank. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; +  /* *****************************   Shutdown   **************************** */ @@ -357,14 +374,11 @@ struct ReserveInInfo    struct GNUNET_HashCode row_off_hash;    /** -   * Number of bytes in @e row_off. -   */ -  size_t row_off_size; - -  /**     * Expected details about the wire transfer. +   * The member "account_url" is to be allocated +   * at the end of this struct!     */ -  struct TALER_WIRE_TransferDetails details; +  struct TALER_BANK_CreditDetails details;    /**     * RowID in reserves_in table. @@ -389,7 +403,7 @@ struct ReserveOutInfo    /**     * Expected details about the wire transfer.     */ -  struct TALER_WIRE_TransferDetails details; +  struct TALER_BANK_DebitDetails details;  }; @@ -427,8 +441,6 @@ free_rii (void *cls,                   GNUNET_CONTAINER_multihashmap_remove (in_map,                                                         key,                                                         rii)); -  GNUNET_free (rii->details.account_url); -  GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */    GNUNET_free (rii);    return GNUNET_OK;  } @@ -453,8 +465,6 @@ free_roi (void *cls,                   GNUNET_CONTAINER_multihashmap_remove (out_map,                                                         key,                                                         roi)); -  GNUNET_free (roi->details.account_url); -  GNUNET_free_non_null (roi->details.wtid_s); /* field not used (yet) */    GNUNET_free (roi);    return GNUNET_OK;  } @@ -495,6 +505,17 @@ do_shutdown (void *cls)  {    struct WireAccount *wa; +  if (NULL != ctx) +  { +    GNUNET_CURL_fini (ctx); +    ctx = NULL; +  } +  if (NULL != rc) +  { +    GNUNET_CURL_gnunet_rc_destroy (rc); +    rc = NULL; +  } +    if (NULL != report_row_inconsistencies)    {      json_t *report; @@ -617,21 +638,22 @@ do_shutdown (void *cls)    }    while (NULL != (wa = wa_head))    { -    if (NULL != wa->hh) +    if (NULL != wa->dhh)      { -      struct TALER_WIRE_Plugin *wp = wa->wire_plugin; - -      wp->get_history_cancel (wp->cls, -                              wa->hh); -      wa->hh = NULL; +      TALER_BANK_debit_history_cancel (wa->dhh); +      wa->dhh = NULL; +    } +    if (NULL != wa->chh) +    { +      TALER_BANK_credit_history_cancel (wa->chh); +      wa->chh = NULL;      }      GNUNET_CONTAINER_DLL_remove (wa_head,                                   wa_tail,                                   wa); -    TALER_WIRE_plugin_unload (wa->wire_plugin); +    TALER_BANK_auth_free (&wa->auth); +    TALER_WIRE_account_free (&wa->account);      GNUNET_free (wa->section_name); -    GNUNET_free_non_null (wa->in_wire_off); -    GNUNET_free_non_null (wa->out_wire_off);      GNUNET_free (wa);    }    if (NULL != adb) @@ -787,8 +809,7 @@ commit (enum GNUNET_DB_QueryStatus qs)                                                        wa->section_name,                                                        &wa->pp,                                                        wa->in_wire_off, -                                                      wa->out_wire_off, -                                                      wa->wire_off_size); +                                                      wa->out_wire_off);      else        qs = adb->insert_wire_auditor_account_progress (adb->cls,                                                        asession, @@ -796,8 +817,7 @@ commit (enum GNUNET_DB_QueryStatus qs)                                                        wa->section_name,                                                        &wa->pp,                                                        wa->in_wire_off, -                                                      wa->out_wire_off, -                                                      wa->wire_off_size); +                                                      wa->out_wire_off);      if (0 >= qs)      {        GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -1250,9 +1270,7 @@ complain_out_not_found (void *cls,                       "amount_wired", TALER_JSON_from_amount (                         &roi->details.amount),                       "amount_justified", TALER_JSON_from_amount (&zero), -                     "wtid", (NULL == roi->details.wtid_s) -                     ? GNUNET_JSON_from_data_auto (&roi->details.wtid) -                     : json_string (roi->details.wtid_s), +                     "wtid", GNUNET_JSON_from_data_auto (&roi->details.wtid),                       "timestamp", json_from_time_abs (                         roi->details.execution_date),                       "diagnostic", @@ -1317,29 +1335,28 @@ check_exchange_wire_out (struct WireAccount *wa)  /**   * This function is called for all transactions that - * are credited to the exchange's account (incoming + * are debited from the exchange's account (outgoing   * transactions).   *   * @param cls `struct WireAccount` with current wire account to process + * @param http_status_code http status of the request   * @param ec error code in case something went wrong - * @param dir direction of the transfer   * @param row_off identification of the position at which we are querying - * @param row_off_size number of bytes in @a row_off   * @param details details about the wire transfer   * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */  static int  history_debit_cb (void *cls, +                  unsigned int http_status_code,                    enum TALER_ErrorCode ec, -                  enum TALER_BANK_Direction dir, -                  const void *row_off, -                  size_t row_off_size, -                  const struct TALER_WIRE_TransferDetails *details) +                  uint64_t row_off, +                  const struct TALER_BANK_DebitDetails *details, +                  const json_t *json)  {    struct WireAccount *wa = cls;    struct ReserveOutInfo *roi; -  if (TALER_BANK_DIRECTION_NONE == dir) +  if (NULL == details)    {      if (TALER_EC_NONE != ec)      { @@ -1348,7 +1365,7 @@ history_debit_cb (void *cls,                    "Error fetching history: %u!\n",                    (unsigned int) ec);      } -    wa->hh = NULL; +    wa->dhh = NULL;      check_exchange_wire_out (wa);      return GNUNET_OK;    } @@ -1357,45 +1374,8 @@ history_debit_cb (void *cls,                GNUNET_STRINGS_absolute_time_to_string (details->execution_date),                TALER_amount2s (&details->amount),                TALER_B2S (&details->wtid)); -  if (NULL != details->wtid_s) -  { -    char *diagnostic; - -    GNUNET_asprintf (&diagnostic, -                     "malformed subject `%s'", -                     details->wtid_s); -    GNUNET_break (GNUNET_OK == -                  TALER_amount_add (&total_wire_format_amount, -                                    &total_wire_format_amount, -                                    &details->amount)); -    report (report_wire_format_inconsistencies, -            json_pack ("{s:o, s:o, s:s}", -                       "amount", TALER_JSON_from_amount (&details->amount), -                       "wire_offset", GNUNET_JSON_from_data (row_off, -                                                             row_off_size), -                       "diagnostic", diagnostic)); -    GNUNET_free (diagnostic); -    return GNUNET_OK; -  } -    /* Update offset */ -  if (NULL == wa->out_wire_off) -  { -    wa->wire_off_size = row_off_size; -    wa->out_wire_off = GNUNET_malloc (row_off_size); -  } -  if (wa->wire_off_size != row_off_size) -  { -    GNUNET_break (0); -    commit (GNUNET_DB_STATUS_HARD_ERROR); -    wa->hh = NULL; -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  memcpy (wa->out_wire_off, -          row_off, -          row_off_size); - +  wa->out_wire_off = row_off;    roi = GNUNET_new (struct ReserveOutInfo);    GNUNET_CRYPTO_hash (&details->wtid,                        sizeof (details->wtid), @@ -1420,10 +1400,9 @@ history_debit_cb (void *cls,                                      &total_wire_format_amount,                                      &details->amount));      report (report_wire_format_inconsistencies, -            json_pack ("{s:o, s:o, s:s}", +            json_pack ("{s:o, s:I, s:s}",                         "amount", TALER_JSON_from_amount (&details->amount), -                       "wire_offset", GNUNET_JSON_from_data (row_off, -                                                             row_off_size), +                       "wire_offset", (json_int_t) row_off,                         "diagnostic", diagnostic));      GNUNET_free (diagnostic);      return GNUNET_OK; @@ -1443,7 +1422,6 @@ static void  process_debits (void *cls)  {    struct WireAccount *wa = cls; -  struct TALER_WIRE_Plugin *wp;    /* skip accounts where DEBIT is not enabled */    while ( (NULL != wa) && @@ -1459,17 +1437,16 @@ process_debits (void *cls)    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Checking bank DEBIT records of account `%s'\n",                wa->section_name); -  GNUNET_assert (NULL == wa->hh); -  wp = wa->wire_plugin; -  wa->hh = wp->get_history (wp->cls, -                            wa->section_name, -                            TALER_BANK_DIRECTION_DEBIT, -                            wa->out_wire_off, -                            wa->wire_off_size, -                            INT64_MAX, -                            &history_debit_cb, -                            wa); -  if (NULL == wa->hh) +  GNUNET_assert (NULL == wa->dhh); +  wa->dhh = TALER_BANK_debit_history (ctx, +                                      wa->account.details.x_taler_bank. +                                      account_base_url, +                                      &wa->auth, +                                      wa->out_wire_off, +                                      INT64_MAX, +                                      &history_debit_cb, +                                      wa); +  if (NULL == wa->dhh)    {      fprintf (stderr,               "Failed to obtain bank transaction history for `%s'\n", @@ -1519,24 +1496,25 @@ conclude_credit_history ()   * @param rowid unique serial ID for the entry in our DB   * @param reserve_pub public key of the reserve (also the WTID)   * @param credit amount that was received - * @param sender_url payto://-URL of the sender's bank account - * @param wire_reference unique identifier for the wire transfer (plugin-specific format) - * @param wire_reference_size number of bytes in @a wire_reference + * @param sender_account_details payto://-URL of the sender's bank account + * @param wire_reference unique identifier for the wire transfer   * @param execution_date when did we receive the funds   * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop   */  static int  reserve_in_cb (void *cls,                 uint64_t rowid, -               const struct TALER_ReservePublicKeyP *reserve_pub, +               const struct +               TALER_ReservePublicKeyP *reserve_pub,                 const struct TALER_Amount *credit, -               const char *sender_url, -               const void *wire_reference, -               size_t wire_reference_size, -               struct GNUNET_TIME_Absolute execution_date) +               const char *sender_account_details, +               uint64_t wire_reference, +               struct GNUNET_TIME_Absolute +               execution_date)  {    struct WireAccount *wa = cls;    struct ReserveInInfo *rii; +  size_t slen;    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Analyzing exchange wire IN (%llu) at %s of %s with reserve_pub %s\n", @@ -1544,21 +1522,20 @@ reserve_in_cb (void *cls,                GNUNET_STRINGS_absolute_time_to_string (execution_date),                TALER_amount2s (credit),                TALER_B2S (reserve_pub)); -  rii = GNUNET_new (struct ReserveInInfo); -  GNUNET_CRYPTO_hash (wire_reference, -                      wire_reference_size, -                      &rii->row_off_hash); -  rii->row_off_size = wire_reference_size; +  slen = strlen (sender_account_details) + 1; +  rii = GNUNET_malloc (sizeof (struct ReserveInInfo) +                       + slen); +  rii->rowid = rowid;    rii->details.amount = *credit;    rii->details.execution_date = execution_date; -  /* reserve public key should be the WTID */ -  GNUNET_assert (sizeof (rii->details.wtid) == -                 sizeof (*reserve_pub)); -  memcpy (&rii->details.wtid, -          reserve_pub, -          sizeof (*reserve_pub)); -  rii->details.account_url = GNUNET_strdup (sender_url); -  rii->rowid = rowid; +  rii->details.reserve_pub = *reserve_pub; +  rii->details.account_url = (const char *) &rii[1]; +  memcpy (&rii[1], +          sender_account_details, +          slen); +  GNUNET_CRYPTO_hash (&wire_reference, +                      sizeof (uint64_t), +                      &rii->row_off_hash);    if (GNUNET_OK !=        GNUNET_CONTAINER_multihashmap_put (in_map,                                           &rii->row_off_hash, @@ -1572,8 +1549,6 @@ reserve_in_cb (void *cls,                         "wire_offset_hash", GNUNET_JSON_from_data_auto (                           &rii->row_off_hash),                         "diagnostic", "duplicate wire offset")); -    GNUNET_free (rii->details.account_url); -    GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */      GNUNET_free (rii);      return GNUNET_OK;    } @@ -1604,7 +1579,8 @@ complain_in_not_found (void *cls,                       "amount_exchange_expected", TALER_JSON_from_amount (                         &rii->details.amount),                       "amount_wired", TALER_JSON_from_amount (&zero), -                     "wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid), +                     "reserve_pub", GNUNET_JSON_from_data_auto ( +                       &rii->details.reserve_pub),                       "timestamp", json_from_time_abs (                         rii->details.execution_date),                       "account", wa->section_name, @@ -1635,25 +1611,24 @@ process_credits (void *cls);   *   * @param cls `struct WireAccount` we are processing   * @param ec error code in case something went wrong - * @param dir direction of the transfer   * @param row_off identification of the position at which we are querying - * @param row_off_size number of bytes in @a row_off   * @param details details about the wire transfer + * @param json raw response   * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */  static int  history_credit_cb (void *cls, +                   unsigned int http_status,                     enum TALER_ErrorCode ec, -                   enum TALER_BANK_Direction dir, -                   const void *row_off, -                   size_t row_off_size, -                   const struct TALER_WIRE_TransferDetails *details) +                   uint64_t row_off, +                   const struct TALER_BANK_CreditDetails *details, +                   const json_t *json)  {    struct WireAccount *wa = cls;    struct ReserveInInfo *rii;    struct GNUNET_HashCode key; -  if (TALER_BANK_DIRECTION_NONE == dir) +  if (NULL == details)    {      if (TALER_EC_NONE != ec)      { @@ -1663,7 +1638,7 @@ history_credit_cb (void *cls,                    (unsigned int) ec);      }      /* end of operation */ -    wa->hh = NULL; +    wa->chh = NULL;      GNUNET_log (GNUNET_ERROR_TYPE_INFO,                  "Reconciling CREDIT processing of account `%s'\n",                  wa->section_name); @@ -1678,12 +1653,12 @@ history_credit_cb (void *cls,      return GNUNET_OK;    }    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Analyzing bank CREDIT at %s of %s with WTID %s\n", +              "Analyzing bank CREDIT at %s of %s with Reserve-pub %s\n",                GNUNET_STRINGS_absolute_time_to_string (details->execution_date),                TALER_amount2s (&details->amount), -              TALER_B2S (&details->wtid)); -  GNUNET_CRYPTO_hash (row_off, -                      row_off_size, +              TALER_B2S (&details->reserve_pub)); +  GNUNET_CRYPTO_hash (&row_off, +                      sizeof (row_off),                        &key);    rii = GNUNET_CONTAINER_multihashmap_get (in_map,                                             &key); @@ -1693,55 +1668,26 @@ history_credit_cb (void *cls,                  "Failed to find wire transfer at `%s' in exchange database. Audit ends at this point in time.\n",                  GNUNET_STRINGS_absolute_time_to_string (                    details->execution_date)); -    wa->hh = NULL; +    wa->chh = NULL;      process_credits (wa->next);      return GNUNET_SYSERR; /* not an error, just end of processing */    }    /* Update offset */ -  if (NULL == wa->in_wire_off) -  { -    wa->wire_off_size = row_off_size; -    wa->in_wire_off = GNUNET_malloc (row_off_size); -  } -  if (wa->wire_off_size != row_off_size) -  { -    GNUNET_break (0); -    commit (GNUNET_DB_STATUS_HARD_ERROR); -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  memcpy (wa->in_wire_off, -          row_off, -          row_off_size); - - +  wa->in_wire_off = row_off;    /* compare records with expected data */ -  if (row_off_size != rii->row_off_size) -  { -    GNUNET_break (0); -    report (report_row_inconsistencies, -            json_pack ("{s:s, s:I, s:o, s:o, s:s}", -                       "table", "reserves_in", -                       "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), -                       "wire_offset_hash", GNUNET_JSON_from_data_auto (&key), -                       "diagnostic", "wire reference size missmatch")); -    return GNUNET_OK; -  } -  if (0 != GNUNET_memcmp (&details->wtid, -                          &rii->details.wtid)) +  if (0 != GNUNET_memcmp (&details->reserve_pub, +                          &rii->details.reserve_pub))    {      report (report_reserve_in_inconsistencies, -            json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}", +            json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",                         "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), +                       "bank_row", (json_int_t) row_off,                         "amount_exchange_expected", TALER_JSON_from_amount (                           &rii->details.amount),                         "amount_wired", TALER_JSON_from_amount (&zero), -                       "wtid", GNUNET_JSON_from_data_auto (&rii->details.wtid), +                       "reserve_pub", GNUNET_JSON_from_data_auto ( +                         &rii->details.reserve_pub),                         "timestamp", json_from_time_abs (                           rii->details.execution_date),                         "diagnostic", "wire subject does not match")); @@ -1750,15 +1696,15 @@ history_credit_cb (void *cls,                                      &total_bad_amount_in_minus,                                      &rii->details.amount));      report (report_reserve_in_inconsistencies, -            json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}", +            json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",                         "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), +                       "bank_row", (json_int_t) row_off,                         "amount_exchange_expected", TALER_JSON_from_amount (                           &zero),                         "amount_wired", TALER_JSON_from_amount (                           &details->amount), -                       "wtid", GNUNET_JSON_from_data_auto (&details->wtid), +                       "reserve_pub", GNUNET_JSON_from_data_auto ( +                         &details->reserve_pub),                         "timestamp", json_from_time_abs (                           details->execution_date),                         "diagnostic", "wire subject does not match")); @@ -1773,15 +1719,15 @@ history_credit_cb (void *cls,                               &details->amount))    {      report (report_reserve_in_inconsistencies, -            json_pack ("{s:I, s:o, s:o, s:o, s:o, s:o, s:s}", +            json_pack ("{s:I, s:I, s:o, s:o, s:o, s:o, s:s}",                         "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), +                       "bank_row", (json_int_t) row_off,                         "amount_exchange_expected", TALER_JSON_from_amount (                           &rii->details.amount),                         "amount_wired", TALER_JSON_from_amount (                           &details->amount), -                       "wtid", GNUNET_JSON_from_data_auto (&details->wtid), +                       "reserve_pub", GNUNET_JSON_from_data_auto ( +                         &details->reserve_pub),                         "timestamp", json_from_time_abs (                           details->execution_date),                         "diagnostic", "wire amount does not match")); @@ -1820,13 +1766,12 @@ history_credit_cb (void *cls,                         rii->details.account_url))    {      report (report_missattribution_in_inconsistencies, -            json_pack ("{s:o, s:I, s:o, s:o}", +            json_pack ("{s:o, s:I, s:I, s:o}",                         "amount", TALER_JSON_from_amount (&rii->details.amount),                         "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), -                       "wtid", GNUNET_JSON_from_data_auto ( -                         &rii->details.wtid))); +                       "bank_row", (json_int_t) row_off, +                       "reserve_pub", GNUNET_JSON_from_data_auto ( +                         &rii->details.reserve_pub)));      GNUNET_break (GNUNET_OK ==                    TALER_amount_add (&total_missattribution_in,                                      &total_missattribution_in, @@ -1836,11 +1781,10 @@ history_credit_cb (void *cls,        rii->details.execution_date.abs_value_us)    {      report (report_row_minor_inconsistencies, -            json_pack ("{s:s, s:I, s:o, s:s}", +            json_pack ("{s:s, s:I, s:I, s:s}",                         "table", "reserves_in",                         "row", (json_int_t) rii->rowid, -                       "raw_bank_row", GNUNET_JSON_from_data (row_off, -                                                              row_off_size), +                       "bank_row", (json_int_t) row_off,                         "diagnostic", "execution date missmatch"));    }  cleanup: @@ -1865,7 +1809,6 @@ static void  process_credits (void *cls)  {    struct WireAccount *wa = cls; -  struct TALER_WIRE_Plugin *wp;    enum GNUNET_DB_QueryStatus qs;    /* skip accounts where CREDIT is not enabled */ @@ -1899,16 +1842,15 @@ process_credits (void *cls)    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                "Starting bank CREDIT history of account `%s'\n",                wa->section_name); -  wp = wa->wire_plugin; -  wa->hh = wp->get_history (wp->cls, -                            wa->section_name, -                            TALER_BANK_DIRECTION_CREDIT, -                            wa->in_wire_off, -                            wa->wire_off_size, -                            INT64_MAX, -                            &history_credit_cb, -                            wa); -  if (NULL == wa->hh) +  wa->chh = TALER_BANK_credit_history (ctx, +                                       wa->account.details.x_taler_bank. +                                       account_base_url, +                                       &wa->auth, +                                       wa->in_wire_off, +                                       INT64_MAX, +                                       &history_credit_cb, +                                       wa); +  if (NULL == wa->chh)    {      fprintf (stderr,               "Failed to obtain bank transaction history\n"); @@ -2037,8 +1979,7 @@ begin_transaction ()                                                    wa->section_name,                                                    &wa->pp,                                                    &wa->in_wire_off, -                                                  &wa->out_wire_off, -                                                  &wa->wire_off_size); +                                                  &wa->out_wire_off);      if (0 > qsx)      {        GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx); @@ -2096,30 +2037,62 @@ process_account_cb (void *cls,                      const struct TALER_EXCHANGEDB_AccountInfo *ai)  {    struct WireAccount *wa; -  struct TALER_WIRE_Plugin *wp;    if ( (GNUNET_NO == ai->debit_enabled) &&         (GNUNET_NO == ai->credit_enabled) )      return; /* not an active exchange account */ -  wp = TALER_WIRE_plugin_load (cfg, -                               ai->plugin_name); -  if (NULL == wp) -  { -    fprintf (stderr, -             "Failed to load wire plugin `%s'\n", -             ai->plugin_name); -    global_ret = 1; -    GNUNET_SCHEDULER_shutdown (); -    return; -  }    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Found exchange account `%s'\n",                ai->section_name);    wa = GNUNET_new (struct WireAccount); -  wa->wire_plugin = wp;    wa->section_name = GNUNET_strdup (ai->section_name);    wa->watch_debit = ai->debit_enabled;    wa->watch_credit = ai->credit_enabled; +  if (GNUNET_OK != +      TALER_BANK_auth_parse_cfg (cfg, +                                 ai->section_name, +                                 &wa->auth)) +  { +    GNUNET_break (0); +    GNUNET_free (wa->section_name); +    GNUNET_free (wa); +    fprintf (stderr, +             "Failed to access bank account `%s'\n", +             wa->section_name); +    global_ret = 1; +    GNUNET_SCHEDULER_shutdown (); +    return; +  } +  if (GNUNET_OK != +      TALER_BANK_account_parse_cfg (cfg, +                                    wa->section_name, +                                    &wa->account)) +  { +    GNUNET_break (0); +    TALER_BANK_auth_free (&wa->auth); +    GNUNET_free (wa->section_name); +    GNUNET_free (wa); +    fprintf (stderr, +             "Failed to access bank account `%s'\n", +             wa->section_name); +    global_ret = 1; +    GNUNET_SCHEDULER_shutdown (); +    return; +  } +  if (TALER_PAC_X_TALER_BANK != wa->account.type) +  { +    GNUNET_break (0); +    TALER_WIRE_account_free (&wa->account); +    TALER_BANK_auth_free (&wa->auth); +    GNUNET_free (wa->section_name); +    GNUNET_free (wa); +    fprintf (stderr, +             "Need x-taler-bank account URL in `%s'\n", +             wa->section_name); +    global_ret = 1; +    GNUNET_SCHEDULER_shutdown (); +    return; +  }    GNUNET_CONTAINER_DLL_insert (wa_head,                                 wa_tail,                                 wa); @@ -2258,6 +2231,14 @@ run (void *cls,    }    GNUNET_SCHEDULER_add_shutdown (&do_shutdown,                                   NULL); +  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, +                          &rc); +  rc = GNUNET_CURL_gnunet_rc_create (ctx); +  if (NULL == ctx) +  { +    GNUNET_break (0); +    return; +  }    esession = edb->get_session (edb->cls);    if (NULL == esession)    { diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c index 060e745d..7360258a 100644 --- a/src/auditordb/plugin_auditordb_postgres.c +++ b/src/auditordb/plugin_auditordb_postgres.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2018 GNUnet e.V. +  Copyright (C) 2014-2020 GNUnet e.V.    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -241,8 +241,8 @@ postgres_create_tables (void *cls)        ",account_name TEXT NOT NULL"        ",last_wire_reserve_in_serial_id INT8 NOT NULL DEFAULT 0"        ",last_wire_wire_out_serial_id INT8 NOT NULL DEFAULT 0" -      ",wire_in_off BYTEA" -      ",wire_out_off BYTEA" +      ",wire_in_off INT8" +      ",wire_out_off INT8"        ")"),      GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_progress"                              "(master_pub BYTEA CONSTRAINT master_pub_ref REFERENCES auditor_exchanges(master_pub) ON DELETE CASCADE" @@ -2135,23 +2135,16 @@ postgres_insert_wire_auditor_account_progress (void *cls,                                                 const struct                                                 TALER_AUDITORDB_WireAccountProgressPoint                                                 *pp, -                                               const void *in_wire_off, -                                               const void *out_wire_off, -                                               size_t wire_off_size) +                                               uint64_t in_wire_off, +                                               uint64_t out_wire_off)  {    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_auto_from_type (master_pub),      GNUNET_PQ_query_param_string (account_name),      GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),      GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), -    GNUNET_PQ_query_param_fixed_size (in_wire_off, -                                      NULL == in_wire_off -                                      ? 0 -                                      : wire_off_size), -    GNUNET_PQ_query_param_fixed_size (out_wire_off, -                                      NULL == out_wire_off -                                      ? 0 -                                      : wire_off_size), +    GNUNET_PQ_query_param_uint64 (&in_wire_off), +    GNUNET_PQ_query_param_uint64 (&out_wire_off),      GNUNET_PQ_query_param_end    }; @@ -2182,21 +2175,14 @@ postgres_update_wire_auditor_account_progress (void *cls,                                                 const struct                                                 TALER_AUDITORDB_WireAccountProgressPoint                                                 *pp, -                                               const void *in_wire_off, -                                               const void *out_wire_off, -                                               size_t wire_off_size) +                                               uint64_t in_wire_off, +                                               uint64_t out_wire_off)  {    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_uint64 (&pp->last_reserve_in_serial_id),      GNUNET_PQ_query_param_uint64 (&pp->last_wire_out_serial_id), -    GNUNET_PQ_query_param_fixed_size (in_wire_off, -                                      NULL == in_wire_off -                                      ? 0 -                                      : wire_off_size), -    GNUNET_PQ_query_param_fixed_size (out_wire_off, -                                      NULL == out_wire_off -                                      ? 0 -                                      : wire_off_size), +    GNUNET_PQ_query_param_uint64 (&in_wire_off), +    GNUNET_PQ_query_param_uint64 (&out_wire_off),      GNUNET_PQ_query_param_auto_from_type (master_pub),      GNUNET_PQ_query_param_string (account_name),      GNUNET_PQ_query_param_end @@ -2231,12 +2217,9 @@ postgres_get_wire_auditor_account_progress (void *cls,                                              struct                                              TALER_AUDITORDB_WireAccountProgressPoint                                              *pp, -                                            void **in_wire_off, -                                            void **out_wire_off, -                                            size_t *wire_off_size) +                                            uint64_t *in_wire_off, +                                            uint64_t *out_wire_off)  { -  size_t xsize; -  enum GNUNET_DB_QueryStatus qs;    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_auto_from_type (master_pub),      GNUNET_PQ_query_param_string (account_name), @@ -2247,30 +2230,17 @@ postgres_get_wire_auditor_account_progress (void *cls,                                    &pp->last_reserve_in_serial_id),      GNUNET_PQ_result_spec_uint64 ("last_wire_wire_out_serial_id",                                    &pp->last_wire_out_serial_id), -    GNUNET_PQ_result_spec_variable_size ("wire_in_off", -                                         in_wire_off, -                                         wire_off_size), -    GNUNET_PQ_result_spec_variable_size ("wire_out_off", -                                         out_wire_off, -                                         &xsize), +    GNUNET_PQ_result_spec_uint64 ("wire_in_off", +                                  in_wire_off), +    GNUNET_PQ_result_spec_uint64 ("wire_out_off", +                                  out_wire_off),      GNUNET_PQ_result_spec_end    }; -  qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn, -                                                 "wire_auditor_account_progress_select", -                                                 params, -                                                 rs); -  if (qs <= 0) -  { -    *wire_off_size = 0; -    xsize = 0; -  } -  if ( (0 != xsize) && -       (0 != *wire_off_size) ) -  { -    GNUNET_assert (xsize == *wire_off_size); -  } -  return qs; +  return GNUNET_PQ_eval_prepared_singleton_select (session->conn, +                                                   "wire_auditor_account_progress_select", +                                                   params, +                                                   rs);  } diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index 3bb86323..371f5e6d 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -39,8 +39,9 @@ libtalerbank_la_LDFLAGS = \  libtalerbank_la_SOURCES = \    bank_api_admin.c \    bank_api_common.c bank_api_common.h \ -  bank_api_history.c \ -  bank_api_reject.c \ +  bank_api_credit.c \ +  bank_api_debit.c \ +  bank_api_transaction.c \    bank_api_parse.c  libtalerbank_la_LIBADD = \    $(top_builddir)/src/json/libtalerjson.la \ @@ -55,10 +56,10 @@ libtalerfakebank_la_LDFLAGS = \    -version-info 0:0:0 \    -no-undefined  libtalerfakebank_la_SOURCES = \ -  fakebank_history.c \ -  fakebank.c fakebank.h +  fakebank.c  libtalerfakebank_la_LIBADD = \    $(top_builddir)/src/json/libtalerjson.la \ +  $(top_builddir)/src/mhd/libtalermhd.la \    -lgnunetjson \    -lgnunetutil \    -ljansson \ @@ -69,8 +70,8 @@ libtalerbanktesting_la_LDFLAGS = \    -version-info 0:0:0 \    -no-undefined  libtalerbanktesting_la_SOURCES = \ -  testing_api_cmd_history.c \ -  testing_api_cmd_reject.c \ +  testing_api_cmd_history_credit.c \ +  testing_api_cmd_history_debit.c \    testing_api_helpers.c  libtalerbanktesting_la_LIBADD = \    $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/bank-lib/bank_api_admin.c b/src/bank-lib/bank_api_admin.c index 5240a372..068fd0e0 100644 --- a/src/bank-lib/bank_api_admin.c +++ b/src/bank-lib/bank_api_admin.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015, 2016, 2017 Taler Systems SA +  Copyright (C) 2015--2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -166,13 +166,11 @@ handle_admin_add_incoming_finished (void *cls,   * to the operators of the bank.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param account_base_url URL of the bank (used to execute this request)   * @param auth authentication data to send to the bank - * @param exchange_base_url base URL of the exchange (for tracking) - * @param subject wire transfer subject for the transfer + * @param reserve_pub wire transfer subject for the transfer   * @param amount amount that was deposited - * @param debit_account_no account number to withdraw from (53 bits at most) - * @param credit_account_no account number to deposit into (53 bits at most) + * @param credit_account account to deposit into (payto)   * @param res_cb the callback to call when the final result for this request is available   * @param res_cb_cls closure for the above callback   * @return NULL @@ -181,13 +179,12 @@ handle_admin_add_incoming_finished (void *cls,   */  struct TALER_BANK_AdminAddIncomingHandle *  TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, -                               const char *bank_base_url, +                               const char *account_base_url,                                 const struct TALER_BANK_AuthenticationData *auth, -                               const char *exchange_base_url, -                               const char *subject, +                               const struct +                               TALER_ReservePublicKeyP *reserve_pub,                                 const struct TALER_Amount *amount, -                               uint64_t debit_account_no, -                               uint64_t credit_account_no, +                               const char *credit_account,                                 TALER_BANK_AdminAddIncomingResultCallback res_cb,                                 void *res_cb_cls)  { @@ -195,18 +192,10 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,    json_t *admin_obj;    CURL *eh; -  if (NULL == exchange_base_url) -  { -    GNUNET_break (0); -    return NULL; -  } -  admin_obj = json_pack ("{s:{s:s}, s:s, s:s, s:o, s:I, s:I}", -                         "auth", "type", "basic", -                         "exchange_url", exchange_base_url, -                         "subject", subject, +  admin_obj = json_pack ("{s:o, s:o, s:s}", +                         "subject", GNUNET_JSON_from_data_auto (reserve_pub),                           "amount", TALER_JSON_from_amount (amount), -                         "debit_account", (json_int_t) debit_account_no, -                         "credit_account", (json_int_t) credit_account_no); +                         "credit_account", credit_account);    if (NULL == admin_obj)    {      GNUNET_break (0); @@ -215,27 +204,33 @@ TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx,    aai = GNUNET_new (struct TALER_BANK_AdminAddIncomingHandle);    aai->cb = res_cb;    aai->cb_cls = res_cb_cls; -  aai->request_url = TALER_BANK_path_to_url_ (bank_base_url, +  aai->request_url = TALER_BANK_path_to_url_ (account_base_url,                                                "/admin/add/incoming"); -  aai->post_ctx.headers = TALER_BANK_make_auth_header_ (auth); - -  GNUNET_assert -    (NULL != (aai->post_ctx.headers = curl_slist_append -                                        (aai->post_ctx.headers, -                                        "Content-Type: application/json"))); +  aai->post_ctx.headers = curl_slist_append +                            (aai->post_ctx.headers, +                            "Content-Type: application/json");    eh = curl_easy_init (); - -  GNUNET_assert (GNUNET_OK == -                 TALER_curl_easy_post (&aai->post_ctx, eh, admin_obj)); - +  if ( (GNUNET_OK != +        TALER_BANK_setup_auth_ (eh, +                                auth)) || +       (CURLE_OK != +        curl_easy_setopt (eh, +                          CURLOPT_URL, +                          aai->request_url)) || +       (GNUNET_OK != +        TALER_curl_easy_post (&aai->post_ctx, +                              eh, +                              admin_obj)) ) +  { +    GNUNET_break (0); +    TALER_BANK_admin_add_incoming_cancel (aai); +    curl_easy_cleanup (eh); +    json_decref (admin_obj); +    return NULL; +  }    json_decref (admin_obj); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_URL, -                                   aai->request_url)); -    aai->job = GNUNET_CURL_job_add2 (ctx,                                     eh,                                     aai->post_ctx.headers, diff --git a/src/bank-lib/bank_api_common.c b/src/bank-lib/bank_api_common.c index 50769dae..8a8f4289 100644 --- a/src/bank-lib/bank_api_common.c +++ b/src/bank-lib/bank_api_common.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015, 2016, 2017 GNUnet e.V. +  Copyright (C) 2015-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -24,67 +24,47 @@  /** - * Append HTTP key-value pair to curl header list. + * Set authentication data in @a easy from @a auth. + * The API currently specifies the use of HTTP basic + * authentication.   * - * @param hdr list to append to, can be NULL - * @param key key to append - * @param value value to append - * @return new list, NULL on error + * @param easy curl handle to setup for authentication + * @param auth authentication data to use + * @return #GNUNET_OK in success   */ -static struct curl_slist * -append (struct curl_slist *hdr, -        const char *key, -        const char *value) +int +TALER_BANK_setup_auth_ (CURL *easy, +                        const struct TALER_BANK_AuthenticationData *auth)  { -  char *str; -  struct curl_slist *ret; - -  GNUNET_asprintf (&str, -                   "%s: %s", -                   key, -                   value); -  ret = curl_slist_append (hdr, -                           str); -  GNUNET_free (str); -  if (NULL == ret) -  { -    GNUNET_break (0); -    curl_slist_free_all (hdr); -    return NULL; -  } -  return ret; -} - - -/** - * Build authentication header from @a auth. - * - * @param auth authentication data to use. - * - * @return NULL on error, otherwise curl headers to use. - */ -struct curl_slist * -TALER_BANK_make_auth_header_ -  (const struct TALER_BANK_AuthenticationData *auth) -{ -  struct curl_slist *authh; +  int ret; +  ret = GNUNET_OK;    switch (auth->method)    {    case TALER_BANK_AUTH_NONE: -    return NULL; +    return GNUNET_OK;    case TALER_BANK_AUTH_BASIC: -    authh = append (NULL, -                    "X-Taler-Bank-Username", -                    auth->details.basic.username); -    if (NULL == authh) -      return NULL; -    authh = append (authh, -                    "X-Taler-Bank-Password", -                    auth->details.basic.password); -    return authh; +    { +      char *up; + +      GNUNET_asprintf (&up, +                       "%s:%s", +                       auth->details.basic.username, +                       auth->details.basic.password); +      if ( (CURLE_OK != +            curl_easy_setopt (easy, +                              CURLOPT_HTTPAUTH, +                              CURLAUTH_BASIC)) || +           (CURLE_OK != +            curl_easy_setopt (easy, +                              CURLOPT_USERPWD, +                              up)) ) +        ret = GNUNET_SYSERR; +      GNUNET_free (up); +      break; +    }    } -  return NULL; +  return ret;  } diff --git a/src/bank-lib/bank_api_common.h b/src/bank-lib/bank_api_common.h index fcf2029d..1120ed94 100644 --- a/src/bank-lib/bank_api_common.h +++ b/src/bank-lib/bank_api_common.h @@ -40,6 +40,18 @@ TALER_BANK_make_auth_header_ (const struct TALER_BANK_AuthenticationData *auth);  /** + * Set authentication data in @a easy from @a auth. + * + * @param easy curl handle to setup for authentication + * @param auth authentication data to use + * @return #GNUNET_OK in success + */ +int +TALER_BANK_setup_auth_ (CURL *easy, +                        const struct TALER_BANK_AuthenticationData *auth); + + +/**   * Obtain the URL to use for an API request.   *   * @param u base URL of the bank diff --git a/src/bank-lib/bank_api_credit.c b/src/bank-lib/bank_api_credit.c new file mode 100644 index 00000000..ed0a1e2a --- /dev/null +++ b/src/bank-lib/bank_api_credit.c @@ -0,0 +1,315 @@ +/* +  This file is part of TALER +  Copyright (C) 2017--2020 Taler Systems SA + +  TALER is free software; you can redistribute it and/or +  modify it under the terms of the GNU General Public License +  as published by the Free Software Foundation; either version 3, +  or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, +  but WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public +  License along with TALER; see the file COPYING.  If not, +  see <http://www.gnu.org/licenses/> +*/ +/** + * @file bank-lib/bank_api_history.c + * @brief Implementation of the /history[-range] + *        requests of the bank's HTTP API. + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "bank_api_common.h" +#include <microhttpd.h> /* just for HTTP status codes */ +#include "taler_signatures.h" + + +/** + * @brief A /history Handle + */ +struct TALER_BANK_CreditHistoryHandle +{ + +  /** +   * The url for this request. +   */ +  char *request_url; + +  /** +   * The base URL of the bank. +   */ +  char *bank_base_url; + +  /** +   * Handle for the request. +   */ +  struct GNUNET_CURL_Job *job; + +  /** +   * Function to call with the result. +   */ +  TALER_BANK_CreditResultCallback hcb; + +  /** +   * Closure for @a cb. +   */ +  void *hcb_cls; +}; + + +/** + * Parse history given in JSON format and invoke the callback on each item. + * + * @param hh handle to the account history request + * @param history JSON array with the history + * @return #GNUNET_OK if history was valid and @a rhistory and @a balance + *         were set, + *         #GNUNET_SYSERR if there was a protocol violation in @a history + */ +static int +parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh, +                       const json_t *history) +{ +  json_t *history_array; + +  if (NULL == (history_array = json_object_get (history, +                                                "data"))) +  { +    GNUNET_break_op (0); +    return GNUNET_SYSERR; +  } +  if (! json_is_array (history_array)) +  { +    GNUNET_break_op (0); +    return GNUNET_SYSERR; +  } +  for (unsigned int i = 0; i<json_array_size (history_array); i++) +  { +    struct TALER_BANK_CreditDetails td; +    uint64_t row_id; +    struct GNUNET_JSON_Specification hist_spec[] = { +      TALER_JSON_spec_amount ("amount", +                              &td.amount), +      GNUNET_JSON_spec_absolute_time ("date", +                                      &td.execution_date), +      GNUNET_JSON_spec_uint64 ("row_id", +                               &row_id), +      GNUNET_JSON_spec_fixed_auto ("reserve_pub", +                                   &td.reserve_pub), +      GNUNET_JSON_spec_string ("counterpart", +                               &td.account_url), +      GNUNET_JSON_spec_end () +    }; +    json_t *transaction = json_array_get (history_array, +                                          i); + +    if (GNUNET_OK != +        GNUNET_JSON_parse (transaction, +                           hist_spec, +                           NULL, NULL)) +    { +      GNUNET_break_op (0); +      return GNUNET_SYSERR; +    } +    hh->hcb (hh->hcb_cls, +             MHD_HTTP_OK, +             TALER_EC_NONE, +             row_id, +             &td, +             transaction); +    GNUNET_JSON_parse_free (hist_spec); +  } +  return GNUNET_OK; +} + + +/** + * Function called when we're done processing the + * HTTP /history request. + * + * @param cls the `struct TALER_BANK_CreditHistoryHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_history_finished (void *cls, +                         long response_code, +                         const void *response) +{ +  struct TALER_BANK_CreditHistoryHandle *hh = cls; +  enum TALER_ErrorCode ec; +  const json_t *j = response; + +  hh->job = NULL; +  switch (response_code) +  { +  case 0: +    ec = TALER_EC_INVALID_RESPONSE; +    break; +  case MHD_HTTP_OK: +    if (GNUNET_OK != +        parse_account_history (hh, +                               j)) +    { +      GNUNET_break_op (0); +      response_code = 0; +      ec = TALER_EC_INVALID_RESPONSE; +      break; +    } +    response_code = MHD_HTTP_NO_CONTENT; /* signal end of list */ +    ec = TALER_EC_NONE; +    break; +  case MHD_HTTP_NO_CONTENT: +    ec = TALER_EC_NONE; +    break; +  case MHD_HTTP_BAD_REQUEST: +    /* This should never happen, either us or the bank is buggy +       (or API version conflict); just pass JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_FORBIDDEN: +    /* Access denied */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_UNAUTHORIZED: +    /* Nothing really to verify, bank says one of the signatures is +       invalid; as we checked them, this should never happen, we +       should pass the JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_NOT_FOUND: +    /* Nothing really to verify, this should never +       happen, we should pass the JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_INTERNAL_SERVER_ERROR: +    /* Server had an internal issue; we should retry, but this API +       leaves this to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  default: +    /* unexpected response code */ +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Unexpected response code %u\n", +                (unsigned int) response_code); +    GNUNET_break (0); +    ec = TALER_BANK_parse_ec_ (j); +    response_code = 0; +    break; +  } +  hh->hcb (hh->hcb_cls, +           response_code, +           ec, +           0LLU, +           NULL, +           j); +  TALER_BANK_credit_history_cancel (hh); +} + + +/** + * Request the credit history of the exchange's bank account. + * + * @param ctx curl context for the event loop + * @param bank_base_url URL of the base INCLUDING account number + * @param auth authentication data to use + * @param start_row from which row on do we want to get results, + *        use UINT64_MAX for the latest; exclusive + * @param num_results how many results do we want; + *        negative numbers to go into the past, positive numbers + *        to go into the future starting at @a start_row; + *        must not be zero. + * @param hres_cb the callback to call with the transaction + *        history + * @param hres_cb_cls closure for the above callback + * @return NULL if the inputs are invalid (i.e. zero value for + *         @e num_results). In this case, the callback is not + *         called. + */ +struct TALER_BANK_CreditHistoryHandle * +TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx, +                           const char *bank_base_url, +                           const struct TALER_BANK_AuthenticationData *auth, +                           uint64_t start_row, +                           int64_t num_results, +                           TALER_BANK_CreditResultCallback hres_cb, +                           void *hres_cb_cls) +{ +  char *url; +  struct TALER_BANK_CreditHistoryHandle *hh; +  CURL *eh; + +  if (0 == num_results) +  { +    GNUNET_break (0); +    return NULL; +  } + +  if (UINT64_MAX == start_row) +    GNUNET_asprintf (&url, +                     "/history&delta=%lld", +                     (long long) num_results); +  else +    GNUNET_asprintf (&url, +                     "/history&delta=%lld&start=%llu", +                     (long long) num_results, +                     start_row); +  hh = GNUNET_new (struct TALER_BANK_CreditHistoryHandle); +  hh->hcb = hres_cb; +  hh->hcb_cls = hres_cb_cls; +  hh->bank_base_url = GNUNET_strdup (bank_base_url); +  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, +                                             url); + +  eh = curl_easy_init (); +  if ( (GNUNET_OK != +        TALER_BANK_setup_auth_ (eh, +                                auth)) || +       (CURLE_OK != +        curl_easy_setopt (eh, +                          CURLOPT_URL, +                          hh->request_url)) ) +  { +    GNUNET_break (0); +    TALER_BANK_credit_history_cancel (hh); +    curl_easy_cleanup (eh); +    GNUNET_free (url); +    return NULL; +  } +  hh->job = GNUNET_CURL_job_add2 (ctx, +                                  eh, +                                  NULL, +                                  &handle_history_finished, +                                  hh); +  GNUNET_free (url); +  return hh; +} + + +/** + * Cancel a history request.  This function cannot be + * used on a request handle if a response is already + * served for it. + * + * @param hh the history request handle + */ +void +TALER_BANK_credit_history_cancel (struct TALER_BANK_CreditHistoryHandle *hh) +{ +  if (NULL != hh->job) +  { +    GNUNET_CURL_job_cancel (hh->job); +    hh->job = NULL; +  } +  GNUNET_free (hh->request_url); +  GNUNET_free (hh->bank_base_url); +  GNUNET_free (hh); +} + + +/* end of bank_api_credit.c */ diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_debit.c index f5013b85..84836243 100644 --- a/src/bank-lib/bank_api_history.c +++ b/src/bank-lib/bank_api_debit.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2017 GNUnet e.V. & Inria +  Copyright (C) 2017--2020 Taler Systems SA    TALER is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License @@ -32,7 +32,7 @@  /**   * @brief A /history Handle   */ -struct TALER_BANK_HistoryHandle +struct TALER_BANK_DebitHistoryHandle  {    /** @@ -51,14 +51,9 @@ struct TALER_BANK_HistoryHandle    struct GNUNET_CURL_Job *job;    /** -   * HTTP authentication-related headers for the request. -   */ -  struct curl_slist *authh; - -  /**     * Function to call with the result.     */ -  TALER_BANK_HistoryResultCallback hcb; +  TALER_BANK_DebitResultCallback hcb;    /**     * Closure for @a cb. @@ -77,37 +72,39 @@ struct TALER_BANK_HistoryHandle   *         #GNUNET_SYSERR if there was a protocol violation in @a history   */  static int -parse_account_history (struct TALER_BANK_HistoryHandle *hh, +parse_account_history (struct TALER_BANK_DebitHistoryHandle *hh,                         const json_t *history)  {    json_t *history_array; -  char *bank_hostname; -  if (NULL == (history_array = json_object_get (history, "data"))) +  if (NULL == (history_array = json_object_get (history, +                                                "data"))) +  { +    GNUNET_break_op (0); +    return GNUNET_SYSERR; +  } +  if (! json_is_array (history_array))    {      GNUNET_break_op (0);      return GNUNET_SYSERR;    }    for (unsigned int i = 0; i<json_array_size (history_array); i++)    { -    struct TALER_BANK_TransferDetails td; -    const char *sign; -    uint64_t other_account; +    struct TALER_BANK_DebitDetails td;      uint64_t row_id; -    enum TALER_BANK_Direction direction;      struct GNUNET_JSON_Specification hist_spec[] = { -      GNUNET_JSON_spec_string ("sign", -                               &sign),        TALER_JSON_spec_amount ("amount",                                &td.amount),        GNUNET_JSON_spec_absolute_time ("date",                                        &td.execution_date),        GNUNET_JSON_spec_uint64 ("row_id",                                 &row_id), -      GNUNET_JSON_spec_string ("wt_subject", -                               (const char **) &td.wire_transfer_subject), -      GNUNET_JSON_spec_uint64 ("counterpart", -                               &other_account), +      GNUNET_JSON_spec_fixed_auto ("wtid", +                                   &td.wtid), +      GNUNET_JSON_spec_string ("counterpart", +                               &td.account_url), +      GNUNET_JSON_spec_string ("exchange_base_url", +                               &td.exchange_base_url),        GNUNET_JSON_spec_end ()      };      json_t *transaction = json_array_get (history_array, @@ -121,45 +118,12 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,        GNUNET_break_op (0);        return GNUNET_SYSERR;      } - -    if (0 == strcasecmp (sign, -                         "+")) -      direction = TALER_BANK_DIRECTION_CREDIT; -    else if (0 == strcasecmp (sign, -                              "-")) -      direction = TALER_BANK_DIRECTION_DEBIT; -    else if (0 == strcasecmp (sign, -                              "cancel+")) -      direction = TALER_BANK_DIRECTION_CREDIT | TALER_BANK_DIRECTION_CANCEL; -    else if (0 == strcasecmp (sign, -                              "cancel-")) -      direction = TALER_BANK_DIRECTION_DEBIT | TALER_BANK_DIRECTION_CANCEL; -    else -    { -      GNUNET_break_op (0); -      GNUNET_JSON_parse_free (hist_spec); -      return GNUNET_SYSERR; -    } -    /* Note, bank_base_url has _always_ the protocol scheme -     * and it proved to be good at this point.  */ -    bank_hostname = strchr (hh->bank_base_url, ':'); -    GNUNET_assert (NULL != bank_hostname); -    bank_hostname += 3; - -    GNUNET_asprintf (&td.account_url, -                     ('/' == bank_hostname[strlen (bank_hostname) - 1]) -                     ? "payto://x-taler-bank/%s%llu" -                     : "payto://x-taler-bank/%s/%llu", -                     bank_hostname, -                     (unsigned long long) other_account);      hh->hcb (hh->hcb_cls,               MHD_HTTP_OK,               TALER_EC_NONE, -             direction,               row_id,               &td,               transaction); -    GNUNET_free (td.account_url);      GNUNET_JSON_parse_free (hist_spec);    }    return GNUNET_OK; @@ -170,7 +134,7 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,   * Function called when we're done processing the   * HTTP /history request.   * - * @param cls the `struct TALER_BANK_HistoryHandle` + * @param cls the `struct TALER_BANK_DebitHistoryHandle`   * @param response_code HTTP response code, 0 on error   * @param response parsed JSON result, NULL on error   */ @@ -179,7 +143,7 @@ handle_history_finished (void *cls,                           long response_code,                           const void *response)  { -  struct TALER_BANK_HistoryHandle *hh = cls; +  struct TALER_BANK_DebitHistoryHandle *hh = cls;    enum TALER_ErrorCode ec;    const json_t *j = response; @@ -243,120 +207,19 @@ handle_history_finished (void *cls,    hh->hcb (hh->hcb_cls,             response_code,             ec, -           TALER_BANK_DIRECTION_NONE,             0LLU,             NULL,             j); -  TALER_BANK_history_cancel (hh); -} - - -/** - * Backend of both the /history[-range] requests. - * - * @param ctx curl context for the event loop - * @param bank_base_url base URL of the bank. - * @param urlargs path + URL arguments. - * @param auth authentication data to use - * @param hres_cb the callback to call with the transaction - *        history - * @param hres_cb_cls closure for the above callback - * @return NULL if the inputs are invalid (i.e. zero value for - *         @e num_results). In this case, the callback is not - *         called. - */ -static struct TALER_BANK_HistoryHandle * -put_history_job (struct GNUNET_CURL_Context *ctx, -                 const char *bank_base_url, -                 const char *urlargs, -                 const struct TALER_BANK_AuthenticationData *auth, -                 TALER_BANK_HistoryResultCallback hres_cb, -                 void *hres_cb_cls) -{ -  struct TALER_BANK_HistoryHandle *hh; -  CURL *eh; - -  hh = GNUNET_new (struct TALER_BANK_HistoryHandle); -  hh->hcb = hres_cb; -  hh->hcb_cls = hres_cb_cls; -  hh->bank_base_url = GNUNET_strdup (bank_base_url); -  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, -                                             urlargs); - -  hh->authh = TALER_BANK_make_auth_header_ (auth); -  eh = curl_easy_init (); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_URL, -                                   hh->request_url)); -  hh->job = GNUNET_CURL_job_add2 (ctx, -                                  eh, -                                  hh->authh, -                                  &handle_history_finished, -                                  hh); -  return hh; +  TALER_BANK_debit_history_cancel (hh);  }  /** - * Convert fixed value 'direction' into string. - * - * @param direction the value to convert. - * @return string representation of @a direction.  NULL on error - */ -static const char * -conv_direction (enum TALER_BANK_Direction direction) -{ -  if (TALER_BANK_DIRECTION_NONE == direction) -  { -    /* Should just never happen.  */ -    GNUNET_break (0); -    return NULL; -  } -  if (TALER_BANK_DIRECTION_BOTH == -      (TALER_BANK_DIRECTION_BOTH & direction)) -    return "both"; -  else if (TALER_BANK_DIRECTION_CREDIT == -           (TALER_BANK_DIRECTION_CREDIT & direction)) -    return "credit"; -  else if (TALER_BANK_DIRECTION_DEBIT == -           (TALER_BANK_DIRECTION_BOTH & direction)) /*why use 'both' flag?*/ -    return "debit"; -  /* Should just never happen.  */ -  GNUNET_break (0); -  return NULL; -} - - -/** - * Convert fixed value 'direction' into string representation - * of the "cancel" argument. - * - * @param direction the value to convert. - * @return string representation of @a direction - */ -static const char * -conv_cancel (enum TALER_BANK_Direction direction) -{ -  if (TALER_BANK_DIRECTION_CANCEL == -      (TALER_BANK_DIRECTION_CANCEL & direction)) -    return "show"; -  return "omit"; -} - - -/** - * Request the wire transfer history of a bank account. + * Request the debit history of the exchange's bank account.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this - *        request) + * @param bank_base_url URL of the base INCLUDING account number   * @param auth authentication data to use - * @param account_number which account number should we query - * @param direction what kinds of wire transfers should be - *        returned - * @param ascending if GNUNET_YES, history elements will - *        be returned in chronological order.   * @param start_row from which row on do we want to get results,   *        use UINT64_MAX for the latest; exclusive   * @param num_results how many results do we want; @@ -370,20 +233,18 @@ conv_cancel (enum TALER_BANK_Direction direction)   *         @e num_results). In this case, the callback is not   *         called.   */ -struct TALER_BANK_HistoryHandle * -TALER_BANK_history (struct GNUNET_CURL_Context *ctx, -                    const char *bank_base_url, -                    const struct TALER_BANK_AuthenticationData *auth, -                    uint64_t account_number, -                    enum TALER_BANK_Direction direction, -                    unsigned int ascending, -                    uint64_t start_row, -                    int64_t num_results, -                    TALER_BANK_HistoryResultCallback hres_cb, -                    void *hres_cb_cls) +struct TALER_BANK_DebitHistoryHandle * +TALER_BANK_debit_history (struct GNUNET_CURL_Context *ctx, +                          const char *bank_base_url, +                          const struct TALER_BANK_AuthenticationData *auth, +                          uint64_t start_row, +                          int64_t num_results, +                          TALER_BANK_DebitResultCallback hres_cb, +                          void *hres_cb_cls)  { -  struct TALER_BANK_HistoryHandle *hh;    char *url; +  struct TALER_BANK_DebitHistoryHandle *hh; +  CURL *eh;    if (0 == num_results)    { @@ -393,28 +254,40 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,    if (UINT64_MAX == start_row)      GNUNET_asprintf (&url, -                     "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s", -                     (unsigned long long) account_number, -                     (long long) num_results, -                     conv_direction (direction), -                     conv_cancel (direction), -                     (GNUNET_YES == ascending) ? "ascending" : "descending"); +                     "/history&delta=%lld", +                     (long long) num_results);    else      GNUNET_asprintf (&url, -                     "/history?auth=basic&account_number=%llu&delta=%lld&direction=%s&cancelled=%s&ordering=%s&start=%llu", -                     (unsigned long long) account_number, +                     "/history&delta=%lld&start=%llu",                       (long long) num_results, -                     conv_direction (direction), -                     conv_cancel (direction), -                     (GNUNET_YES == ascending) ? "ascending" : "descending",                       start_row); -  hh = put_history_job (ctx, -                        bank_base_url, -                        url, -                        auth, -                        hres_cb, -                        hres_cb_cls); +  hh = GNUNET_new (struct TALER_BANK_DebitHistoryHandle); +  hh->hcb = hres_cb; +  hh->hcb_cls = hres_cb_cls; +  hh->bank_base_url = GNUNET_strdup (bank_base_url); +  hh->request_url = TALER_BANK_path_to_url_ (bank_base_url, +                                             url); +  eh = curl_easy_init (); +  if ( (GNUNET_OK != +        TALER_BANK_setup_auth_ (eh, +                                auth)) || +       (CURLE_OK != +        curl_easy_setopt (eh, +                          CURLOPT_URL, +                          hh->request_url)) ) +  { +    GNUNET_break (0); +    TALER_BANK_debit_history_cancel (hh); +    curl_easy_cleanup (eh); +    GNUNET_free (url); +    return NULL; +  } +  hh->job = GNUNET_CURL_job_add2 (ctx, +                                  eh, +                                  NULL, +                                  &handle_history_finished, +                                  hh);    GNUNET_free (url);    return hh;  } @@ -428,18 +301,17 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,   * @param hh the history request handle   */  void -TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh) +TALER_BANK_debit_history_cancel (struct TALER_BANK_DebitHistoryHandle *hh)  {    if (NULL != hh->job)    {      GNUNET_CURL_job_cancel (hh->job);      hh->job = NULL;    } -  curl_slist_free_all (hh->authh);    GNUNET_free (hh->request_url);    GNUNET_free (hh->bank_base_url);    GNUNET_free (hh);  } -/* end of bank_api_history.c */ +/* end of bank_api_debit.c */ diff --git a/src/bank-lib/bank_api_parse.c b/src/bank-lib/bank_api_parse.c index 582e2a7d..86288802 100644 --- a/src/bank-lib/bank_api_parse.c +++ b/src/bank-lib/bank_api_parse.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2018 Taler Systems SA +  Copyright (C) 2018-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -24,6 +24,58 @@  /** + * Convenience method for parsing configuration section with bank account data. + * + * @param cfg configuration to parse + * @param section the section with the configuration data + * @param acc[out] set to the account details + * @return #GNUNET_OK on success + */ +int +TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, +                              const char *section, +                              struct TALER_Account *acc) +{ +  char *account_url; + +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (cfg, +                                             section, +                                             "URL", +                                             &account_url)) +  { +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               section, +                               "URL"); +    return GNUNET_SYSERR; +  } +  if (TALER_EC_NONE != +      TALER_WIRE_payto_to_account (account_url, +                                   acc)) +  { +    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, +                               section, +                               "URL", +                               "Malformed payto:// URL for x-taler-bank method"); +    GNUNET_free (account_url); +    return GNUNET_SYSERR; +  } +  if (TALER_PAC_X_TALER_BANK != acc->type) +  { +    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, +                               section, +                               "URL", +                               "Malformed payto:// URL for x-taler-bank method"); +    GNUNET_free (account_url); +    TALER_WIRE_account_free (acc); +    return GNUNET_SYSERR; +  } +  GNUNET_free (account_url); +  return GNUNET_OK; +} + + +/**   * Parse configuration section with bank authentication data.   *   * @param cfg configuration to parse diff --git a/src/bank-lib/bank_api_reject.c b/src/bank-lib/bank_api_reject.c deleted file mode 100644 index 3f181bc3..00000000 --- a/src/bank-lib/bank_api_reject.c +++ /dev/null @@ -1,242 +0,0 @@ -/* -  This file is part of TALER -  Copyright (C) 2015, 2016, 2017 Taler Systems SA - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see -  <http://www.gnu.org/licenses/> -*/ -/** - * @file bank-lib/bank_api_reject.c - * @brief Implementation of the /reject request of the bank's HTTP API - * @author Christian Grothoff - */ -#include "platform.h" -#include "bank_api_common.h" -#include <microhttpd.h> /* just for HTTP status codes */ -#include "taler_signatures.h" - - -/** - * @brief A /reject Handle - */ -struct TALER_BANK_RejectHandle -{ - -  /** -   * The url for this request. -   */ -  char *request_url; - -  /** -   * JSON encoding of the request to POST. -   */ -  char *json_enc; - -  /** -   * Handle for the request. -   */ -  struct GNUNET_CURL_Job *job; - -  /** -   * HTTP authentication-related headers for the request. -   */ -  struct curl_slist *authh; - -  /** -   * Function to call with the result. -   */ -  TALER_BANK_RejectResultCallback cb; - -  /** -   * Closure for @a cb. -   */ -  void *cb_cls; - -}; - - -/** - * Function called when we're done processing the - * HTTP /reject request. - * - * @param cls the `struct TALER_BANK_RejectHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reject_finished (void *cls, -                        long response_code, -                        const void *response) -{ -  struct TALER_BANK_RejectHandle *rh = cls; -  enum TALER_ErrorCode ec; -  const json_t *j = response; - -  rh->job = NULL; -  switch (response_code) -  { -  case 0: -    ec = TALER_EC_INVALID_RESPONSE; -    break; -  case MHD_HTTP_OK: -    GNUNET_break_op (0); -    response_code = 0; -    ec = TALER_EC_INVALID_RESPONSE; -    break; -  case MHD_HTTP_NO_CONTENT: -    ec = TALER_EC_NONE; -    break; -  case MHD_HTTP_BAD_REQUEST: -    /* This should never happen, either us or the bank is buggy -       (or API version conflict); just pass JSON reply to the application */ -    ec = TALER_BANK_parse_ec_ (j); -    break; -  case MHD_HTTP_FORBIDDEN: -    /* Access denied */ -    ec = TALER_BANK_parse_ec_ (j); -    break; -  case MHD_HTTP_UNAUTHORIZED: -    /* Nothing really to verify, bank says one of the signatures is -       invalid; as we checked them, this should never happen, we -       should pass the JSON reply to the application */ -    ec = TALER_BANK_parse_ec_ (j); -    break; -  case MHD_HTTP_NOT_FOUND: -    /* Nothing really to verify, this should never -       happen, we should pass the JSON reply to the application */ -    ec = TALER_BANK_parse_ec_ (j); -    break; -  case MHD_HTTP_INTERNAL_SERVER_ERROR: -    /* Server had an internal issue; we should retry, but this API -       leaves this to the application */ -    ec = TALER_BANK_parse_ec_ (j); -    break; -  default: -    /* unexpected response code */ -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Unexpected response code %u\n", -                (unsigned int) response_code); -    GNUNET_break (0); -    ec = TALER_BANK_parse_ec_ (j); -    response_code = 0; -    break; -  } -  rh->cb (rh->cb_cls, -          response_code, -          ec); -  TALER_BANK_reject_cancel (rh); -} - - -/** - * Request rejection of a wire transfer, marking it as cancelled and voiding - * its effects. - * - * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) - * @param auth authentication data to use - * @param account_number which account number should we query - * @param rowid transfer to reject - * @param rcb the callback to call with the operation result - * @param rcb_cls closure for @a rcb - * @return NULL - *         if the inputs are invalid. - *         In this case, the callback is not called. - */ -struct TALER_BANK_RejectHandle * -TALER_BANK_reject (struct GNUNET_CURL_Context *ctx, -                   const char *bank_base_url, -                   const struct TALER_BANK_AuthenticationData *auth, -                   uint64_t account_number, -                   uint64_t rowid, -                   TALER_BANK_RejectResultCallback rcb, -                   void *rcb_cls) -{ -  struct TALER_BANK_RejectHandle *rh; -  json_t *reject_obj; -  CURL *eh; - -  reject_obj = json_pack ("{s:{s:s}, s:I, s:I}", -                          "auth", "type", "basic", -                          "row_id", (json_int_t) rowid, -                          "account_number", (json_int_t) account_number); -  if (NULL == reject_obj) -  { -    GNUNET_break (0); -    return NULL; -  } -  rh = GNUNET_new (struct TALER_BANK_RejectHandle); -  rh->cb = rcb; -  rh->cb_cls = rcb_cls; -  rh->request_url = TALER_BANK_path_to_url_ (bank_base_url, -                                             "/reject"); -  rh->authh = TALER_BANK_make_auth_header_ (auth); -  /* Append content type header here, can't do it in GNUNET_CURL_job_add -     as that would override the CURLOPT_HTTPHEADER instead of appending. */ -  { -    struct curl_slist *ext; - -    ext = curl_slist_append (rh->authh, -                             "Content-Type: application/json"); -    if (NULL == ext) -      GNUNET_break (0); -    else -      rh->authh = ext; -  } -  eh = curl_easy_init (); -  GNUNET_assert (NULL != (rh->json_enc = -                            json_dumps (reject_obj, -                                        JSON_COMPACT))); -  json_decref (reject_obj); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_URL, -                                   rh->request_url)); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_POSTFIELDS, -                                   rh->json_enc)); -  GNUNET_assert (CURLE_OK == -                 curl_easy_setopt (eh, -                                   CURLOPT_POSTFIELDSIZE, -                                   strlen (rh->json_enc))); -  rh->job = GNUNET_CURL_job_add2 (ctx, -                                  eh, -                                  rh->authh, -                                  &handle_reject_finished, -                                  rh); -  return rh; -} - - -/** - * Cancel an reject request.  This function cannot be used on a request - * handle if the response was is already served for it. - * - * @param rh the reject request handle - */ -void -TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh) -{ -  if (NULL != rh->job) -  { -    GNUNET_CURL_job_cancel (rh->job); -    rh->job = NULL; -  } -  curl_slist_free_all (rh->authh); -  GNUNET_free (rh->request_url); -  GNUNET_free (rh->json_enc); -  GNUNET_free (rh); -} - - -/* end of bank_api_reject.c */ diff --git a/src/bank-lib/bank_api_transaction.c b/src/bank-lib/bank_api_transaction.c new file mode 100644 index 00000000..17732848 --- /dev/null +++ b/src/bank-lib/bank_api_transaction.c @@ -0,0 +1,368 @@ +/* +  This file is part of TALER +  Copyright (C) 2015--2020 Taler Systems SA + +  TALER is free software; you can redistribute it and/or modify it under the +  terms of the GNU General Public License as published by the Free Software +  Foundation; either version 3, or (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but WITHOUT ANY +  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. + +  You should have received a copy of the GNU General Public License along with +  TALER; see the file COPYING.  If not, see +  <http://www.gnu.org/licenses/> +*/ +/** + * @file bank-lib/bank_api_transaction.c + * @brief Implementation of the /transaction/ requests of the bank's HTTP API + * @author Christian Grothoff + */ +#include "platform.h" +#include "bank_api_common.h" +#include <microhttpd.h> /* just for HTTP status codes */ +#include "taler_signatures.h" +#include "taler_curl_lib.h" +#include "taler_bank_service.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Data structure serialized in the prepare stage. + */ +struct WirePackP +{ +  /** +   * Random unique identifier for the request. +   */ +  struct GNUNET_HashCode request_uid; + +  /** +   * Amount to be transferred. +   */ +  struct TALER_AmountNBO amount; + +  /** +   * Wire transfer identifier to use. +   */ +  struct TALER_WireTransferIdentifierRawP wtid; + +  /** +   * Length of the payto:// URL of the target account, +   * including 0-terminator, in network byte order. +   */ +  uint32_t account_len GNUNET_PACKED; + +  /** +   * Length of the exchange's base URL, +   * including 0-terminator, in network byte order. +   */ +  uint32_t exchange_url_len GNUNET_PACKED; + +}; + +GNUNET_NETWORK_STRUCT_END + +/** + * Prepare for exeuction of a wire transfer. + * + * @param destination_account_url payto:// URL identifying where to send the money + * @param amount amount to transfer, already rounded + * @param exchange_base_url base URL of this exchange (included in subject + *        to facilitate use of tracking API by merchant backend) + * @param wtid wire transfer identifier to use + * @param buf[out] set to transaction data to persist, NULL on error + * @param buf_size[out] set to number of bytes in @a buf, 0 on error + */ +void +TALER_BANK_prepare_wire_transfer (const char *destination_account_url, +                                  const struct TALER_Amount *amount, +                                  const char *exchange_base_url, +                                  const struct +                                  TALER_WireTransferIdentifierRawP *wtid, +                                  void **buf, +                                  size_t *buf_size) +{ +  struct WirePackP *wp; +  size_t d_len = strlen (destination_account_url) + 1; +  size_t u_len = strlen (exchange_base_url) + 1; +  char *end; + +  *buf_size = sizeof (*wp) + d_len + u_len; +  wp = GNUNET_malloc (*buf_size); +  GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_NONCE, +                                    &wp->request_uid); +  TALER_amount_hton (&wp->amount, +                     amount); +  wp->wtid = *wtid; +  wp->account_len = htonl ((uint32_t) d_len); +  wp->exchange_url_len = htonl ((uint32_t) u_len); +  end = (char *) &wp[1]; +  memcpy (end, +          destination_account_url, +          d_len); +  memcpy (end + d_len, +          exchange_base_url, +          u_len); +  *buf = (char *) wp; +} + + +/** + * @brief An transaction Handle + */ +struct TALER_BANK_WireExecuteHandle +{ + +  /** +   * The url for this request. +   */ +  char *request_url; + +  /** +   * POST context. +   */ +  struct TEAH_PostContext post_ctx; + +  /** +   * Handle for the request. +   */ +  struct GNUNET_CURL_Job *job; + +  /** +   * Function to call with the result. +   */ +  TALER_BANK_ConfirmationCallback cb; + +  /** +   * Closure for @a cb. +   */ +  void *cb_cls; + +}; + + +/** + * Function called when we're done processing the + * HTTP /transaction request. + * + * @param cls the `struct TALER_BANK_WireExecuteHandle` + * @param response_code HTTP response code, 0 on error + * @param response parsed JSON result, NULL on error + */ +static void +handle_transaction_finished (void *cls, +                             long response_code, +                             const void *response) +{ +  struct TALER_BANK_WireExecuteHandle *weh = cls; +  uint64_t row_id = UINT64_MAX; +  struct GNUNET_TIME_Absolute timestamp; +  enum TALER_ErrorCode ec; +  const json_t *j = response; + +  weh->job = NULL; +  timestamp = GNUNET_TIME_UNIT_FOREVER_ABS; +  switch (response_code) +  { +  case 0: +    ec = TALER_EC_INVALID_RESPONSE; +    break; +  case MHD_HTTP_OK: +    { +      struct GNUNET_JSON_Specification spec[] = { +        GNUNET_JSON_spec_uint64 ("row_id", +                                 &row_id), +        GNUNET_JSON_spec_absolute_time ("timestamp", +                                        ×tamp), +        GNUNET_JSON_spec_end () +      }; + +      if (GNUNET_OK != +          GNUNET_JSON_parse (j, +                             spec, +                             NULL, NULL)) +      { +        GNUNET_break_op (0); +        response_code = 0; +        ec = TALER_EC_INVALID_RESPONSE; +        break; +      } +      ec = TALER_EC_NONE; +    } +    break; +  case MHD_HTTP_BAD_REQUEST: +    /* This should never happen, either us or the bank is buggy +       (or API version conflict); just pass JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_FORBIDDEN: +    /* Access denied */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_UNAUTHORIZED: +    /* Nothing really to verify, bank says one of the signatures is +       invalid; as we checked them, this should never happen, we +       should pass the JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_NOT_FOUND: +    /* Nothing really to verify, this should never +       happen, we should pass the JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_NOT_ACCEPTABLE: +    /* Nothing really to verify, this should never +       happen, we should pass the JSON reply to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  case MHD_HTTP_INTERNAL_SERVER_ERROR: +    /* Server had an internal issue; we should retry, but this API +       leaves this to the application */ +    ec = TALER_BANK_parse_ec_ (j); +    break; +  default: +    /* unexpected response code */ +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Unexpected response code %u\n", +                (unsigned int) response_code); +    GNUNET_break (0); +    ec = TALER_BANK_parse_ec_ (j); +    response_code = 0; +    break; +  } +  weh->cb (weh->cb_cls, +           response_code, +           ec, +           row_id, +           timestamp); +  TALER_BANK_execute_wire_transfer_cancel (weh); +} + + +/** + * Execute a wire transfer. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param buf buffer with the prepared execution details + * @param buf_size number of bytes in @a buf + * @param cc function to call upon success + * @param cc_cls closure for @a cc + * @return NULL on error + */ +struct TALER_BANK_WireExecuteHandle * +TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx, +                                  const char *bank_base_url, +                                  const struct +                                  TALER_BANK_AuthenticationData *auth, +                                  const void *buf, +                                  size_t buf_size, +                                  TALER_BANK_ConfirmationCallback cc, +                                  void *cc_cls) +{ +  struct TALER_BANK_WireExecuteHandle *weh; +  json_t *transaction_obj; +  CURL *eh; +  const struct WirePackP *wp = buf; +  uint32_t d_len; +  uint32_t u_len; +  const char *destination_account_url; +  const char *exchange_base_url; +  struct TALER_Amount amount; + +  if (sizeof (*wp) > buf_size) +  { +    GNUNET_break (0); +    return NULL; +  } +  d_len = ntohl (wp->account_len); +  u_len = ntohl (wp->exchange_url_len); +  if (sizeof (*wp) + d_len + u_len != buf_size) +  { +    GNUNET_break (0); +    return NULL; +  } +  destination_account_url = (const char *) &wp[1]; +  exchange_base_url = destination_account_url + d_len; +  if (NULL == bank_base_url) +  { +    GNUNET_break (0); +    return NULL; +  } +  TALER_amount_ntoh (&amount, +                     &wp->amount); +  transaction_obj = json_pack ("{s:o, s:o, s:s, s:o, s:o, s:s}", +                               "request_uid", GNUNET_JSON_from_data_auto ( +                                 &wp->request_uid), +                               "amount", TALER_JSON_from_amount (&amount), +                               "exchange_url", exchange_base_url, +                               "wtid", GNUNET_JSON_from_data_auto (&wp->wtid), +                               "credit_account", destination_account_url); +  if (NULL == transaction_obj) +  { +    GNUNET_break (0); +    return NULL; +  } +  weh = GNUNET_new (struct TALER_BANK_WireExecuteHandle); +  weh->cb = cc; +  weh->cb_cls = cc_cls; +  weh->request_url = TALER_BANK_path_to_url_ (bank_base_url, +                                              "/transaction"); +  weh->post_ctx.headers = curl_slist_append +                            (weh->post_ctx.headers, +                            "Content-Type: application/json"); + +  eh = curl_easy_init (); +  if ( (GNUNET_OK != +        TALER_BANK_setup_auth_ (eh, +                                auth)) || +       (CURLE_OK != +        curl_easy_setopt (eh, +                          CURLOPT_URL, +                          weh->request_url)) || +       (GNUNET_OK != +        TALER_curl_easy_post (&weh->post_ctx, +                              eh, +                              transaction_obj)) ) +  { +    GNUNET_break (0); +    TALER_BANK_execute_wire_transfer_cancel (weh); +    curl_easy_cleanup (eh); +    json_decref (transaction_obj); +    return NULL; +  } +  json_decref (transaction_obj); + +  weh->job = GNUNET_CURL_job_add2 (ctx, +                                   eh, +                                   weh->post_ctx.headers, +                                   &handle_transaction_finished, +                                   weh); +  return weh; +} + + +/** + * Cancel a wire transfer.  This function cannot be used on a request handle + * if a response is already served for it. + * + * @param weh the wire transfer request handle + */ +void +TALER_BANK_execute_wire_transfer_cancel (struct +                                         TALER_BANK_WireExecuteHandle *weh) +{ +  if (NULL != weh->job) +  { +    GNUNET_CURL_job_cancel (weh->job); +    weh->job = NULL; +  } +  TALER_curl_easy_post_finished (&weh->post_ctx); +  GNUNET_free (weh->request_url); +  GNUNET_free (weh); +} + + +/* end of bank_api_transaction.c */ diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index d8ea392b..1706ca8f 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2016, 2017, 2018 Inria and GNUnet e.V. +  (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License @@ -25,7 +25,7 @@  #include "platform.h"  #include "taler_fakebank_lib.h"  #include "taler_bank_service.h" -#include "fakebank.h" +#include "taler_mhd_lib.h"  /**   * Maximum POST request size (for /admin/add/incoming) @@ -34,6 +34,65 @@  /** + * Details about a transcation we (as the simulated bank) received. + */ +struct Transaction +{ +  /** +   * We store transactions in a DLL. +   */ +  struct Transaction *next; + +  /** +   * We store transactions in a DLL. +   */ +  struct Transaction *prev; + +  /** +   * Amount to be transferred. +   */ +  struct TALER_Amount amount; + +  /** +   * Account to debit. +   */ +  char *debit_account; + +  /** +   * Account to credit. +   */ +  char *credit_account; + +  /** +   * Subject of the transfer. +   */ +  char *subject; + +  /** +   * Base URL of the exchange. +   */ +  char *exchange_base_url; + +  /** +   * When did the transaction happen? +   */ +  struct GNUNET_TIME_Absolute date; + +  /** +   * Number of this transaction. +   */ +  uint64_t row_id; + +  /** +   * Has this transaction been subjected to #TALER_FAKEBANK_check() +   * and should thus no longer be counted in +   * #TALER_FAKEBANK_check_empty()? +   */ +  int checked; +}; + + +/**   * Handle for the fake bank.   */  struct TALER_FAKEBANK_Handle @@ -63,6 +122,11 @@ struct TALER_FAKEBANK_Handle     */    uint64_t serial_counter; +  /** +   * Our port number. +   */ +  uint16_t port; +  #if EPOLL_SUPPORT    /**     * Boxed @e mhd_fd. @@ -95,8 +159,8 @@ struct TALER_FAKEBANK_Handle  int  TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,                        const struct TALER_Amount *want_amount, -                      uint64_t want_debit, -                      uint64_t want_credit, +                      const char *want_debit, +                      const char *want_credit,                        const char *exchange_base_url,                        char **subject)  { @@ -151,8 +215,8 @@ TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,   */  uint64_t  TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h, -                              uint64_t debit_account, -                              uint64_t credit_account, +                              const char *debit_account, +                              const char *credit_account,                                const struct TALER_Amount *amount,                                const char *subject,                                const char *exchange_base_url) @@ -160,15 +224,15 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,    struct Transaction *t;    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Making transfer from %llu to %llu over %s and subject %s; for exchange: %s\n", -              (unsigned long long) debit_account, -              (unsigned long long) credit_account, +              "Making transfer from %s to %s over %s and subject %s; for exchange: %s\n", +              debit_account, +              credit_account,                TALER_amount2s (amount),                subject,                exchange_base_url);    t = GNUNET_new (struct Transaction); -  t->debit_account = debit_account; -  t->credit_account = credit_account; +  t->debit_account = GNUNET_strdup (debit_account); +  t->credit_account = GNUNET_strdup (credit_account);    t->amount = *amount;    t->exchange_base_url = GNUNET_strdup (exchange_base_url);    t->row_id = ++h->serial_counter; @@ -183,31 +247,6 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,  /** - * Reject incoming wire transfer to account @a credit_account - * as identified by @a rowid. - * - * @param h fake bank handle - * @param rowid identifies transfer to reject - * @param credit_account account number of owner of credited account - * @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found - */ -int -TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h, -                                uint64_t rowid, -                                uint64_t credit_account) -{ -  for (struct Transaction *t = h->transactions_head; NULL != t; t = t->next) -    if ( (t->row_id == rowid) && -         (t->credit_account == credit_account) ) -    { -      t->rejected = GNUNET_YES; -      return GNUNET_YES; -    } -  return GNUNET_NO; -} - - -/**   * Check that no wire transfers were ordered (or at least none   * that have not been taken care of via #TALER_FAKEBANK_check()).   * If any transactions are onrecord, return #GNUNET_SYSERR. @@ -223,8 +262,7 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)    t = h->transactions_head;    while (NULL != t)    { -    if ( (GNUNET_YES != t->checked) && -         (GNUNET_YES != t->rejected) ) +    if (GNUNET_YES != t->checked)        break;      t = t->next;    } @@ -234,16 +272,15 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)             "Expected empty transaction set, but I have:\n");    while (NULL != t)    { -    if ( (GNUNET_YES != t->checked) && -         (GNUNET_YES != t->rejected) ) +    if (GNUNET_YES != t->checked)      {        char *s;        s = TALER_amount_to_string (&t->amount);        fprintf (stderr, -               "%llu -> %llu (%s) from %s\n", -               (unsigned long long) t->debit_account, -               (unsigned long long) t->credit_account, +               "%s -> %s (%s) from %s\n", +               t->debit_account, +               t->credit_account,                 s,                 t->exchange_base_url);        GNUNET_free (s); @@ -270,6 +307,8 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)                                   h->transactions_tail,                                   t);      GNUNET_free (t->subject); +    GNUNET_free (t->debit_account); +    GNUNET_free (t->credit_account);      GNUNET_free (t->exchange_base_url);      GNUNET_free (t);    } @@ -291,62 +330,6 @@ TALER_FAKEBANK_stop (struct TALER_FAKEBANK_Handle *h)  /** - * Create and queue a bank error message with the HTTP response - * code @a response_code on connection @a connection. - * - * @param connection where to queue the reply - * @param response_code http status code to use - * @param ec taler error code to use - * @param message human readable error message - * @return MHD status code - */ -static int -create_bank_error (struct MHD_Connection *connection, -                   unsigned int response_code, -                   enum TALER_ErrorCode ec, -                   const char *message) -{ -  json_t *json; -  struct MHD_Response *resp; -  void *json_str; -  size_t json_len; -  int ret; - -  json = json_pack ("{s:s, s:I}", -                    "error", -                    message, -                    "ec", -                    (json_int_t) ec); -  json_str = json_dumps (json, -                         JSON_INDENT (2)); -  json_decref (json); -  if (NULL == json_str) -  { -    GNUNET_break (0); -    return MHD_NO; -  } -  json_len = strlen (json_str); -  resp = MHD_create_response_from_buffer (json_len, -                                          json_str, -                                          MHD_RESPMEM_MUST_FREE); -  if (NULL == resp) -  { -    GNUNET_break (0); -    free (json_str); -    return MHD_NO; -  } -  (void) MHD_add_response_header (resp, -                                  MHD_HTTP_HEADER_CONTENT_TYPE, -                                  "application/json"); -  ret = MHD_queue_response (connection, -                            response_code, -                            resp); -  MHD_destroy_response (resp); -  return ret; -} - - -/**   * Function called whenever MHD is done with a request.  If the   * request was a POST, we may have stored a `struct Buffer *` in the   * @a con_cls that might still need to be cleaned up.  Call the @@ -394,8 +377,6 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,  {    enum GNUNET_JSON_PostResult pr;    json_t *json; -  struct MHD_Response *resp; -  int ret;    uint64_t row_id;    pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX, @@ -422,15 +403,14 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,    }    {      const char *subject; -    uint64_t debit_account; -    uint64_t credit_account; +    const char *debit_account; +    const char *credit_account;      const char *base_url;      struct TALER_Amount amount; -    char *amount_s;      struct GNUNET_JSON_Specification spec[] = {        GNUNET_JSON_spec_string ("subject", &subject), -      GNUNET_JSON_spec_uint64 ("debit_account", &debit_account), -      GNUNET_JSON_spec_uint64 ("credit_account", &credit_account), +      GNUNET_JSON_spec_string ("debit_account", &debit_account), +      GNUNET_JSON_spec_string ("credit_account", &credit_account),        TALER_JSON_spec_amount ("amount", &amount),        GNUNET_JSON_spec_string ("exchange_url", &base_url),        GNUNET_JSON_spec_end () @@ -450,80 +430,49 @@ handle_admin_add_incoming (struct TALER_FAKEBANK_Handle *h,                                             &amount,                                             subject,                                             base_url); -    amount_s = TALER_amount_to_string (&amount);      GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Receiving incoming wire transfer: %llu->%llu, subject: %s, amount: %s, from %s\n", -                (unsigned long long) debit_account, -                (unsigned long long) credit_account, +                "Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s, from %s\n", +                debit_account, +                credit_account,                  subject, -                amount_s, +                TALER_amount2s (&amount),                  base_url); -    GNUNET_free (amount_s);    }    json_decref (json);    /* Finally build response object */ -  { -    void *json_str; -    size_t json_len; - -    json = json_pack ("{s:I, s:o}", -                      "row_id", -                      (json_int_t) row_id, -                      "timestamp", GNUNET_JSON_from_time_abs (GNUNET_TIME_UNIT_ZERO_ABS)); /*dummy tmp */ - -    json_str = json_dumps (json, -                           JSON_INDENT (2)); -    json_decref (json); -    if (NULL == json_str) -    { -      GNUNET_break (0); -      return MHD_NO; -    } -    json_len = strlen (json_str); -    resp = MHD_create_response_from_buffer (json_len, -                                            json_str, -                                            MHD_RESPMEM_MUST_FREE); -    if (NULL == resp) -    { -      GNUNET_break (0); -      free (json_str); -      return MHD_NO; -    } -    (void) MHD_add_response_header (resp, -                                    MHD_HTTP_HEADER_CONTENT_TYPE, -                                    "application/json"); -  } -  ret = MHD_queue_response (connection, -                            MHD_HTTP_OK, -                            resp); -  MHD_destroy_response (resp); -  return ret; +  return TALER_MHD_reply_json_pack (connection, +                                    MHD_HTTP_OK, +                                    "{s:I, s:o}", +                                    "row_id", +                                    (json_int_t) row_id, +                                    "timestamp", GNUNET_JSON_from_time_abs ( +                                      GNUNET_TIME_UNIT_ZERO_ABS));                                       /*dummy tmp */  }  /** - * Handle incoming HTTP request for /reject. + * Handle incoming HTTP request for /transaction.   *   * @param h the fakebank handle   * @param connection the connection + * @param account account making the transaction   * @param upload_data request data   * @param upload_data_size size of @a upload_data in bytes   * @param con_cls closure for request (a `struct Buffer *`)   * @return MHD result code   */  static int -handle_reject (struct TALER_FAKEBANK_Handle *h, -               struct MHD_Connection *connection, -               const char *upload_data, -               size_t *upload_data_size, -               void **con_cls) +handle_transaction (struct TALER_FAKEBANK_Handle *h, +                    struct MHD_Connection *connection, +                    const char *account, +                    const char *upload_data, +                    size_t *upload_data_size, +                    void **con_cls)  {    enum GNUNET_JSON_PostResult pr;    json_t *json; -  struct MHD_Response *resp; -  int ret; -  int found; +  uint64_t row_id;    pr = GNUNET_JSON_post_parser (REQUEST_BUFFER_MAX,                                  connection, @@ -548,13 +497,25 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,      break;    }    { -    uint64_t row_id; -    uint64_t credit_account; +    struct GNUNET_HashCode uuid; +    struct TALER_WireTransferIdentifierRawP wtid; +    const char *credit_account; +    const char *base_url; +    struct TALER_Amount amount;      struct GNUNET_JSON_Specification spec[] = { -      GNUNET_JSON_spec_uint64 ("row_id", &row_id), -      GNUNET_JSON_spec_uint64 ("account_number", &credit_account), +      GNUNET_JSON_spec_fixed_auto ("request_uid", +                                   &uuid), +      TALER_JSON_spec_amount ("amount", +                              &amount), +      GNUNET_JSON_spec_string ("exchange_base_url", +                               &base_url), +      GNUNET_JSON_spec_fixed_auto ("wtid", +                                   &wtid), +      GNUNET_JSON_spec_string ("credit_account", +                               &credit_account),        GNUNET_JSON_spec_end ()      }; +      if (GNUNET_OK !=          GNUNET_JSON_parse (json,                             spec, @@ -564,31 +525,38 @@ handle_reject (struct TALER_FAKEBANK_Handle *h,        json_decref (json);        return MHD_NO;      } -    found = TALER_FAKEBANK_reject_transfer (h, -                                            row_id, -                                            credit_account); -    GNUNET_log (GNUNET_ERROR_TYPE_INFO, -                "Rejected wire transfer #%llu (to %llu)\n", -                (unsigned long long) row_id, -                (unsigned long long) credit_account); +    { +      char *subject; + +      subject = GNUNET_STRINGS_data_to_string_alloc (&wtid, +                                                     sizeof (wtid)); +      // FIXME: use uuid here!!! +      row_id = TALER_FAKEBANK_make_transfer (h, +                                             account, +                                             credit_account, +                                             &amount, +                                             subject, +                                             base_url); +      GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                  "Receiving incoming wire transfer: %s->%s, subject: %s, amount: %s, from %s\n", +                  account, +                  credit_account, +                  subject, +                  TALER_amount2s (&amount), +                  base_url); +      GNUNET_free (subject); +    }    }    json_decref (json); -  if (GNUNET_OK != found) -    return create_bank_error -             (connection, -             MHD_HTTP_NOT_FOUND, -             TALER_EC_BANK_TRANSACTION_NOT_FOUND, -             "transaction unknown"); -  /* finally build regular response */ -  resp = MHD_create_response_from_buffer (0, -                                          NULL, -                                          MHD_RESPMEM_PERSISTENT); -  ret = MHD_queue_response (connection, -                            MHD_HTTP_NO_CONTENT, -                            resp); -  MHD_destroy_response (resp); -  return ret; +  /* Finally build response object */ +  return TALER_MHD_reply_json_pack (connection, +                                    MHD_HTTP_OK, +                                    "{s:I, s:o}", +                                    "row_id", +                                    (json_int_t) row_id, +                                    "timestamp", GNUNET_JSON_from_time_abs ( +                                      GNUNET_TIME_UNIT_ZERO_ABS));                                       /*dummy tmp */  } @@ -626,75 +594,245 @@ handle_home_page (struct TALER_FAKEBANK_Handle *h,  /** - * Handle incoming HTTP request for /history + * This is the "base" structure for both the /history and the + * /history-range API calls. + */ +struct HistoryArgs +{ + +  /** +   * Bank account number of the requesting client. +   */ +  uint64_t account_number; + +  /** +   * Index of the starting transaction. +   */ +  uint64_t start_idx; + +  /** +   * Requested number of results and order +   * (positive: ascending, negative: descending) +   */ +  int64_t delta; + +  /** +   * Timeout for long polling. +   */ +  struct GNUNET_TIME_Relative lp_timeout; + +  /** +   * #GNUNET_YES if starting point was given. +   */ +  int have_start; + +}; + + +/** + * Parse URL history arguments, of _both_ APIs: + * /history/incoming and /history/outgoing. + * + * @param connection MHD connection. + * @param function_name name of the caller. + * @param ha[out] will contain the parsed values. + * @return GNUNET_OK only if the parsing succeedes. + */ +static int +parse_history_common_args (struct MHD_Connection *connection, +                           struct HistoryArgs *ha) +{ +  const char *start; +  const char *delta; +  const char *long_poll_ms; +  unsigned long long lp_timeout; +  unsigned long long sval; +  long long d; + +  start = MHD_lookup_connection_value (connection, +                                       MHD_GET_ARGUMENT_KIND, +                                       "start"); +  ha->have_start = (NULL != start); +  delta = MHD_lookup_connection_value (connection, +                                       MHD_GET_ARGUMENT_KIND, +                                       "delta"); +  long_poll_ms = MHD_lookup_connection_value (connection, +                                              MHD_GET_ARGUMENT_KIND, +                                              "long_poll_ms"); +  lp_timeout = 0; +  if ( (NULL == delta) || +       (1 != sscanf (delta, +                     "%lld", +                     &d)) || +       ( (NULL != long_poll_ms) && +         (1 != sscanf (long_poll_ms, +                       "%llu", +                       &lp_timeout)) ) || +       ( (NULL != start) && +         (1 != sscanf (start, +                       "%llu", +                       &sval)) ) ) +  { +    /* Fail if one of the above failed.  */ +    /* Invalid request, given that this is fakebank we impolitely +     * just kill the connection instead of returning a nice error. +     */ +    GNUNET_break (0); +    return GNUNET_NO; +  } +  if (NULL == start) +    ha->start_idx = (d > 0) ? 0 : UINT64_MAX; +  else +    ha->start_idx = (uint64_t) sval; +  ha->delta = (int64_t) d; +  ha->lp_timeout +    = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, +                                     lp_timeout); +  return GNUNET_OK; +} + + +/** + * Handle incoming HTTP request for /history/incoming   *   * @param h the fakebank handle   * @param connection the connection - * @param con_cls place to store state, not used + * @param account which account the request is about   * @return MHD result code   */  static int -handle_history (struct TALER_FAKEBANK_Handle *h, -                struct MHD_Connection *connection, -                void **con_cls) +handle_credit_history (struct TALER_FAKEBANK_Handle *h, +                       struct MHD_Connection *connection, +                       const char *account)  {    struct HistoryArgs ha; -  struct HistoryRangeIds hri; -  const char *start; -  const char *delta;    struct Transaction *pos; +  json_t *history; -  (void) con_cls;    if (GNUNET_OK != -      TFH_parse_history_common_args (connection, -                                     &ha)) +      parse_history_common_args (connection, +                                 &ha))    {      GNUNET_break (0);      return MHD_NO;    } -  start = MHD_lookup_connection_value (connection, -                                       MHD_GET_ARGUMENT_KIND, -                                       "start"); -  delta = MHD_lookup_connection_value (connection, -                                       MHD_GET_ARGUMENT_KIND, -                                       "delta"); -  if ( ((NULL != start) && (1 != sscanf (start, -                                         "%llu", -                                         &hri.start))) || -       (NULL == delta) || (1 != sscanf (delta, -                                        "%lld", -                                        &hri.count)) ) +  if (! ha.have_start) +  { +    pos = (0 > ha.delta) +          ? h->transactions_tail +          : h->transactions_head; +  } +  else if (NULL != h->transactions_head) +  { +    for (pos = h->transactions_head; +         NULL != pos; +         pos = pos->next) +      if (pos->row_id  == ha.start_idx) +        break; +    if (NULL == pos) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Invalid start specified, transaction %llu not known!\n", +                  (unsigned long long) ha.start_idx); +      return MHD_NO; +    } +    /* range is exclusive, skip the matching entry */ +    if (ha.delta > 0) +      pos = pos->next; +    if (ha.delta < 0) +      pos = pos->prev; +  } +  else +  { +    /* list is empty */ +    pos = NULL; +  } +  history = json_array (); +  while ( (0 != ha.delta) && +          (NULL != pos) ) +  { +    if (0 == strcasecmp (pos->credit_account, +                         account)) +    { +      json_t *trans; + +      trans = json_pack +                ("{s:I, s:o, s:o, s:s, s:s, s:s}", +                "row_id", (json_int_t) pos->row_id, +                "date", GNUNET_JSON_from_time_abs (pos->date), +                "amount", TALER_JSON_from_amount (&pos->amount), +                "credit_account", account, +                "debit_account", pos->debit_account, +                "wtid", pos->subject /* we "know" it is OK */); +      GNUNET_assert (0 == +                     json_array_append_new (history, +                                            trans)); +      if (ha.delta > 0) +        ha.delta--; +      else +        ha.delta++; +    } +    if (ha.delta > 0) +      pos = pos->prev; +    else +      pos = pos->next; +  } +  return TALER_MHD_reply_json (connection, +                               history, +                               MHD_HTTP_OK); +} + + +/** + * Handle incoming HTTP request for /history/incoming + * + * @param h the fakebank handle + * @param connection the connection + * @param account which account the request is about + * @return MHD result code + */ +static int +handle_debit_history (struct TALER_FAKEBANK_Handle *h, +                      struct MHD_Connection *connection, +                      const char *account) +{ +  struct HistoryArgs ha; +  struct Transaction *pos; +  json_t *history; + +  if (GNUNET_OK != +      parse_history_common_args (connection, +                                 &ha))    {      GNUNET_break (0);      return MHD_NO;    } -  ha.range = &hri; -  if (NULL == start) +  if (! ha.have_start)    { -    pos = 0 > hri.count ? -          h->transactions_tail : h->transactions_head; +    pos = (0 > ha.delta) +          ? h->transactions_tail +          : h->transactions_head;    }    else if (NULL != h->transactions_head)    {      for (pos = h->transactions_head;           NULL != pos;           pos = pos->next) -      if (pos->row_id  == hri.start) +      if (pos->row_id  == ha.start_idx)          break;      if (NULL == pos)      {        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Invalid range specified," -                  " transaction %llu not known!\n", -                  (unsigned long long) hri.start); +                  "Invalid start specified, transaction %llu not known!\n", +                  (unsigned long long) ha.start_idx);        return MHD_NO;      }      /* range is exclusive, skip the matching entry */ -    if (hri.count > 0) +    if (ha.delta > 0)        pos = pos->next; -    if (hri.count < 0) +    if (ha.delta < 0)        pos = pos->prev;    }    else @@ -702,56 +840,77 @@ handle_history (struct TALER_FAKEBANK_Handle *h,      /* list is empty */      pos = NULL;    } -  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "/history, start row (0 == no transactions exist): %llu\n", -              NULL != pos ? pos->row_id : 0LL); -  return TFH_build_history_response (connection, -                                     pos, -                                     &ha, -                                     &TFH_handle_history_skip, -                                     &TFH_handle_history_step, -                                     &TFH_handle_history_advance); +  history = json_array (); +  while ( (0 != ha.delta) && +          (NULL != pos) ) +  { +    if (0 == strcasecmp (pos->debit_account, +                         account)) +    { +      json_t *trans; + +      trans = json_pack +                ("{s:I, s:o, s:o, s:s, s:s, s:s}", +                "row_id", (json_int_t) pos->row_id, +                "date", GNUNET_JSON_from_time_abs (pos->date), +                "amount", TALER_JSON_from_amount (&pos->amount), +                "credit_account", pos->credit_account, +                "debit_account", account, +                "reserve_pub", pos->subject /* we "know" it is OK */); +      GNUNET_assert (0 == +                     json_array_append_new (history, +                                            trans)); +      if (ha.delta > 0) +        ha.delta--; +      else +        ha.delta++; +    } +    if (ha.delta > 0) +      pos = pos->prev; +    else +      pos = pos->next; +  } +  return TALER_MHD_reply_json (connection, +                               history, +                               MHD_HTTP_OK);  }  /**   * Handle incoming HTTP request.   * - * @param cls a `struct TALER_FAKEBANK_Handle` + * @param h our handle   * @param connection the connection   * @param url the requested url   * @param method the method (POST, GET, ...) - * @param version HTTP version (ignored) + * @param account which account should process the request   * @param upload_data request data   * @param upload_data_size size of @a upload_data in bytes   * @param con_cls closure for request (a `struct Buffer *`)   * @return MHD result code   */  static int -handle_mhd_request (void *cls, -                    struct MHD_Connection *connection, -                    const char *url, -                    const char *method, -                    const char *version, -                    const char *upload_data, -                    size_t *upload_data_size, -                    void **con_cls) +serve (struct TALER_FAKEBANK_Handle *h, +       struct MHD_Connection *connection, +       const char *account, +       const char *url, +       const char *method, +       const char *upload_data, +       size_t *upload_data_size, +       void **con_cls)  { -  struct TALER_FAKEBANK_Handle *h = cls; - -  (void) version;    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                "Fakebank, serving: %s\n",                url); -  if ( (0 == strcasecmp (url, -                         "/")) && +  if ( (0 == strcmp (url, +                     "/")) &&         (0 == strcasecmp (method,                           MHD_HTTP_METHOD_GET)) )      return handle_home_page (h,                               connection,                               con_cls); -  if ( (0 == strcasecmp (url, -                         "/admin/add/incoming")) && +  if ( (0 == strcmp (url, +                     "/admin/add/incoming")) &&         (0 == strcasecmp (method,                           MHD_HTTP_METHOD_POST)) )      return handle_admin_add_incoming (h, @@ -759,22 +918,33 @@ handle_mhd_request (void *cls,                                        upload_data,                                        upload_data_size,                                        con_cls); -  if ( (0 == strcasecmp (url, -                         "/reject")) && +  if ( (0 == strcmp (url, +                     "/transaction")) && +       (NULL != account) &&         (0 == strcasecmp (method,                           MHD_HTTP_METHOD_POST)) ) -    return handle_reject (h, -                          connection, -                          upload_data, -                          upload_data_size, -                          con_cls); -  if ( (0 == strcasecmp (url, -                         "/history")) && +    return handle_transaction (h, +                               connection, +                               account, +                               upload_data, +                               upload_data_size, +                               con_cls); +  if ( (0 == strcmp (url, +                     "/history/incoming")) && +       (NULL != account) && +       (0 == strcasecmp (method, +                         MHD_HTTP_METHOD_GET)) ) +    return handle_credit_history (h, +                                  connection, +                                  account); +  if ( (0 == strcmp (url, +                     "/history/outgoing")) && +       (NULL != account) &&         (0 == strcasecmp (method,                           MHD_HTTP_METHOD_GET)) ) -    return handle_history (h, -                           connection, -                           con_cls); +    return handle_debit_history (h, +                                 connection, +                                 account);    /* Unexpected URL path, just close the connection. */    /* we're rather impolite here, but it's a testcase. */ @@ -786,6 +956,55 @@ handle_mhd_request (void *cls,  /** + * Handle incoming HTTP request. + * + * @param cls a `struct TALER_FAKEBANK_Handle` + * @param connection the connection + * @param url the requested url + * @param method the method (POST, GET, ...) + * @param version HTTP version (ignored) + * @param upload_data request data + * @param upload_data_size size of @a upload_data in bytes + * @param con_cls closure for request (a `struct Buffer *`) + * @return MHD result code + */ +static int +handle_mhd_request (void *cls, +                    struct MHD_Connection *connection, +                    const char *url, +                    const char *method, +                    const char *version, +                    const char *upload_data, +                    size_t *upload_data_size, +                    void **con_cls) +{ +  struct TALER_FAKEBANK_Handle *h = cls; +  char *account = NULL; +  char *end; +  int ret; + +  (void) version; +  if ( (strlen (url) > 1) && +       (NULL != (end = strchr (url + 1, '/'))) ) +  { +    account = GNUNET_strndup (url + 1, +                              end - url - 1); +    url = end; +  } +  ret = serve (h, +               connection, +               account, +               url, +               method, +               upload_data, +               upload_data_size, +               con_cls); +  GNUNET_free_non_null (account); +  return ret; +} + + +/**   * Task run whenever HTTP server operations are pending.   *   * @param cls the `struct TALER_FAKEBANK_Handle` @@ -918,6 +1137,7 @@ TALER_FAKEBANK_start (uint16_t port)    struct TALER_FAKEBANK_Handle *h;    h = GNUNET_new (struct TALER_FAKEBANK_Handle); +  h->port = port;    h->mhd_bank = MHD_start_daemon (MHD_USE_DEBUG  #if EPOLL_SUPPORT                                    | MHD_USE_EPOLL_INTERNAL_THREAD diff --git a/src/bank-lib/fakebank.h b/src/bank-lib/fakebank.h index cc235901..c52902f1 100644 --- a/src/bank-lib/fakebank.h +++ b/src/bank-lib/fakebank.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2016, 2017, 2018 Inria and GNUnet e.V. +  (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License @@ -19,7 +19,7 @@  /**   * @file bank-lib/fakebank.h - * @brief definitions for the "/history[-range]" layer. + * @brief definitions for the "/history" layer.   * @author Marcello Stanisci <stanisci.m@gmail.com>   */ @@ -29,283 +29,4 @@  #include <gnunet/gnunet_util_lib.h>  #include "taler_bank_service.h" -/** - * Details about a transcation we (as the simulated bank) received. - */ -struct Transaction -{ -  /** -   * We store transactions in a DLL. -   */ -  struct Transaction *next; - -  /** -   * We store transactions in a DLL. -   */ -  struct Transaction *prev; - -  /** -   * Amount to be transferred. -   */ -  struct TALER_Amount amount; - -  /** -   * Account to debit. -   */ -  uint64_t debit_account; - -  /** -   * Account to credit. -   */ -  uint64_t credit_account; - -  /** -   * Subject of the transfer. -   */ -  char *subject; - -  /** -   * Base URL of the exchange. -   */ -  char *exchange_base_url; - -  /** -   * When did the transaction happen? -   */ -  struct GNUNET_TIME_Absolute date; - -  /** -   * Number of this transaction. -   */ -  long long unsigned int row_id; - -  /** -   * Flag set if the transfer was rejected. -   */ -  int rejected; - -  /** -   * Has this transaction been subjected to #TALER_FAKEBANK_check() -   * and should thus no longer be counted in -   * #TALER_FAKEBANK_check_empty()? -   */ -  int checked; -}; - - -/****************************************** - * Definitions for "/history" start here. * - ******************************************/ - -/** - * Needed to implement ascending/descending ordering - * of /history results. - */ -struct HistoryElement -{ - -  /** -   * History JSON element. -   */ -  json_t *element; - -  /** -   * Previous element. -   */ -  struct HistoryElement *prev; - -  /** -   * Next element. -   */ -  struct HistoryElement *next; -}; - - -/** - * Values to implement the "/history-range" range. - */ -struct HistoryRangeDates -{ -  /** -   * Oldest row in the results. -   */ -  struct GNUNET_TIME_Absolute start; - -  /** -   * Youngest row in the results. -   */ -  struct GNUNET_TIME_Absolute end; -}; - -/** - * Values to implement the "/history" range. - */ -struct HistoryRangeIds -{ - -  /** -   * (Exclusive) row ID for the result set. -   */ -  unsigned long long start; - -  /** -   * How many transactions we want in the result set.  If -   * negative/positive, @a start will be strictly younger/older -   * of any element in the result set. -   */ -  long long count; -}; - - -/** - * This is the "base" structure for both the /history and the - * /history-range API calls. - */ -struct HistoryArgs -{ - -  /** -   * Direction asked by the client: CREDIT / DEBIT / BOTH / CANCEL. -   */ -  enum TALER_BANK_Direction direction; - -  /** -   * Bank account number of the requesting client. -   */ -  unsigned long long account_number; - -  /** -   * Ordering of the results. -   */ -  unsigned int ascending; - -  /** -   * Overloaded type that indicates the "range" to be returned -   * in the results; this can be either a date range, or a -   * starting row id + the count. -   */ -  void *range; -}; - - -/** - * Type for a function that decides whether or not - * the history-building loop should iterate once again. - * Typically called from inside the 'while' condition. - * - * @param ha history argument. - * @param pos current position. - * @return GNUNET_YES if the iteration shuold go on. - */ -typedef int (*CheckAdvance)(const struct HistoryArgs *ha, -                            const struct Transaction *pos); - -/** - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * _got_ included in the result. - */ -typedef struct Transaction * (*Step)(const struct HistoryArgs *ha, -                                     const struct Transaction *pos); - -/* - * Type for a function that steps over the next element - * in the list of all transactions, after the current @a pos - * did _not_ get included in the result. - */ -typedef struct Transaction * (*Skip)(const struct HistoryArgs *ha, -                                     const struct Transaction *pos); - -/** - * Actual history response builder. - * - * @param pos first (included) element in the result set. - * @param ha history arguments. - * @param caller_name which function is building the history. - * @return MHD_YES / MHD_NO, after having enqueued the response - *         object into MHD. - */ -int -TFH_build_history_response (struct MHD_Connection *connection, -                            struct Transaction *pos, -                            struct HistoryArgs *ha, -                            Skip skip, -                            Step step, -                            CheckAdvance advance); - - -/** - * Parse URL history arguments, of _both_ APIs: - * /history and /history-range. - * - * @param connection MHD connection. - * @param function_name name of the caller. - * @param ha[out] will contain the parsed values. - * @return GNUNET_OK only if the parsing succeedes. - */ -int -TFH_parse_history_common_args (struct MHD_Connection *connection, -                               struct HistoryArgs *ha); - - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -int -TFH_handle_history_advance (const struct HistoryArgs *ha, -                            const struct Transaction *pos); - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -struct Transaction * -TFH_handle_history_skip (const struct HistoryArgs *ha, -                         const struct Transaction *pos); - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element _gets_ inserted in the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -struct Transaction * -TFH_handle_history_step (const struct HistoryArgs *ha, -                         const struct Transaction *pos); - -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -int -TFH_handle_history_range_advance (const struct HistoryArgs *ha, -                                  const struct Transaction *pos); - -/** - * Iterates towards the "next" element to be processed.  To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -struct Transaction * -TFH_handle_history_range_skip (const struct HistoryArgs *ha, -                               const struct Transaction *pos); -  #endif diff --git a/src/bank-lib/fakebank_history.c b/src/bank-lib/fakebank_history.c index f4c615c5..2781cdca 100644 --- a/src/bank-lib/fakebank_history.c +++ b/src/bank-lib/fakebank_history.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2016, 2017, 2018 Inria and GNUnet e.V. +  (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or    modify it under the terms of the GNU General Public License @@ -19,92 +19,15 @@  /**   * @file bank-lib/fakebank_history.c - * @brief definitions for the "/history[-range]" layer. + * @brief definitions for the "/history" layer.   * @author Marcello Stanisci <stanisci.m@gmail.com>   */ -  #include "platform.h"  #include <gnunet/gnunet_util_lib.h>  #include "taler_json_lib.h"  #include "fakebank.h" -/** - * Decides whether the history builder will advance or not - * to the next element. - * - * @param ha history args - * @return GNUNET_YES/NO to advance/not-advance. - */ -int -TFH_handle_history_advance (const struct HistoryArgs *ha, -                            const struct Transaction *pos) -{ -  const struct HistoryRangeIds *hri = ha->range; - -  return (NULL != pos) && (0 != hri->count); -} - - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element does not get inserted in - * the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -struct Transaction * -TFH_handle_history_skip (const struct HistoryArgs *ha, -                         const struct Transaction *pos) -{ -  const struct HistoryRangeIds *hri = ha->range; - -  if (hri->count > 0) -    return pos->next; -  if (hri->count < 0) -    return pos->prev; -  return NULL; -} - - -/** - * Iterates on the "next" element to be processed.  To - * be used when the current element _gets_ inserted in the result. - * - * @param ha history arguments. - * @param pos current element being processed. - * @return the next element to be processed. - */ -struct Transaction * -TFH_handle_history_step (const struct HistoryArgs *ha, -                         const struct Transaction *pos) -{ -  struct HistoryRangeIds *hri = ha->range; - -  if (hri->count > 0) -  { -    hri->count--; -    return pos->next; -  } -  if (hri->count < 0) -  { -    hri->count++; -    return pos->prev; -  } -  return NULL; -} - -/** - * Actual history response builder. - * - * @param pos first (included) element in the result set, NULL if history is empty - * @param ha history arguments. - * @param caller_name which function is building the history. - * @return MHD_YES / MHD_NO, after having enqueued the response - *         object into MHD. - */  int  TFH_build_history_response (struct MHD_Connection *connection,                              struct Transaction *pos, @@ -257,126 +180,3 @@ TFH_build_history_response (struct MHD_Connection *connection,    }    return ret;  } - - -/** - * Parse URL history arguments, of _both_ APIs: - * /history and /history-range. - * - * @param connection MHD connection. - * @param function_name name of the caller. - * @param ha[out] will contain the parsed values. - * @return GNUNET_OK only if the parsing succeedes. - */ -int -TFH_parse_history_common_args (struct MHD_Connection *connection, -                               struct HistoryArgs *ha) -{ -  /** -   * @variable -   * Just check if given and == "basic", no need to keep around. -   */ -  const char *auth; - -  /** -   * All those will go into the structure, after parsing. -   */ -  const char *direction; -  const char *cancelled; -  const char *ordering; -  const char *account_number; - - -  auth = MHD_lookup_connection_value (connection, -                                      MHD_GET_ARGUMENT_KIND, -                                      "auth"); -  direction = MHD_lookup_connection_value (connection, -                                           MHD_GET_ARGUMENT_KIND, -                                           "direction"); -  cancelled = MHD_lookup_connection_value (connection, -                                           MHD_GET_ARGUMENT_KIND, -                                           "cancelled"); -  ordering = MHD_lookup_connection_value (connection, -                                          MHD_GET_ARGUMENT_KIND, -                                          "ordering"); -  account_number = MHD_lookup_connection_value -                     (connection, -                     MHD_GET_ARGUMENT_KIND, -                     "account_number"); - -  /* Fail if one of the above failed.  */ -  if ( (NULL == direction) || -       (NULL == cancelled) || -       ( (0 != strcasecmp (cancelled, -                           "OMIT")) && -         (0 != strcasecmp (cancelled, -                           "SHOW")) ) || -       ( (0 != strcasecmp (direction, -                           "BOTH")) && -         (0 != strcasecmp (direction, -                           "CREDIT")) && -         (0 != strcasecmp (direction, -                           "DEBIT")) ) || -       (1 != sscanf (account_number, -                     "%llu", -                     &ha->account_number)) || -       ( (NULL == auth) || (0 != strcasecmp (auth, -                                             "basic")) ) ) -  { -    /* Invalid request, given that this is fakebank we impolitely -     * just kill the connection instead of returning a nice error. -     */ -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if (0 == strcasecmp (direction, -                       "CREDIT")) -  { -    ha->direction = TALER_BANK_DIRECTION_CREDIT; -  } -  else if (0 == strcasecmp (direction, -                            "DEBIT")) -  { -    ha->direction = TALER_BANK_DIRECTION_DEBIT; -  } -  else if (0 == strcasecmp (direction, -                            "BOTH")) -  { -    ha->direction = TALER_BANK_DIRECTION_BOTH; -  } - -  /* Direction is invalid.  */ -  else -  { -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if (0 == strcasecmp (cancelled, -                       "OMIT")) -  { -    /* nothing */ -  } -  else if (0 == strcasecmp (cancelled, -                            "SHOW")) -  { -    ha->direction |= TALER_BANK_DIRECTION_CANCEL; -  } - -  /* Cancel-showing policy is invalid.  */ -  else -  { -    GNUNET_break (0); -    return GNUNET_NO; -  } - -  if ((NULL != ordering) -      && (0 == strcmp ("ascending", -                       ordering))) -    ha->ascending = GNUNET_YES; -  else -    ha->ascending = GNUNET_NO; - -  return GNUNET_OK; -} diff --git a/src/bank-lib/taler-bank-transfer.c b/src/bank-lib/taler-bank-transfer.c index 625545b6..c52c4b38 100644 --- a/src/bank-lib/taler-bank-transfer.c +++ b/src/bank-lib/taler-bank-transfer.c @@ -25,9 +25,9 @@  #include "taler_bank_service.h"  /** - * Bank URL. + * Account base URL.   */ -static char *bank_url; +static char *account_base_url;  /**   * Amount to transfer. @@ -35,14 +35,9 @@ static char *bank_url;  static struct TALER_Amount amount;  /** - * Debit account number. + * Credit account payto://-URI.   */ -static unsigned long long debit_account_no; - -/** - * Credit account number. - */ -static unsigned long long credit_account_no; +static char *credit_account;  /**   * Wire transfer subject. @@ -168,11 +163,23 @@ run (void *cls,       const struct GNUNET_CONFIGURATION_Handle *cfg)  {    struct TALER_BANK_AuthenticationData auth; +  struct TALER_ReservePublicKeyP reserve_pub;    (void) cls;    (void) args;    (void) cfgfile;    (void) cfg; +  if (GNUNET_OK != +      GNUNET_STRINGS_string_to_data (subject, +                                     strlen (subject), +                                     &reserve_pub, +                                     sizeof (reserve_pub))) +  { +    fprintf (stderr, +             "Error: wire transfer subject must be a reserve public key\n"); +    return; +  } +    ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,                            &rc);    GNUNET_assert (NULL != ctx); @@ -182,13 +189,11 @@ run (void *cls,    auth.details.basic.username = username;    auth.details.basic.password = password;    op = TALER_BANK_admin_add_incoming (ctx, -                                      bank_url, +                                      account_base_url,                                        &auth, -                                      "https://exchange.com/legacy", -                                      subject, +                                      &reserve_pub,                                        &amount, -                                      debit_account_no, -                                      credit_account_no, +                                      credit_account,                                        &res_cb,                                        NULL);    GNUNET_SCHEDULER_add_shutdown (&do_shutdown, @@ -219,26 +224,20 @@ main (int argc, char *const *argv)        (GNUNET_GETOPT_option_string ('b',                                      "bank",                                      "URL", -                                    "base URL of the bank", -                                    &bank_url)), +                                    "base URL of the account at the bank", +                                    &account_base_url)),      GNUNET_GETOPT_option_help ("Deposit funds into a Taler reserve"),      GNUNET_GETOPT_option_mandatory -      (GNUNET_GETOPT_option_ulong ('C', -                                   "credit", -                                   "ACCOUNT", -                                   "number of the bank account to credit", -                                   &credit_account_no)), -    GNUNET_GETOPT_option_mandatory -      (GNUNET_GETOPT_option_ulong ('D', -                                   "debit", -                                   "ACCOUNT", -                                   "number of the bank account to debit", -                                   &debit_account_no)), +      (GNUNET_GETOPT_option_string ('C', +                                    "credit", +                                    "ACCOUNT", +                                    "payto URL of the bank account to credit", +                                    &credit_account)),      GNUNET_GETOPT_option_mandatory        (GNUNET_GETOPT_option_string ('s',                                      "subject",                                      "STRING", -                                    "specifies the wire transfer subject", +                                    "specifies the wire transfer subject (must be a reserve public key)",                                      &subject)),      GNUNET_GETOPT_option_mandatory        (GNUNET_GETOPT_option_string ('u', diff --git a/src/bank-lib/test_bank_api.c b/src/bank-lib/test_bank_api.c index d15984a9..087e4484 100644 --- a/src/bank-lib/test_bank_api.c +++ b/src/bank-lib/test_bank_api.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2016, 2017 GNUnet e.V. +  Copyright (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as diff --git a/src/bank-lib/testing_api_cmd_history.c b/src/bank-lib/testing_api_cmd_history_credit.c index dc5cd2d9..5c2b34d0 100644 --- a/src/bank-lib/testing_api_cmd_history.c +++ b/src/bank-lib/testing_api_cmd_history_credit.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2018 Taler Systems SA +  Copyright (C) 2018-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as @@ -16,13 +16,11 @@    License along with TALER; see the file COPYING.  If not, see    <http://www.gnu.org/licenses/>  */ -  /**   * @file bank-lib/testing_api_cmd_history.c   * @brief command to check the /history API from the bank.   * @author Marcello Stanisci   */ -  #include "platform.h"  #include "taler_json_lib.h"  #include <gnunet/gnunet_curl_lib.h> @@ -40,35 +38,26 @@  struct HistoryState  {    /** -   * Base URL of the bank offering the "history" operation. -   */ -  const char *bank_url; - -  /** -   * Account number to ask the history for. -   */ -  uint64_t account_no; - -  /** -   * Which type of records we are interested: in-transfers -   * / out-transfers / rejected transfers. +   * Base URL of the account offering the "history" operation.     */ -  enum TALER_BANK_Direction direction; +  char *account_url;    /** -   * First row number we want in the result. +   * Reference to command defining the +   * first row number we want in the result.     */    const char *start_row_reference;    /** -   * How many rows we want in the result, _at most_. +   * How many rows we want in the result, _at most_, +   * and ascending/descending.     */ -  unsigned long long num_results; +  long long num_results;    /**     * Handle to a pending "history" operation.     */ -  struct TALER_BANK_HistoryHandle *hh; +  struct TALER_BANK_CreditHistoryHandle *hh;    /**     * Expected number of results (= rows). @@ -81,34 +70,9 @@ struct HistoryState     */    int failed; -  /** -   * If GNUNET_YES, this parameter will ask for results in -   * chronological order. -   */ -  unsigned int ascending; - -  /********************************** -   * Following defs are specific to * -   * the "/history-range" version.  * -   **********************************/ - -  /** -   * Last row number we want in the result.  Only used -   * as a trait source when using the /history-range API. -   */ -  const char *end_row_reference; - -  /** -   * Start date for /history-range. -   */ -  struct GNUNET_TIME_Absolute start_date; - -  /** -   * End date for /history-range. -   */ -  struct GNUNET_TIME_Absolute end_date;  }; +  /**   * Item in the transaction history, as reconstructed from the   * command history. @@ -119,7 +83,7 @@ struct History    /**     * Wire details.     */ -  struct TALER_BANK_TransferDetails details; +  struct TALER_BANK_CreditDetails details;    /**     * Serial ID of the wire transfer. @@ -127,20 +91,13 @@ struct History    uint64_t row_id;    /** -   * Direction of the transfer. +   * URL to free.     */ -  enum TALER_BANK_Direction direction; - +  char *url;  };  /** - * Array mapping bank account numbers to login credentials. - */ -extern struct TALER_BANK_AuthenticationData AUTHS[]; - - -/**   * Offer internal data to other commands.   *   * @param cls closure. @@ -167,51 +124,6 @@ history_traits (void *cls,  /** - * Test if the CMD at offset @a off has been /rejected, and - * is indeed a wire transfer CMD. - * - * @param is interpreter state (where we are right now) - * @param off offset of the command to test for rejection. - * - * @return GNUNET_YES if the command at @a off was cancelled. - */ -static int -test_cancelled (struct TALER_TESTING_Interpreter *is, -                unsigned int off) -{ -  const char *rejected_reference; -  const struct TALER_TESTING_Command *current_cmd; - -  current_cmd = &is->commands[off]; -  TALER_LOG_INFO ("Is `%s' rejected?\n", -                  current_cmd->label); -  for (int i = 0; i<is->ip; i++) -  { -    const struct TALER_TESTING_Command *c = &is->commands[i]; - - -    /* XXX: Errors reported here are NOT fatal */ - -    /* Rejected wire transfers have a non-NULL reference to a -     * reject command to mark them as rejected. So errors -     * about "reject traits" not found are NOT fatal here */ -    if (GNUNET_OK != TALER_TESTING_get_trait_rejected -          (c, 0, &rejected_reference)) -      continue; - -    TALER_LOG_INFO ("Command `%s' was rejected by `%s'.\n", -                    current_cmd->label, -                    c->label); - -    if (0 == strcmp (rejected_reference, -                     current_cmd->label)) -      return GNUNET_YES; -  } -  return GNUNET_NO; -} - - -/**   * Free history @a h of length @a h_len.   *   * @param h history array to free. @@ -222,10 +134,7 @@ free_history (struct History *h,                uint64_t h_len)  {    for (uint64_t off = 0; off<h_len; off++) -  { -    GNUNET_free (h[off].details.wire_transfer_subject); -    GNUNET_free (h[off].details.account_url); -  } +    GNUNET_free (h[off].url);    GNUNET_free_non_null (h);  } @@ -251,14 +160,12 @@ print_expected (struct History *h,    for (uint64_t i = 0; i<h_len; i++)    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "H(%llu): %s%s (serial: %llu, subject: %s," +                "H(%llu): %s (serial: %llu, subject: %s,"                  " counterpart: %s)\n",                  (unsigned long long) i, -                (TALER_BANK_DIRECTION_CREDIT == h[i].direction) ? -                "+" : "-",                  TALER_amount2s (&h[i].details.amount),                  (unsigned long long) h[i].row_id, -                h[i].details.wire_transfer_subject, +                TALER_B2S (&h[i].details.reserve_pub),                  h[i].details.account_url);    }  } @@ -280,20 +187,6 @@ build_history_hit_limit (uint64_t total,                           const struct HistoryState *hs,                           const struct TALER_TESTING_Command *pos)  { -  /* "/history-range" case.  */ -  if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != -      hs->start_date.abs_value_us) -  { -    const struct GNUNET_TIME_Absolute *timestamp; - -    GNUNET_assert (GNUNET_OK == -                   TALER_TESTING_get_trait_absolute_time (pos, -                                                          0, -                                                          ×tamp)); -    GNUNET_assert (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != -                   hs->end_date.abs_value_us); -    return timestamp->abs_value_us >= hs->end_date.abs_value_us; -  }    return total >= hs->num_results;  } @@ -305,13 +198,6 @@ build_history_hit_limit (uint64_t total,   * to be allocated, and the second to actually populate every   * element.   * - * This command has a limitation currently: it orders the history - * list with descending elements if and only if the 'delta' was - * given negative; and will order the list with ascending elements - * if and only if the 'delta' was given positive.  Therefore, - * for now it is NOT possible to test such a "/history" request: - * "/history?auth=basic&direction=both&delta=10&ordering=descending" - *   * @param is interpreter state (supposedly having the   *        current CMD pointing at a "history" CMD).   * @param[out] rh history array to initialize. @@ -350,10 +236,7 @@ build_history (struct TALER_TESTING_Interpreter *is,                       (add_incoming_cmd, 0, &row_id_start));    } -  GNUNET_assert ((0 != hs->num_results) || /* "/history" */ -                 (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != /* "/history-range" */ -                  hs->start_date.abs_value_us)); - +  GNUNET_assert (0 != hs->num_results);    if (0 == is->ip)    {      TALER_LOG_DEBUG ("Checking history at first CMD..\n"); @@ -387,8 +270,9 @@ build_history (struct TALER_TESTING_Interpreter *is,    for (unsigned int off = start; off != end + inc; off += inc)    {      const struct TALER_TESTING_Command *pos = &is->commands[off]; -    int cancelled;      const uint64_t *row_id; +    const char *credit_account; +    const char *debit_account;      /**       * The following command allows us to skip over those CMDs @@ -411,28 +295,6 @@ build_history (struct TALER_TESTING_Interpreter *is,        }      } -    /* Seek "/history-range" starting row, _if_ that's the case */ -    if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != -         hs->start_date.abs_value_us) && (GNUNET_YES != ok)) -    { -      const struct GNUNET_TIME_Absolute *timestamp; - -      TALER_TESTING_get_trait_absolute_time (pos, -                                             0, -                                             ×tamp); -      TALER_LOG_DEBUG -        ("Seeking first row, start vs timestamp: %llu vs %llu\n", -        (long long unsigned int) hs->start_date.abs_value_us, -        (long long unsigned int) timestamp->abs_value_us); - -      if (hs->start_date.abs_value_us <= timestamp->abs_value_us) -      { -        total = 0; -        ok = GNUNET_YES; -        continue; -      } -    } -      /* when 'start' was _not_ given, then ok == GNUNET_YES */      if (GNUNET_NO == ok)        continue; /* skip until we find the marker */ @@ -447,37 +309,23 @@ build_history (struct TALER_TESTING_Interpreter *is,        break;      } -    cancelled = test_cancelled (is, off); - -    if ( (GNUNET_YES == cancelled) && -         (0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) ) -    { -      TALER_LOG_INFO ("Ignoring canceled wire" -                      " transfer from history\n"); -      continue; -    } - -    const uint64_t *credit_account_no; -    const uint64_t *debit_account_no;      GNUNET_assert        (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT -        (pos, &credit_account_no)); +        (pos, &credit_account));      GNUNET_assert        (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT -        (pos, &debit_account_no)); +        (pos, &debit_account));      TALER_LOG_INFO ("Potential history element:" -                    " %llu->%llu; my account: %llu\n", -                    (unsigned long long) *debit_account_no, -                    (unsigned long long) *credit_account_no, -                    (unsigned long long) hs->account_no); - -    if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) && -           (hs->account_no == *credit_account_no)) || -         ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) && -           (hs->account_no == *debit_account_no)) ) +                    " %s->%s; my account: %s\n", +                    debit_account, +                    credit_account, +                    hs->account_url); + +    if (0 == strcasecmp (hs->account_url, +                         credit_account))      {        TALER_LOG_INFO ("+1 my history\n");        total++; /* found matching record */ @@ -508,11 +356,10 @@ build_history (struct TALER_TESTING_Interpreter *is,    for (unsigned int off = start; off != end + inc; off += inc)    {      const struct TALER_TESTING_Command *pos = &is->commands[off]; -    int cancelled;      const uint64_t *row_id;      char *bank_hostname; -    const uint64_t *credit_account_no; -    const uint64_t *debit_account_no; +    const char *credit_account; +    const char *debit_account;      if (GNUNET_OK != TALER_TESTING_GET_TRAIT_ROW_ID            (pos, &row_id)) @@ -533,28 +380,6 @@ build_history (struct TALER_TESTING_Interpreter *is,        }      } -    /* Seek "/history-range" starting row, _if_ that's the case */ -    if ((GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != -         hs->start_date.abs_value_us) && (GNUNET_YES != ok)) -    { -      const struct GNUNET_TIME_Absolute *timestamp; - -      TALER_TESTING_get_trait_absolute_time (pos, -                                             0, -                                             ×tamp); -      TALER_LOG_DEBUG -        ("Seeking first row, start vs timestamp (2): %llu vs %llu\n", -        (long long unsigned int) hs->start_date.abs_value_us, -        (long long unsigned int) timestamp->abs_value_us); - -      if (hs->start_date.abs_value_us <= timestamp->abs_value_us) -      { -        total = 0; -        ok = GNUNET_YES; -        continue; -      } -    } -      TALER_LOG_INFO ("Found first row (2)\n");      if (GNUNET_NO == ok) @@ -574,43 +399,31 @@ build_history (struct TALER_TESTING_Interpreter *is,      GNUNET_assert        (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT -        (pos, &credit_account_no)); +        (pos, &credit_account));      GNUNET_assert        (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT -        (pos, &debit_account_no)); +        (pos, &debit_account));      TALER_LOG_INFO ("Potential history bit:" -                    " %llu->%llu; my account: %llu\n", -                    (unsigned long long) *debit_account_no, -                    (unsigned long long) *credit_account_no, -                    (unsigned long long) hs->account_no); +                    " %s->%s; my account: %s\n", +                    debit_account, +                    credit_account, +                    hs->account_url);      /**       * Discard transactions where the audited account played       * _both_ the credit and the debit roles, but _only if_       * the audit goes on both directions..  This needs more       * explaination! -     */if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) && -           (hs->account_no == *credit_account_no)) && -         ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) && -           (hs->account_no == *debit_account_no)) ) +     */if (0 == strcasecmp (hs->account_url, +                         credit_account))      {        GNUNET_break (0);        continue;      } -    cancelled = test_cancelled (is, off); -    if ( (GNUNET_YES == cancelled) && -         (0 == (hs->direction & TALER_BANK_DIRECTION_CANCEL)) ) -    { -      TALER_LOG_WARNING ("`%s' was cancelled\n", -                         TALER_TESTING_interpreter_get_current_label -                           (is)); -      continue; -    } - -    bank_hostname = strchr (hs->bank_url, ':'); +    bank_hostname = strchr (hs->account_url, ':');      GNUNET_assert (NULL != bank_hostname);      bank_hostname += 3; @@ -618,68 +431,36 @@ build_history (struct TALER_TESTING_Interpreter *is,       * information.  */      /* Asked for credit, and account got the credit.  */ -    if ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) && -         (hs->account_no == *credit_account_no)) -    { -      h[total].direction = TALER_BANK_DIRECTION_CREDIT; -      if (GNUNET_YES == cancelled) -        h[total].direction |= TALER_BANK_DIRECTION_CANCEL; - -      GNUNET_asprintf -        (&h[total].details.account_url, -        ('/' == bank_hostname[strlen (bank_hostname) - 1]) -        ? "payto://x-taler-bank/%s%llu" -        : "payto://x-taler-bank/%s/%llu", -        bank_hostname, -        (unsigned long long) *debit_account_no); -    } - -    /* Asked for debit, and account got the debit.  */ -    if ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) && -         (hs->account_no == *debit_account_no)) +    if (0 == strcasecmp (hs->account_url, +                         credit_account))      { -      h[total].direction = TALER_BANK_DIRECTION_DEBIT; -      if (GNUNET_YES == cancelled) -        h[total].direction |= TALER_BANK_DIRECTION_CANCEL; - -      GNUNET_asprintf -        (&h[total].details.account_url, -        ('/' == bank_hostname[strlen (bank_hostname) - 1]) -        ? "payto://x-taler-bank/%s%llu" -        : "payto://x-taler-bank/%s/%llu", -        bank_hostname, -        (unsigned long long) *credit_account_no); +      h[total].url = GNUNET_strdup (debit_account); +      h[total].details.account_url = h[total].url;      }      /* This block _completes_ the information of the current item,       * with amount / subject / exchange URL.  */ -    if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) && -           (hs->account_no == *credit_account_no)) || -         ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) && -           (hs->account_no == *debit_account_no)) ) +    if (0 == strcasecmp (hs->account_url, +                         credit_account))      {        const struct TALER_Amount *amount; -      const char *subject; -      const char *exchange_url; - -      GNUNET_assert -        (GNUNET_OK == TALER_TESTING_get_trait_amount_obj -          (pos, 0, &amount)); - -      GNUNET_assert -        (GNUNET_OK == TALER_TESTING_get_trait_transfer_subject -          (pos, 0, &subject)); - -      GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_url -                       (pos, 0, &exchange_url)); - +      const struct TALER_ReservePublicKeyP *reserve_pub; +      const char *account_url; + +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_amount_obj +                       (pos, 0, &amount)); +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_reserve_pub +                       (pos, 0, &reserve_pub)); +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_url +                       (pos, 1, +                       &account_url));        h[total].details.amount = *amount; -        h[total].row_id = *row_id; -      GNUNET_asprintf (&h[total].details.wire_transfer_subject, -                       "%s %s", -                       subject, -                       exchange_url); +      h[total].details.reserve_pub = *reserve_pub; +      h[total].details.account_url = account_url;        TALER_LOG_INFO ("+1-bit of my history\n");        total++;      } @@ -723,8 +504,7 @@ compute_result_count (struct TALER_TESTING_Interpreter *is)  static int  check_result (struct TALER_TESTING_Interpreter *is,                unsigned int off, -              enum TALER_BANK_Direction dir, -              const struct TALER_BANK_TransferDetails *details) +              const struct TALER_BANK_CreditDetails *details)  {    uint64_t total;    struct History *h; @@ -737,27 +517,22 @@ check_result (struct TALER_TESTING_Interpreter *is,                  " results, but got result #%u to check\n",                  (unsigned int) total,                  off); -    print_expected (h, total, off); -    return GNUNET_SYSERR; -  } -  if (h[off].direction != dir) -  { -    GNUNET_break (0); -    print_expected (h, total, off); -    free_history (h, -                  total); +    print_expected (h, +                    total, +                    off);      return GNUNET_SYSERR;    } - -  if ( (0 != strcmp (h[off].details.wire_transfer_subject, -                     details->wire_transfer_subject)) || +  if ( (0 != GNUNET_memcmp (&h[off].details.reserve_pub, +                            &details->reserve_pub)) ||         (0 != TALER_amount_cmp (&h[off].details.amount,                                 &details->amount)) ||         (0 != strcasecmp (h[off].details.account_url,                           details->account_url)) )    {      GNUNET_break (0); -    print_expected (h, total, off); +    print_expected (h, +                    total, +                    off);      free_history (h,                    total);      return GNUNET_SYSERR; @@ -789,22 +564,30 @@ check_result (struct TALER_TESTING_Interpreter *is,   * @param details details about the wire transfer.   * @param json detailed response from the HTTPD, or NULL if   *        reply was not in JSON. + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */ -static void +static int  history_cb (void *cls,              unsigned int http_status,              enum TALER_ErrorCode ec, -            enum TALER_BANK_Direction dir,              uint64_t row_id, -            const struct TALER_BANK_TransferDetails *details, +            const struct TALER_BANK_CreditDetails *details,              const json_t *json)  {    struct TALER_TESTING_Interpreter *is = cls;    struct HistoryState *hs = is->commands[is->ip].cls;    (void) row_id; -  /*NOTE: "204 No Content" is used to signal the end of results.*/ -  if (MHD_HTTP_NO_CONTENT == http_status) +  if (MHD_HTTP_OK != http_status) +  { +    hs->hh = NULL; +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Unwanted response code from /history: %u\n", +                http_status); +    TALER_TESTING_interpreter_fail (is); +    return GNUNET_SYSERR; +  } +  if (NULL == details)    {      hs->hh = NULL;      if ( (hs->results_obtained != compute_result_count (is)) || @@ -829,47 +612,33 @@ history_cb (void *cls,        free_history (h,                      total);        TALER_TESTING_interpreter_fail (is); -      return; +      return GNUNET_SYSERR;      }      TALER_TESTING_interpreter_next (is); -    return; -  } - -  if (MHD_HTTP_OK != http_status) -  { -    hs->hh = NULL; -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Unwanted response code from /history[-range]: %u\n", -                http_status); -    TALER_TESTING_interpreter_fail (is); -    return; +    return GNUNET_OK;    }    /* check current element */    if (GNUNET_OK != check_result (is,                                   hs->results_obtained, -                                 dir,                                   details))    { -    GNUNET_break (0); - -    { -      char *acc; - -      acc = json_dumps (json, -                        JSON_COMPACT); -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Result %u was `%s'\n", -                  (unsigned int) hs->results_obtained++, -                  acc); -      if (NULL != acc) -        free (acc); -    } +    char *acc; +    GNUNET_break (0); +    acc = json_dumps (json, +                      JSON_COMPACT); +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Result %u was `%s'\n", +                (unsigned int) hs->results_obtained++, +                acc); +    if (NULL != acc) +      free (acc);      hs->failed = GNUNET_YES; -    return; +    return GNUNET_SYSERR;    }    hs->results_obtained++; +  return GNUNET_OK;  } @@ -886,9 +655,8 @@ history_run (void *cls,               struct TALER_TESTING_Interpreter *is)  {    struct HistoryState *hs = cls; -  uint64_t row_id = UINT64_MAX; -  const uint64_t *row_id_ptr = &row_id; -  struct TALER_BANK_AuthenticationData *auth; +  uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; +  const uint64_t *row_ptr;    (void) cmd;    /* Get row_id from trait. */ @@ -902,27 +670,24 @@ history_run (void *cls,      if (NULL == history_cmd)        TALER_TESTING_FAIL (is); -    if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (history_cmd, -                                                     0, -                                                     &row_id_ptr)) +    if (GNUNET_OK != +        TALER_TESTING_get_trait_uint64 (history_cmd, +                                        0, +                                        &row_ptr))        TALER_TESTING_FAIL (is); -    row_id = *row_id_ptr; - +    else +      row_id = *row_ptr;      TALER_LOG_DEBUG ("row id (from trait) is %llu\n",                       (unsigned long long) row_id);    } -  auth = &AUTHS[hs->account_no - 1]; -  hs->hh = TALER_BANK_history (is->ctx, -                               hs->bank_url, -                               auth, -                               hs->account_no, -                               hs->direction, -                               hs->ascending, -                               row_id, -                               hs->num_results, -                               &history_cb, -                               is); +  hs->hh = TALER_BANK_credit_history (is->ctx, +                                      hs->account_url, +                                      NULL, +                                      row_id, +                                      hs->num_results, +                                      &history_cb, +                                      is);    GNUNET_assert (NULL != hs->hh);  } @@ -944,8 +709,9 @@ history_cleanup (void *cls,    if (NULL != hs->hh)    {      TALER_LOG_WARNING ("/history did not complete\n"); -    TALER_BANK_history_cancel (hs->hh); +    TALER_BANK_credit_history_cancel (hs->hh);    } +  GNUNET_free (hs->account_url);    GNUNET_free (hs);  } @@ -954,12 +720,8 @@ history_cleanup (void *cls,   * Make a "history" CMD.   *   * @param label command label. - * @param bank_url base URL of the bank offering the "history" + * @param account_url base URL of the account offering the "history"   *        operation. - * @param account_no bank account number to ask the history for. - * @param direction which direction this operation is interested. - * @param ascending if #GNUNET_YES, the bank will return the rows - *        in ascending (= chronological) order.   * @param start_row_reference reference to a command that can   *        offer a row identifier, to be used as the starting row   *        to accept in the result. @@ -967,25 +729,17 @@ history_cleanup (void *cls,   * @return the command.   */  struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_history (const char *label, -                                const char *bank_url, -                                uint64_t account_no, -                                enum TALER_BANK_Direction direction, -                                unsigned int ascending, +TALER_TESTING_cmd_bank_credits (const char *label, +                                const char *account_url,                                  const char *start_row_reference, -                                unsigned long long num_results) +                                long long num_results)  {    struct HistoryState *hs;    hs = GNUNET_new (struct HistoryState); -  hs->bank_url = bank_url; -  hs->account_no = account_no; -  hs->direction = direction; +  hs->account_url = GNUNET_strdup (account_url);    hs->start_row_reference = start_row_reference;    hs->num_results = num_results; -  hs->ascending = ascending; -  hs->start_date = GNUNET_TIME_UNIT_FOREVER_ABS; -  hs->end_date = GNUNET_TIME_UNIT_FOREVER_ABS;    {      struct TALER_TESTING_Command cmd = { @@ -1001,4 +755,4 @@ TALER_TESTING_cmd_bank_history (const char *label,  } -/* end of testing_api_cmd_history.c */ +/* end of testing_api_cmd_credit_history.c */ diff --git a/src/bank-lib/testing_api_cmd_history_debit.c b/src/bank-lib/testing_api_cmd_history_debit.c new file mode 100644 index 00000000..93f84da0 --- /dev/null +++ b/src/bank-lib/testing_api_cmd_history_debit.c @@ -0,0 +1,758 @@ +/* +  This file is part of TALER +  Copyright (C) 2018-2020 Taler Systems SA + +  TALER is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as +  published by the Free Software Foundation; either version 3, or +  (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public +  License along with TALER; see the file COPYING.  If not, see +  <http://www.gnu.org/licenses/> +*/ + +/** + * @file bank-lib/testing_api_cmd_history.c + * @brief command to check the /history API from the bank. + * @author Marcello Stanisci + */ + +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "taler_exchange_service.h" +#include "taler_testing_lib.h" +#include "taler_testing_bank_lib.h" +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_fakebank_lib.h" + + +/** + * State for a "history" CMD. + */ +struct HistoryState +{ +  /** +   * Base URL of the account offering the "history" operation. +   */ +  const char *account_url; + +  /** +   * Reference to command defining the +   * first row number we want in the result. +   */ +  const char *start_row_reference; + +  /** +   * How many rows we want in the result, _at most_, +   * and ascending/descending. +   */ +  long long num_results; + +  /** +   * Handle to a pending "history" operation. +   */ +  struct TALER_BANK_DebitHistoryHandle *hh; + +  /** +   * Expected number of results (= rows). +   */ +  uint64_t results_obtained; + +  /** +   * Set to GNUNET_YES if the callback detects something +   * unexpected. +   */ +  int failed; + +}; + + +/** + * Item in the transaction history, as reconstructed from the + * command history. + */ +struct History +{ + +  /** +   * Wire details. +   */ +  struct TALER_BANK_DebitDetails details; + +  /** +   * Serial ID of the wire transfer. +   */ +  uint64_t row_id; + +  /** +   * URL to free. +   */ +  char *url; +}; + + +/** + * Offer internal data to other commands. + * + * @param cls closure. + * @param ret[out] set to the wanted data. + * @param trait name of the trait. + * @param index index number of the traits to be returned. + * + * @return #GNUNET_OK on success + */ +static int +history_traits (void *cls, +                const void **ret, +                const char *trait, +                unsigned int index) +{ +  (void) cls; +  (void) ret; +  (void) trait; +  (void) index; +  /* Must define this function because some callbacks +   * look for certain traits on _all_ the commands. */ +  return GNUNET_SYSERR; +} + + +/** + * Free history @a h of length @a h_len. + * + * @param h history array to free. + * @param h_len number of entries in @a h. + */ +static void +free_history (struct History *h, +              uint64_t h_len) +{ +  for (uint64_t off = 0; off<h_len; off++) +    GNUNET_free (h[off].url); +  GNUNET_free_non_null (h); +} + + +/** + * Log which history we expected.  Called when an error occurs. + * + * @param h what we expected. + * @param h_len number of entries in @a h. + * @param off position of the missmatch. + */ +static void +print_expected (struct History *h, +                uint64_t h_len, +                unsigned int off) +{ +  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +              "Transaction history missmatch at position %u/%llu\n", +              off, +              (unsigned long long) h_len); +  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +              "Expected history:\n"); +  for (uint64_t i = 0; i<h_len; i++) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "H(%llu): %s (serial: %llu, subject: %s," +                " counterpart: %s)\n", +                (unsigned long long) i, +                TALER_amount2s (&h[i].details.amount), +                (unsigned long long) h[i].row_id, +                TALER_B2S (&h[i].details.wtid), +                h[i].details.account_url); +  } +} + + +/** + * Tell if the current item is beyond the allowed limit. + * + * @param total current number of items in the built history list. + *        Note, this is the list we build locally and compare with + *        what the server returned. + * @param hs the history CMD state. + * @param pos current item to be evaluated or not (if the list + *        has already enough elements). + * @return GNUNET_OK / GNUNET_NO. + */ +static int +build_history_hit_limit (uint64_t total, +                         const struct HistoryState *hs, +                         const struct TALER_TESTING_Command *pos) +{ +  return total >= hs->num_results; +} + + +/** + * This function constructs the list of history elements that + * interest the account number of the caller.  It has two main + * loops: the first to figure out how many history elements have + * to be allocated, and the second to actually populate every + * element. + * + * @param is interpreter state (supposedly having the + *        current CMD pointing at a "history" CMD). + * @param[out] rh history array to initialize. + * + * @return number of entries in @a rh. + */ +static uint64_t +build_history (struct TALER_TESTING_Interpreter *is, +               struct History **rh) +{ +  struct HistoryState *hs = is->commands[is->ip].cls; +  uint64_t total; +  struct History *h; +  const struct TALER_TESTING_Command *add_incoming_cmd; +  int inc; +  unsigned int start; +  unsigned int end; + +  /** +   * @var turns GNUNET_YES whenever either no 'start' value was +   *      given for the history query, or the given value is found +   *      in the list of all the CMDs. +   */int ok; +  const uint64_t *row_id_start = NULL; + +  if (NULL != hs->start_row_reference) +  { +    TALER_LOG_INFO +      ("`%s': start row given via reference `%s'\n", +      TALER_TESTING_interpreter_get_current_label  (is), +      hs->start_row_reference); +    add_incoming_cmd = TALER_TESTING_interpreter_lookup_command +                         (is, hs->start_row_reference); +    GNUNET_assert (NULL != add_incoming_cmd); +    GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_uint64 +                     (add_incoming_cmd, 0, &row_id_start)); +  } + +  GNUNET_assert (0 != hs->num_results); +  if (0 == is->ip) +  { +    TALER_LOG_DEBUG ("Checking history at first CMD..\n"); +    *rh = NULL; +    return 0; +  } + +  /* AKA 'delta'.  */ +  if (hs->num_results > 0) +  { +    inc = 1;  /* _inc_rement */ +    start = 0; +    end = is->ip - 1; +  } +  else +  { +    inc = -1; +    start = is->ip - 1; +    end = 0; +  } + +  total = 0; +  ok = GNUNET_NO; + +  if (NULL == row_id_start) +    ok = GNUNET_YES; + +  /* This loop counts how many commands _later than "start"_ belong +   * to the history of the caller.  This is stored in the @var total +   * variable.  */ +  for (unsigned int off = start; off != end + inc; off += inc) +  { +    const struct TALER_TESTING_Command *pos = &is->commands[off]; +    const uint64_t *row_id; +    const char *debit_account; +    const char *credit_account; + +    /** +     * The following command allows us to skip over those CMDs +     * that do not offer a "row_id" trait.  Such skipped CMDs are +     * not interesting for building a history. +     */if (GNUNET_OK != TALER_TESTING_get_trait_uint64 (pos, +                                                     0, +                                                     &row_id)) +      continue; + +    /* Seek "/history" starting row.  */ +    if (NULL != row_id_start) +    { +      if (*row_id_start == *row_id) +      { +        /* Doesn't count, start is excluded from output. */ +        total = 0; +        ok = GNUNET_YES; +        continue; +      } +    } + +    /* when 'start' was _not_ given, then ok == GNUNET_YES */ +    if (GNUNET_NO == ok) +      continue; /* skip until we find the marker */ + +    TALER_LOG_DEBUG ("Found first row\n"); + +    if (build_history_hit_limit (total, +                                 hs, +                                 pos)) +    { +      TALER_LOG_DEBUG ("Hit history limit\n"); +      break; +    } + +    GNUNET_assert +      (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT +        (pos, &debit_account)); + +    GNUNET_assert +      (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT +        (pos, &credit_account)); + +    TALER_LOG_INFO ("Potential history element:" +                    " %s->%s; my account: %s\n", +                    debit_account, +                    credit_account, +                    hs->account_url); + +    if (0 == strcasecmp (hs->account_url, +                         debit_account)) +    { +      TALER_LOG_INFO ("+1 my history\n"); +      total++; /* found matching record */ +    } +  } + +  GNUNET_assert (GNUNET_YES == ok); + +  if (0 == total) +  { +    TALER_LOG_DEBUG ("Checking history at first CMD.. (2)\n"); +    *rh = NULL; +    return 0; +  } + + +  GNUNET_assert (total < UINT_MAX); +  h = GNUNET_new_array ((unsigned int) total, +                        struct History); +  total = 0; +  ok = GNUNET_NO; +  if (NULL == row_id_start) +    ok = GNUNET_YES; + +  /** +   * This loop _only_ populates the array of history elements. +   */ +  for (unsigned int off = start; off != end + inc; off += inc) +  { +    const struct TALER_TESTING_Command *pos = &is->commands[off]; +    const uint64_t *row_id; +    char *bank_hostname; +    const char *credit_account; +    const char *debit_account; + +    if (GNUNET_OK != TALER_TESTING_GET_TRAIT_ROW_ID +          (pos, &row_id)) +      continue; + +    if (NULL != row_id_start) +    { + +      if (*row_id_start == *row_id) +      { +        /** +         * Warning: this zeroing is superfluous, as +         * total doesn't get incremented if 'start' +         * was given and couldn't be found. +         */total = 0; +        ok = GNUNET_YES; +        continue; +      } +    } + +    TALER_LOG_INFO ("Found first row (2)\n"); + +    if (GNUNET_NO == ok) +    { +      TALER_LOG_INFO ("Skip on `%s'\n", +                      pos->label); +      continue; /* skip until we find the marker */ +    } + +    if (build_history_hit_limit (total, +                                 hs, +                                 pos)) +    { +      TALER_LOG_INFO ("Hit history limit (2)\n"); +      break; +    } + +    GNUNET_assert +      (GNUNET_OK == TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT +        (pos, &debit_account)); + +    GNUNET_assert +      (GNUNET_OK == TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT +        (pos, &credit_account)); + +    TALER_LOG_INFO ("Potential history bit:" +                    " %s->%s; my account: %s\n", +                    debit_account, +                    credit_account, +                    hs->account_url); + +    /** +     * Discard transactions where the audited account played +     * _both_ the debit and the debit roles, but _only if_ +     * the audit goes on both directions..  This needs more +     * explaination! +     */if (0 == strcasecmp (hs->account_url, +                         debit_account)) +    { +      GNUNET_break (0); +      continue; +    } + +    bank_hostname = strchr (hs->account_url, ':'); +    GNUNET_assert (NULL != bank_hostname); +    bank_hostname += 3; + +    /* Next two blocks only put the 'direction' and 'banking' +     * information.  */ + +    /* Asked for debit, and account got the debit.  */ +    if (0 == strcasecmp (hs->account_url, +                         debit_account)) +    { +      h[total].url = GNUNET_strdup (credit_account); +      h[total].details.account_url = h[total].url; +    } + +    /* This block _completes_ the information of the current item, +     * with amount / subject / exchange URL.  */ +    if (0 == strcasecmp (hs->account_url, +                         debit_account)) +    { +      const struct TALER_Amount *amount; +      const struct TALER_WireTransferIdentifierRawP *wtid; +      const char *account_url; + +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_amount_obj +                       (pos, 0, &amount)); +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_wtid +                       (pos, 0, &wtid)); +      GNUNET_assert (GNUNET_OK == +                     TALER_TESTING_get_trait_url +                       (pos, 1, +                       &account_url)); +      h[total].details.amount = *amount; +      h[total].row_id = *row_id; +      h[total].details.wtid = *wtid; +      h[total].details.account_url = account_url; +      TALER_LOG_INFO ("+1-bit of my history\n"); +      total++; +    } +  } +  *rh = h; +  return total; +} + + +/** + * Compute how many results we expect to be returned for + * the current command at @a is. + * + * @param is the interpreter state to inspect. + * @return number of results expected. + */ +static uint64_t +compute_result_count (struct TALER_TESTING_Interpreter *is) +{ +  uint64_t total; +  struct History *h; + +  total = build_history (is, &h); +  free_history (h, total); +  return total; +} + + +/** + * Check that the "/history" response matches the + * CMD whose offset in the list of CMDs is @a off. + * + * @param is the interpreter state. + * @param off the offset (of the CMD list) where the command + *        to check is. + * @param dir the expected direction of the transaction. + * @param details the expected transaction details. + * + * @return #GNUNET_OK if the transaction is what we expect. + */ +static int +check_result (struct TALER_TESTING_Interpreter *is, +              unsigned int off, +              const struct TALER_BANK_DebitDetails *details) +{ +  uint64_t total; +  struct History *h; + +  total = build_history (is, &h); +  if (off >= total) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Test says history has at most %u" +                " results, but got result #%u to check\n", +                (unsigned int) total, +                off); +    print_expected (h, +                    total, +                    off); +    return GNUNET_SYSERR; +  } +  if ( (0 != GNUNET_memcmp (&h[off].details.wtid, +                            &details->wtid)) || +       (0 != TALER_amount_cmp (&h[off].details.amount, +                               &details->amount)) || +       (0 != strcasecmp (h[off].details.account_url, +                         details->account_url)) ) +  { +    GNUNET_break (0); +    print_expected (h, +                    total, +                    off); +    free_history (h, +                  total); +    return GNUNET_SYSERR; +  } +  free_history (h, +                total); +  return GNUNET_OK; +} + + +/** + * This callback will (1) check that the HTTP response code + * is acceptable and (2) that the history is consistent.  The + * consistency is checked by going through all the past CMDs, + * reconstructing then the expected history as of those, and + * finally check it against what the bank returned. + * + * @param cls closure. + * @param http_status HTTP response code, #MHD_HTTP_OK (200) + *        for successful status request 0 if the bank's reply is + *        bogus (fails to follow the protocol), + *        #MHD_HTTP_NO_CONTENT if there are no more results; on + *        success the last callback is always of this status + *        (even if `abs(num_results)` were already returned). + * @param ec taler status code. + * @param dir direction of the transfer. + * @param row_id monotonically increasing counter corresponding to + *        the transaction. + * @param details details about the wire transfer. + * @param json detailed response from the HTTPD, or NULL if + *        reply was not in JSON. + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration + */ +static int +history_cb (void *cls, +            unsigned int http_status, +            enum TALER_ErrorCode ec, +            uint64_t row_id, +            const struct TALER_BANK_DebitDetails *details, +            const json_t *json) +{ +  struct TALER_TESTING_Interpreter *is = cls; +  struct HistoryState *hs = is->commands[is->ip].cls; + +  (void) row_id; +  if (MHD_HTTP_OK != http_status) +  { +    hs->hh = NULL; +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Unwanted response code from /history: %u\n", +                http_status); +    TALER_TESTING_interpreter_fail (is); +    return GNUNET_SYSERR; +  } +  if (NULL == details) +  { +    hs->hh = NULL; +    if ( (hs->results_obtained != compute_result_count (is)) || +         (GNUNET_YES == hs->failed) ) +    { +      uint64_t total; +      struct History *h; + +      GNUNET_break (0); +      total = build_history (is, &h); +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Expected history of length %llu, got %llu;" +                  " HTTP status code: %u/%d, failed: %d\n", +                  (unsigned long long) total, +                  (unsigned long long) hs->results_obtained, +                  http_status, +                  (int) ec, +                  hs->failed); +      print_expected (h, +                      total, +                      UINT_MAX); +      free_history (h, +                    total); +      TALER_TESTING_interpreter_fail (is); +      return GNUNET_SYSERR; +    } +    TALER_TESTING_interpreter_next (is); +    return GNUNET_OK; +  } + +  /* check current element */ +  if (GNUNET_OK != check_result (is, +                                 hs->results_obtained, +                                 details)) +  { +    char *acc; + +    GNUNET_break (0); +    acc = json_dumps (json, +                      JSON_COMPACT); +    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                "Result %u was `%s'\n", +                (unsigned int) hs->results_obtained++, +                acc); +    if (NULL != acc) +      free (acc); +    hs->failed = GNUNET_YES; +    return GNUNET_SYSERR; +  } +  hs->results_obtained++; +  return GNUNET_OK; +} + + +/** + * Run the command. + * + * @param cls closure. + * @param cmd the command to execute. + * @param is the interpreter state. + */ +static void +history_run (void *cls, +             const struct TALER_TESTING_Command *cmd, +             struct TALER_TESTING_Interpreter *is) +{ +  struct HistoryState *hs = cls; +  uint64_t row_id = (hs->num_results > 0) ? 0 : UINT64_MAX; +  const uint64_t *row_ptr; + +  (void) cmd; +  /* Get row_id from trait. */ +  if (NULL != hs->start_row_reference) +  { +    const struct TALER_TESTING_Command *history_cmd; + +    history_cmd = TALER_TESTING_interpreter_lookup_command +                    (is, hs->start_row_reference); + +    if (NULL == history_cmd) +      TALER_TESTING_FAIL (is); + +    if (GNUNET_OK != +        TALER_TESTING_get_trait_uint64 (history_cmd, +                                        0, +                                        &row_ptr)) +      TALER_TESTING_FAIL (is); +    else +      row_id = *row_ptr; +    TALER_LOG_DEBUG ("row id (from trait) is %llu\n", +                     (unsigned long long) row_id); +  } + +  hs->hh = TALER_BANK_debit_history (is->ctx, +                                     hs->account_url, +                                     NULL, +                                     row_id, +                                     hs->num_results, +                                     &history_cb, +                                     is); +  GNUNET_assert (NULL != hs->hh); +} + + +/** + * Free the state from a "history" CMD, and possibly cancel + * a pending operation thereof. + * + * @param cls closure. + * @param cmd the command which is being cleaned up. + */ +static void +history_cleanup (void *cls, +                 const struct TALER_TESTING_Command *cmd) +{ +  struct HistoryState *hs = cls; + +  (void) cmd; +  if (NULL != hs->hh) +  { +    TALER_LOG_WARNING ("/history did not complete\n"); +    TALER_BANK_debit_history_cancel (hs->hh); +  } +  GNUNET_free (hs); +} + + +/** + * Make a "history" CMD. + * + * @param label command label. + * @param account_url base URL of the account offering the "history" + *        operation. + * @param start_row_reference reference to a command that can + *        offer a row identifier, to be used as the starting row + *        to accept in the result. + * @param num_results how many rows we want in the result. + * @return the command. + */ +struct TALER_TESTING_Command +TALER_TESTING_cmd_bank_debits (const char *label, +                               const char *account_url, +                               const char *start_row_reference, +                               long long num_results) +{ +  struct HistoryState *hs; + +  hs = GNUNET_new (struct HistoryState); +  hs->account_url = account_url; +  hs->start_row_reference = start_row_reference; +  hs->num_results = num_results; + +  { +    struct TALER_TESTING_Command cmd = { +      .label = label, +      .cls = hs, +      .run = &history_run, +      .cleanup = &history_cleanup, +      .traits = &history_traits +    }; + +    return cmd; +  } +} + + +/* end of testing_api_cmd_history_debit.c */ diff --git a/src/bank-lib/testing_api_cmd_reject.c b/src/bank-lib/testing_api_cmd_reject.c deleted file mode 100644 index 01c189f1..00000000 --- a/src/bank-lib/testing_api_cmd_reject.c +++ /dev/null @@ -1,223 +0,0 @@ -/* -  This file is part of TALER -  Copyright (C) 2018 Taler Systems SA - -  TALER is free software; you can redistribute it and/or modify -  it under the terms of the GNU General Public License as -  published by the Free Software Foundation; either version 3, or -  (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but -  WITHOUT ANY WARRANTY; without even the implied warranty of -  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -  GNU General Public License for more details. - -  You should have received a copy of the GNU General Public -  License along with TALER; see the file COPYING.  If not, see -  <http://www.gnu.org/licenses/> -*/ - -/** - * @file bank-lib/testing_api_cmd_reject.c - * @brief command to check the /reject API from the bank. - * @author Marcello Stanisci - */ - -#include "platform.h" -#include "taler_json_lib.h" -#include <gnunet/gnunet_curl_lib.h> -#include "taler_exchange_service.h" -#include "taler_testing_lib.h" -#include "taler_fakebank_lib.h" -#include "taler_bank_service.h" -#include "taler_fakebank_lib.h" - - -/** - * State for a "reject" CMD. - */ -struct RejectState -{ - -  /** -   * Handle of a ongoing "reject" operation. -   */ -  struct TALER_BANK_RejectHandle *rh; - -  /** -   * Reference to any command that can offer a wire -   * transfer "row id" and its credit account so as -   * to give input data to the "reject" operation. -   */ -  const char *deposit_reference; - -  /** -   * Base URL of the bank implementing the "reject" -   * operation. -   */ -  const char *bank_url; -}; - -/** - * Check that the response code from the "reject" opetation - * is acceptable, namely it equals "204 No Content". - * - * @param cls closure. - * @param http_status HTTP response code. - * @param ec taler-specific error code. - */ -static void -reject_cb (void *cls, -           unsigned int http_status, -           enum TALER_ErrorCode ec) -{ -  struct TALER_TESTING_Interpreter *is = cls; -  struct RejectState *rs = is->commands[is->ip].cls; - -  rs->rh = NULL; -  if (MHD_HTTP_NO_CONTENT != http_status) -  { -    GNUNET_break (0); -    fprintf (stderr, -             "Unexpected response code %u/%d\n", -             http_status, -             (int) ec); -    TALER_TESTING_interpreter_fail (is); -    return; -  } -  TALER_TESTING_interpreter_next (is); -} - - -/** - * Cleanup the state of a "reject" CMD, and possibly - * cancel a pending operation thereof. - * - * @param cls closure. - * @param cmd the command. - */ -static void -reject_cleanup (void *cls, -                const struct TALER_TESTING_Command *cmd) -{ -  struct RejectState *rs = cls; - -  (void) cmd; -  if (NULL != rs->rh) -  { -    TALER_LOG_WARNING ("/reject did not complete\n"); -    TALER_BANK_reject_cancel (rs->rh); -  } -  GNUNET_free (rs); -} - - -/** - * Run the command. - * - * @param cls closure. - * @param cmd the command to execute. - * @param is the interpreter state. - */ -static void -reject_run (void *cls, -            const struct TALER_TESTING_Command *cmd, -            struct TALER_TESTING_Interpreter *is) -{ -  struct RejectState *rs = cls; -  const struct TALER_TESTING_Command *deposit_cmd; -  const uint64_t *credit_account; -  const uint64_t *row_id; -  extern struct TALER_BANK_AuthenticationData AUTHS[]; - -  (void) cmd; -  deposit_cmd -    = TALER_TESTING_interpreter_lookup_command (is, -                                                rs->deposit_reference); -  if (NULL == deposit_cmd) -    TALER_TESTING_FAIL (is); -  GNUNET_assert (GNUNET_OK == -                 TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT (deposit_cmd, -                                                         &credit_account)); -  GNUNET_assert (GNUNET_OK == -                 TALER_TESTING_GET_TRAIT_ROW_ID (deposit_cmd, -                                                 &row_id)); -  TALER_LOG_INFO ("Account %llu rejects deposit\n", -                  (unsigned long long) *credit_account); -  rs->rh = TALER_BANK_reject (is->ctx, -                              rs->bank_url, -                              &AUTHS[*credit_account - 1], -                              *credit_account, -                              *row_id, -                              &reject_cb, -                              is); -  GNUNET_assert (NULL != rs->rh); -} - - -/** - * Offer internal data from a "reject" CMD to other commands. - * - * @param cls closure. - * @param ret[out] result. - * @param trait name of the trait. - * @param index index number of the trait to return. - * - * @return #GNUNET_OK on success. - */ -static int -reject_traits (void *cls, -               const void **ret, -               const char *trait, -               unsigned int index) -{ -  struct RejectState *rs = cls; -  struct TALER_TESTING_Trait traits[] = { -    TALER_TESTING_make_trait_rejected (0, rs->deposit_reference), -    TALER_TESTING_trait_end () -  }; - -  return TALER_TESTING_get_trait (traits, -                                  ret, -                                  trait, -                                  index); -} - - -/** - * Create a "reject" CMD. - * - * @param label command label. - * @param bank_url base URL of the bank implementing the - *        "reject" operation. - * @param deposit_reference reference to a command that will - *        provide a "row id" and credit (bank) account to craft - *        the "reject" request. - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_reject (const char *label, -                               const char *bank_url, -                               const char *deposit_reference) -{ -  struct RejectState *rs; - -  rs = GNUNET_new (struct RejectState); -  rs->bank_url = bank_url; -  rs->deposit_reference = deposit_reference; - -  { -    struct TALER_TESTING_Command cmd = { -      .cls = rs, -      .run = &reject_run, -      .cleanup = &reject_cleanup, -      .label = label, -      .traits = &reject_traits -    }; - -    return cmd; -  } -} - - -/* end of testing_api_cmd_reject.c */ diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 31dbdf15..b931c3c9 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2014-2019 Taler Systems SA +  (C) 2014-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it    under the terms of the GNU Affero General Public License as @@ -16,15 +16,13 @@    along with TALER; see the file COPYING.  If not,    see <http://www.gnu.org/licenses/>  */ -  /** - * @file merchant/backend/taler-merchant-httpd.c + * @file benchmark/taler-exchange-benchmark.c   * @brief HTTP serving layer intended to perform crypto-work and   * communication with the exchange   * @author Marcello Stanisci   * @author Christian Grothoff   */ -  #include "platform.h"  #include <gnunet/gnunet_util_lib.h>  #include <microhttpd.h> @@ -58,23 +56,14 @@ enum BenchmarkError   */  #define UNITY_SIZE 6 -/** - * Account number of the merchant.  Fakebank likes any number, - * the only requirement is that this number then matches the - * number given when building payto URLs at deposit time. - */ -#define TALER_TESTING_USER_ACCOUNT_NUMBER 3 -  #define FIRST_INSTRUCTION -1  #define CMD_TRANSFER_TO_EXCHANGE(label, amount) \    TALER_TESTING_cmd_fakebank_transfer_retry \      (TALER_TESTING_cmd_fakebank_transfer (label, amount, \ -                                          exchange_bank_account.details. \ -                                          x_taler_bank.bank_base_url, \ -                                          TALER_TESTING_USER_ACCOUNT_NUMBER, \ -                                          exchange_bank_account.details. \ -                                          x_taler_bank.no, \ +                                          user_bank_account.details.                                      \ +                                          x_taler_bank.account_base_url, \ +                                          exchange_payto_url, \                                            "dummy_user", \                                            "dummy_password", \                                            "http://example.com/")) @@ -108,6 +97,11 @@ enum BenchmarkMode  static struct TALER_Account exchange_bank_account;  /** + * Hold information about a user at the bank. + */ +static struct TALER_Account user_bank_account; + +/**   * Time snapshot taken right before executing the CMDs.   */  static struct GNUNET_TIME_Absolute start_time; @@ -169,6 +163,11 @@ static enum BenchmarkMode mode;  static char *cfg_filename;  /** + * payto://-URL of the exchange's bank account. + */ +static char *exchange_payto_url; + +/**   * Currency used.   */  static char *currency; @@ -405,12 +404,12 @@ stop_fakebank (void *cls)  static void  launch_fakebank (void *cls)  { -  const char *bank_base_url = cls; +  const char *hostname = cls;    const char *port;    long pnum;    struct TALER_FAKEBANK_Handle *fakebank; -  port = strrchr (bank_base_url, +  port = strrchr (hostname,                    (unsigned char) ':');    if (NULL == port)      pnum = 80; @@ -419,7 +418,7 @@ launch_fakebank (void *cls)    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Starting Fakebank on port %u (%s)\n",                (unsigned int) pnum, -              bank_base_url); +              hostname);    fakebank = TALER_FAKEBANK_start ((uint16_t) pnum);    if (NULL == fakebank)    { @@ -466,8 +465,7 @@ parallel_benchmark (TALER_TESTING_Main main_cb,                          NULL == loglev ? "INFO" : loglev,                          logfile);        GNUNET_SCHEDULER_run (&launch_fakebank, -                            exchange_bank_account.details.x_taler_bank. -                            bank_base_url); +                            exchange_bank_account.details.x_taler_bank.hostname);        exit (0);      }      if (-1 == fakebank) @@ -824,10 +822,36 @@ main (int argc,      return BAD_CLI_ARG;    } +  { +    char *user_payto_url; + +    if (GNUNET_OK != +        GNUNET_CONFIGURATION_get_value_string +          (cfg, +          "benchmark", +          "user-url", +          &user_payto_url)) +    { +      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                                 "benchmark", +                                 "user-url"); +      return BAD_CONFIG_FILE; +    } +    if (TALER_EC_NONE != +        TALER_WIRE_payto_to_account (user_payto_url, +                                     &user_bank_account)) +    { +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  _ ("Malformed payto:// URL `%s' in configuration\n"), +                  user_payto_url); +      GNUNET_free (user_payto_url); +      return BAD_CONFIG_FILE; +    } +    GNUNET_free (user_payto_url); +  }    {      const char *bank_details_section; -    char *exchange_payto_url;      GNUNET_CONFIGURATION_iterate_sections        (cfg, @@ -873,7 +897,6 @@ main (int argc,        GNUNET_free (exchange_payto_url);        return BAD_CONFIG_FILE;      } -    GNUNET_free (exchange_payto_url);    }    if ( (MODE_EXCHANGE == mode) || (MODE_BOTH == mode) )    { diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am index 64b4cee8..0b9a2d52 100644 --- a/src/exchange-tools/Makefile.am +++ b/src/exchange-tools/Makefile.am @@ -23,7 +23,9 @@ taler_wire_SOURCES = \    taler-wire.c  taler_wire_LDADD = \    $(top_builddir)/src/util/libtalerutil.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \ +  -lgnunetcurl \    -lgnunetutil  taler_exchange_keyup_SOURCES = \ @@ -32,6 +34,7 @@ taler_exchange_keyup_LDADD = \    $(LIBGCRYPT_LIBS) \    $(top_builddir)/src/util/libtalerutil.la \    $(top_builddir)/src/pq/libtalerpq.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \    $(top_builddir)/src/exchangedb/libtalerexchangedb.la \    -lgnunetutil $(XLIB) @@ -44,6 +47,7 @@ taler_exchange_wire_LDADD = \    $(LIBGCRYPT_LIBS) \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/exchangedb/libtalerexchangedb.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \    $(top_builddir)/src/util/libtalerutil.la \    -lgnunetjson \ diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c index e6e3db0d..f2ec3ca8 100644 --- a/src/exchange-tools/taler-exchange-keyup.c +++ b/src/exchange-tools/taler-exchange-keyup.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2018 Taler Systems SA +  Copyright (C) 2014-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -923,17 +923,17 @@ exchange_keys_update_denomkeys ()   * Sign @a af with @a priv   *   * @param[in,out] af fee structure to sign - * @param wireplugin name of the plugin for which we sign + * @param method name of the wire method for which we sign   * @param priv private key to use for signing   */  static void  sign_af (struct TALER_EXCHANGEDB_AggregateFees *af, -         const char *wireplugin, +         const char *method,           const struct GNUNET_CRYPTO_EddsaPrivateKey *priv)  {    struct TALER_MasterWireFeePS wf; -  TALER_EXCHANGEDB_fees_2_wf (wireplugin, +  TALER_EXCHANGEDB_fees_2_wf (method,                                af,                                &wf);    GNUNET_assert (GNUNET_OK == @@ -1101,28 +1101,15 @@ create_wire_fee_by_account (void *cls,                              const struct TALER_EXCHANGEDB_AccountInfo *ai)  {    int *ret = cls; -  struct TALER_WIRE_Plugin *plugin;    if (GNUNET_NO == ai->credit_enabled)      return; -  plugin = TALER_WIRE_plugin_load (kcfg, -                                   ai->plugin_name); -  if (NULL == plugin) -  { -    fprintf (stderr, -             "Failed to load wire plugin `%s' configured for account `%s'\n", -             ai->plugin_name, -             ai->section_name); -    *ret = GNUNET_SYSERR; -    return; -  }    /* We may call this function repeatedly for the same method       if there are multiple accounts with plugins using the       same method, but except for some minor performance loss,       this is harmless. */    create_wire_fee_for_method (ret, -                              plugin->method); -  TALER_WIRE_plugin_unload (plugin); +                              ai->method);  } diff --git a/src/exchange-tools/taler-wire.c b/src/exchange-tools/taler-wire.c index 12963324..5e3c18a6 100644 --- a/src/exchange-tools/taler-wire.c +++ b/src/exchange-tools/taler-wire.c @@ -22,11 +22,10 @@   * @author Marcello Stanisci   * @author Christian Grothoff   */ -  #include <platform.h>  #include <gnunet/gnunet_util_lib.h>  #include "taler_util.h" -#include "taler_wire_lib.h" +#include "taler_bank_service.h"  /**   * If set to #GNUNET_YES, then we'll ask the bank for a list @@ -36,17 +35,12 @@  static int history;  /** - * If set to GNUNET_YES, then we'll ask the bank to execute a + * If set to #GNUNET_YES, then we'll ask the bank to execute a   * wire transfer.   */  static int transfer;  /** - * Name of the wire plugin to use with the bank. - */ -static char *plugin_name; - -/**   * Global return code.   */  static unsigned int global_ret = 1; @@ -59,11 +53,9 @@ static unsigned int global_ret = 1;  static char *amount;  /** - * Base32 encoding of a transaction ID.  When asking the - * bank for a transaction history, all the results will - * have a transaction ID settled *after* this one. + * Starting row.   */ -static char *since_when; +static unsigned long long start_row;  /**   * Which config section has the credentials to access the bank. @@ -77,19 +69,29 @@ static char *account_section;  static char *destination_account_url;  /** - * Handle for the wire transfer preparation task. + * Handle for executing the wire transfer.   */ -static struct TALER_WIRE_PrepareHandle *ph; +static struct TALER_BANK_WireExecuteHandle *eh;  /** - * Wire plugin handle. + * Handle to ongoing history operation.   */ -static struct TALER_WIRE_Plugin *plugin_handle; +static struct TALER_BANK_CreditHistoryHandle *hh;  /** - * Handle to ongoing history operation. + * For authentication. + */ +static struct TALER_BANK_AuthenticationData auth; + +/** + * Handle to the context for interacting with the bank.   */ -static struct TALER_WIRE_HistoryHandle *hh; +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc;  /** @@ -108,16 +110,16 @@ static struct TALER_WIRE_HistoryHandle *hh;   */  static int  history_cb (void *cls, +            unsigned int http_status,              enum TALER_ErrorCode ec, -            enum TALER_BANK_Direction dir, -            const void *row_off, -            size_t row_off_size, -            const struct TALER_WIRE_TransferDetails *details) +            uint64_t serial_id, +            const struct TALER_BANK_CreditDetails *details, +            const json_t *json)  { -  char *row_off_enc; -    (void) cls; -  if (TALER_BANK_DIRECTION_NONE == dir) +  (void) ec; +  (void) http_status; +  if (NULL == details)    {      fprintf (stdout,               "End of transactions list.\n"); @@ -126,15 +128,9 @@ history_cb (void *cls,      return GNUNET_NO;    } -  row_off_enc = GNUNET_STRINGS_data_to_string_alloc (row_off, -                                                     row_off_size); -  /* Give more details on screen (??) */    fprintf (stdout, -           "%s\n", -           row_off_enc); - -  GNUNET_free (row_off_enc); - +           "%llu\n", +           (unsigned long long) serial_id);    return GNUNET_OK;  } @@ -142,72 +138,37 @@ history_cb (void *cls,  /**   * Callback that processes the outcome of a wire transfer   * execution. + * + * @param cls closure + * @param response_code HTTP status code + * @param ec taler error code + * @param row_id unique ID of the wire transfer in the bank's records + * @param timestamp when did the transaction go into effect   */  static void  confirmation_cb (void *cls, -                 int success, -                 const void *row_id, -                 size_t row_id_size, -                 const char *emsg) +                 unsigned int response_code, +                 enum TALER_ErrorCode ec, +                 uint64_t row_id, +                 struct GNUNET_TIME_Absolute timestamp)  { -  if (GNUNET_YES != success) +  if (MHD_HTTP_OK != response_code)    {      fprintf (stderr, -             "The wire transfer didn't execute correctly.\n"); -    GNUNET_assert (NULL != emsg); -    fprintf (stderr, -             "%s", -             emsg); +             "The wire transfer didn't execute correctly (%d).\n", +             ec);      GNUNET_SCHEDULER_shutdown ();      return;    }    fprintf (stdout,             "Wire transfer executed successfully.\n"); -    global_ret = 0;    GNUNET_SCHEDULER_shutdown ();  }  /** - * Takes prepared blob and executes the wire-transfer. - * - * @param cls NULL. - * @param buf prepared wire transfer data. - * @param buf_size size of the prepared wire transfer data. - */ -static void -prepare_cb (void *cls, -            const char *buf, -            size_t buf_size) -{ -  struct TALER_WIRE_ExecuteHandle *eh; - -  if (NULL == (eh = plugin_handle->execute_wire_transfer -                      (plugin_handle->cls, -                      buf, -                      buf_size, -                      confirmation_cb, -                      NULL))) -  { -    fprintf (stderr, -             "Could not execute the wire transfer\n"); - -    plugin_handle->prepare_wire_transfer_cancel -      (plugin_handle->cls, -      ph); - -    plugin_handle->execute_wire_transfer_cancel -      (plugin_handle->cls, -      eh); - -    GNUNET_SCHEDULER_shutdown (); -  } -} - - -/**   * Ask the bank to execute a wire transfer.   */  static void @@ -215,6 +176,8 @@ execute_wire_transfer ()  {    struct TALER_Amount a;    struct TALER_WireTransferIdentifierRawP wtid; +  void *buf; +  size_t buf_size;    if (NULL == amount)    { @@ -223,7 +186,6 @@ execute_wire_transfer ()      GNUNET_SCHEDULER_shutdown ();      return;    } -    if (GNUNET_OK != TALER_string_to_amount (amount,                                             &a))    { @@ -240,19 +202,25 @@ execute_wire_transfer ()      GNUNET_SCHEDULER_shutdown ();      return;    } -  if (NULL == (ph = plugin_handle->prepare_wire_transfer -                      (plugin_handle->cls, -                      account_section, -                      destination_account_url, -                      &a, -                      "http://exchange.example.com/", -                      &wtid, /* Any value will do.  */ -                      prepare_cb, -                      NULL))) +  TALER_BANK_prepare_wire_transfer (destination_account_url, +                                    &a, +                                    "http://exchange.example.com/", +                                    &wtid, +                                    &buf, +                                    &buf_size); +  eh = TALER_BANK_execute_wire_transfer (ctx, +                                         destination_account_url, +                                         &auth, +                                         buf, +                                         buf_size, +                                         &confirmation_cb, +                                         NULL); +  if (NULL == eh)    {      fprintf (stderr, -             "Could not prepare the wire transfer\n"); +             "Could not execute the wire transfer\n");      GNUNET_SCHEDULER_shutdown (); +    return;    }  } @@ -264,30 +232,14 @@ execute_wire_transfer ()  static void  execute_history ()  { -  size_t bin_len = 0; -  void *since_when_bin = NULL; - -  if (NULL != since_when) -  { -    bin_len = (strlen (since_when) * 5) / 8; - -    since_when_bin = GNUNET_malloc (bin_len); -    GNUNET_assert -      (GNUNET_OK == GNUNET_STRINGS_string_to_data -        (since_when, -        strlen (since_when), -        since_when_bin, -        bin_len)); -  } - -  if (NULL == (hh = plugin_handle->get_history (plugin_handle->cls, -                                                account_section, -                                                TALER_BANK_DIRECTION_BOTH, -                                                since_when_bin, -                                                bin_len, -                                                -10, -                                                &history_cb, -                                                NULL))) +  hh = TALER_BANK_credit_history (ctx, +                                  destination_account_url, +                                  &auth, +                                  start_row, +                                  -10, +                                  &history_cb, +                                  NULL); +  if (NULL == hh)    {      fprintf (stderr,               "Could not request the transaction history.\n"); @@ -305,19 +257,27 @@ execute_history ()  static void  do_shutdown (void *cls)  { +  if (NULL != ctx) +  { +    GNUNET_CURL_fini (ctx); +    ctx = NULL; +  } +  if (NULL != rc) +  { +    GNUNET_CURL_gnunet_rc_destroy (rc); +    rc = NULL; +  }    if (NULL != hh)    { -    plugin_handle->get_history_cancel (plugin_handle->cls, -                                       hh); +    TALER_BANK_credit_history_cancel (hh);      hh = NULL;    } -  if (NULL != ph) +  if (NULL != eh)    { -    plugin_handle->prepare_wire_transfer_cancel (plugin_handle->cls, -                                                 ph); -    ph = NULL; +    TALER_BANK_execute_wire_transfer_cancel (eh); +    eh = NULL;    } -  TALER_WIRE_plugin_unload (plugin_handle); +  TALER_BANK_auth_free (&auth);  } @@ -342,27 +302,18 @@ run (void *cls,               "The option: -s ACCOUNT-SECTION, is mandatory.\n");      return;    } - -  if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string -        (cfg, -        account_section, -        "plugin", -        &plugin_name)) +  if (GNUNET_OK != +      TALER_BANK_auth_parse_cfg (cfg, +                                 account_section, +                                 &auth))    {      fprintf (stderr, -             "Could not find the 'plugin' value under %s\n", +             "Authentication information not found in configuration section `%s'\n",               account_section); +    GNUNET_SCHEDULER_shutdown ();      return;    } -  plugin_handle = TALER_WIRE_plugin_load (cfg, -                                          plugin_name); -  if (NULL == plugin_handle) -  { -    fprintf (stderr, -             "Could not load the wire plugin\n"); -    return; -  }    if (GNUNET_YES == history)      execute_history (); @@ -372,6 +323,14 @@ run (void *cls,      fprintf (stderr,               "Please give either --history/-H or --transfer/t\n"); +  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, +                          &rc); +  rc = GNUNET_CURL_gnunet_rc_create (ctx); +  if (NULL == ctx) +  { +    GNUNET_break (0); +    return; +  }    GNUNET_SCHEDULER_add_shutdown (&do_shutdown,                                   NULL);  } @@ -400,22 +359,23 @@ main (int argc,                                 "transfer",                                 "Execute a wire transfer.",                                 &transfer), -    GNUNET_GETOPT_option_string ('w', -                                 "since-when", -                                 "SW", -                                 "When asking the bank for" -                                 " transactions history, this" -                                 " option commands that all the" -                                 " results should have IDs settled" -                                 " after SW.  If not given, then" -                                 " the 10 youngest transactions" -                                 " are returned.", -                                 &since_when), -    GNUNET_GETOPT_option_string ('s', -                                 "section", -                                 "ACCOUNT-SECTION", -                                 "Which config section has the credentials to access the bank.  Mandatory.\n", -                                 &account_section), +    GNUNET_GETOPT_option_ulong ('w', +                                "since-when", +                                "SW", +                                "When asking the bank for" +                                " transactions history, this" +                                " option commands that all the" +                                " results should have IDs settled" +                                " after SW.  If not given, then" +                                " the 10 youngest transactions" +                                " are returned.", +                                &start_row), +    GNUNET_GETOPT_option_mandatory +      (GNUNET_GETOPT_option_string ('s', +                                    "section", +                                    "ACCOUNT-SECTION", +                                    "Which config section has the credentials to access the bank.  Mandatory.\n", +                                    &account_section)),      GNUNET_GETOPT_option_string ('a',                                   "amount",                                   "AMOUNT", diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 3453683a..b08c85c6 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -29,9 +29,11 @@ taler_exchange_aggregator_LDADD = \    $(LIBGCRYPT_LIBS) \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \    $(top_builddir)/src/exchangedb/libtalerexchangedb.la \    -ljansson \ +  -lgnunetcurl \    -lgnunetutil  taler_exchange_wirewatch_SOURCES = \ @@ -40,9 +42,11 @@ taler_exchange_wirewatch_LDADD = \    $(LIBGCRYPT_LIBS) \    $(top_builddir)/src/json/libtalerjson.la \    $(top_builddir)/src/util/libtalerutil.la \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \    $(top_builddir)/src/exchangedb/libtalerexchangedb.la \    -ljansson \ +  -lgnunetcurl \    -lgnunetutil  taler_exchange_httpd_SOURCES = \ @@ -66,6 +70,7 @@ taler_exchange_httpd_SOURCES = \    taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h  taler_exchange_httpd_LDADD = \    $(LIBGCRYPT_LIBS) \ +  $(top_builddir)/src/bank-lib/libtalerbank.la \    $(top_builddir)/src/wire/libtalerwire.la \    $(top_builddir)/src/mhd/libtalermhd.la \    $(top_builddir)/src/json/libtalerjson.la \ diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 71a3efd7..2704f591 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2016-2018 Taler Systems SA +  Copyright (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU Affero General Public License as published by the Free Software @@ -26,6 +26,7 @@  #include "taler_exchangedb_lib.h"  #include "taler_exchangedb_plugin.h"  #include "taler_json_lib.h" +#include "taler_bank_service.h"  #include "taler_wire_lib.h" @@ -45,9 +46,14 @@ struct WireAccount    struct WireAccount *prev;    /** -   * Handle to the plugin. +   * Account information.     */ -  struct TALER_WIRE_Plugin *wire_plugin; +  struct TALER_Account account; + +  /** +   * Authentication data. +   */ +  struct TALER_BANK_AuthenticationData auth;    /**     * Wire transfer fee structure. @@ -59,6 +65,11 @@ struct WireAccount     */    char *section_name; +  /** +   * Name of the wire method underlying the account. +   */ +  char *method; +  }; @@ -77,7 +88,7 @@ struct WirePrepareData    /**     * Wire execution handle.     */ -  struct TALER_WIRE_ExecuteHandle *eh; +  struct TALER_BANK_WireExecuteHandle *eh;    /**     * Wire plugin used for this preparation. @@ -187,10 +198,6 @@ struct AggregationUnit   */  struct CloseTransferContext  { -  /** -   * Handle for preparing the wire transfer. -   */ -  struct TALER_WIRE_PrepareHandle *ph;    /**     * Our database session. @@ -263,6 +270,16 @@ static struct WirePrepareData *wpd;  static struct AggregationUnit *au;  /** + * Handle to the context for interacting with the bank. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + +/**   * Value to return from main(). #GNUNET_OK on success, #GNUNET_SYSERR   * on serious errors.   */ @@ -339,7 +356,7 @@ update_fees (struct WireAccount *wa,      return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;    /* Let's try to load it from disk... */    wa->af = TALER_EXCHANGEDB_fees_read (cfg, -                                       wa->wire_plugin->method); +                                       wa->method);    advance_fees (wa,                  now);    for (struct TALER_EXCHANGEDB_AggregateFees *p = wa->af; @@ -348,7 +365,7 @@ update_fees (struct WireAccount *wa,    {      qs = db_plugin->insert_wire_fee (db_plugin->cls,                                       session, -                                     wa->wire_plugin->method, +                                     wa->method,                                       p->start_date,                                       p->end_date,                                       &p->wire_fee, @@ -365,7 +382,7 @@ update_fees (struct WireAccount *wa,      return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;    GNUNET_log (GNUNET_ERROR_TYPE_ERROR,                "Failed to find current wire transfer fees for `%s'\n", -              wa->wire_plugin->method); +              wa->method);    return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;  } @@ -381,7 +398,7 @@ find_account_by_method (const char *method)  {    for (struct WireAccount *wa = wa_head; NULL != wa; wa = wa->next)      if (0 == strcmp (method, -                     wa->wire_plugin->method)) +                     wa->method))        return wa;    return NULL;  } @@ -431,13 +448,40 @@ add_account_cb (void *cls,    if (GNUNET_YES != ai->debit_enabled)      return; /* not enabled for us, skip */    wa = GNUNET_new (struct WireAccount); -  wa->wire_plugin = TALER_WIRE_plugin_load (cfg, -                                            ai->plugin_name); -  if (NULL == wa->wire_plugin) +  if (GNUNET_OK != +      GNUNET_CONFIGURATION_get_value_string (cfg, +                                             ai->section_name, +                                             "METHOD", +                                             &wa->method))    { -    fprintf (stderr, -             "Failed to load wire plugin for `%s'\n", -             ai->plugin_name); +    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, +                               ai->section_name, +                               "METHOD"); +    GNUNET_free (wa); +    return; +  } +  if (GNUNET_OK != +      TALER_BANK_auth_parse_cfg (cfg, +                                 ai->section_name, +                                 &wa->auth)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, +                "Failed to load account `%s'\n", +                ai->section_name); +    GNUNET_free (wa->method); +    GNUNET_free (wa); +    return; +  } +  if (GNUNET_OK != +      TALER_BANK_account_parse_cfg (cfg, +                                    ai->section_name, +                                    &wa->account)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, +                "Failed to load account `%s'\n", +                ai->section_name); +    TALER_BANK_auth_free (&wa->auth); +    GNUNET_free (wa->method);      GNUNET_free (wa);      return;    } @@ -476,6 +520,16 @@ static void  shutdown_task (void *cls)  {    (void) cls; +  if (NULL != ctx) +  { +    GNUNET_CURL_fini (ctx); +    ctx = NULL; +  } +  if (NULL != rc) +  { +    GNUNET_CURL_gnunet_rc_destroy (rc); +    rc = NULL; +  }    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Running shutdown\n");    if (NULL != task) @@ -487,9 +541,7 @@ shutdown_task (void *cls)    {      if (NULL != wpd->eh)      { -      wpd->wa->wire_plugin->execute_wire_transfer_cancel ( -        wpd->wa->wire_plugin->cls, -        wpd->eh); +      TALER_BANK_execute_wire_transfer_cancel (wpd->eh);        wpd->eh = NULL;      }      db_plugin->rollback (db_plugin->cls, @@ -499,23 +551,12 @@ shutdown_task (void *cls)    }    if (NULL != au)    { -    if (NULL != au->ph) -    { -      au->wa->wire_plugin->prepare_wire_transfer_cancel ( -        au->wa->wire_plugin->cls, -        au->ph); -      au->ph = NULL; -    }      db_plugin->rollback (db_plugin->cls,                           au->session);      cleanup_au ();    }    if (NULL != ctc)    { -    ctc->wa->wire_plugin->prepare_wire_transfer_cancel ( -      ctc->wa->wire_plugin->cls, -      ctc->ph); -    ctc->ph = NULL;      db_plugin->rollback (db_plugin->cls,                           ctc->session);      GNUNET_free (ctc->method); @@ -532,9 +573,11 @@ shutdown_task (void *cls)        GNUNET_CONTAINER_DLL_remove (wa_head,                                     wa_tail,                                     wa); -      TALER_WIRE_plugin_unload (wa->wire_plugin); +      TALER_WIRE_account_free (&wa->account); +      TALER_BANK_auth_free (&wa->auth);        TALER_EXCHANGEDB_fees_free (wa->af);        GNUNET_free (wa->section_name); +      GNUNET_free (wa->method);        GNUNET_free (wa);      }    } @@ -922,20 +965,6 @@ aggregate_cb (void *cls,  /** - * Function to be called with the prepared transfer data - * when running an aggregation on a merchant. - * - * @param cls closure with the `struct AggregationUnit` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, -            const char *buf, -            size_t buf_size); - - -/**   * Main work function that finds and triggers transfers for reserves   * closures.   * @@ -989,83 +1018,6 @@ commit_or_warn (struct TALER_EXCHANGEDB_Session *session)  /** - * Function to be called with the prepared transfer data - * when closing a reserve. - * - * @param cls closure with a `struct CloseTransferContext` - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_close_cb (void *cls, -                  const char *buf, -                  size_t buf_size) -{ -  enum GNUNET_DB_QueryStatus qs; - -  GNUNET_assert (cls == ctc); - -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Prepared for reserve closing\n"); -  ctc->ph = NULL; -  if (NULL == buf) -  { -    GNUNET_break (0); /* why? how to best recover? */ -    db_plugin->rollback (db_plugin->cls, -                         ctc->session); -    /* start again */ -    GNUNET_free (ctc->method); -    GNUNET_free (ctc); -    ctc = NULL; -    task = GNUNET_SCHEDULER_add_now (&run_aggregation, -                                     NULL); -    return; -  } - -  /* Commit our intention to execute the wire transfer! */ -  qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, -                                            ctc->session, -                                            ctc->method, -                                            buf, -                                            buf_size); -  if (GNUNET_DB_STATUS_HARD_ERROR == qs) -  { -    GNUNET_break (0); -    db_plugin->rollback (db_plugin->cls, -                         ctc->session); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    GNUNET_free (ctc->method); -    GNUNET_free (ctc); -    ctc = NULL; -    return; -  } -  if (GNUNET_DB_STATUS_SOFT_ERROR == qs) -  { -    db_plugin->rollback (db_plugin->cls, -                         ctc->session); -    /* start again */ -    task = GNUNET_SCHEDULER_add_now (&run_aggregation, -                                     NULL); -    GNUNET_free (ctc->method); -    GNUNET_free (ctc); -    ctc = NULL; -    return; -  } - -  /* finally commit */ -  (void) commit_or_warn (ctc->session); -  GNUNET_free (ctc->method); -  GNUNET_free (ctc); -  ctc = NULL; -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Reserve closure committed, running transfer\n"); -  task = GNUNET_SCHEDULER_add_now (&run_transfers, -                                   NULL); -} - - -/**   * Closure for #expired_reserve_cb().   */  struct ExpiredReserveContext @@ -1113,6 +1065,8 @@ expired_reserve_cb (void *cls,    int ret;    enum GNUNET_DB_QueryStatus qs;    struct WireAccount *wa; +  void *buf; +  size_t buf_size;    /* NOTE: potential optimization: use custom SQL API to not       fetch this: */ @@ -1121,7 +1075,7 @@ expired_reserve_cb (void *cls,    now = GNUNET_TIME_absolute_get ();    (void) GNUNET_TIME_round_abs (&now); -  /* lookup wire plugin */ +  /* lookup account we should use */    wa = find_account_by_url (account_details);    if (NULL == wa)    { @@ -1161,6 +1115,18 @@ expired_reserve_cb (void *cls,                     TALER_amount_get_zero (left->currency,                                            &amount_without_fee));    } +  /* round down to enable transfer */ +  if (GNUNET_SYSERR == +      TALER_WIRE_amount_round (&amount_without_fee)) +  { +    GNUNET_break (0); +    global_ret = GNUNET_SYSERR; +    GNUNET_SCHEDULER_shutdown (); +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  if ( (0 == amount_without_fee.value) && +       (0 == amount_without_fee.fraction) ) +    ret = GNUNET_NO;    /* NOTE: sizeof (*reserve_pub) == sizeof (wtid) right now, but to       be future-compatible, we use the memset + min construction */ @@ -1171,61 +1137,23 @@ expired_reserve_cb (void *cls,            reserve_pub,            GNUNET_MIN (sizeof (wtid),                        sizeof (*reserve_pub))); - -  qs = db_plugin->insert_reserve_closed (db_plugin->cls, -                                         session, -                                         reserve_pub, -                                         now, -                                         account_details, -                                         &wtid, -                                         left, -                                         closing_fee); - +  if (GNUNET_SYSERR != ret) +    qs = db_plugin->insert_reserve_closed (db_plugin->cls, +                                           session, +                                           reserve_pub, +                                           now, +                                           account_details, +                                           &wtid, +                                           left, +                                           closing_fee); +  else +    ret = GNUNET_DB_STATUS_HARD_ERROR;    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Closing reserve %s over %s (%d, %d)\n",                TALER_B2S (reserve_pub),                TALER_amount2s (left),                ret,                qs); -  if ( (GNUNET_OK == ret) && -       (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs) ) -  { -    /* success, perform wire transfer */ -    if (GNUNET_SYSERR == -        wa->wire_plugin->amount_round (wa->wire_plugin->cls, -                                       &amount_without_fee)) -    { -      GNUNET_break (0); -      global_ret = GNUNET_SYSERR; -      GNUNET_SCHEDULER_shutdown (); -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -    ctc = GNUNET_new (struct CloseTransferContext); -    ctc->wa = wa; -    ctc->session = session; -    ctc->method = TALER_WIRE_payto_get_method (account_details); -    ctc->ph -      = wa->wire_plugin->prepare_wire_transfer (wa->wire_plugin->cls, -                                                wa->section_name, -                                                account_details, -                                                &amount_without_fee, -                                                exchange_base_url, -                                                &wtid, -                                                &prepare_close_cb, -                                                ctc); -    if (NULL == ctc->ph) -    { -      GNUNET_break (0); -      global_ret = GNUNET_SYSERR; -      GNUNET_SCHEDULER_shutdown (); -      GNUNET_free (ctc->method); -      GNUNET_free (ctc); -      ctc = NULL; -      return GNUNET_DB_STATUS_HARD_ERROR; -    } -    erc->async_cont = GNUNET_YES; -    return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; -  }    /* Check for hard failure */    if ( (GNUNET_SYSERR == ret) ||         (GNUNET_DB_STATUS_HARD_ERROR == qs) ) @@ -1235,10 +1163,59 @@ expired_reserve_cb (void *cls,      GNUNET_SCHEDULER_shutdown ();      return GNUNET_DB_STATUS_HARD_ERROR;    } -  /* Reserve balance was almost zero OR soft error */ -  GNUNET_log (GNUNET_ERROR_TYPE_INFO, -              "Reserve was virtually empty, moving on\n"); -  return qs; +  if ( (GNUNET_OK != ret) || +       (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs) ) +  { +    /* Reserve balance was almost zero OR soft error */ +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                "Reserve was virtually empty, moving on\n"); +    (void) commit_or_warn (ctc->session); +    GNUNET_free (ctc->method); +    GNUNET_free (ctc); +    ctc = NULL; +    task = GNUNET_SCHEDULER_add_now (&run_transfers, +                                     NULL); +    return qs; +  } + +  /* success, perform wire transfer */ +  ctc = GNUNET_new (struct CloseTransferContext); +  ctc->wa = wa; +  ctc->session = session; +  ctc->method = TALER_WIRE_payto_get_method (account_details); +  TALER_BANK_prepare_wire_transfer (account_details, +                                    &amount_without_fee, +                                    exchange_base_url, +                                    &wtid, +                                    &buf, +                                    &buf_size); +  /* Commit our intention to execute the wire transfer! */ +  qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, +                                            ctc->session, +                                            ctc->method, +                                            buf, +                                            buf_size); +  GNUNET_free (buf); +  if (GNUNET_DB_STATUS_HARD_ERROR == qs) +  { +    GNUNET_break (0); +    GNUNET_free (ctc->method); +    GNUNET_free (ctc); +    ctc = NULL; +    return GNUNET_DB_STATUS_HARD_ERROR; +  } +  if (GNUNET_DB_STATUS_SOFT_ERROR == qs) +  { +    /* start again */ +    GNUNET_free (ctc->method); +    GNUNET_free (ctc); +    ctc = NULL; +    return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; +  } +  erc->async_cont = GNUNET_YES; +  task = GNUNET_SCHEDULER_add_now (&run_transfers, +                                   NULL); +  return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;  } @@ -1344,6 +1321,8 @@ run_aggregation (void *cls)    struct TALER_EXCHANGEDB_Session *session;    enum GNUNET_DB_QueryStatus qs;    const struct GNUNET_SCHEDULER_TaskContext *tc; +  void *buf; +  size_t buf_size;    (void) cls;    task = NULL; @@ -1470,8 +1449,7 @@ run_aggregation (void *cls)                                 &au->total_amount,                                 &au->wire_fee)) ||         (GNUNET_SYSERR == -        au->wa->wire_plugin->amount_round (au->wa->wire_plugin->cls, -                                           &au->final_amount)) || +        TALER_WIRE_amount_round (&au->final_amount)) ||         ( (0 == au->final_amount.value) &&           (0 == au->final_amount.fraction) ) )    { @@ -1555,70 +1533,26 @@ run_aggregation (void *cls)      char *url;      url = TALER_JSON_wire_to_payto (au->wire); -    au->ph = au->wa->wire_plugin->prepare_wire_transfer ( -      au->wa->wire_plugin->cls, -      au->wa->section_name, -      url, -      &au->final_amount, -      exchange_base_url, -      &au->wtid, -      &prepare_cb, -      au); +    TALER_BANK_prepare_wire_transfer (url, +                                      &au->final_amount, +                                      exchange_base_url, +                                      &au->wtid, +                                      &buf, +                                      &buf_size);      GNUNET_free (url);    } -  if (NULL == au->ph) -  { -    /* something went very wrong, likely bad configuration, -       abort */ -    db_plugin->rollback (db_plugin->cls, -                         session); -    cleanup_au (); -    GNUNET_SCHEDULER_shutdown (); -    return; -  } -  /* otherwise we continue with #prepare_cb(), see below */ -} - - -/** - * Function to be called with the prepared transfer data. - * - * @param cls NULL - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, -            const char *buf, -            size_t buf_size) -{ -  struct TALER_EXCHANGEDB_Session *session = au->session; -  enum GNUNET_DB_QueryStatus qs; - -  (void) cls;    GNUNET_free_non_null (au->additional_rows);    au->additional_rows = NULL; -  if (NULL == buf) -  { -    GNUNET_break (0); /* why? how to best recover? */ -    db_plugin->rollback (db_plugin->cls, -                         session); -    /* start again */ -    task = GNUNET_SCHEDULER_add_now (&run_aggregation, -                                     NULL); -    cleanup_au (); -    return; -  } -    GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                "Storing %u bytes of wire prepare data\n",                (unsigned int) buf_size);    /* Commit our intention to execute the wire transfer! */    qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,                                              session, -                                            au->wa->wire_plugin->method, +                                            au->wa->method,                                              buf,                                              buf_size); +  GNUNET_free (buf);    /* Commit the WTID data to 'wire_out' to finally satisfy aggregation       table constraints */    if (qs >= 0) @@ -1691,29 +1625,30 @@ prepare_cb (void *cls,   * Function called with the result from the execute step.   *   * @param cls NULL - * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure - * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error - * @param emsg NULL on success, otherwise an error message + * @param http_status_code #MHD_HTTP_OK on success + * @param ec taler error code + * @param row_id unique ID of the wire transfer in the bank's records + * @param wire_timestamp when did the transfer happen   */  static void  wire_confirm_cb (void *cls, -                 int success, -                 const void *row_id, -                 size_t row_id_size, -                 const char *emsg) +                 unsigned int http_status_code, +                 enum TALER_ErrorCode ec, +                 uint64_t row_id, +                 struct GNUNET_TIME_Absolute wire_timestamp)  {    struct TALER_EXCHANGEDB_Session *session = wpd->session;    enum GNUNET_DB_QueryStatus qs;    (void) cls;    (void) row_id; -  (void) row_id_size;    wpd->eh = NULL; -  if (GNUNET_SYSERR == success) +  if (MHD_HTTP_OK != http_status_code)    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Wire transaction failed: %s\n", -                emsg); +                "Wire transaction failed: %u/%d\n", +                http_status_code, +                ec);      db_plugin->rollback (db_plugin->cls,                           session);      global_ret = GNUNET_SYSERR; @@ -1792,6 +1727,8 @@ wire_prepare_cb (void *cls,                   const char *buf,                   size_t buf_size)  { +  struct WireAccount *wa; +    (void) cls;    wpd->row_id = rowid;    GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -1811,12 +1748,15 @@ wire_prepare_cb (void *cls,      wpd = NULL;      return;    } -  wpd->eh = wpd->wa->wire_plugin->execute_wire_transfer ( -    wpd->wa->wire_plugin->cls, -    buf, -    buf_size, -    &wire_confirm_cb, -    NULL); +  wa = wpd->wa; +  wpd->eh = TALER_BANK_execute_wire_transfer (ctx, +                                              wa->account.details.x_taler_bank. +                                              account_base_url, +                                              &wa->auth, +                                              buf, +                                              buf_size, +                                              &wire_confirm_cb, +                                              NULL);    if (NULL == wpd->eh)    {      GNUNET_break (0); /* why? how to best recover? */ @@ -1927,6 +1867,7 @@ run (void *cls,    (void) cls;    (void) args;    (void) cfgfile; +    if (GNUNET_OK !=        GNUNET_CONFIGURATION_get_value_string (c,                                               "exchange", @@ -1947,6 +1888,15 @@ run (void *cls,      global_ret = 1;      return;    } +  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, +                          &rc); +  rc = GNUNET_CURL_gnunet_rc_create (ctx); +  if (NULL == ctx) +  { +    GNUNET_break (0); +    return; +  } +    task = GNUNET_SCHEDULER_add_now (&run_transfers,                                     NULL);    GNUNET_SCHEDULER_add_shutdown (&shutdown_task, diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 02448238..96e30e43 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -400,7 +400,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,    json_t *json;    int res;    json_t *wire; -  char *emsg;    enum TALER_ErrorCode ec;    unsigned int hc;    struct TALER_EXCHANGEDB_Deposit deposit; @@ -460,18 +459,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,                                         "refund_deadline");    } -  if (TALER_EC_NONE != -      (ec = TEH_json_validate_wireformat (wire, -                                          &emsg))) -  { -    GNUNET_JSON_parse_free (spec); -    res = TALER_MHD_reply_with_error (connection, -                                      MHD_HTTP_BAD_REQUEST, -                                      ec, -                                      emsg); -    GNUNET_free (emsg); -    return res; -  }    if (GNUNET_OK !=        check_timestamp_current (deposit.timestamp))    { diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c index 23dbbf24..d0371e93 100644 --- a/src/exchange/taler-exchange-httpd_validation.c +++ b/src/exchange/taler-exchange-httpd_validation.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2016, 2017, 2018 Taler Systems SA +  Copyright (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU Affero General Public License as published by the Free Software @@ -30,40 +30,6 @@  /** - * Information we keep for each plugin. - */ -struct Plugin -{ - -  /** -   * We keep plugins in a DLL. -   */ -  struct Plugin *next; - -  /** -   * We keep plugins in a DLL. -   */ -  struct Plugin *prev; - -  /** -   * Pointer to the plugin. -   */ -  struct TALER_WIRE_Plugin *plugin; - -}; - - -/** - * Head of DLL of wire plugins. - */ -static struct Plugin *wire_head; - -/** - * Tail of DLL of wire plugins. - */ -static struct Plugin *wire_tail; - -/**   * Array of wire methods supported by this exchange.   */  static json_t *wire_accounts_array; @@ -191,9 +157,8 @@ load_account (void *cls,      else      {        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Wire fees not specified for `%s', ignoring plugin %s\n", -                  method, -                  ai->plugin_name); +                  "Wire fees not specified for `%s'\n", +                  method);        *ret = GNUNET_SYSERR;      }      GNUNET_free (method); @@ -201,35 +166,15 @@ load_account (void *cls,    if (GNUNET_YES == ai->debit_enabled)    { -    struct Plugin *p; - -    p = GNUNET_new (struct Plugin); -    p->plugin = TALER_WIRE_plugin_load (cfg, -                                        ai->plugin_name); -    if (NULL == p->plugin) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Failed to load plugin %s\n", -                  ai->plugin_name); -      GNUNET_free (p); -      *ret = GNUNET_SYSERR; -      return; -    }      if (GNUNET_OK != -        load_fee (p->plugin->method)) +        load_fee (ai->method))      {        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "Disabling plugin `%s' as wire transfer fees for `%s' are not given correctly\n", -                  ai->plugin_name, -                  p->plugin->method); -      TALER_WIRE_plugin_unload (p->plugin); -      GNUNET_free (p); +                  "Wire transfer fees for `%s' are not given correctly\n", +                  ai->method);        *ret = GNUNET_SYSERR;        return;      } -    GNUNET_CONTAINER_DLL_insert (wire_head, -                                 wire_tail, -                                 p);    }  } @@ -251,12 +196,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)    TALER_EXCHANGEDB_find_accounts (cfg,                                    &load_account,                                    &ret); -  if (NULL == wire_head) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Failed to find properly configured wire transfer method\n"); -    ret = GNUNET_SYSERR; -  }    if (GNUNET_OK != ret)      TEH_VALIDATION_done ();    return ret; @@ -269,16 +208,6 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)  void  TEH_VALIDATION_done ()  { -  struct Plugin *p; - -  while (NULL != (p = wire_head)) -  { -    GNUNET_CONTAINER_DLL_remove (wire_head, -                                 wire_tail, -                                 p); -    TALER_WIRE_plugin_unload (p->plugin); -    GNUNET_free (p); -  }    json_decref (wire_fee_object);    wire_fee_object = NULL;    json_decref (wire_accounts_array); @@ -287,65 +216,6 @@ TEH_VALIDATION_done ()  /** - * Check if the given wire format JSON object is correctly formatted as - * a wire address. - * - * @param wire the JSON wire format object - * @param[out] emsg set to error message if we return an error code - * @return #TALER_EC_NONE if correctly formatted; otherwise error code - */ -enum TALER_ErrorCode -TEH_json_validate_wireformat (const json_t *wire, -                              char **emsg) -{ -  const char *payto_url; -  json_error_t error; -  char *method; - -  *emsg = NULL; -  if (0 != json_unpack_ex ((json_t *) wire, -                           &error, 0, -                           "{s:s}", -                           "url", &payto_url)) -  { -    GNUNET_asprintf (emsg, -                     "No `url' specified in the wire details\n"); -    return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING; -  } -  method = TALER_WIRE_payto_get_method (payto_url); -  if (NULL == method) -  { -    GNUNET_asprintf (emsg, -                     "Malformed payto URL `%s'\n", -                     payto_url); -    return TALER_EC_PAYTO_MALFORMED; -  } -  for (struct Plugin *p = wire_head; NULL != p; p = p->next) -  { -    if (0 == strcasecmp (p->plugin->method, -                         method)) -    { -      enum TALER_ErrorCode ec; - -      GNUNET_free (method); -      ec = p->plugin->wire_validate (p->plugin->cls, -                                     payto_url); -      if (TALER_EC_NONE != ec) -        GNUNET_asprintf (emsg, -                         "Payto URL `%s' rejected by plugin\n", -                         payto_url); -      return ec; -    } -  } -  GNUNET_asprintf (emsg, -                   "Wire format type `%s' is not supported by this exchange\n", -                   method); -  GNUNET_free (method); -  return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED; -} - - -/**   * Obtain JSON response for /wire   *   * @return JSON array with the supported validation methods, NULL on error diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 21f62cd8..091f4ba2 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -27,6 +27,7 @@  #include "taler_exchangedb_lib.h"  #include "taler_exchangedb_plugin.h"  #include "taler_json_lib.h" +#include "taler_bank_service.h"  #include "taler_wire_lib.h"  /** @@ -37,23 +38,6 @@  /** - * Closure for #reject_cb(). - */ -struct RejectContext -{ -  /** -   * Wire transfer subject that was illformed. -   */ -  char *wtid_s; - -  /** -   * Database session that encountered the problem. -   */ -  struct TALER_EXCHANGEDB_Session *session; -}; - - -/**   * Information we keep for each supported account.   */  struct WireAccount @@ -69,14 +53,19 @@ struct WireAccount    struct WireAccount *prev;    /** -   * Handle to the plugin. +   * Name of the section that configures this account.     */ -  struct TALER_WIRE_Plugin *wire_plugin; +  char *section_name;    /** -   * Name of the section that configures this account. +   * Account information.     */ -  char *section_name; +  struct TALER_Account account; + +  /** +   * Authentication data. +   */ +  struct TALER_BANK_AuthenticationData auth;    /**     * Are we running from scratch and should re-process all transactions @@ -108,6 +97,16 @@ static struct WireAccount *wa_tail;  static struct WireAccount *wa_pos;  /** + * Handle to the context for interacting with the bank. + */ +static struct GNUNET_CURL_Context *ctx; + +/** + * Scheduler context for running the @e ctx. + */ +static struct GNUNET_CURL_RescheduleContext *rc; + +/**   * Which currency is used by this exchange?   */  static char *exchange_currency_string; @@ -132,23 +131,13 @@ static int global_ret;   * Encoded offset in the wire transfer list from where   * to start the next query with the bank.   */ -static void *last_row_off; - -/** - * Number of bytes in #last_row_off. - */ -static size_t last_row_off_size; +static uint64_t last_row_off;  /**   * Latest row offset seen in this transaction, becomes   * the new #last_row_off upon commit.   */ -static void *latest_row_off; - -/** - * Number of bytes in #latest_row_off. - */ -static size_t latest_row_off_size; +static uint64_t latest_row_off;  /**   * Should we delay the next request to the wire plugin a bit? @@ -183,12 +172,7 @@ static struct GNUNET_SCHEDULER_Task *task;  /**   * Active request for history.   */ -static struct TALER_WIRE_HistoryHandle *hh; - -/** - * Active request to reject a wire transfer. - */ -static struct TALER_WIRE_RejectHandle *rt; +static struct TALER_BANK_CreditHistoryHandle *hh;  /** @@ -202,6 +186,16 @@ shutdown_task (void *cls)    struct WireAccount *wa;    (void) cls; +  if (NULL != ctx) +  { +    GNUNET_CURL_fini (ctx); +    ctx = NULL; +  } +  if (NULL != rc) +  { +    GNUNET_CURL_gnunet_rc_destroy (rc); +    rc = NULL; +  }    if (NULL != task)    {      GNUNET_SCHEDULER_cancel (task); @@ -209,20 +203,9 @@ shutdown_task (void *cls)    }    if (NULL != hh)    { -    wa_pos->wire_plugin->get_history_cancel (wa_pos->wire_plugin->cls, -                                             hh); +    TALER_BANK_credit_history_cancel (hh);      hh = NULL;    } -  if (NULL != rt) -  { -    char *wtid_s; - -    wtid_s = wa_pos->wire_plugin->reject_transfer_cancel ( -      wa_pos->wire_plugin->cls, -      rt); -    rt = NULL; -    GNUNET_free (wtid_s); -  }    TALER_EXCHANGEDB_plugin_unload (db_plugin);    db_plugin = NULL;    while (NULL != (wa = wa_head)) @@ -230,14 +213,13 @@ shutdown_task (void *cls)      GNUNET_CONTAINER_DLL_remove (wa_head,                                   wa_tail,                                   wa); -    TALER_WIRE_plugin_unload (wa->wire_plugin); +    TALER_WIRE_account_free (&wa->account); +    TALER_BANK_auth_free (&wa->auth);      GNUNET_free (wa->section_name);      GNUNET_free (wa);    }    wa_pos = NULL; -  GNUNET_free_non_null (last_row_off); -  last_row_off = NULL; -  last_row_off_size = 0; +  last_row_off = 0;  } @@ -259,13 +241,26 @@ add_account_cb (void *cls,      return; /* not enabled for us, skip */    wa = GNUNET_new (struct WireAccount);    wa->reset_mode = reset_mode; -  wa->wire_plugin = TALER_WIRE_plugin_load (cfg, -                                            ai->plugin_name); -  if (NULL == wa->wire_plugin) +  if (GNUNET_OK != +      TALER_BANK_auth_parse_cfg (cfg, +                                 ai->section_name, +                                 &wa->auth))    {      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, -                "Failed to load wire plugin for `%s'\n", -                ai->plugin_name); +                "Failed to load account `%s'\n", +                ai->section_name); +    GNUNET_free (wa); +    return; +  } +  if (GNUNET_OK != +      TALER_BANK_account_parse_cfg (cfg, +                                    ai->section_name, +                                    &wa->account)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, +                "Failed to load account `%s'\n", +                ai->section_name); +    TALER_BANK_auth_free (&wa->auth);      GNUNET_free (wa);      return;    } @@ -336,70 +331,28 @@ find_transfers (void *cls);  /** - * Function called upon completion of the rejection of a wire transfer. - * - * @param cls closure with the `struct RejectContext` - * @param ec error code for the operation - */ -static void -reject_cb (void *cls, -           enum TALER_ErrorCode ec) -{ -  struct RejectContext *rtc = cls; -  enum GNUNET_DB_QueryStatus qs; - -  rt = NULL; -  if (TALER_EC_NONE != ec) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Failed to wire back transfer `%s': %d\n", -                rtc->wtid_s, -                ec); -    GNUNET_free (rtc->wtid_s); -    db_plugin->rollback (db_plugin->cls, -                         rtc->session); -    GNUNET_free (rtc); -    GNUNET_SCHEDULER_shutdown (); -    return; -  } -  GNUNET_free (rtc->wtid_s); -  qs = db_plugin->commit (db_plugin->cls, -                          rtc->session); -  GNUNET_break (0 <= qs); -  GNUNET_free (rtc); -  task = GNUNET_SCHEDULER_add_now (&find_transfers, -                                   NULL); -} - - -/**   * Callbacks of this type are used to serve the result of asking   * the bank for the transaction history.   *   * @param cls closure with the `struct TALER_EXCHANGEDB_Session *`   * @param ec taler error code - * @param dir direction of the transfer - * @param row_off identification of the position at which we are querying - * @param row_off_size number of bytes in @a row_off + * @param serial_id identification of the position at which we are querying   * @param details details about the wire transfer + * @param json raw JSON response   * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */  static int  history_cb (void *cls, +            unsigned int http_status,              enum TALER_ErrorCode ec, -            enum TALER_BANK_Direction dir, -            const void *row_off, -            size_t row_off_size, -            const struct TALER_WIRE_TransferDetails *details) +            uint64_t serial_id, +            const struct TALER_BANK_CreditDetails *details, +            const json_t *json)  {    struct TALER_EXCHANGEDB_Session *session = cls;    enum GNUNET_DB_QueryStatus qs; -  struct TALER_ReservePublicKeyP reserve_pub; -  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, -              "Got history callback, direction %u!\n", -              (unsigned int) dir); -  if (TALER_BANK_DIRECTION_NONE == dir) +  if (NULL == details)    {      hh = NULL;      if (TALER_EC_NONE != ec) @@ -428,11 +381,8 @@ history_cb (void *cls,      if (0 < qs)      {        /* transaction success, update #last_row_off */ -      GNUNET_free_non_null (last_row_off);        last_row_off = latest_row_off; -      last_row_off_size = latest_row_off_size; -      latest_row_off = NULL; -      latest_row_off_size = 0; +      latest_row_off = 0;        /* if successful at limit, try increasing transaction batch size (AIMD) */        if (current_batch_size == batch_size) @@ -462,49 +412,10 @@ history_cb (void *cls,                                      NULL);      return GNUNET_OK; /* will be ignored anyway */    } -  if (NULL != details->wtid_s) -  { -    struct RejectContext *rtc; - -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                "Wire transfer over %s has invalid subject `%s', sending it back!\n", -                TALER_amount2s (&details->amount), -                details->wtid_s); -    GNUNET_break (0 != row_off_size); -    if (latest_row_off_size != row_off_size) -    { -      GNUNET_free_non_null (latest_row_off); -      latest_row_off = GNUNET_malloc (row_off_size); -      latest_row_off_size = row_off_size; -    } -    memcpy (latest_row_off, -            row_off, -            row_off_size); -    rtc = GNUNET_new (struct RejectContext); -    rtc->session = session; -    rtc->wtid_s = GNUNET_strdup (details->wtid_s); -    rt = wa_pos->wire_plugin->reject_transfer (wa_pos->wire_plugin->cls, -                                               wa_pos->section_name, -                                               row_off, -                                               row_off_size, -                                               &reject_cb, -                                               rtc); -    if (NULL == rt) -    { -      GNUNET_break (0); -      db_plugin->rollback (db_plugin->cls, -                           session); -      GNUNET_assert (NULL == task); -      task = GNUNET_SCHEDULER_add_now (&find_transfers, -                                       NULL); -    } -    return GNUNET_SYSERR; /* will continue later... */ -  } -    GNUNET_log (GNUNET_ERROR_TYPE_INFO,                "Adding wire transfer over %s with (hashed) subject `%s'\n",                TALER_amount2s (&details->amount), -              TALER_B2S (&details->wtid)); +              TALER_B2S (&details->reserve_pub));    /**     * Debug block. @@ -515,8 +426,8 @@ history_cb (void *cls,      char wtid_s[PUBSIZE];      GNUNET_break -      (NULL != GNUNET_STRINGS_data_to_string (&details->wtid, -                                              sizeof (details->wtid), +      (NULL != GNUNET_STRINGS_data_to_string (&details->reserve_pub, +                                              sizeof (details->reserve_pub),                                                &wtid_s[0],                                                PUBSIZE));      GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -525,20 +436,14 @@ history_cb (void *cls,    }    current_batch_size++; -  /* Wire transfer identifier == reserve public key */ -  GNUNET_assert (sizeof (reserve_pub) == sizeof (details->wtid)); -  memcpy (&reserve_pub, -          &details->wtid, -          sizeof (reserve_pub));    qs = db_plugin->reserves_in_insert (db_plugin->cls,                                        session, -                                      &reserve_pub, +                                      &details->reserve_pub,                                        &details->amount,                                        details->execution_date,                                        details->account_url,                                        wa_pos->section_name, -                                      row_off, -                                      row_off_size); +                                      serial_id);    if (GNUNET_DB_STATUS_HARD_ERROR == qs)    {      GNUNET_break (0); @@ -560,15 +465,7 @@ history_cb (void *cls,      return GNUNET_SYSERR;    } -  if (latest_row_off_size != row_off_size) -  { -    GNUNET_free_non_null (latest_row_off); -    latest_row_off = GNUNET_malloc (row_off_size); -    latest_row_off_size = row_off_size; -  } -  memcpy (latest_row_off, -          row_off, -          row_off_size); +  latest_row_off = serial_id;    return GNUNET_OK;  } @@ -615,8 +512,7 @@ find_transfers (void *cls)      qs = db_plugin->get_latest_reserve_in_reference (db_plugin->cls,                                                       session,                                                       wa_pos->section_name, -                                                     &last_row_off, -                                                     &last_row_off_size); +                                                     &last_row_off);      if (GNUNET_DB_STATUS_HARD_ERROR == qs)      {        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -638,20 +534,17 @@ find_transfers (void *cls)      }    }    wa_pos->reset_mode = GNUNET_NO; -  GNUNET_assert ( (NULL == last_row_off) || -                  ( (NULL != last_row_off) && -                    (0 != last_row_off_size) ) );    delay = GNUNET_YES;    current_batch_size = 0; -  hh = wa_pos->wire_plugin->get_history (wa_pos->wire_plugin->cls, -                                         wa_pos->section_name, -                                         TALER_BANK_DIRECTION_CREDIT, -                                         last_row_off, -                                         last_row_off_size, -                                         batch_size, -                                         &history_cb, -                                         session); +  hh = TALER_BANK_credit_history (ctx, +                                  wa_pos->account.details.x_taler_bank. +                                  account_base_url, +                                  &wa_pos->auth, +                                  last_row_off, +                                  batch_size, +                                  &history_cb, +                                  session);    if (NULL == hh)    {      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, @@ -695,6 +588,14 @@ run (void *cls,                                     NULL);    GNUNET_SCHEDULER_add_shutdown (&shutdown_task,                                   cls); +  ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, +                          &rc); +  rc = GNUNET_CURL_gnunet_rc_create (ctx); +  if (NULL == ctx) +  { +    GNUNET_break (0); +    return; +  }  } diff --git a/src/exchangedb/exchangedb_accounts.c b/src/exchangedb/exchangedb_accounts.c index e3150902..03779395 100644 --- a/src/exchangedb/exchangedb_accounts.c +++ b/src/exchangedb/exchangedb_accounts.c @@ -58,7 +58,7 @@ check_for_account (void *cls,                     const char *section)  {    struct FindAccountContext *ctx = cls; -  char *plugin_name; +  char *method;    char *payto_url;    char *wire_response_filename;    struct TALER_EXCHANGEDB_AccountInfo ai; @@ -81,12 +81,12 @@ check_for_account (void *cls,    if (GNUNET_OK !=        GNUNET_CONFIGURATION_get_value_string (ctx->cfg,                                               section, -                                             "PLUGIN", -                                             &plugin_name)) +                                             "METHOD", +                                             &method))    {      GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,                                 section, -                               "PLUGIN"); +                               "METHOD");      GNUNET_free (payto_url);      return;    } @@ -97,7 +97,7 @@ check_for_account (void *cls,                                                 &wire_response_filename))      wire_response_filename = NULL;    ai.section_name = section; -  ai.plugin_name = plugin_name; +  ai.method = method;    ai.payto_url = payto_url;    ai.wire_response_filename = wire_response_filename; @@ -112,7 +112,7 @@ check_for_account (void *cls,    ctx->cb (ctx->cb_cls,             &ai);    GNUNET_free (payto_url); -  GNUNET_free (plugin_name); +  GNUNET_free (method);    GNUNET_free_non_null (wire_response_filename);  } diff --git a/src/exchangedb/exchangedb_fees.c b/src/exchangedb/exchangedb_fees.c index f06be73a..386c5de9 100644 --- a/src/exchangedb/exchangedb_fees.c +++ b/src/exchangedb/exchangedb_fees.c @@ -144,12 +144,12 @@ TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg,  /**   * Convert @a af to @a wf.   * - * @param wireplugin name of the wire plugin the fees are for + * @param method name of the wire method the fees are for   * @param[in,out] af aggregate fees, host format (updated to round time)   * @param[out] wf aggregate fees, disk / signature format   */  void -TALER_EXCHANGEDB_fees_2_wf (const char *wireplugin, +TALER_EXCHANGEDB_fees_2_wf (const char *method,                              struct TALER_EXCHANGEDB_AggregateFees *af,                              struct TALER_MasterWireFeePS *wf)  { @@ -157,8 +157,8 @@ TALER_EXCHANGEDB_fees_2_wf (const char *wireplugin,    (void) GNUNET_TIME_round_abs (&af->end_date);    wf->purpose.size = htonl (sizeof (*wf));    wf->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES); -  GNUNET_CRYPTO_hash (wireplugin, -                      strlen (wireplugin) + 1, +  GNUNET_CRYPTO_hash (method, +                      strlen (method) + 1,                        &wf->h_wire_method);    wf->start_date = GNUNET_TIME_absolute_hton (af->start_date);    wf->end_date = GNUNET_TIME_absolute_hton (af->end_date); diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c index 6ddbead9..5f2c6716 100644 --- a/src/exchangedb/plugin_exchangedb_postgres.c +++ b/src/exchangedb/plugin_exchangedb_postgres.c @@ -253,7 +253,7 @@ postgres_create_tables (void *cls)      GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS reserves_in"                              "(reserve_in_serial_id BIGSERIAL UNIQUE"                              ",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE" -                            ",wire_reference BYTEA NOT NULL" +                            ",wire_reference INT8 NOT NULL"                              ",credit_val INT8 NOT NULL"                              ",credit_frac INT4 NOT NULL"                              ",sender_account_details TEXT NOT NULL" @@ -2158,8 +2158,7 @@ reserves_update (void *cls,   * @param sender_account_details account information for the sender (payto://-URL)   * @param exchange_account_section name of the section in the configuration for the exchange's   *                       account into which the deposit was made - * @param wire_reference unique reference identifying the wire transfer (binary blob) - * @param wire_reference_size number of bytes in @a wire_reference + * @param wire_ref unique reference identifying the wire transfer   * @return transaction status code   */  static enum GNUNET_DB_QueryStatus @@ -2170,8 +2169,7 @@ postgres_reserves_in_insert (void *cls,                               struct GNUNET_TIME_Absolute execution_time,                               const char *sender_account_details,                               const char *exchange_account_section, -                             const void *wire_reference, -                             size_t wire_reference_size) +                             uint64_t wire_ref)  {    struct PostgresClosure *pg = cls;    enum GNUNET_DB_QueryStatus reserve_exists; @@ -2252,8 +2250,7 @@ postgres_reserves_in_insert (void *cls,    {      struct GNUNET_PQ_QueryParam params[] = {        GNUNET_PQ_query_param_auto_from_type (&reserve.pub), -      GNUNET_PQ_query_param_fixed_size (wire_reference, -                                        wire_reference_size), +      GNUNET_PQ_query_param_uint64 (&wire_ref),        TALER_PQ_query_param_amount (balance),        GNUNET_PQ_query_param_string (exchange_account_section),        GNUNET_PQ_query_param_string (sender_account_details), @@ -2311,8 +2308,7 @@ postgres_reserves_in_insert (void *cls,   * @param session the database session handle   * @param exchange_account_name name of the section in the exchange's configuration   *                       for the account that we are tracking here - * @param[out] wire_reference set to unique reference identifying the wire transfer (binary blob) - * @param[out] wire_reference_size set to number of bytes in @a wire_reference + * @param[out] wire_ref set to unique reference identifying the wire transfer   * @return transaction status code   */  static enum GNUNET_DB_QueryStatus @@ -2320,17 +2316,15 @@ postgres_get_latest_reserve_in_reference (void *cls,                                            struct TALER_EXCHANGEDB_Session *                                            session,                                            const char *exchange_account_name, -                                          void **wire_reference, -                                          size_t *wire_reference_size) +                                          uint64_t *wire_reference)  {    struct GNUNET_PQ_QueryParam params[] = {      GNUNET_PQ_query_param_string (exchange_account_name),      GNUNET_PQ_query_param_end    };    struct GNUNET_PQ_ResultSpec rs[] = { -    GNUNET_PQ_result_spec_variable_size ("wire_reference", -                                         wire_reference, -                                         wire_reference_size), +    GNUNET_PQ_result_spec_uint64 ("wire_reference", +                                  wire_reference),      GNUNET_PQ_result_spec_end    }; @@ -6192,14 +6186,12 @@ reserves_in_serial_helper_cb (void *cls,      char *sender_account_details;      struct GNUNET_TIME_Absolute execution_date;      uint64_t rowid; -    void *wire_reference; -    size_t wire_reference_size; +    uint64_t wire_reference;      struct GNUNET_PQ_ResultSpec rs[] = {        GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",                                              &reserve_pub), -      GNUNET_PQ_result_spec_variable_size ("wire_reference", -                                           &wire_reference, -                                           &wire_reference_size), +      GNUNET_PQ_result_spec_uint64 ("wire_reference", +                                    &wire_reference),        TALER_PQ_RESULT_SPEC_AMOUNT ("credit",                                     &credit),        TALER_PQ_result_spec_absolute_time ("execution_date", @@ -6227,7 +6219,6 @@ reserves_in_serial_helper_cb (void *cls,                      &credit,                      sender_account_details,                      wire_reference, -                    wire_reference_size,                      execution_date);      GNUNET_PQ_cleanup_result (rs);      if (GNUNET_OK != ret) diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c index a1e20e83..583e3c17 100644 --- a/src/exchangedb/test_exchangedb.c +++ b/src/exchangedb/test_exchangedb.c @@ -944,8 +944,7 @@ audit_refund_cb (void *cls,   * @param reserve_pub public key of the reserve (also the WTID)   * @param credit amount that was received   * @param sender_account_details information about the sender's bank account - * @param wire_reference unique reference identifying the wire transfer (binary blob) - * @param wire_reference_size number of bytes in @a wire_reference + * @param wire_reference unique reference identifying the wire transfer   * @param execution_date when did we receive the funds   * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop   */ @@ -955,8 +954,7 @@ audit_reserve_in_cb (void *cls,                       const struct TALER_ReservePublicKeyP *reserve_pub,                       const struct TALER_Amount *credit,                       const char *sender_account_details, -                     const void *wire_reference, -                     size_t wire_reference_size, +                     uint64_t wire_reference,                       struct GNUNET_TIME_Absolute execution_date)  {    auditor_row_cnt++; @@ -1507,8 +1505,7 @@ run (void *cls)    const char *sndr = "payto://x-taler-bank/localhost:8080/1";    unsigned int matched;    unsigned int cnt; -  void *rr; -  size_t rr_size; +  uint64_t rr;    enum GNUNET_DB_QueryStatus qs;    struct GNUNET_TIME_Absolute now; @@ -1578,8 +1575,7 @@ run (void *cls)            plugin->get_latest_reserve_in_reference (plugin->cls,                                                     session,                                                     "account-1", -                                                   &rr, -                                                   &rr_size)); +                                                   &rr));    now = GNUNET_TIME_absolute_get ();    (void) GNUNET_TIME_round_abs (&now);    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != @@ -1590,17 +1586,13 @@ run (void *cls)                                        now,                                        sndr,                                        "account-1", -                                      "TEST",                                        4));    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=            plugin->get_latest_reserve_in_reference (plugin->cls,                                                     session,                                                     "account-1", -                                                   &rr, -                                                   &rr_size)); -  FAILIF (4 != rr_size); -  FAILIF (0 != memcmp ("TEST", rr, 4)); -  GNUNET_free (rr); +                                                   &rr)); +  FAILIF (4 != rr);    FAILIF (GNUNET_OK !=            check_reserve (session,                           &reserve_pub, @@ -1617,24 +1609,18 @@ run (void *cls)                                        now,                                        sndr,                                        "account-1", -                                      "TEST2",                                        5));    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=            plugin->get_latest_reserve_in_reference (plugin->cls,                                                     session,                                                     "account-1", -                                                   &rr, -                                                   &rr_size)); -  GNUNET_free (rr); +                                                   &rr));    FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=            plugin->get_latest_reserve_in_reference (plugin->cls,                                                     session,                                                     "account-1", -                                                   &rr, -                                                   &rr_size)); -  FAILIF (5 != rr_size); -  FAILIF (0 != memcmp ("TEST2", rr, 5)); -  GNUNET_free (rr); +                                                   &rr)); +  FAILIF (5 != rr);    FAILIF (GNUNET_OK !=            check_reserve (session,                           &reserve_pub, diff --git a/src/include/Makefile.am b/src/include/Makefile.am index af91f117..25bc67b2 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am @@ -31,8 +31,6 @@ talerinclude_HEADERS = \    taler_mhd_lib.h \    taler_pq_lib.h \    taler_signatures.h \ -  taler_wire_lib.h \ -  taler_wire_plugin.h \    taler_testing_bank_lib.h   endif diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h index 03a1c6d4..14d477d3 100644 --- a/src/include/taler_auditordb_plugin.h +++ b/src/include/taler_auditordb_plugin.h @@ -870,7 +870,6 @@ struct TALER_AUDITORDB_Plugin     * @param pp where is the auditor in processing     * @param in_wire_off how far are we in the incoming wire transaction history     * @param out_wire_off how far are we in the outgoing wire transaction history -   * @param wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?     * @return transaction status code     */    enum GNUNET_DB_QueryStatus @@ -883,9 +882,8 @@ struct TALER_AUDITORDB_Plugin                                            const struct                                            TALER_AUDITORDB_WireAccountProgressPoint                                            *pp, -                                          const void *in_wire_off, -                                          const void *out_wire_off, -                                          size_t wire_off_size); +                                          uint64_t in_wire_off, +                                          uint64_t out_wire_off);    /** @@ -899,7 +897,6 @@ struct TALER_AUDITORDB_Plugin     * @param pp where is the auditor in processing     * @param in_wire_off how far are we in the incoming wire transaction history     * @param out_wire_off how far are we in the outgoing wire transaction history -   * @param wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?     * @return transaction status code     */    enum GNUNET_DB_QueryStatus @@ -912,9 +909,8 @@ struct TALER_AUDITORDB_Plugin                                            const struct                                            TALER_AUDITORDB_WireAccountProgressPoint                                            *pp, -                                          const void *in_wire_off, -                                          const void *out_wire_off, -                                          size_t wire_off_size); +                                          uint64_t in_wire_off, +                                          uint64_t out_wire_off);    /** @@ -927,7 +923,6 @@ struct TALER_AUDITORDB_Plugin     * @param[out] pp where is the auditor in processing     * @param[out] in_wire_off how far are we in the incoming wire transaction history     * @param[out] out_wire_off how far are we in the outgoing wire transaction history -   * @param[out] wire_off_size how many bytes do @a in_wire_off and @a out_wire_off take?     * @return transaction status code     */    enum GNUNET_DB_QueryStatus @@ -939,9 +934,8 @@ struct TALER_AUDITORDB_Plugin                                         struct                                         TALER_AUDITORDB_WireAccountProgressPoint                                         *pp, -                                       void **in_wire_off, -                                       void **out_wire_off, -                                       size_t *wire_off_size); +                                       uint64_t *in_wire_off, +                                       uint64_t *out_wire_off);    /** diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h index a7246ad2..a2eec49a 100644 --- a/src/include/taler_bank_service.h +++ b/src/include/taler_bank_service.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2015, 2016, 2017 Taler Systems SA +  Copyright (C) 2015-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU Affero General Public License as published by the Free Software @@ -25,6 +25,7 @@  #include <jansson.h>  #include <gnunet/gnunet_curl_lib.h>  #include "taler_util.h" +#include "taler_wire_lib.h"  #include "taler_error_codes.h" @@ -122,13 +123,11 @@ typedef void   * to the operators of the bank.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param account_base_url URL of the account (used to execute this request)   * @param auth authentication data to use - * @param exchange_base_url base URL of the exchange (for tracking) - * @param subject wire transfer subject for the transfer + * @param reserve_pub wire transfer subject for the transfer   * @param amount amount that was deposited - * @param debit_account_no account number to withdraw from (53 bits at most) - * @param credit_account_no account number to deposit into (53 bits at most) + * @param credit_account account to deposit into   * @param res_cb the callback to call when the final result for this request is available   * @param res_cb_cls closure for the above callback   * @return NULL @@ -137,13 +136,12 @@ typedef void   */  struct TALER_BANK_AdminAddIncomingHandle *  TALER_BANK_admin_add_incoming (struct GNUNET_CURL_Context *ctx, -                               const char *bank_base_url, +                               const char *account_base_url,                                 const struct TALER_BANK_AuthenticationData *auth, -                               const char *exchange_base_url, -                               const char *subject, +                               const struct +                               TALER_ReservePublicKeyP *reserve_pub,                                 const struct TALER_Amount *amount, -                               uint64_t debit_account_no, -                               uint64_t credit_account_no, +                               const char *credit_account,                                 TALER_BANK_AdminAddIncomingResultCallback res_cb,                                 void *res_cb_cls); @@ -159,53 +157,103 @@ TALER_BANK_admin_add_incoming_cancel (struct                                        TALER_BANK_AdminAddIncomingHandle *aai); +/* ********************* /taler/transfer *********************** */ +  /** - * Which types of transactions should be (or is being) returned? + * Prepare for exeuction of a wire transfer. + * + * @param destination_account_url payto:// URL identifying where to send the money + * @param amount amount to transfer, already rounded + * @param exchange_base_url base URL of this exchange (included in subject + *        to facilitate use of tracking API by merchant backend) + * @param wtid wire transfer identifier to use + * @param buf[out] set to transaction data to persist, NULL on error + * @param buf_size[out] set to number of bytes in @a buf, 0 on error   */ -enum TALER_BANK_Direction -{ +void +TALER_BANK_prepare_wire_transfer (const char *destination_account_url, +                                  const struct TALER_Amount *amount, +                                  const char *exchange_base_url, +                                  const struct +                                  TALER_WireTransferIdentifierRawP *wtid, +                                  void **buf, +                                  size_t *buf_size); -  /** -   * Base case, used to indicate errors or end of list. -   */ -  TALER_BANK_DIRECTION_NONE = 0, -  /** -   * Transactions where the bank account receives money. -   */ -  TALER_BANK_DIRECTION_CREDIT = 1, +/** + * Handle for active wire transfer. + */ +struct TALER_BANK_WireExecuteHandle; -  /** -   * Transactions where the bank account looses money. -   */ -  TALER_BANK_DIRECTION_DEBIT = 2, -  /** -   * Return both types of transactions. -   */ -  TALER_BANK_DIRECTION_BOTH = (TALER_BANK_DIRECTION_CREDIT -                               | TALER_BANK_DIRECTION_DEBIT), +/** + * Function called with the result from the execute step. + * + * @param cls closure + * @param response_code HTTP status code + * @param ec taler error code + * @param row_id unique ID of the wire transfer in the bank's records + * @param timestamp when did the transaction go into effect + */ +typedef void +(*TALER_BANK_ConfirmationCallback)(void *cls, +                                   unsigned int response_code, +                                   enum TALER_ErrorCode ec, +                                   uint64_t row_id, +                                   struct GNUNET_TIME_Absolute timestamp); -  /** -   * Bit mask that is applied to view transactions that have been -   * cancelled. The bit is set for cancelled transactions that are -   * returned from /history, and must also be set in order for -   * cancelled transactions to show up in the /history. -   */ -  TALER_BANK_DIRECTION_CANCEL = 4 -}; +/** + + * Execute a wire transfer. + * + * @param ctx context for HTTP interaction + * @param bank_base_url URL of the base INCLUDING account number + * @param buf buffer with the prepared execution details + * @param buf_size number of bytes in @a buf + * @param cc function to call upon success + * @param cc_cls closure for @a cc + * @return NULL on error + */ +struct TALER_BANK_WireExecuteHandle * +TALER_BANK_execute_wire_transfer (struct GNUNET_CURL_Context *ctx, +                                  const char *bank_base_url, +                                  const struct +                                  TALER_BANK_AuthenticationData *auth, +                                  const void *buf, +                                  size_t buf_size, +                                  TALER_BANK_ConfirmationCallback cc, +                                  void *cc_cls);  /** - * Handle for querying the bank's transaction history. + * Abort execution of a wire transfer. For example, because we are + * shutting down.  Note that if an execution is aborted, it may or + * may not still succeed. The caller MUST run @e + * execute_wire_transfer again for the same request as soon as + * possilbe, to ensure that the request either ultimately succeeds + * or ultimately fails. Until this has been done, the transaction is + * in limbo (i.e. may or may not have been committed). + * + * @param eh execution to cancel   */ -struct TALER_BANK_HistoryHandle; +void +TALER_BANK_execute_wire_transfer_cancel (struct +                                         TALER_BANK_WireExecuteHandle *eh); + + +/* ********************* /taler/credits *********************** */  /** - * Details about a wire transfer. + * Handle for querying the bank for transactions + * made to the exchange.   */ -struct TALER_BANK_TransferDetails +struct TALER_BANK_CreditHistoryHandle; + +/** + * Details about a wire transfer to the exchange. + */ +struct TALER_BANK_CreditDetails  {    /**     * Amount that was transferred @@ -218,21 +266,22 @@ struct TALER_BANK_TransferDetails    struct GNUNET_TIME_Absolute execution_date;    /** -   * Wire transfer subject.  Usually a reserve public key -   * followed by the base URL of the exchange. +   * Reserve public key encoded in the wire +   * transfer subject.     */ -  char *wire_transfer_subject; +  struct TALER_ReservePublicKeyP reserve_pub;    /** -   * payto://-URL of the other account that was involved +   * payto://-URL of the source account that +   * send the funds.     */ -  char *account_url; +  const char *account_url;  };  /**   * Callbacks of this type are used to serve the result of asking - * the bank for the transaction history. + * the bank for the credit transaction history.   *   * @param cls closure   * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request @@ -241,31 +290,27 @@ struct TALER_BANK_TransferDetails   *                    last callback is always of this status (even if `abs(num_results)` were   *                    already returned).   * @param ec detailed error code - * @param dir direction of the transfer   * @param serial_id monotonically increasing counter corresponding to the transaction   * @param details details about the wire transfer   * @param json detailed response from the HTTPD, or NULL if reply was not in JSON + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */ -typedef void -(*TALER_BANK_HistoryResultCallback) (void *cls, -                                     unsigned int http_status, -                                     enum TALER_ErrorCode ec, -                                     enum TALER_BANK_Direction dir, -                                     uint64_t serial_id, -                                     const struct -                                     TALER_BANK_TransferDetails *details, -                                     const json_t *json); +typedef int +(*TALER_BANK_CreditResultCallback) (void *cls, +                                    unsigned int http_status, +                                    enum TALER_ErrorCode ec, +                                    uint64_t serial_id, +                                    const struct +                                    TALER_BANK_CreditDetails *details, +                                    const json_t *json);  /** - * Request the wire transfer history of a bank account. + * Request the wire credit history of an exchange's bank account.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param account_base_url URL of the base INCLUDING account number   * @param auth authentication data to use - * @param account_number which account number should we query - * @param direction what kinds of wire transfers should be returned - * @param ascending if GNUNET_YES, history elements will be returned in chronological order.   * @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive   * @param num_results how many results do we want; negative numbers to go into the past,   *                    positive numbers to go into the future starting at @a start_row; @@ -276,17 +321,14 @@ typedef void   *         if the inputs are invalid (i.e. zero value for @e num_results).   *         In this case, the callback is not called.   */ -struct TALER_BANK_HistoryHandle * -TALER_BANK_history (struct GNUNET_CURL_Context *ctx, -                    const char *bank_base_url, -                    const struct TALER_BANK_AuthenticationData *auth, -                    uint64_t account_number, -                    enum TALER_BANK_Direction direction, -                    unsigned int ascending, -                    uint64_t start_row, -                    int64_t num_results, -                    TALER_BANK_HistoryResultCallback hres_cb, -                    void *hres_cb_cls); +struct TALER_BANK_CreditHistoryHandle * +TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx, +                           const char *account_base_url, +                           const struct TALER_BANK_AuthenticationData *auth, +                           uint64_t start_row, +                           int64_t num_results, +                           TALER_BANK_CreditResultCallback hres_cb, +                           void *hres_cb_cls);  /** @@ -297,64 +339,127 @@ TALER_BANK_history (struct GNUNET_CURL_Context *ctx,   * @param hh the history request handle   */  void -TALER_BANK_history_cancel (struct TALER_BANK_HistoryHandle *hh); +TALER_BANK_credit_history_cancel (struct TALER_BANK_CreditHistoryHandle *hh); + +/* ********************* /taler/debits *********************** */  /** - * Handle for #TALER_BANK_reject() operation. + * Handle for querying the bank for transactions + * made from the exchange to merchants.   */ -struct TALER_BANK_RejectHandle; +struct TALER_BANK_DebitHistoryHandle; + +/** + * Details about a wire transfer made by the exchange + * to a merchant. + */ +struct TALER_BANK_DebitDetails +{ +  /** +   * Amount that was transferred +   */ +  struct TALER_Amount amount; + +  /** +   * Time of the the transfer +   */ +  struct GNUNET_TIME_Absolute execution_date; + +  /** +   * Wire transfer identifier used by the exchange. +   */ +  struct TALER_WireTransferIdentifierRawP wtid; + +  /** +   * Exchange's base URL as given in the wire transfer. +   */ +  const char *exchange_base_url; + +  /** +   * payto://-URL of the source account that +   * send the funds. +   */ +  const char *account_url; +};  /**   * Callbacks of this type are used to serve the result of asking - * the bank to reject an incoming wire transfer. + * the bank for the debit transaction history.   *   * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request; - *                    #MHD_HTTP_NOT_FOUND if the rowid is unknown; + * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request   *                    0 if the bank's reply is bogus (fails to follow the protocol), + *                    #MHD_HTTP_NO_CONTENT if there are no more results; on success the + *                    last callback is always of this status (even if `abs(num_results)` were + *                    already returned).   * @param ec detailed error code + * @param serial_id monotonically increasing counter corresponding to the transaction + * @param details details about the wire transfer + * @param json detailed response from the HTTPD, or NULL if reply was not in JSON + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */ -typedef void -(*TALER_BANK_RejectResultCallback) (void *cls, -                                    unsigned int http_status, -                                    enum TALER_ErrorCode ec); +typedef int +(*TALER_BANK_DebitResultCallback) (void *cls, +                                   unsigned int http_status, +                                   enum TALER_ErrorCode ec, +                                   uint64_t serial_id, +                                   const struct +                                   TALER_BANK_DebitDetails *details, +                                   const json_t *json);  /** - * Request rejection of a wire transfer, marking it as cancelled and voiding - * its effects. + * Request the wire credit history of an exchange's bank account.   *   * @param ctx curl context for the event loop - * @param bank_base_url URL of the bank (used to execute this request) + * @param bank_base_url URL of the base INCLUDING account number   * @param auth authentication data to use   * @param account_number which account number should we query - * @param rowid transfer to reject - * @param rcb the callback to call with the operation result - * @param rcb_cls closure for @a rcb + * @param start_row from which row on do we want to get results, use UINT64_MAX for the latest; exclusive + * @param num_results how many results do we want; negative numbers to go into the past, + *                    positive numbers to go into the future starting at @a start_row; + *                    must not be zero. + * @param hres_cb the callback to call with the transaction history + * @param hres_cb_cls closure for the above callback   * @return NULL - *         if the inputs are invalid. + *         if the inputs are invalid (i.e. zero value for @e num_results).   *         In this case, the callback is not called.   */ -struct TALER_BANK_RejectHandle * -TALER_BANK_reject (struct GNUNET_CURL_Context *ctx, -                   const char *bank_base_url, -                   const struct TALER_BANK_AuthenticationData *auth, -                   uint64_t account_number, -                   uint64_t rowid, -                   TALER_BANK_RejectResultCallback rcb, -                   void *rcb_cls); +struct TALER_BANK_DebitHistoryHandle * +TALER_BANK_debit_history (struct GNUNET_CURL_Context *ctx, +                          const char *bank_base_url, +                          const struct TALER_BANK_AuthenticationData *auth, +                          uint64_t start_row, +                          int64_t num_results, +                          TALER_BANK_DebitResultCallback hres_cb, +                          void *hres_cb_cls);  /** - * Cancel an reject request.  This function cannot be used on a request - * handle if the response was is already served for it. + * Cancel an history request.  This function cannot be used on a request + * handle if the last response (anything with a status code other than + * 200) is already served for it.   * - * @param rh the reject request handle + * @param hh the history request handle   */  void -TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh); +TALER_BANK_debit_history_cancel (struct TALER_BANK_DebitHistoryHandle *hh); + + +/** + * Convenience method for parsing configuration section with bank account data. + * + * @param cfg configuration to parse + * @param section the section with the configuration data + * @param acc[out] set to the account details + * @return #GNUNET_OK on success + */ +int +TALER_BANK_account_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, +                              const char *section, +                              struct TALER_Account *acc);  /** diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h index e6364062..1681c45a 100644 --- a/src/include/taler_exchangedb_lib.h +++ b/src/include/taler_exchangedb_lib.h @@ -425,12 +425,12 @@ TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg,  /**   * Convert @a af to @a wf.   * - * @param wireplugin name of the wire plugin the fees are for + * @param wiremethod name of the wire method the fees are for   * @param[in,out] af aggregate fees, host format (updated to round time)   * @param[out] wf aggregate fees, disk / signature format   */  void -TALER_EXCHANGEDB_fees_2_wf (const char *wireplugin, +TALER_EXCHANGEDB_fees_2_wf (const char *wiremethod,                              struct TALER_EXCHANGEDB_AggregateFees *af,                              struct TALER_MasterWireFeePS *wf); @@ -470,10 +470,9 @@ struct TALER_EXCHANGEDB_AccountInfo    const char *section_name;    /** -   * Name of the wire plugin that should be used to access -   * the account. +   * Name of the wire method used by this account.     */ -  const char *plugin_name; +  const char *method;    /**     * payto://-URL of the account. diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 0dcf4b84..09e3b180 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -960,8 +960,7 @@ typedef int   * @param reserve_pub public key of the reserve (also the WTID)   * @param credit amount that was received   * @param sender_account_details information about the sender's bank account, in payto://-format - * @param wire_reference unique identifier for the wire transfer (plugin-specific format) - * @param wire_reference_size number of bytes in @a wire_reference + * @param wire_reference unique identifier for the wire transfer   * @param execution_date when did we receive the funds   * @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop   */ @@ -972,8 +971,7 @@ typedef int                                        TALER_ReservePublicKeyP *reserve_pub,                                        const struct TALER_Amount *credit,                                        const char *sender_account_details, -                                      const void *wire_reference, -                                      size_t wire_reference_size, +                                      uint64_t wire_reference,                                        struct GNUNET_TIME_Absolute                                        execution_date); @@ -1500,8 +1498,7 @@ struct TALER_EXCHANGEDB_Plugin     * @param balance the amount that has to be added to the reserve     * @param execution_time when was the amount added     * @param sender_account_details information about the sender's bank account, in payto://-format -   * @param wire_reference unique reference identifying the wire transfer (binary blob) -   * @param wire_reference_size number of bytes in @a wire_reference +   * @param wire_reference unique reference identifying the wire transfer     * @return transaction status code     */    enum GNUNET_DB_QueryStatus @@ -1512,8 +1509,7 @@ struct TALER_EXCHANGEDB_Plugin                          struct GNUNET_TIME_Absolute execution_time,                          const char *sender_account_details,                          const char *exchange_account_name, -                        const void *wire_reference, -                        size_t wire_reference_size); +                        uint64_t wire_reference);    /** @@ -1521,16 +1517,14 @@ struct TALER_EXCHANGEDB_Plugin     *     * @param cls the @e cls of this struct with the plugin-specific state     * @param db the database connection handle -   * @param[out] wire_reference set to unique reference identifying the wire transfer (binary blob) -   * @param[out] wire_reference_size set to number of bytes in @a wire_reference +   * @param[out] wire_ref set to unique reference identifying the wire transfer     * @return transaction status code     */    enum GNUNET_DB_QueryStatus    (*get_latest_reserve_in_reference)(void *cls,                                       struct TALER_EXCHANGEDB_Session *db,                                       const char *exchange_account_name, -                                     void **wire_reference, -                                     size_t *wire_reference_size); +                                     uint64_t *wire_ref);    /** diff --git a/src/include/taler_fakebank_lib.h b/src/include/taler_fakebank_lib.h index f3f92534..474c6627 100644 --- a/src/include/taler_fakebank_lib.h +++ b/src/include/taler_fakebank_lib.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2016 Inria and GNUnet e.V. +  (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -74,8 +74,8 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h);   */  uint64_t  TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h, -                              uint64_t debit_account, -                              uint64_t credit_account, +                              const char *debit_account, +                              const char *credit_account,                                const struct TALER_Amount *amount,                                const char *subject,                                const char *exchange_base_url); @@ -101,28 +101,13 @@ TALER_FAKEBANK_make_transfer (struct TALER_FAKEBANK_Handle *h,  int  TALER_FAKEBANK_check (struct TALER_FAKEBANK_Handle *h,                        const struct TALER_Amount *want_amount, -                      uint64_t want_debit, -                      uint64_t want_credit, +                      const char *want_debit, +                      const char *want_credit,                        const char *exchange_base_url,                        char **subject);  /** - * Reject incoming wire transfer to account @a credit_account - * as identified by @a rowid. - * - * @param h fake bank handle - * @param rowid identifies transfer to reject - * @param credit_account account number of owner of credited account - * @return #GNUNET_YES on success, #GNUNET_NO if the wire transfer was not found - */ -int -TALER_FAKEBANK_reject_transfer (struct TALER_FAKEBANK_Handle *h, -                                uint64_t rowid, -                                uint64_t credit_account); - - -/**   * Stop running the fake bank.   *   * @param h bank to stop diff --git a/src/include/taler_mhd_lib.h b/src/include/taler_mhd_lib.h index 6aefbd77..c836e446 100644 --- a/src/include/taler_mhd_lib.h +++ b/src/include/taler_mhd_lib.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014 GNUnet e.V. +  Copyright (C) 2014-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU Affero General Public License as published by the Free Software diff --git a/src/include/taler_testing_bank_lib.h b/src/include/taler_testing_bank_lib.h index 350aca3b..43d12d33 100644 --- a/src/include/taler_testing_bank_lib.h +++ b/src/include/taler_testing_bank_lib.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  (C) 2018 Taler Systems SA +  (C) 2018-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as @@ -103,46 +103,42 @@ TALER_TESTING_has_in_name (const char *prog,  /* ************** Specific interpreter commands ************ */  /** - * Make a "history" CMD. + * Make a credit "history" CMD.   *   * @param label command label. - * @param bank_url base URL of the bank offering the "history" + * @param account_url base URL of the account offering the "history"   *        operation. - * @param account_no bank account number to ask the history for. - * @param direction which direction this operation is interested - * @param ascending if #GNUNET_YES, it ask the bank to return results - *        in chronological order.   * @param start_row_reference reference to a command that can   *        offer a row identifier, to be used as the starting row   *        to accept in the result. - * @param num_results how many rows we want in the result. + * @param num_results how many rows we want in the result, + *        and ascending/descending call   * @return the command.   */  struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_history (const char *label, -                                const char *bank_url, -                                uint64_t account_no, -                                enum TALER_BANK_Direction direction, -                                unsigned int ascending, +TALER_TESTING_cmd_bank_credits (const char *label, +                                const char *account_url,                                  const char *start_row_reference, -                                unsigned long long num_results); +                                long long num_results);  /** - * Create a "reject" CMD. + * Make a debit "history" CMD.   *   * @param label command label. - * @param bank_url base URL of the bank implementing the - *        "reject" operation. - * @param deposit_reference reference to a command that will - *        provide a "row id" and credit (bank) account to craft - *        the "reject" request. - * + * @param account_url base URL of the account offering the "history" + *        operation. + * @param start_row_reference reference to a command that can + *        offer a row identifier, to be used as the starting row + *        to accept in the result. + * @param num_results how many rows we want in the result.   * @return the command.   */  struct TALER_TESTING_Command -TALER_TESTING_cmd_bank_reject (const char *label, -                               const char *bank_url, -                               const char *deposit_reference); +TALER_TESTING_cmd_bank_debits (const char *label, +                               const char *account_url, +                               const char *start_row_reference, +                               long long num_results); +  #endif diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index a039f0ec..33f07070 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -48,23 +48,24 @@    } while (0) +#define TALER_TESTING_GET_TRAIT_ROW_ID(cmd,out) \ +  TALER_TESTING_get_trait_uint64 (cmd, 3, out) + +#define TALER_TESTING_MAKE_TRAIT_ROW_ID(data) \ +  TALER_TESTING_make_trait_uint64 (3, data) + +  #define TALER_TESTING_GET_TRAIT_CREDIT_ACCOUNT(cmd,out) \ -  TALER_TESTING_get_trait_uint64 (cmd, 0, out) +  TALER_TESTING_get_trait_string (cmd, 4, out)  #define TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT(data) \ -  TALER_TESTING_make_trait_uint64 (0, data) +  TALER_TESTING_make_trait_string (4, data)  #define TALER_TESTING_GET_TRAIT_DEBIT_ACCOUNT(cmd,out) \ -  TALER_TESTING_get_trait_uint64 (cmd, 1, out) +  TALER_TESTING_get_trait_string (cmd, 5, out)  #define TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT(data) \ -  TALER_TESTING_make_trait_uint64 (1, data) - -#define TALER_TESTING_GET_TRAIT_ROW_ID(cmd,out) \ -  TALER_TESTING_get_trait_uint64 (cmd, 3, out) - -#define TALER_TESTING_MAKE_TRAIT_ROW_ID(data) \ -  TALER_TESTING_make_trait_uint64 (3, data) +  TALER_TESTING_make_trait_string (5, data)  /** @@ -715,13 +716,9 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,   *   * @param label command label.   * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - *        wire transer.  For simplicity, both credit and debit - *        bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. + * @param account_base_url base URL of the account that implements this + *        wire transer (which account gives money). + * @param payto_credit_account which account receives money.   * @param auth_username username identifying the @a   *        debit_account_no at the bank.   * @param auth_password password for @a auth_username. @@ -734,51 +731,14 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,  struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer (const char *label,                                       const char *amount, -                                     const char *bank_url, -                                     uint64_t debit_account_no, -                                     uint64_t credit_account_no, +                                     const char *account_base_url, +                                     const char *payto_credit_account,                                       const char *auth_username,                                       const char *auth_password,                                       const char *exchange_url);  /** - * Create "fakebank transfer" CMD, letting the caller specifying - * the subject line. - * - * @param label command label. - * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - *        wire transer.  For simplicity, both credit and debit - *        bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. - * - * @param auth_username username identifying the @a - *        debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param subject wire transfer's subject line. - * @param exchange_url which exchange is involved in this transfer. - *        This data is used for tracking purposes (FIXME: explain - *        _how_). - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label, -                                                  const char *amount, -                                                  const char *bank_url, -                                                  uint64_t debit_account_no, -                                                  uint64_t credit_account_no, -                                                  const char *auth_username, -                                                  const char *auth_password, -                                                  const char *subject, -                                                  const char *exchange_url); - - -/**   * Create "fakebank transfer" CMD, letting the caller specify   * a reference to a command that can offer a reserve private key.   * This private key will then be used to construct the subject line @@ -786,11 +746,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,   *   * @param label command label.   * @param amount the amount to transfer. - * @param bank_url base URL of the bank running the transfer. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. + * @param account_base_url base URL of the account that implements this + *        wire transer (which account gives money). + * @param payto_credit_account which account receives money.   * @param auth_username username identifying the @a   *        debit_account_no at the bank.   * @param auth_password password for @a auth_username. @@ -804,9 +762,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_subject (const char *label,  struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,                                                const char *amount, -                                              const char *bank_url, -                                              uint64_t debit_account_no, -                                              uint64_t credit_account_no, +                                              const char *account_base_url, +                                              const char *payto_credit_account, +                                                const char *auth_username,                                                const char *auth_password,                                                const char *ref, @@ -822,14 +780,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,   *   * @param label command label.   * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - *        wire transer.  For simplicity, both credit and debit - *        bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. - * + * @param account_base_url base URL of the account that implements this + *        wire transer (which account gives money). + * @param payto_credit_account which account receives money.   * @param auth_username username identifying the @a   *        debit_account_no at the bank.   * @param auth_password password for @a auth_username. @@ -847,9 +800,9 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref (const char *label,  struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer_with_instance (const char *label,                                                     const char *amount, -                                                   const char *bank_url, -                                                   uint64_t debit_account_no, -                                                   uint64_t credit_account_no, +                                                   const char *account_base_url, +                                                   const char * +                                                   payto_credit_account,                                                     const char *auth_username,                                                     const char *auth_password,                                                     const char *instance, @@ -1268,8 +1221,8 @@ struct TALER_TESTING_Command  TALER_TESTING_cmd_check_bank_transfer (const char *label,                                         const char *exchange_base_url,                                         const char *amount, -                                       uint64_t debit_account, -                                       uint64_t credit_account); +                                       const char *debit_account, +                                       const char *credit_account);  /** @@ -1617,7 +1570,6 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,   *   * @return the trait.   */ -  struct TALER_TESTING_Trait  TALER_TESTING_make_trait_reserve_priv (unsigned int index,                                         const struct @@ -1641,6 +1593,34 @@ TALER_TESTING_get_trait_reserve_priv (const struct TALER_TESTING_Command *cmd,  /** + * Offer a reserve public key. + * + * @param index reserve pubs's index number. + * @param reserve_priv reserve public key to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_reserve_pub (unsigned int index, +                                      const struct +                                      TALER_ReservePublicKeyP *reserve_pub); + + +/** + * Obtain a reserve public key from a @a cmd. + * + * @param cmd command to extract the reserve pub from. + * @param index reserve pub's index number. + * @param reserve_pub[out] set to the reserve pub. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_reserve_pub (const struct TALER_TESTING_Command *cmd, +                                     unsigned int index, +                                     const struct +                                     TALER_ReservePublicKeyP **reserve_pub); + + +/**   * Make a trait for a exchange signature.   *   * @param index index number to associate to the offered exchange pub. @@ -2129,34 +2109,34 @@ TALER_TESTING_make_trait_peer_key_pub (unsigned int index,  /** - * Obtain a transfer subject from @a cmd. + * Obtain a string from @a cmd.   *   * @param cmd command to extract the subject from.   * @param index index number associated with the transfer   *        subject to offer. - * @param transfer_subject[out] where to write the offered - *        transfer subject. + * @param s[out] where to write the offered + *        string.   *   * @return #GNUNET_OK on success.   */  int -TALER_TESTING_get_trait_transfer_subject (const struct -                                          TALER_TESTING_Command *cmd, -                                          unsigned int index, -                                          const char **transfer_subject); +TALER_TESTING_get_trait_string (const struct +                                TALER_TESTING_Command *cmd, +                                unsigned int index, +                                const char **s);  /** - * Offer transfer subject. + * Offer string subject.   *   * @param index index number associated with the transfer   *        subject being offered. - * @param transfer_subject transfer subject to offer. + * @param s string to offer.   * @return the trait.   */  struct TALER_TESTING_Trait -TALER_TESTING_make_trait_transfer_subject (unsigned int index, -                                           const char *transfer_subject); +TALER_TESTING_make_trait_string (unsigned int index, +                                 const char *s);  /** @@ -2223,7 +2203,6 @@ TALER_TESTING_get_trait_amount (const struct TALER_TESTING_Command *cmd,   * @param index which url is to be picked,   *        in case multiple are offered.   * @param url the url to offer. - *   * @return the trait.   */  struct TALER_TESTING_Trait diff --git a/src/include/taler_wire_lib.h b/src/include/taler_wire_lib.h index 3c851091..c7d9f78d 100644 --- a/src/include/taler_wire_lib.h +++ b/src/include/taler_wire_lib.h @@ -22,7 +22,7 @@  #define TALER_WIRE_H  #include <gnunet/gnunet_util_lib.h> -#include "taler_wire_plugin.h" +  /**   * Different account types supported by payto://. @@ -46,6 +46,7 @@ enum TALER_PaytoAccountType    TALER_PAC_IBAN  }; +  /**   * Information about an account extracted from a payto://-URL.   */ @@ -71,19 +72,15 @@ struct TALER_Account      {        /** -       * Hostname of the bank (possibly including port). +       * Bank account base URL.         */ -      char *hostname; +      char *account_base_url;        /** -       * Bank account number. +       * Only the hostname of the bank.         */ -      unsigned long long no; +      char *hostname; -      /** -       * Base URL of the bank hosting the account above. -       */ -      char *bank_base_url;      } x_taler_bank;      /** @@ -114,6 +111,18 @@ TALER_WIRE_account_free (struct TALER_Account *acc);  /** + * Round the amount to something that can be + * transferred on the wire. + * + * @param[in,out] amount amount to round down + * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, + *         #GNUNET_SYSERR if the amount or currency was invalid + */ +int +TALER_WIRE_amount_round (struct TALER_Amount *amount); + + +/**   * Parse @a payto_url and store the result in @a acc   *   * @param payto_url URL to parse @@ -135,36 +144,4 @@ char *  TALER_WIRE_payto_get_method (const char *payto_url); -/** - * Get the plugin name from the payment method. - * - * @param method the method implemented by the plugin (for - *  simplicity, we assume 1 method is implemented by 1 plugin). - * @return the plugin name, NULL if not found. - */ -const char * -TALER_WIRE_get_plugin_from_method (const char *method); - - -/** - * Load a WIRE plugin. - * - * @param cfg configuration to use - * @param plugin_name name of the plugin to load - * @return #GNUNET_OK on success - */ -struct TALER_WIRE_Plugin * -TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg, -                        const char *plugin_name); - - -/** - * Unload a WIRE plugin. - * - * @param plugin the plugin to unload - */ -void -TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin); - -  #endif diff --git a/src/include/taler_wire_plugin.h b/src/include/taler_wire_plugin.h index ffc7adf5..b5621e68 100644 --- a/src/include/taler_wire_plugin.h +++ b/src/include/taler_wire_plugin.h @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2016, 2017 GNUnet e.V. & Inria +  Copyright (C) 2016-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it under the    terms of the GNU General Public License as published by the Free Software @@ -41,22 +41,9 @@ typedef void  /** - * Callback to process a merchant registration outcome. - * - * @param cls closure - * @param status GNUNET_OK if the registration succeeded, - *        GNUNET_NO otherwise. - */ -typedef void -(*TALER_WIRE_MerchantRegisterCallback) (void *cls, -                                        unsigned int status); - -/**   * Details about a valid wire transfer to the exchange. - * It is the plugin's responsibility to filter and undo - * invalid transfers.   */ -struct TALER_WIRE_TransferDetails +struct TALER_WIRE_CreditDetails  {    /**     * Amount that was transferred @@ -69,22 +56,44 @@ struct TALER_WIRE_TransferDetails    struct GNUNET_TIME_Absolute execution_date;    /** -   * Binary data that was encoded in the wire transfer subject, if -   * it decoded properly.  Otherwise all-zeros and @e wtid_s is set. +   * Binary data that was encoded in the wire transfer subject.     */ -  struct TALER_WireTransferIdentifierRawP wtid; +  struct TALER_ReservePublicKeyP reserve_pub; + +  /** +   * payto://-URL of the source's account (used +   * when the reserve is closed or for debugging). +   */ +  const char *source_account_url; +}; + + +/** + * Details about a valid wire transfer made by the + * exchange's aggregator to a merchant. + */ +struct TALER_WIRE_DebitDetails +{ +  /** +   * Amount that was transferred +   */ +  struct TALER_Amount amount;    /** -   * Wire transfer identifer as a string.  Set to NULL if the -   * identifier was properly Base32 encoded and this @e wtid could be -   * set instead. +   * Time of the the transfer +   */ +  struct GNUNET_TIME_Absolute execution_date; + +  /** +   * Binary data that was encoded in the wire transfer subject.     */ -  char *wtid_s; +  struct TALER_WireTransferIdentifierRawP wtid;    /** -   * payto://-URL of the other account that was involved +   * payto://-URL of the target account which received +   * the funds.     */ -  char *account_url; +  const char *target_account_url;  }; @@ -96,33 +105,40 @@ struct TALER_WIRE_TransferDetails   *   * @param cls closure   * @param ec taler error code - * @param dir direction of the transfer, #TALER_BANK_DIRECTION_NONE when - *            the iteration is complete   * @param row_off identification of the position at which we are querying   * @param row_off_size number of bytes in @a row_off   * @param details details about the wire transfer   * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */  typedef int -(*TALER_WIRE_HistoryResultCallback) (void *cls, -                                     enum TALER_ErrorCode ec, -                                     enum TALER_BANK_Direction dir, -                                     const void *row_off, -                                     size_t row_off_size, -                                     const struct -                                     TALER_WIRE_TransferDetails *details); +(*TALER_WIRE_CreditResultCallback) (void *cls, +                                    enum TALER_ErrorCode ec, +                                    const void *row_off, +                                    size_t row_off_size, +                                    const struct +                                    TALER_WIRE_CreditDetails *details);  /**   * Callbacks of this type are used to serve the result of asking - * the bank to reject a wire transfer. + * the bank for the transaction history.  NOTE: this function will + * NOT get the list of history elements, but rather get (iteratively) + * called for each (parsed) history element.   *   * @param cls closure - * @param ec status of the operation, #TALER_EC_NONE on success + * @param ec taler error code + * @param row_off identification of the position at which we are querying + * @param row_off_size number of bytes in @a row_off + * @param details details about the wire transfer + * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration   */ -typedef void -(*TALER_WIRE_RejectTransferCallback) (void *cls, -                                      enum TALER_ErrorCode ec); +typedef int +(*TALER_WIRE_DebitResultCallback) (void *cls, +                                   enum TALER_ErrorCode ec, +                                   const void *row_off, +                                   size_t row_off_size, +                                   const struct +                                   TALER_WIRE_DebitDetails *details);  /** @@ -136,9 +152,14 @@ struct TALER_WIRE_PrepareHandle;  struct TALER_WIRE_ExecuteHandle;  /** - * Handle returned for querying the transaction history. + * Handle returned for querying the credit transaction history.   */ -struct TALER_WIRE_HistoryHandle; +struct TALER_WIRE_CreditHistoryHandle; + +/** + * Handle returned for querying the debit transaction history. + */ +struct TALER_WIRE_DebitHistoryHandle;  /** @@ -146,7 +167,8 @@ struct TALER_WIRE_HistoryHandle;   *   * @param cls closure   * @param success #GNUNET_OK on success, #GNUNET_SYSERR on failure - * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error + * @param row_id unique ID of the wire transfer in the bank's records; NULL on error + * @param row_id_size number of bytes in @e row_id   * @param emsg NULL on success, otherwise an error message   */  typedef void @@ -156,6 +178,7 @@ typedef void                                     size_t row_id_size,                                     const char *emsg); +  /**   * @brief The plugin API, returned from the plugin's "init" function.   * The argument given to "init" is simply a configuration handle. @@ -176,11 +199,10 @@ struct TALER_WIRE_Plugin    /**     * Which wire method (payto://METHOD/") is supported by this plugin? -   * For example, "iban" or "x-taler-bank". +   * For example, "x-taler-bank" or "iban".     */    const char *method; -    /**     * Round amount DOWN to the amount that can be transferred via the wire     * method.  For example, Taler may support 0.000001 EUR as a unit of @@ -210,80 +232,7 @@ struct TALER_WIRE_Plugin    /** -   * Prepare for exeuction of a wire transfer. -   * -   * @param cls the @e cls of this struct with the plugin-specific state -   * @param origin_account_section configuration section specifying the origin -   *        account of the exchange to use -   * @param destination_account_url payto:// URL identifying where to send the money -   * @param amount amount to transfer, already rounded -   * @param exchange_base_url base URL of this exchange (included in subject -   *        to facilitate use of tracking API by merchant backend) -   * @param wtid wire transfer identifier to use -   * @param ptc function to call with the prepared data to persist -   * @param ptc_cls closure for @a ptc -   * @return NULL on failure -   */ -  struct TALER_WIRE_PrepareHandle * -  (*prepare_wire_transfer) (void *cls, -                            const char *origin_account_section, -                            const char *destination_account_url, -                            const struct TALER_Amount *amount, -                            const char *exchange_base_url, -                            const struct TALER_WireTransferIdentifierRawP *wtid, -                            TALER_WIRE_PrepareTransactionCallback ptc, -                            void *ptc_cls); - - -  /** -   * Abort preparation of a wire transfer. For example, -   * because we are shutting down. -   * -   * @param cls the @e cls of this struct with the plugin-specific state -   * @param pth preparation to cancel -   */ -  void -  (*prepare_wire_transfer_cancel) (void *cls, -                                   struct TALER_WIRE_PrepareHandle *pth); - - -  /** -   * Execute a wire transfer. -   * -   * @param cls the @e cls of this struct with the plugin-specific state -   * @param buf buffer with the prepared execution details -   * @param buf_size number of bytes in @a buf -   * @param cc function to call upon success -   * @param cc_cls closure for @a cc -   * @return NULL on error -   */ -  struct TALER_WIRE_ExecuteHandle * -  (*execute_wire_transfer) (void *cls, -                            const char *buf, -                            size_t buf_size, -                            TALER_WIRE_ConfirmationCallback cc, -                            void *cc_cls); - - -  /** -   * Abort execution of a wire transfer. For example, because we are -   * shutting down.  Note that if an execution is aborted, it may or -   * may not still succeed. The caller MUST run @e -   * execute_wire_transfer again for the same request as soon as -   * possilbe, to ensure that the request either ultimately succeeds -   * or ultimately fails. Until this has been done, the transaction is -   * in limbo (i.e. may or may not have been committed). -   * -   * @param cls the @e cls of this struct with the plugin-specific state -   * @param eh execution to cancel -   */ -  void -  (*execute_wire_transfer_cancel) (void *cls, -                                   struct TALER_WIRE_ExecuteHandle *eh); - - -  /** -   * Query transfer history of an account.  We use the variable-size +   * Query credits made to exchange account.  We use the variable-size     * @a start_off to indicate which transfers we are interested in as     * different banking systems may have different ways to identify     * transfers.  The @a start_off value must thus match the value of @@ -295,7 +244,6 @@ struct TALER_WIRE_Plugin     * @param cls the @e cls of this struct with the plugin-specific state     * @param account_section specifies the configuration section which     *        identifies the account for which we should get the history -   * @param direction what kinds of wire transfers should be returned     * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive     * @param start_off_len number of bytes in @a start_off     * @param num_results how many results do we want; negative numbers to go into the past, @@ -304,70 +252,65 @@ struct TALER_WIRE_Plugin     * @param hres_cb the callback to call with the transaction history     * @param hres_cb_cls closure for the above callback     */ -  struct TALER_WIRE_HistoryHandle * -  (*get_history) (void *cls, +  struct TALER_WIRE_CreditHistoryHandle * +  (*get_credits) (void *cls,                    const char *account_section, -                  enum TALER_BANK_Direction direction,                    const void *start_off,                    size_t start_off_len,                    int64_t num_results, -                  TALER_WIRE_HistoryResultCallback hres_cb, +                  TALER_WIRE_CreditResultCallback hres_cb,                    void *hres_cb_cls);    /**     * Cancel going over the account's history.     *     * @param cls plugins' closure -   * @param whh operation to cancel +   * @param chh operation to cancel     */    void -  (*get_history_cancel) (void *cls, -                         struct TALER_WIRE_HistoryHandle *whh); +  (*get_credits_cancel) (void *cls, +                         struct TALER_WIRE_CreditHistoryHandle *chh);    /** -   * Reject an incoming wire transfer that was obtained from the -   * history. This function can be used to transfer funds back to -   * the sender if the WTID was malformed (i.e. due to a typo). -   * -   * Calling `reject_transfer` twice on the same wire transfer should -   * be idempotent, i.e. not cause the funds to be wired back twice. -   * Furthermore, the transfer should henceforth be removed from the -   * results returned by @e get_history. +   * Query debits (transfers to merchants) made by an exchange.  We use the +   * variable-size @a start_off to indicate which transfers we are interested +   * in as different banking systems may have different ways to identify +   * transfers.  The @a start_off value must thus match the value of a +   * `row_off` argument previously given to the @a hres_cb.  Use NULL to query +   * transfers from the beginning of time (with positive @a num_results) or +   * from the latest committed transfers (with negative @a num_results).     * -   * @param cls plugin's closure +   * @param cls the @e cls of this struct with the plugin-specific state     * @param account_section specifies the configuration section which -   *        identifies the account to use to reject the transfer -   * @param start_off offset of the wire transfer in plugin-specific format +   *        identifies the account for which we should get the history +   * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive     * @param start_off_len number of bytes in @a start_off -   * @param rej_cb function to call with the result of the operation -   * @param rej_cb_cls closure for @a rej_cb -   * @return handle to cancel the operation +   * @param num_results how many results do we want; negative numbers to go into the past, +   *                    positive numbers to go into the future starting at @a start_row; +   *                    must not be zero. +   * @param hres_cb the callback to call with the transaction history +   * @param hres_cb_cls closure for the above callback     */ -  struct TALER_WIRE_RejectHandle * -  (*reject_transfer)(void *cls, -                     const char *account_section, -                     const void *start_off, -                     size_t start_off_len, -                     TALER_WIRE_RejectTransferCallback rej_cb, -                     void *rej_cb_cls); - +  struct TALER_WIRE_DebitHistoryHandle * +  (*get_debits) (void *cls, +                 const char *account_section, +                 const void *start_off, +                 size_t start_off_len, +                 int64_t num_results, +                 TALER_WIRE_DebitResultCallback hres_cb, +                 void *hres_cb_cls);    /** -   * Cancel ongoing reject operation.  Note that the rejection may still -   * proceed. Basically, if this function is called, the rejection may -   * have happened or not.  This function is usually used during shutdown -   * or system upgrades.  At a later point, the application must call -   * @e reject_transfer again for this wire transfer, unless the -   * @e get_history shows that the wire transfer no longer exists. +   * Cancel going over the account's history.     *     * @param cls plugins' closure -   * @param rh operation to cancel -   * @return closure of the callback of the operation +   * @param dhh operation to cancel     */ -  void * -  (*reject_transfer_cancel)(void *cls, -                            struct TALER_WIRE_RejectHandle *rh); +  void +  (*get_debits_cancel) (void *cls, +                        struct TALER_WIRE_DebitHistoryHandle *dhh); +  }; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index de0c8935..ee8389f6 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -103,6 +103,7 @@ libtalertesting_la_SOURCES = \    testing_api_trait_exchange_sig.c \    testing_api_trait_json.c \    testing_api_trait_process.c \ +  testing_api_trait_reserve_pub.c \    testing_api_trait_reserve_priv.c \    testing_api_trait_number.c \    testing_api_trait_fresh_coin.c \ diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index abb95816..6b51519f 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -1262,7 +1262,7 @@ keys_completed_cb (void *cls,      for (unsigned int i = 0; i<kd_old.num_denom_keys; i++)        kd.denom_keys[i].key.rsa_public_key          = GNUNET_CRYPTO_rsa_public_key_dup ( -            kd_old.denom_keys[i].key.rsa_public_key); +        kd_old.denom_keys[i].key.rsa_public_key);      kd.num_auditors = kd_old.num_auditors;      kd.auditors = GNUNET_new_array (kd.num_auditors, diff --git a/src/lib/testing_api_cmd_bank_check.c b/src/lib/testing_api_cmd_bank_check.c index f51c535a..f74f7afe 100644 --- a/src/lib/testing_api_cmd_bank_check.c +++ b/src/lib/testing_api_cmd_bank_check.c @@ -52,12 +52,12 @@ struct BankCheckState    /**     * Expected debit bank account.     */ -  uint64_t debit_account; +  const char *debit_account;    /**     * Expected credit bank account.     */ -  uint64_t credit_account; +  const char *credit_account;    /**     * Wire transfer subject (set by fakebank-lib). @@ -95,18 +95,16 @@ check_bank_transfer_run (void *cls,                           struct TALER_TESTING_Interpreter *is)  {    struct BankCheckState *bcs = cls; -    struct TALER_Amount amount; -  const uint64_t *debit_account; -  const uint64_t *credit_account; +  const char *debit_account; +  const char *credit_account;    const char *exchange_base_url; -    if (NULL == bcs->deposit_reference)    {      TALER_LOG_INFO ("Deposit reference NOT given\n"); -    debit_account = &bcs->debit_account; -    credit_account = &bcs->credit_account; +    debit_account = bcs->debit_account; +    credit_account = bcs->credit_account;      exchange_base_url = bcs->exchange_base_url;      if (GNUNET_OK != @@ -154,14 +152,13 @@ check_bank_transfer_run (void *cls,      GNUNET_assert        (GNUNET_OK == TALER_TESTING_get_trait_url          (deposit_cmd, 0, &exchange_base_url)); // check 0 works! -    }    if (GNUNET_OK !=        TALER_FAKEBANK_check (is->fakebank,                              &amount, -                            *debit_account, -                            *credit_account, +                            debit_account, +                            credit_account,                              exchange_base_url,                              &bcs->subject))    { @@ -217,18 +214,18 @@ check_bank_transfer_traits (void *cls,      wtid_ptr = NULL;    else      wtid_ptr = &bcs->wtid; - -  struct TALER_TESTING_Trait traits[] = { -    TALER_TESTING_make_trait_transfer_subject (0, bcs->subject), -    TALER_TESTING_make_trait_wtid (0, wtid_ptr), -    TALER_TESTING_make_trait_url (0, bcs->exchange_base_url), -    TALER_TESTING_trait_end () -  }; - -  return TALER_TESTING_get_trait (traits, -                                  ret, -                                  trait, -                                  index); +  { +    struct TALER_TESTING_Trait traits[] = { +      TALER_TESTING_make_trait_wtid (0, wtid_ptr), +      TALER_TESTING_make_trait_url (0, bcs->exchange_base_url), +      TALER_TESTING_trait_end () +    }; + +    return TALER_TESTING_get_trait (traits, +                                    ret, +                                    trait, +                                    index); +  }  } @@ -250,8 +247,8 @@ TALER_TESTING_cmd_check_bank_transfer    (const char *label,    const char *exchange_base_url,    const char *amount, -  uint64_t debit_account, -  uint64_t credit_account) +  const char *debit_account, +  const char *credit_account)  {    struct BankCheckState *bcs; @@ -260,18 +257,18 @@ TALER_TESTING_cmd_check_bank_transfer    bcs->amount = amount;    bcs->debit_account = debit_account;    bcs->credit_account = credit_account; -    bcs->deposit_reference = NULL; - -  struct TALER_TESTING_Command cmd = { -    .label = label, -    .cls = bcs, -    .run = &check_bank_transfer_run, -    .cleanup = &check_bank_transfer_cleanup, -    .traits = &check_bank_transfer_traits -  }; - -  return cmd; +  { +    struct TALER_TESTING_Command cmd = { +      .label = label, +      .cls = bcs, +      .run = &check_bank_transfer_run, +      .cleanup = &check_bank_transfer_cleanup, +      .traits = &check_bank_transfer_traits +    }; + +    return cmd; +  }  } diff --git a/src/lib/testing_api_cmd_fakebank_transfer.c b/src/lib/testing_api_cmd_fakebank_transfer.c index 81378238..e212fd31 100644 --- a/src/lib/testing_api_cmd_fakebank_transfer.c +++ b/src/lib/testing_api_cmd_fakebank_transfer.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2018 Taler Systems SA +  Copyright (C) 2018-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify it    under the terms of the GNU General Public License as published by @@ -51,24 +51,14 @@ struct FakebankTransferState    struct TALER_Amount amount;    /** -   * Wire transfer subject. +   * Base URL of the debit account.     */ -  const char *subject; +  const char *debit_url;    /** -   * Base URL of the bank serving the request. +   * Money receiver account URL.     */ -  const char *bank_url; - -  /** -   * Money sender account number. -   */ -  uint64_t debit_account_no; - -  /** -   * Money receiver account number. -   */ -  uint64_t credit_account_no; +  const char *payto_credit_account;    /**     * Username to use for authentication. @@ -87,6 +77,11 @@ struct FakebankTransferState    struct TALER_ReservePrivateKeyP reserve_priv;    /** +   * Reserve public key matching @e reserve_priv. +   */ +  struct TALER_ReservePublicKeyP reserve_pub; + +  /**     * Handle to the pending request at the fakebank.     */    struct TALER_BANK_AdminAddIncomingHandle *aih; @@ -188,16 +183,15 @@ do_retry (void *cls)   * @param ec taler-specific error code, #TALER_EC_NONE on success   * @param serial_id unique ID of the wire transfer   * @param timestamp time stamp of the transaction made. - * @param full_response full response from the exchange (for - *        logging, in case of errors) + * @param json raw response   */  static void -add_incoming_cb (void *cls, +confirmation_cb (void *cls,                   unsigned int http_status,                   enum TALER_ErrorCode ec,                   uint64_t serial_id,                   struct GNUNET_TIME_Absolute timestamp, -                 const json_t *full_response) +                 const json_t *json)  {    struct FakebankTransferState *fts = cls;    struct TALER_TESTING_Interpreter *is = fts->is; @@ -256,130 +250,115 @@ fakebank_transfer_run (void *cls,                         struct TALER_TESTING_Interpreter *is)  {    struct FakebankTransferState *fts = cls; -  char *subject;    struct TALER_BANK_AuthenticationData auth; -  struct TALER_ReservePublicKeyP reserve_pub; -  if (NULL != fts->subject) +  /* Use reserve public key as subject */ +  if (NULL != fts->reserve_reference)    { -    subject = GNUNET_strdup (fts->subject); +    const struct TALER_TESTING_Command *ref; +    const struct TALER_ReservePrivateKeyP *reserve_priv; + +    ref = TALER_TESTING_interpreter_lookup_command +            (is, fts->reserve_reference); +    if (NULL == ref) +    { +      GNUNET_break (0); +      TALER_TESTING_interpreter_fail (is); +      return; +    } +    if (GNUNET_OK != +        TALER_TESTING_get_trait_reserve_priv (ref, +                                              0, +                                              &reserve_priv)) +    { +      GNUNET_break (0); +      TALER_TESTING_interpreter_fail (is); +      return; +    } +    fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv;    }    else    { -    /* Use reserve public key as subject */ -    if (NULL != fts->reserve_reference) +    if (NULL != fts->instance)      { -      const struct TALER_TESTING_Command *ref; -      const struct TALER_ReservePrivateKeyP *reserve_priv; +      char *section; +      char *keys; +      struct GNUNET_CRYPTO_EddsaPrivateKey *priv; +      struct GNUNET_CONFIGURATION_Handle *cfg; -      ref = TALER_TESTING_interpreter_lookup_command -              (is, fts->reserve_reference); -      if (NULL == ref) +      GNUNET_assert (NULL != fts->config_filename); +      cfg = GNUNET_CONFIGURATION_create (); +      if (GNUNET_OK != +          GNUNET_CONFIGURATION_load (cfg, +                                     fts->config_filename))        {          GNUNET_break (0);          TALER_TESTING_interpreter_fail (is);          return;        } + +      GNUNET_asprintf (§ion, +                       "instance-%s", +                       fts->instance);        if (GNUNET_OK != -          TALER_TESTING_get_trait_reserve_priv (ref, -                                                0, -                                                &reserve_priv)) +          GNUNET_CONFIGURATION_get_value_filename +            (cfg, +            section, +            "TIP_RESERVE_PRIV_FILENAME", +            &keys))        { -        GNUNET_break (0); +        GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                    "Configuration fails to specify reserve" +                    " private key filename in section %s\n", +                    section); +        GNUNET_free (section);          TALER_TESTING_interpreter_fail (is);          return;        } -      fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv; -    } -    else -    { -      if (NULL != fts->instance) +      priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); +      GNUNET_free (keys); +      if (NULL == priv)        { -        char *section; -        char *keys; -        struct GNUNET_CRYPTO_EddsaPrivateKey *priv; -        struct GNUNET_CONFIGURATION_Handle *cfg; - -        GNUNET_assert (NULL != fts->config_filename); -        cfg = GNUNET_CONFIGURATION_create (); -        if (GNUNET_OK != -            GNUNET_CONFIGURATION_load (cfg, -                                       fts->config_filename)) -        { -          GNUNET_break (0); -          TALER_TESTING_interpreter_fail (is); -          return; -        } - -        GNUNET_asprintf (§ion, -                         "instance-%s", -                         fts->instance); -        if (GNUNET_OK != -            GNUNET_CONFIGURATION_get_value_filename -              (cfg, -              section, -              "TIP_RESERVE_PRIV_FILENAME", -              &keys)) -        { -          GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                      "Configuration fails to specify reserve" -                      " private key filename in section %s\n", -                      section); -          GNUNET_free (section); -          TALER_TESTING_interpreter_fail (is); -          return; -        } -        priv = GNUNET_CRYPTO_eddsa_key_create_from_file (keys); -        GNUNET_free (keys); -        if (NULL == priv) -        { -          GNUNET_log_config_invalid -            (GNUNET_ERROR_TYPE_ERROR, -            section, -            "TIP_RESERVE_PRIV_FILENAME", -            "Failed to read private key"); -          GNUNET_free (section); -          TALER_TESTING_interpreter_fail (is); -          return; -        } -        fts->reserve_priv.eddsa_priv = *priv; +        GNUNET_log_config_invalid +          (GNUNET_ERROR_TYPE_ERROR, +          section, +          "TIP_RESERVE_PRIV_FILENAME", +          "Failed to read private key");          GNUNET_free (section); -        GNUNET_free (priv); -        GNUNET_CONFIGURATION_destroy (cfg); +        TALER_TESTING_interpreter_fail (is); +        return;        } -      else -      { -        /* No referenced reserve, no instance to take priv -         * from, no explicit subject given: create new key! */ -        struct GNUNET_CRYPTO_EddsaPrivateKey *priv; +      fts->reserve_priv.eddsa_priv = *priv; +      GNUNET_free (section); +      GNUNET_free (priv); +      GNUNET_CONFIGURATION_destroy (cfg); +    } +    else +    { +      /* No referenced reserve, no instance to take priv +       * from, no explicit subject given: create new key! */ +      struct GNUNET_CRYPTO_EddsaPrivateKey *priv; -        priv = GNUNET_CRYPTO_eddsa_key_create (); -        fts->reserve_priv.eddsa_priv = *priv; -        GNUNET_free (priv); -      } +      priv = GNUNET_CRYPTO_eddsa_key_create (); +      fts->reserve_priv.eddsa_priv = *priv; +      GNUNET_free (priv);      } -    GNUNET_CRYPTO_eddsa_key_get_public -      (&fts->reserve_priv.eddsa_priv, &reserve_pub.eddsa_pub); -    subject = GNUNET_STRINGS_data_to_string_alloc -                (&reserve_pub, sizeof (reserve_pub));    } - +  GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv, +                                      &fts->reserve_pub.eddsa_pub);    auth.method = TALER_BANK_AUTH_BASIC;    auth.details.basic.username = (char *) fts->auth_username;    auth.details.basic.password = (char *) fts->auth_password;    fts->is = is;    fts->aih = TALER_BANK_admin_add_incoming                 (TALER_TESTING_interpreter_get_context (is), -               fts->bank_url, +               fts->debit_url,                 &auth, -               fts->exchange_url, -               subject, +               &fts->reserve_pub,                 &fts->amount, -               fts->debit_account_no, -               fts->credit_account_no, -               &add_incoming_cb, +               fts->payto_credit_account, +               &confirmation_cb,                 fts); -  GNUNET_free (subject);    if (NULL == fts->aih)    {      GNUNET_break (0); @@ -408,6 +387,7 @@ fakebank_transfer_cleanup (void *cls,                  "Command %s did not complete\n",                  cmd->label);      TALER_BANK_admin_add_incoming_cancel (fts->aih); +    fts->aih = NULL;    }    if (NULL != fts->retry_task)    { @@ -435,32 +415,21 @@ fakebank_transfer_traits (void *cls,                            unsigned int index)  {    struct FakebankTransferState *fts = cls; -  #define MANDATORY 7 -  struct TALER_TESTING_Trait traits[MANDATORY + 1] = { -    TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT -      (&fts->debit_account_no), -    TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT -      (&fts->credit_account_no), +  struct TALER_TESTING_Trait traits[] = {      TALER_TESTING_make_trait_url (0, fts->exchange_url), +    TALER_TESTING_make_trait_url (1, fts->debit_url),      TALER_TESTING_MAKE_TRAIT_ROW_ID (&fts->serial_id), +    TALER_TESTING_MAKE_TRAIT_CREDIT_ACCOUNT (fts->payto_credit_account), +    TALER_TESTING_MAKE_TRAIT_DEBIT_ACCOUNT (fts->debit_url),      TALER_TESTING_make_trait_amount_obj (0, &fts->amount), -    TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp) +    TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp), +    TALER_TESTING_make_trait_reserve_priv (0, +                                           &fts->reserve_priv), +    TALER_TESTING_make_trait_reserve_pub (0, +                                          &fts->reserve_pub), +    TALER_TESTING_trait_end ()    }; -  /** -   * The user gave explicit subject, -   * there must be NO reserve priv.  */ -  if (NULL != fts->subject) -    traits[MANDATORY - 1] = -      TALER_TESTING_make_trait_transfer_subject (0, -                                                 fts->subject); -  /* A reserve priv must exist if no subject was given.  */ -  else -    traits[MANDATORY - 1] = TALER_TESTING_make_trait_reserve_priv -                              (0, &fts->reserve_priv), - -    traits[MANDATORY] = TALER_TESTING_trait_end (); -    return TALER_TESTING_get_trait (traits,                                    ret,                                    trait, @@ -475,27 +444,21 @@ fakebank_transfer_traits (void *cls,   *   * @param label command label.   * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - *        wire transer.  For simplicity, both credit and debit - *        bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. + * @param account_base_url base URL of the account that implements this + *        wire transer (which account gives money). + * @param payto_credit_account which account receives money.   * @param auth_username username identifying the @a   *        debit_account_no at the bank.   * @param auth_password password for @a auth_username.   * @param exchange_url which exchange is involved in this transfer. - *   * @return the command.   */  struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer    (const char *label,    const char *amount, -  const char *bank_url, -  uint64_t debit_account_no, -  uint64_t credit_account_no, +  const char *account_base_url, +  const char *payto_credit_account,    const char *auth_username,    const char *auth_password,    const char *exchange_url) @@ -503,9 +466,8 @@ TALER_TESTING_cmd_fakebank_transfer    struct FakebankTransferState *fts;    fts = GNUNET_new (struct FakebankTransferState); -  fts->bank_url = bank_url; -  fts->credit_account_no = credit_account_no; -  fts->debit_account_no = debit_account_no; +  fts->debit_url = account_base_url; +  fts->payto_credit_account = payto_credit_account;    fts->auth_username = auth_username;    fts->auth_password = auth_password;    fts->exchange_url = exchange_url; @@ -520,87 +482,17 @@ TALER_TESTING_cmd_fakebank_transfer      GNUNET_assert (0);    } -  struct TALER_TESTING_Command cmd = { -    .cls = fts, -    .label = label, -    .run = &fakebank_transfer_run, -    .cleanup = &fakebank_transfer_cleanup, -    .traits = &fakebank_transfer_traits -  }; - -  return cmd; -} - - -/** - * Create "fakebank transfer" CMD, letting the caller specifying - * the subject line. - * - * @param label command label. - * @param amount amount to transfer. - * @param bank_url base URL of the bank that implements this - *        wire transer.  For simplicity, both credit and debit - *        bank account exist at the same bank. - * @param debit_account_no which account (expressed as a number) - *        gives money. - * @param credit_account_no which account (expressed as a number) - *        receives money. - * - * @param auth_username username identifying the @a - *        debit_account_no at the bank. - * @param auth_password password for @a auth_username. - * @param subject wire transfer's subject line. - * @param exchange_url which exchange is involved in this transfer. - * - * @return the command. - */ -struct TALER_TESTING_Command -TALER_TESTING_cmd_fakebank_transfer_with_subject -  (const char *label, -  const char *amount, -  const char *bank_url, -  uint64_t debit_account_no, -  uint64_t credit_account_no, -  const char *auth_username, -  const char *auth_password, -  const char *subject, -  const char *exchange_url) -{ -  struct FakebankTransferState *fts; - -  fts = GNUNET_new (struct FakebankTransferState); - -  TALER_LOG_DEBUG ("%s:FTS@%p\n", -                   label, -                   fts); - -  fts->bank_url = bank_url; -  fts->credit_account_no = credit_account_no; -  fts->debit_account_no = debit_account_no; -  fts->auth_username = auth_username; -  fts->auth_password = auth_password; -  fts->subject = subject; -  fts->exchange_url = exchange_url; -  if (GNUNET_OK != -      TALER_string_to_amount (amount, -                              &fts->amount))    { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Failed to parse amount `%s' at %s\n", -                amount, -                label); -    GNUNET_assert (0); +    struct TALER_TESTING_Command cmd = { +      .cls = fts, +      .label = label, +      .run = &fakebank_transfer_run, +      .cleanup = &fakebank_transfer_cleanup, +      .traits = &fakebank_transfer_traits +    }; + +    return cmd;    } - -  struct TALER_TESTING_Command cmd = { -    .cls = fts, -    .label = label, -    .run = &fakebank_transfer_run, -    .cleanup = &fakebank_transfer_cleanup, -    .traits = &fakebank_transfer_traits -  }; - -  return cmd;  } @@ -631,9 +523,8 @@ struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer_with_ref    (const char *label,    const char *amount, -  const char *bank_url, -  uint64_t debit_account_no, -  uint64_t credit_account_no, +  const char *account_base_url, +  const char *payto_credit_account,    const char *auth_username,    const char *auth_password,    const char *ref, @@ -642,9 +533,8 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref    struct FakebankTransferState *fts;    fts = GNUNET_new (struct FakebankTransferState); -  fts->bank_url = bank_url; -  fts->credit_account_no = credit_account_no; -  fts->debit_account_no = debit_account_no; +  fts->debit_url = account_base_url; +  fts->payto_credit_account = payto_credit_account;    fts->auth_username = auth_username;    fts->auth_password = auth_password;    fts->reserve_reference = ref; @@ -659,16 +549,17 @@ TALER_TESTING_cmd_fakebank_transfer_with_ref                  label);      GNUNET_assert (0);    } - -  struct TALER_TESTING_Command cmd = { -    .cls = fts, -    .label = label, -    .run = &fakebank_transfer_run, -    .cleanup = &fakebank_transfer_cleanup, -    .traits = &fakebank_transfer_traits -  }; - -  return cmd; +  { +    struct TALER_TESTING_Command cmd = { +      .cls = fts, +      .label = label, +      .run = &fakebank_transfer_run, +      .cleanup = &fakebank_transfer_cleanup, +      .traits = &fakebank_transfer_traits +    }; + +    return cmd; +  }  } @@ -705,9 +596,8 @@ struct TALER_TESTING_Command  TALER_TESTING_cmd_fakebank_transfer_with_instance    (const char *label,    const char *amount, -  const char *bank_url, -  uint64_t debit_account_no, -  uint64_t credit_account_no, +  const char *account_base_url, +  const char *payto_credit_account,    const char *auth_username,    const char *auth_password,    const char *instance, @@ -717,9 +607,8 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance    struct FakebankTransferState *fts;    fts = GNUNET_new (struct FakebankTransferState); -  fts->bank_url = bank_url; -  fts->credit_account_no = credit_account_no; -  fts->debit_account_no = debit_account_no; +  fts->debit_url = account_base_url; +  fts->payto_credit_account = payto_credit_account;    fts->auth_username = auth_username;    fts->auth_password = auth_password;    fts->instance = instance; @@ -735,16 +624,17 @@ TALER_TESTING_cmd_fakebank_transfer_with_instance                  label);      GNUNET_assert (0);    } - -  struct TALER_TESTING_Command cmd = { -    .cls = fts, -    .label = label, -    .run = &fakebank_transfer_run, -    .cleanup = &fakebank_transfer_cleanup, -    .traits = &fakebank_transfer_traits -  }; - -  return cmd; +  { +    struct TALER_TESTING_Command cmd = { +      .cls = fts, +      .label = label, +      .run = &fakebank_transfer_run, +      .cleanup = &fakebank_transfer_cleanup, +      .traits = &fakebank_transfer_traits +    }; + +    return cmd; +  }  } diff --git a/src/lib/testing_api_cmd_status.c b/src/lib/testing_api_cmd_status.c index 398221a1..2da404fb 100644 --- a/src/lib/testing_api_cmd_status.c +++ b/src/lib/testing_api_cmd_status.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2018 Taler Systems SA +  Copyright (C) 2014-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as @@ -146,6 +146,7 @@ status_run (void *cls,    const struct TALER_TESTING_Command *create_reserve;    const struct TALER_ReservePrivateKeyP *reserve_priv;    struct TALER_ReservePublicKeyP reserve_pub; +  const struct TALER_ReservePublicKeyP *reserve_pubp;    ss->is = is;    GNUNET_assert (NULL != ss->reserve_reference); @@ -163,44 +164,31 @@ status_run (void *cls,    /* NOTE: the following line might generate a ERROR log     * statements, but it can be ignored.  */ -  if (GNUNET_OK == TALER_TESTING_get_trait_reserve_priv -        (create_reserve, -        0, -        &reserve_priv)) +  if (GNUNET_OK == +      TALER_TESTING_get_trait_reserve_priv (create_reserve, +                                            0, +                                            &reserve_priv))    {      GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,                                          &reserve_pub.eddsa_pub); +    reserve_pubp = &reserve_pub;    }    else    { -    const char *transfer_subject; - -    if (GNUNET_OK != TALER_TESTING_get_trait_transfer_subject -          (create_reserve, -          0, -          &transfer_subject)) -    { -      GNUNET_break (0); -      TALER_LOG_ERROR ("The reserve has neither a priv nor a subject line.\n"); -      TALER_TESTING_interpreter_fail (is); -      return; -    } -      if (GNUNET_OK != -        GNUNET_STRINGS_string_to_data (transfer_subject, -                                       strlen (transfer_subject), -                                       &reserve_pub.eddsa_pub, -                                       sizeof (struct TALER_ReservePublicKeyP))) +        TALER_TESTING_get_trait_reserve_pub (create_reserve, +                                             0, +                                             &reserve_pubp))      {        GNUNET_break (0); -      TALER_LOG_ERROR ("Transfer subject is not a public key.\n"); +      TALER_LOG_ERROR ("The reserve has neither a priv nor a pub.\n");        TALER_TESTING_interpreter_fail (is);        return;      }    }    ss->rsh = TALER_EXCHANGE_reserve_status (is->exchange, -                                           &reserve_pub, +                                           reserve_pubp,                                             &reserve_status_cb,                                             ss);  } diff --git a/src/lib/testing_api_cmd_track.c b/src/lib/testing_api_cmd_track.c index 41c6be17..070218cf 100644 --- a/src/lib/testing_api_cmd_track.c +++ b/src/lib/testing_api_cmd_track.c @@ -1,6 +1,6 @@  /*    This file is part of TALER -  Copyright (C) 2014-2018 Taler Systems SA +  Copyright (C) 2014-2020 Taler Systems SA    TALER is free software; you can redistribute it and/or modify    it under the terms of the GNU General Public License as @@ -190,15 +190,11 @@ deposit_wtid_cb      if (NULL != tts->bank_transfer_reference)      {        const struct TALER_TESTING_Command *bank_transfer_cmd; -      char *ws; +      const struct TALER_WireTransferIdentifierRawP *wtid_want;        /* _this_ wire transfer subject line.  */ -      ws = GNUNET_STRINGS_data_to_string_alloc (wtid, -                                                sizeof (*wtid)); -        bank_transfer_cmd = TALER_TESTING_interpreter_lookup_command                              (is, tts->bank_transfer_reference); -        if (NULL == bank_transfer_cmd)        {          GNUNET_break (0); @@ -206,12 +202,9 @@ deposit_wtid_cb          return;        } -      /* expected wire transfer subject line.  */ -      const char *transfer_subject; -        if (GNUNET_OK != -          TALER_TESTING_get_trait_transfer_subject -            (bank_transfer_cmd, 0, &transfer_subject)) +          TALER_TESTING_get_trait_wtid +            (bank_transfer_cmd, 0, &wtid_want))        {          GNUNET_break (0);          TALER_TESTING_interpreter_fail (is); @@ -219,15 +212,13 @@ deposit_wtid_cb        }        /* Compare that expected and gotten subjects match.  */ -      if (0 != strcmp (ws, transfer_subject)) +      if (0 != GNUNET_memcmp (wtid, +                              wtid_want))        {          GNUNET_break (0); -        GNUNET_free (ws);          TALER_TESTING_interpreter_fail (tts->is);          return;        } - -      GNUNET_free (ws);      }      break;    case MHD_HTTP_ACCEPTED: diff --git a/src/lib/testing_api_trait_reserve_pub.c b/src/lib/testing_api_trait_reserve_pub.c new file mode 100644 index 00000000..b9cd070d --- /dev/null +++ b/src/lib/testing_api_trait_reserve_pub.c @@ -0,0 +1,77 @@ +/* +  This file is part of TALER +  Copyright (C) 2018-2020 Taler Systems SA + +  TALER is free software; you can redistribute it and/or modify +  it under the terms of the GNU General Public License as +  published by the Free Software Foundation; either version 3, or +  (at your option) any later version. + +  TALER is distributed in the hope that it will be useful, but +  WITHOUT ANY WARRANTY; without even the implied warranty of +  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +  GNU General Public License for more details. + +  You should have received a copy of the GNU General Public +  License along with TALER; see the file COPYING.  If not, see +  <http://www.gnu.org/licenses/> +*/ +/** + * @file exchange-lib/testing_api_trait_reserve_pub.c + * @brief implements reserve public key trait + * @author Christian Grothoff + * @author Marcello Stanisci + */ +#include "platform.h" +#include "taler_json_lib.h" +#include <gnunet/gnunet_curl_lib.h> +#include "exchange_api_handle.h" +#include "taler_signatures.h" +#include "taler_testing_lib.h" + +#define TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY \ +  "reserve-public-key" + +/** + * Obtain a reserve public key from a @a cmd. + * + * @param cmd command to extract the reserve pub from. + * @param index reserve pub's index number. + * @param reserve_pub[out] set to the reserve pub. + * @return #GNUNET_OK on success. + */ +int +TALER_TESTING_get_trait_reserve_pub +  (const struct TALER_TESTING_Command *cmd, +  unsigned int index, +  const struct TALER_ReservePublicKeyP **reserve_pub) +{ +  return cmd->traits (cmd->cls, +                      (const void **) reserve_pub, +                      TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, +                      index); +} + + +/** + * Offer a reserve public key. + * + * @param index reserve pub's index number. + * @param reserve_pub reserve public key to offer. + * @return the trait. + */ +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_reserve_pub +  (unsigned int index, +  const struct TALER_ReservePublicKeyP *reserve_pub) +{ +  struct TALER_TESTING_Trait ret = { +    .index = index, +    .trait_name = TALER_TESTING_TRAIT_RESERVE_PUBLIC_KEY, +    .ptr = (const void *) reserve_pub +  }; +  return ret; +} + + +/* end of testing_api_trait_reserve_pub.c */ diff --git a/src/lib/testing_api_trait_string.c b/src/lib/testing_api_trait_string.c index 8d3d5df0..b9f57ab7 100644 --- a/src/lib/testing_api_trait_string.c +++ b/src/lib/testing_api_trait_string.c @@ -30,7 +30,7 @@  #include "taler_testing_lib.h"  #define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms" -#define TALER_TESTING_TRAIT_TRANSFER_SUBJECT "transfer-subject" +#define TALER_TESTING_TRAIT_STRING "string"  #define TALER_TESTING_TRAIT_AMOUNT "amount"  #define TALER_TESTING_TRAIT_URL "url"  #define TALER_TESTING_TRAIT_ORDER_ID "order-id" @@ -80,46 +80,45 @@ TALER_TESTING_make_trait_contract_terms  /** - * Obtain a transfer subject from @a cmd. + * Obtain a string from @a cmd.   *   * @param cmd command to extract the subject from.   * @param index index number associated with the transfer   *        subject to offer. - * @param transfer_subject[out] where to write the offered - *        transfer subject. + * @param s[out] where to write the offered + *        string   * @return #GNUNET_OK on success.   */  int -TALER_TESTING_get_trait_transfer_subject +TALER_TESTING_get_trait_string    (const struct TALER_TESTING_Command *cmd,    unsigned int index, -  const char **transfer_subject) +  const char **s)  {    return cmd->traits (cmd->cls, -                      (const void **) transfer_subject, -                      TALER_TESTING_TRAIT_TRANSFER_SUBJECT, +                      (const void **) s, +                      TALER_TESTING_TRAIT_STRING,                        index);  }  /** - * Offer transfer subject. + * Offer string.   *   * @param index index number associated with the transfer   *        subject being offered. - * @param transfer_subject transfer subject to offer. - * + * @param s transfer subject to offer.   * @return the trait.   */  struct TALER_TESTING_Trait -TALER_TESTING_make_trait_transfer_subject +TALER_TESTING_make_trait_string    (unsigned int index, -  const char *transfer_subject) +  const char *s)  {    struct TALER_TESTING_Trait ret = {      .index = index, -    .trait_name = TALER_TESTING_TRAIT_TRANSFER_SUBJECT, -    .ptr = (const void *) transfer_subject +    .trait_name = TALER_TESTING_TRAIT_STRING, +    .ptr = (const void *) s    };    return ret;  } diff --git a/src/wire-plugins/Makefile.am b/src/wire-plugins/Makefile.am deleted file mode 100644 index 6d5b3e8b..00000000 --- a/src/wire-plugins/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -# This Makefile.am is in the public domain -AM_CPPFLAGS = -I$(top_srcdir)/src/include - -if USE_COVERAGE -  AM_CFLAGS = --coverage -O0 -  XLIB = -lgcov -endif - -pkgcfgdir = $(prefix)/share/taler/config.d/ - -EXTRA_DIST = \ -  test_wire_plugin.conf \ -  test_wire_plugin_transactions_taler-bank.conf - -plugindir = $(libdir)/taler - -if HAVE_LIBCURL -plugin_LTLIBRARIES = \ - libtaler_plugin_wire_taler_bank.la -else -if HAVE_LIBGNURL -plugin_LTLIBRARIES = \ - libtaler_plugin_wire_taler_bank.la -endif -endif - -noinst_LTLIBRARIES = \ -  libtaler_plugin_wire_template.la - - -libtaler_plugin_wire_taler_bank_la_SOURCES = \ -  plugin_wire_taler-bank.c -libtaler_plugin_wire_taler_bank_la_LIBADD = \ -  $(LTLIBINTL) -libtaler_plugin_wire_taler_bank_la_LDFLAGS = \ -  $(TALER_PLUGIN_LDFLAGS) \ -  $(top_builddir)/src/bank-lib/libtalerbank.la \ -  $(top_builddir)/src/json/libtalerjson.la \ -  $(top_builddir)/src/wire/libtalerwire.la \ -  $(top_builddir)/src/util/libtalerutil.la \ -  -lgnunetcurl \ -  -lgnunetutil $(XLIB) - - -libtaler_plugin_wire_template_la_SOURCES = \ -  plugin_wire_template.c -libtaler_plugin_wire_template_la_LIBADD = \ -  $(LTLIBINTL) -libtaler_plugin_wire_template_la_LDFLAGS = \ -  $(TALER_PLUGIN_LDFLAGS) \ -  $(top_builddir)/src/util/libtalerutil.la \ -  -lgnunetutil $(XLIB) - - -AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; - -TESTS = \ - test_wire_plugin \ - test_wire_plugin_transactions_taler_bank - -check_PROGRAMS= $(TESTS) - - -test_wire_plugin_SOURCES = \ -  test_wire_plugin.c -test_wire_plugin_LDADD = \ -  -lgnunetutil \ -  $(top_builddir)/src/wire/libtalerwire.la \ -  $(top_builddir)/src/util/libtalerutil.la - - -test_wire_plugin_transactions_taler_bank_SOURCES = \ -  test_wire_plugin_transactions_taler-bank.c -test_wire_plugin_transactions_taler_bank_LDADD = \ -  -lgnunetjson \ -  -lgnunetutil \ -  -ljansson \ -  $(top_builddir)/src/wire/libtalerwire.la \ -  $(top_builddir)/src/bank-lib/libtalerbank.la \ -  $(top_builddir)/src/bank-lib/libtalerfakebank.la \ -  $(top_builddir)/src/util/libtalerutil.la diff --git a/src/wire-plugins/plugin_wire_taler-bank.c b/src/wire-plugins/plugin_wire_taler-bank.c deleted file mode 100644 index ad8daa4e..00000000 --- a/src/wire-plugins/plugin_wire_taler-bank.c +++ /dev/null @@ -1,1306 +0,0 @@ -/* -  This file is part of TALER -  Copyright (C) 2017, 2018 Taler Systems SA - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file plugin_wire_taler_bank.c - * @brief plugin for the "x-taler-bank" wire method - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_wire_plugin.h" -#include "taler_json_lib.h" -#include "taler_wire_lib.h" -#include "taler_bank_service.h" -#include "taler_signatures.h" -#include <gnunet/gnunet_curl_lib.h> - -/* only for HTTP status codes */ -#include <microhttpd.h> - -/** - * Type of the "cls" argument given to each of the functions in - * our API. - */ -struct TalerBankClosure -{ - -  /** -   * Which currency do we support? -   */ -  char *currency; - -  /** -   * Handle to the context for sending funds to the bank. -   */ -  struct GNUNET_CURL_Context *ctx; - -  /** -   * Scheduler context for running the @e ctx. -   */ -  struct GNUNET_CURL_RescheduleContext *rc; - -  /** -   * Configuration we use to lookup account information. -   */ -  struct GNUNET_CONFIGURATION_Handle *cfg; - -}; - - -/** - * Handle returned by #taler_bank_prepare_wire_transfer. - */ -struct TALER_WIRE_PrepareHandle -{ - -  /** -   * Task we use for async execution. -   */ -  struct GNUNET_SCHEDULER_Task *task; - -  /** -   * TalerBank closure we run in. -   */ -  struct TalerBankClosure *tc; - -  /** -   * Authentication information. -   */ -  struct TALER_BANK_AuthenticationData auth; - -  /** -   * Which account should be debited? Given as the respective -   * section in the configuration file. -   */ -  char *origin_account_url; - -  /** -   * Which account should be credited? -   */ -  char *destination_account_url; - -  /** -   * Base URL to use for the exchange. -   */ -  char *exchange_base_url; - -  /** -   * Function to call with the serialized data. -   */ -  TALER_WIRE_PrepareTransactionCallback ptc; - -  /** -   * Closure for @e ptc. -   */ -  void *ptc_cls; - -  /** -   * Amount to transfer. -   */ -  struct TALER_Amount amount; - -  /** -   * Subject of the wire transfer. -   */ -  struct TALER_WireTransferIdentifierRawP wtid; - - -}; - - -/** - * Handle returned by #taler_bank_execute_wire_transfer. - */ -struct TALER_WIRE_ExecuteHandle -{ - -  /** -   * Handle to the HTTP request to the bank. -   */ -  struct TALER_BANK_AdminAddIncomingHandle *aaih; - -  /** -   * Function to call with the result. -   */ -  TALER_WIRE_ConfirmationCallback cc; - -  /** -   * Closure for @e cc. -   */ -  void *cc_cls; -}; - - -/** - * Round amount DOWN to the amount that can be transferred via the wire - * method.  For example, Taler may support 0.000001 EUR as a unit of - * payment, but SEPA only supports 0.01 EUR.  This function would - * round 0.125 EUR to 0.12 EUR in this case. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param[in,out] amount amount to round down - * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, - *         #GNUNET_SYSERR if the amount or currency was invalid - */ -static int -taler_bank_amount_round (void *cls, -                         struct TALER_Amount *amount) -{ -  struct TalerBankClosure *tc = cls; -  uint32_t delta; - -  if (NULL == tc->currency) -  { -    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                               "taler", -                               "CURRENCY"); -    return GNUNET_SYSERR; /* not configured with currency */ -  } -  if (0 != strcasecmp (amount->currency, -                       tc->currency)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  /* 'taler_bank' method supports 1/100 of the unit currency, i.e. 0.01 CUR */ -  delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100); -  if (0 == delta) -    return GNUNET_NO; -  amount->fraction -= delta; -  return GNUNET_OK; -} - - -/** - * Check if the given payto:// URL is correctly formatted. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param account_url an account URL - * @return #TALER_EC_NONE if correctly formatted - */ -static enum TALER_ErrorCode -taler_bank_wire_validate (void *cls, -                          const char *account_url) -{ -  (void) cls; -  struct TALER_Account acc; -  enum TALER_ErrorCode ec; - -  ec = TALER_WIRE_payto_to_account (account_url, -                                    &acc); -  if (TALER_EC_NONE == ec) -  { -    if (TALER_PAC_X_TALER_BANK != acc.type) -      ec = TALER_EC_PAYTO_WRONG_METHOD; -    TALER_WIRE_account_free (&acc); -  } -  return ec; -} - - -GNUNET_NETWORK_STRUCT_BEGIN -/** - * Format we used for serialized transaction data. - */ -struct BufFormatP -{ - -  /** -   * The wire transfer identifier. -   */ -  struct TALER_WireTransferIdentifierRawP wtid; - -  /** -   * The amount. -   */ -  struct TALER_AmountNBO amount; - -  /* followed by 0-terminated origin account URL */ - -  /* followed by 0-terminated destination account URL */ - -  /* followed by 0-terminated exchange base URL */ - -  /* optionally followed by 0-terminated origin username URL */ - -  /* optionally followed by 0-terminated origin password URL */ - -}; -GNUNET_NETWORK_STRUCT_END - - -/** - * Abort preparation of a wire transfer. For example, - * because we are shutting down. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param pth preparation to cancel - */ -static void -taler_bank_prepare_wire_transfer_cancel (void *cls, -                                         struct TALER_WIRE_PrepareHandle *pth) -{ -  (void) cls; -  if (NULL != pth->task) -    GNUNET_SCHEDULER_cancel (pth->task); -  TALER_BANK_auth_free (&pth->auth); -  GNUNET_free (pth->origin_account_url); -  GNUNET_free (pth->destination_account_url); -  GNUNET_free (pth->exchange_base_url); -  GNUNET_free (pth); -} - - -/** - * Prepare for exeuction of a wire transfer.  Calls the - * callback with the serialized state. - * - * @param cls the `struct TALER_WIRE_PrepareHandle` - */ -static void -do_prepare (void *cls) -{ -  struct TALER_WIRE_PrepareHandle *pth = cls; -  size_t len_i; -  size_t len_o; -  size_t len_au; -  size_t len_ap; -  size_t len_b; -  struct BufFormatP bf; - -  pth->task = NULL; -  /* serialize the state into a 'buf' */ -  len_o = strlen (pth->origin_account_url) + 1; -  len_i = strlen (pth->destination_account_url) + 1; -  len_b = strlen (pth->exchange_base_url) + 1; -  len_au = 0; -  len_ap = 0; -  switch (pth->auth.method) -  { -  case TALER_BANK_AUTH_NONE: -    break; -  case TALER_BANK_AUTH_BASIC: -    len_au = strlen (pth->auth.details.basic.username) + 1; -    len_ap = strlen (pth->auth.details.basic.password) + 1; -    break; -  } -  bf.wtid = pth->wtid; -  TALER_amount_hton (&bf.amount, -                     &pth->amount); -  { -    char buf[sizeof (struct BufFormatP) + len_o + len_i + len_b + len_au -             + len_ap]; - -    memcpy (buf, -            &bf, -            sizeof (struct BufFormatP)); -    memcpy (&buf[sizeof (struct BufFormatP)], -            pth->origin_account_url, -            len_o); -    memcpy (&buf[sizeof (struct BufFormatP) + len_o], -            pth->destination_account_url, -            len_i); -    memcpy (&buf[sizeof (struct BufFormatP) + len_o + len_i], -            pth->exchange_base_url, -            len_b); -    switch (pth->auth.method) -    { -    case TALER_BANK_AUTH_NONE: -      break; -    case TALER_BANK_AUTH_BASIC: -      memcpy (&buf[sizeof (struct BufFormatP) + len_o + len_i + len_b], -              pth->auth.details.basic.username, -              len_au); -      memcpy (&buf[sizeof (struct BufFormatP) + len_o + len_i + len_b + len_au], -              pth->auth.details.basic.password, -              len_ap); -      break; -    } -    /* finally give the state back */ -    pth->ptc (pth->ptc_cls, -              buf, -              sizeof (buf)); -  } -  taler_bank_prepare_wire_transfer_cancel (NULL, -                                           pth); -} - - -/** - * Parse account configuration from @a cfg in @a section into @a account. - * Obtains the URL option and initializes @a account from it. - * - * @param cfg configuration to parse - * @param section section with the account configuration - * @param account[out] account information to initialize - * @return #GNUNET_OK on success - */ -static int -parse_account_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, -                   const char *section, -                   struct TALER_Account *account) -{ -  char *account_url; - -  if (GNUNET_OK != -      GNUNET_CONFIGURATION_get_value_string (cfg, -                                             section, -                                             "URL", -                                             &account_url)) -  { -    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                               section, -                               "URL"); -    return GNUNET_SYSERR; -  } - -  if (TALER_EC_NONE != -      TALER_WIRE_payto_to_account (account_url, -                                   account)) -  { -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               section, -                               "URL", -                               "Malformed payto:// URL for x-taler-bank method"); -    GNUNET_free (account_url); -    return GNUNET_SYSERR; -  } -  if (TALER_PAC_X_TALER_BANK != account->type) -  { -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               section, -                               "URL", -                               "Malformed payto:// URL for x-taler-bank method"); -    GNUNET_free (account_url); -    TALER_WIRE_account_free (account); -    return GNUNET_SYSERR; -  } -  GNUNET_free (account_url); -  return GNUNET_OK; -} - - -/** - * Prepare for exeuction of a wire transfer.  Note that we should call - * @a ptc asynchronously (as that is what the API requires, because - * some transfer methods need it).  So while we could immediately call - * @a ptc, we first bundle up all the data and schedule a task to do - * the work. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param origin_account_section configuration section specifying the origin - *        account of the exchange to use - * @param destination_account_url payto:// URL identifying where to send the money - * @param amount amount to transfer, already rounded - * @param exchange_base_url base URL of this exchange - * @param wtid wire transfer identifier to use - * @param ptc function to call with the prepared data to persist - * @param ptc_cls closure for @a ptc - * @return NULL on failure - */ -static struct TALER_WIRE_PrepareHandle * -taler_bank_prepare_wire_transfer (void *cls, -                                  const char *origin_account_section, -                                  const char *destination_account_url, -                                  const struct TALER_Amount *amount, -                                  const char *exchange_base_url, -                                  const struct -                                  TALER_WireTransferIdentifierRawP *wtid, -                                  TALER_WIRE_PrepareTransactionCallback ptc, -                                  void *ptc_cls) -{ -  struct TalerBankClosure *tc = cls; -  struct TALER_WIRE_PrepareHandle *pth; -  char *origin_account_url; -  struct TALER_Account a_in; -  struct TALER_Account a_out; - -  /* Check that payto:// URLs are valid */ -  if (TALER_EC_NONE != -      TALER_WIRE_payto_to_account (destination_account_url, -                                   &a_out)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "payto://-URL `%s' is invalid!\n", -                destination_account_url); -    return NULL; -  } -  if (TALER_PAC_X_TALER_BANK != a_out.type) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "payto://-URL `%s' is invalid!\n", -                destination_account_url); -    TALER_WIRE_account_free (&a_out); -    return NULL; -  } -  if (GNUNET_OK != -      GNUNET_CONFIGURATION_get_value_string (tc->cfg, -                                             origin_account_section, -                                             "URL", -                                             &origin_account_url)) -  { -    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                               origin_account_section, -                               "URL"); -    TALER_WIRE_account_free (&a_out); -    return NULL; -  } -  if (TALER_EC_NONE != -      TALER_WIRE_payto_to_account (origin_account_url, -                                   &a_in)) -  { -    GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, -                               origin_account_section, -                               "URL", -                               "Malformed payto:// URL for x-taler-bank method"); -    GNUNET_free (origin_account_url); -    TALER_WIRE_account_free (&a_out); -    return NULL; -  } -  if (TALER_PAC_X_TALER_BANK != a_in.type) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "payto://-URL `%s' is invalid!\n", -                origin_account_url); -    GNUNET_free (origin_account_url); -    TALER_WIRE_account_free (&a_in); -    TALER_WIRE_account_free (&a_out); -    return NULL; -  } - -  /* Make sure the bank is the same! */ -  if (0 != strcasecmp (a_in.details.x_taler_bank.hostname, -                       a_out.details.x_taler_bank.hostname)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                "x-taler-bank hostname missmatch: `%s' != `%s'\n", -                a_in.details.x_taler_bank.hostname, -                a_out.details.x_taler_bank.hostname); -    TALER_WIRE_account_free (&a_in); -    TALER_WIRE_account_free (&a_out); -    GNUNET_free (origin_account_url); -    return NULL; -  } -  TALER_WIRE_account_free (&a_in); -  TALER_WIRE_account_free (&a_out); - -  pth = GNUNET_new (struct TALER_WIRE_PrepareHandle); -  if (GNUNET_OK != -      TALER_BANK_auth_parse_cfg (tc->cfg, -                                 origin_account_section, -                                 &pth->auth)) -  { -    GNUNET_free (pth); -    GNUNET_free (origin_account_url); -    return NULL; -  } - -  pth->tc = tc; -  pth->origin_account_url = origin_account_url; -  pth->destination_account_url = GNUNET_strdup (destination_account_url); -  pth->exchange_base_url = GNUNET_strdup (exchange_base_url); -  pth->wtid = *wtid; -  pth->ptc = ptc; -  pth->ptc_cls = ptc_cls; -  pth->amount = *amount; -  pth->task = GNUNET_SCHEDULER_add_now (&do_prepare, -                                        pth); -  return pth; -} - - -/** - * Called with the result of submitting information about an incoming - * transaction to a bank. - * - * @param cls closure with the `struct TALER_WIRE_ExecuteHandle` - * @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful status request - *                    0 if the bank's reply is bogus (fails to follow the protocol) - * @param ec error code from the bank - * @param serial_id unique ID of the wire transfer in the bank's records; UINT64_MAX on error - * @param timestamp time when the transfer was settled by the bank. - * @param json detailed response from the HTTPD, or NULL if reply was not JSON - */ -static void -execute_cb (void *cls, -            unsigned int http_status, -            enum TALER_ErrorCode ec, -            uint64_t serial_id, -            struct GNUNET_TIME_Absolute timestamp, -            const json_t *json) -{ -  struct TALER_WIRE_ExecuteHandle *eh = cls; -  json_t *reason; -  const char *emsg; -  char *s; -  uint64_t serial_id_nbo; - -  (void) timestamp; -  eh->aaih = NULL; -  emsg = NULL; -  if (NULL != json) -  { -    reason = json_object_get (json, -                              "reason"); -    if (NULL != reason) -      emsg = json_string_value (reason); -  } -  if (NULL != emsg) -    GNUNET_asprintf (&s, -                     "%u/%u (%s)", -                     http_status, -                     (unsigned int) ec, -                     emsg); -  else -    GNUNET_asprintf (&s, -                     "%u/%u", -                     http_status, -                     (unsigned int) ec); -  serial_id_nbo = GNUNET_htonll (serial_id); -  eh->cc (eh->cc_cls, -          (MHD_HTTP_OK == http_status) ? GNUNET_OK : GNUNET_SYSERR, -          &serial_id_nbo, -          sizeof (uint64_t), -          (MHD_HTTP_OK == http_status) ? NULL : s); -  GNUNET_free (s); -  GNUNET_free (eh); -} - - -/** - * Execute a wire transfer. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param buf buffer with the prepared execution details - * @param buf_size number of bytes in @a buf - * @param cc function to call upon success - * @param cc_cls closure for @a cc - * @return NULL on error - */ -static struct TALER_WIRE_ExecuteHandle * -taler_bank_execute_wire_transfer (void *cls, -                                  const char *buf, -                                  size_t buf_size, -                                  TALER_WIRE_ConfirmationCallback cc, -                                  void *cc_cls) -{ -  struct TalerBankClosure *tc = cls; -  struct TALER_WIRE_ExecuteHandle *eh; -  struct TALER_Amount amount; -  struct TALER_Account origin_account; -  struct TALER_Account destination_account; -  struct BufFormatP bf; -  const char *exchange_base_url; -  const char *origin_account_url; -  const char *destination_account_url; -  struct TALER_BANK_AuthenticationData auth; -  size_t left; -  size_t slen; -  char *wire_s; - -  if (NULL == tc->ctx) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Bank not initialized, cannot do transfers!\n"); -    return NULL; /* not initialized with configuration, cannot do transfers */ -  } -  if ( (buf_size <= sizeof (struct BufFormatP)) || -       ('\0' != buf[buf_size - 1]) ) -  { -    GNUNET_break (0); -    return NULL; -  } -  memcpy (&bf, -          buf, -          sizeof (bf)); -  TALER_amount_ntoh (&amount, -                     &bf.amount); -  origin_account_url = &buf[sizeof (struct BufFormatP)]; -  left = buf_size - sizeof (struct BufFormatP); -  slen = strlen (origin_account_url) + 1; -  /* make sure there's enough space to accomodate what's been taken now */ -  GNUNET_assert (left >= slen); -  left -= slen; -  if (0 == left) -  { -    GNUNET_break (0); -    return NULL; -  } -  destination_account_url = &origin_account_url[slen]; -  slen = strlen (destination_account_url) + 1; -  GNUNET_assert (left >= slen); -  left -= slen; -  if (0 == left) -  { -    GNUNET_break (0); -    return NULL; -  } -  exchange_base_url = &destination_account_url[slen]; -  slen = strlen (exchange_base_url) + 1; -  GNUNET_assert (left >= slen); -  left -= slen; -  if (0 == left) -  { -    auth.method = TALER_BANK_AUTH_NONE; -  } -  else -  { -    auth.method = TALER_BANK_AUTH_BASIC; -    auth.details.basic.username = (char *) &exchange_base_url[slen]; -    slen = strlen (auth.details.basic.username) + 1; -    GNUNET_assert (left >= slen); -    left -= slen; -    if (0 == left) -    { -      GNUNET_break (0); -      return NULL; -    } -    auth.details.basic.password = &auth.details.basic.username[slen]; -    slen = strlen (auth.details.basic.password) + 1; -    GNUNET_assert (left >= slen); -    left -= slen; -    if (0 != left) -    { -      GNUNET_break (0); -      return NULL; -    } -  } - -  if (TALER_EC_NONE != -      TALER_WIRE_payto_to_account (origin_account_url, -                                   &origin_account)) -  { -    GNUNET_break (0); -    return NULL; -  } -  if (TALER_EC_NONE != -      TALER_WIRE_payto_to_account (destination_account_url, -                                   &destination_account)) -  { -    TALER_WIRE_account_free (&origin_account); -    GNUNET_break (0); -    return NULL; -  } -  if ( (TALER_PAC_X_TALER_BANK != origin_account.type) || -       (TALER_PAC_X_TALER_BANK != destination_account.type) || -       (0 != strcasecmp (origin_account.details.x_taler_bank.hostname, -                         destination_account.details.x_taler_bank.hostname)) ) -  { -    GNUNET_break (0); -    TALER_WIRE_account_free (&origin_account); -    TALER_WIRE_account_free (&destination_account); -    return NULL; -  } - -  eh = GNUNET_new (struct TALER_WIRE_ExecuteHandle); -  eh->cc = cc; -  eh->cc_cls = cc_cls; -  wire_s = GNUNET_STRINGS_data_to_string_alloc (&bf.wtid, -                                                sizeof (bf.wtid)); -  eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx, -                                            origin_account.details.x_taler_bank. -                                            bank_base_url, -                                            &auth, -                                            exchange_base_url, -                                            wire_s, -                                            &amount, -                                            (uint64_t) origin_account.details. -                                            x_taler_bank.no, -                                            (uint64_t) destination_account. -                                            details.x_taler_bank.no, -                                            &execute_cb, -                                            eh); -  TALER_WIRE_account_free (&origin_account); -  TALER_WIRE_account_free (&destination_account); -  GNUNET_free (wire_s); -  if (NULL == eh->aaih) -  { -    GNUNET_break (0); -    GNUNET_free (eh); -    return NULL; -  } -  return eh; -} - - -/** - * Abort execution of a wire transfer. For example, because we are - * shutting down.  Note that if an execution is aborted, it may or - * may not still succeed. The caller MUST run @e - * execute_wire_transfer again for the same request as soon as - * possilbe, to ensure that the request either ultimately succeeds - * or ultimately fails. Until this has been done, the transaction is - * in limbo (i.e. may or may not have been committed). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param eh execution to cancel - */ -static void -taler_bank_execute_wire_transfer_cancel (void *cls, -                                         struct TALER_WIRE_ExecuteHandle *eh) -{ -  (void) cls; -  TALER_BANK_admin_add_incoming_cancel (eh->aaih); -  GNUNET_free (eh); -} - - -/** - * Handle for a #taler_bank_get_history() request. - */ -struct TALER_WIRE_HistoryHandle -{ - -  /** -   * Function to call with results, can become NULL if the -   * application cancels the iteration. -   */ -  TALER_WIRE_HistoryResultCallback hres_cb; - -  /** -   * Closure for @e hres_cb. -   */ -  void *hres_cb_cls; - -  /** -   * Request to the bank. -   */ -  struct TALER_BANK_HistoryHandle *hh; - -  /** -   * Authentication to use for access. -   */ -  struct TALER_BANK_AuthenticationData auth; - -}; - - -/** - * Cancel going over the account's history. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param whh operation to cancel - */ -static void -taler_bank_get_history_cancel (void *cls, -                               struct TALER_WIRE_HistoryHandle *whh) -{ -  (void) cls; -  if (NULL != whh->hh) -  { -    TALER_BANK_history_cancel (whh->hh); -    whh->hh = NULL; -  } -  TALER_BANK_auth_free (&whh->auth); -  GNUNET_free (whh); -} - - -/** - * Function called with results from the bank - * about the transaction history. - * - * @param cls the `struct TALER_WIRE_HistoryHandle` - * @param http_status HTTP response code, #MHD_HTTP_OK (200) - *        for successful status request 0 if the bank's reply - *        is bogus (fails to follow the protocol), - *        #MHD_HTTP_NO_CONTENT if there are no more results; on - *        success the last callback is always of this status - *        (even if `abs(num_results)` were already returned). - * @param ec taler error code - * @param dir direction of the transfer - * @param serial_id monotonically increasing - *        counter corresponding to the transaction - * @param details details about the wire transfer - * @param json detailed response from the HTTPD, - *        or NULL if reply was not in JSON - */ -static void -bhist_cb (void *cls, -          unsigned int http_status, -          enum TALER_ErrorCode ec, -          enum TALER_BANK_Direction dir, -          uint64_t serial_id, -          const struct TALER_BANK_TransferDetails *details, -          const json_t *json) -{ -  struct TALER_WIRE_HistoryHandle *whh = cls; -  uint64_t bserial_id = GNUNET_htonll (serial_id); -  struct TALER_WIRE_TransferDetails wd; - -  (void) json; -  switch (http_status) -  { -  case MHD_HTTP_OK: -    { -      char *subject; -      char *space; - -      wd.amount = details->amount; -      wd.execution_date = details->execution_date; -      subject = GNUNET_strdup (details->wire_transfer_subject); -      space = strchr (subject, -                      (unsigned char) ' '); -      if (NULL != space) -      { -        /* Space separates the actual wire transfer subject -           from the exchange base URL (if present, expected -           only for outgoing transactions).  So we cut the -           string off at the space. */ -        *space = '\0'; -      } -      /* NOTE: For a real bank, the subject should include a -         checksum! */ -      if (GNUNET_OK != -          GNUNET_STRINGS_string_to_data (subject, -                                         strlen (subject), -                                         &wd.wtid, -                                         sizeof (wd.wtid))) -      { -        /* Ill-formed wire subject, set binary version to all zeros -           and pass as a string, this time including the part after -           the space. */ -        memset (&wd.wtid, -                0, -                sizeof (wd.wtid)); -        wd.wtid_s = details->wire_transfer_subject; -      } -      else -      { -        wd.wtid_s = NULL; -      } -      GNUNET_free (subject); -      wd.account_url = details->account_url; -      if ( (NULL != whh->hres_cb) && -           (GNUNET_OK != -            whh->hres_cb (whh->hres_cb_cls, -                          TALER_EC_NONE, -                          dir, -                          &bserial_id, -                          sizeof (bserial_id), -                          &wd)) ) -        whh->hres_cb = NULL; -      GNUNET_break (NULL != whh->hh); -      /* Once we get the sentinel element, the handle becomes invalid. */ -      if (TALER_BANK_DIRECTION_NONE == dir) -      { -        whh->hh = NULL; -        taler_bank_get_history_cancel (NULL, -                                       whh); -      } -      return; -    } -  case MHD_HTTP_NO_CONTENT: -    if (NULL != whh->hres_cb) -      (void) whh->hres_cb (whh->hres_cb_cls, -                           ec, -                           TALER_BANK_DIRECTION_NONE, -                           NULL, -                           0, -                           NULL); -    whh->hh = NULL; -    taler_bank_get_history_cancel (NULL, -                                   whh); -    return; -  default: -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Bank failed with HTTP status %u (EC: %u)\n", -                http_status, -                ec); -    if (NULL != whh->hres_cb) -      (void) whh->hres_cb (whh->hres_cb_cls, -                           ec, -                           TALER_BANK_DIRECTION_NONE, -                           NULL, -                           0, -                           NULL); -    whh->hh = NULL; -    taler_bank_get_history_cancel (NULL, -                                   whh); -    return; -  } -} - - -/** - * Query transfer history of an account.  We use the variable-size - * @a start_off to indicate which transfers we are interested in as - * different banking systems may have different ways to identify - * transfers.  The @a start_off value must thus match the value of - * a `row_off` argument previously given to the @a hres_cb.  Use - * NULL to query transfers from the beginning of time (with - * positive @a num_results) or from the lataler_bank committed - * transfers (with negative @a num_results). - * - * @param cls the @e cls of this struct with the plugin-specific - *        state - * @param account_section specifies the configuration section which - *        identifies the account for which we should get the history - * @param direction what kinds of wire transfers should be returned - * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive - * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`. - * @param num_results how many results do we want; negative numbers to go into the past, - *                    positive numbers to go into the future starting at @a start_row; - *                    must not be zero. - * @param hres_cb the callback to call with the transaction history - * @param hres_cb_cls closure for the above callback - */ -static struct TALER_WIRE_HistoryHandle * -taler_bank_get_history (void *cls, -                        const char *account_section, -                        enum TALER_BANK_Direction direction, -                        const void *start_off, -                        size_t start_off_len, -                        int64_t num_results, -                        TALER_WIRE_HistoryResultCallback hres_cb, -                        void *hres_cb_cls) -{ -  struct TalerBankClosure *tc = cls; -  struct TALER_WIRE_HistoryHandle *whh; -  const uint64_t *start_off_b64; -  uint64_t start_row; -  struct TALER_Account account; - -  GNUNET_assert (NULL != hres_cb); -  if (0 == num_results) -  { -    GNUNET_break (0); -    return NULL; -  } -  if (TALER_BANK_DIRECTION_NONE == direction) -  { -    GNUNET_break (0); -    return NULL; -  } -  if ( (NULL != start_off) && -       (sizeof (uint64_t) != start_off_len) ) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Wire plugin 'taler_bank' got" -                " start offset of wrong size (%llu" -                " instead of %llu)\n", -                (unsigned long long) start_off_len, -                (unsigned long long) sizeof (uint64_t)); -    GNUNET_break (0); - -    /** -     * Probably something is wrong with the DB, some -     * other component wrote a wrong value to it.  Instead -     * of completely stopping to work, we just scan from the -     * beginning. */start_off = NULL; -  } -  if (NULL == start_off) -  { -    start_row = UINT64_MAX; /* no start row */ -  } -  else -  { -    start_off_b64 = start_off; -    start_row = GNUNET_ntohll (*start_off_b64); -  } -  if (GNUNET_OK != -      parse_account_cfg (tc->cfg, -                         account_section, -                         &account)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Could not parse the config section '%s'\n", -                account_section); -    return NULL; -  } - -  whh = GNUNET_new (struct TALER_WIRE_HistoryHandle); -  if (GNUNET_OK != -      TALER_BANK_auth_parse_cfg (tc->cfg, -                                 account_section, -                                 &whh->auth)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                "Could not parse the auth values from '%s'\n", -                account_section); -    TALER_WIRE_account_free (&account); -    GNUNET_free (whh); -    return NULL; -  } -  whh->hres_cb = hres_cb; -  whh->hres_cb_cls = hres_cb_cls; -  whh->hh = TALER_BANK_history (tc->ctx, -                                account.details.x_taler_bank.bank_base_url, -                                &whh->auth, -                                (uint64_t) account.details.x_taler_bank.no, -                                direction, -                                /* Defaults to descending ordering always. */ -                                GNUNET_NO, -                                start_row, -                                num_results, -                                &bhist_cb, -                                whh); -  if (NULL == whh->hh) -  { -    GNUNET_break (0); -    taler_bank_get_history_cancel (tc, -                                   whh); -    TALER_WIRE_account_free (&account); -    return NULL; -  } -  TALER_WIRE_account_free (&account); -  return whh; -} - - -/** - * Context for a rejection operation. - */ -struct TALER_WIRE_RejectHandle -{ -  /** -   * Function to call with the result. -   */ -  TALER_WIRE_RejectTransferCallback rej_cb; - -  /** -   * Closure for @e rej_cb. -   */ -  void *rej_cb_cls; - -  /** -   * Handle for the reject operation. -   */ -  struct TALER_BANK_RejectHandle *brh; - -  /** -   * Authentication information to use. -   */ -  struct TALER_BANK_AuthenticationData auth; -}; - - -/** - * Callbacks of this type are used to serve the result of asking - * the bank to reject an incoming wire transfer. - * - * @param cls closure - * @param http_status HTTP response code, #MHD_HTTP_NO_CONTENT (204) for successful status request; - *                    #MHD_HTTP_NOT_FOUND if the rowid is unknown; - *                    0 if the bank's reply is bogus (fails to follow the protocol), - * @param ec detailed error code - */ -static void -reject_cb (void *cls, -           unsigned int http_status, -           enum TALER_ErrorCode ec) -{ -  struct TALER_WIRE_RejectHandle *rh = cls; - -  (void) http_status; -  rh->brh = NULL; -  rh->rej_cb (rh->rej_cb_cls, -              ec); -  GNUNET_free (rh); -} - - -/** - * Cancel ongoing reject operation.  Note that the rejection may still - * proceed. Basically, if this function is called, the rejection may - * have happened or not.  This function is usually used during shutdown - * or system upgrades.  At a later point, the application must call - * @e reject_transfer again for this wire transfer, unless the - * @e get_history shows that the wire transfer no longer exists. - * - * @param cls plugins' closure - * @param rh operation to cancel - * @return closure of the callback of the operation - */ -static void * -taler_bank_reject_transfer_cancel (void *cls, -                                   struct TALER_WIRE_RejectHandle *rh) -{ -  void *ret = rh->rej_cb_cls; - -  (void) cls; -  if (NULL != rh->brh) -    TALER_BANK_reject_cancel (rh->brh); -  TALER_BANK_auth_free (&rh->auth); -  GNUNET_free (rh); -  return ret; -} - - -/** - * Reject an incoming wire transfer that was obtained from the - * history. This function can be used to transfer funds back to - * the sender if the WTID was malformed (i.e. due to a typo). - * - * Calling `reject_transfer` twice on the same wire transfer should - * be idempotent, i.e. not cause the funds to be wired back twice. - * Furthermore, the transfer should henceforth be removed from the - * results returned by @e get_history. - * - * @param cls plugin's closure - * @param account_section specifies the configuration section which - *        identifies the account to use to reject the transfer - * @param start_off offset of the wire transfer in plugin-specific format - * @param start_off_len number of bytes in @a start_off - * @param rej_cb function to call with the result of the operation - * @param rej_cb_cls closure for @a rej_cb - * @return handle to cancel the operation - */ -static struct TALER_WIRE_RejectHandle * -taler_bank_reject_transfer (void *cls, -                            const char *account_section, -                            const void *start_off, -                            size_t start_off_len, -                            TALER_WIRE_RejectTransferCallback rej_cb, -                            void *rej_cb_cls) -{ -  struct TalerBankClosure *tc = cls; -  const uint64_t *rowid_b64 = start_off; -  struct TALER_WIRE_RejectHandle *rh; -  struct TALER_Account account; - -  if (sizeof (uint64_t) != start_off_len) -  { -    GNUNET_break (0); -    return NULL; -  } -  rh = GNUNET_new (struct TALER_WIRE_RejectHandle); -  if (GNUNET_OK != -      TALER_BANK_auth_parse_cfg (tc->cfg, -                                 account_section, -                                 &rh->auth)) -  { -    GNUNET_free (rh); -    return NULL; -  } -  if (GNUNET_OK != -      parse_account_cfg (tc->cfg, -                         account_section, -                         &account)) -  { -    (void) taler_bank_reject_transfer_cancel (tc, -                                              rh); -    return NULL; -  } -  rh->rej_cb = rej_cb; -  rh->rej_cb_cls = rej_cb_cls; -  TALER_LOG_INFO ("Rejecting over %s bank URL\n", -                  account.details.x_taler_bank.hostname); -  rh->brh = TALER_BANK_reject (tc->ctx, -                               account.details.x_taler_bank.bank_base_url, -                               &rh->auth, -                               (uint64_t) account.details.x_taler_bank.no, -                               GNUNET_ntohll (*rowid_b64), -                               &reject_cb, -                               rh); -  if (NULL == rh->brh) -  { -    (void) taler_bank_reject_transfer_cancel (tc, -                                              rh); -    TALER_WIRE_account_free (&account); -    return NULL; -  } -  TALER_WIRE_account_free (&account); -  return rh; -} - - -/** - * Initialize taler_bank-wire subsystem. - * - * @param cls a configuration instance - * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin` - */ -void * -libtaler_plugin_wire_taler_bank_init (void *cls) -{ -  struct GNUNET_CONFIGURATION_Handle *cfg = cls; -  struct TalerBankClosure *tc; -  struct TALER_WIRE_Plugin *plugin; - -  tc = GNUNET_new (struct TalerBankClosure); -  tc->cfg = cfg; -  if (GNUNET_OK != -      GNUNET_CONFIGURATION_get_value_string (cfg, -                                             "taler", -                                             "CURRENCY", -                                             &tc->currency)) -  { -    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                               "taler", -                               "CURRENCY"); -    GNUNET_free (tc); -    return NULL; -  } -  tc->ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule, -                              &tc->rc); -  tc->rc = GNUNET_CURL_gnunet_rc_create (tc->ctx); -  if (NULL == tc->ctx) -  { -    GNUNET_break (0); -    GNUNET_free (tc->currency); -    GNUNET_free (tc); -    return NULL; -  } -  plugin = GNUNET_new (struct TALER_WIRE_Plugin); -  plugin->cls = tc; -  plugin->method = "x-taler-bank"; -  plugin->amount_round = &taler_bank_amount_round; -  plugin->wire_validate = &taler_bank_wire_validate; -  plugin->prepare_wire_transfer = &taler_bank_prepare_wire_transfer; -  plugin->prepare_wire_transfer_cancel = -    &taler_bank_prepare_wire_transfer_cancel; -  plugin->execute_wire_transfer = &taler_bank_execute_wire_transfer; -  plugin->execute_wire_transfer_cancel = -    &taler_bank_execute_wire_transfer_cancel; -  plugin->get_history = &taler_bank_get_history; -  plugin->get_history_cancel = &taler_bank_get_history_cancel; -  plugin->reject_transfer = &taler_bank_reject_transfer; -  plugin->reject_transfer_cancel = &taler_bank_reject_transfer_cancel; -  return plugin; -} - - -/** - * Shutdown taler-bank wire subsystem. - * - * @param cls a `struct TALER_WIRE_Plugin` - * @return NULL (always) - */ -void * -libtaler_plugin_wire_taler_bank_done (void *cls) -{ -  struct TALER_WIRE_Plugin *plugin = cls; -  struct TalerBankClosure *tc = plugin->cls; - -  if (NULL != tc->ctx) -  { -    GNUNET_CURL_fini (tc->ctx); -    tc->ctx = NULL; -  } -  if (NULL != tc->rc) -  { -    GNUNET_CURL_gnunet_rc_destroy (tc->rc); -    tc->rc = NULL; -  } -  GNUNET_free_non_null (tc->currency); -  GNUNET_free (tc); -  GNUNET_free (plugin); -  return NULL; -} - - -/* end of plugin_wire_taler-bank.c */ diff --git a/src/wire-plugins/plugin_wire_template.c b/src/wire-plugins/plugin_wire_template.c deleted file mode 100644 index 731885ac..00000000 --- a/src/wire-plugins/plugin_wire_template.c +++ /dev/null @@ -1,384 +0,0 @@ -/* -  This file is part of TALER -  Copyright (C) 2016, 2018 GNUnet e.V. - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file plugin_wire_template.c - * @brief template for wire plugins; replace "template" with real plugin name! - * @author Florian Dold - * @author Christian Grothoff - * @author Sree Harsha Totakura - */ -#include "platform.h" -#include "taler_wire_plugin.h" - - -/** - * Type of the "cls" argument given to each of the functions in - * our API. - */ -struct TemplateClosure -{ - -  /** -   * Which currency do we support? -   */ -  char *currency; - -  /** -   * Which configuration do we use to lookup accounts? -   */ -  struct GNUNET_CONFIGURATION_Handle *cfg; - -}; - - -/** - * Round amount DOWN to the amount that can be transferred via the wire - * method.  For example, Taler may support 0.000001 EUR as a unit of - * payment, but SEPA only supports 0.01 EUR.  This function would - * round 0.125 EUR to 0.12 EUR in this case. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param[in,out] amount amount to round down - * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, - *         #GNUNET_SYSERR if the amount or currency was invalid - */ -static int -template_amount_round (void *cls, -                       struct TALER_Amount *amount) -{ -  struct TemplateClosure *tc = cls; - -  if (0 != strcasecmp (amount->currency, -                       tc->currency)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  GNUNET_break (0); // not implemented -  return GNUNET_SYSERR; -} - - -/** - * Check if the given payto:// URL is correctly formatted for this plugin - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param account_url the payto:// URL - * @return #TALER_EC_NONE if correctly formatted - */ -static enum TALER_ErrorCode -template_wire_validate (void *cls, -                        const char *account_url) -{ -  (void) cls; -  (void) account_url; -  GNUNET_break (0); -  return TALER_EC_NOT_IMPLEMENTED; -} - - -/** - * Prepare for exeuction of a wire transfer. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param origin_account_section configuration section specifying the origin - *        account of the exchange to use - * @param destination_account_url payto:// URL identifying where to send the money - * @param amount amount to transfer, already rounded - * @param exchange_base_url base URL of the exchange (for tracking) - * @param wtid wire transfer identifier to use - * @param ptc function to call with the prepared data to persist - * @param ptc_cls closure for @a ptc - * @return NULL on failure - */ -static struct TALER_WIRE_PrepareHandle * -template_prepare_wire_transfer (void *cls, -                                const char *origin_account_section, -                                const char *destination_account_url, -                                const struct TALER_Amount *amount, -                                const char *exchange_base_url, -                                const struct -                                TALER_WireTransferIdentifierRawP *wtid, -                                TALER_WIRE_PrepareTransactionCallback ptc, -                                void *ptc_cls) -{ -  (void) cls; -  (void) origin_account_section; -  (void) destination_account_url; -  (void) amount; -  (void) exchange_base_url; -  (void) wtid; -  (void) ptc; -  (void) ptc_cls; -  GNUNET_break (0); -  return NULL; -} - - -/** - * Abort preparation of a wire transfer. For example, - * because we are shutting down. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param pth preparation to cancel - */ -static void -template_prepare_wire_transfer_cancel (void *cls, -                                       struct TALER_WIRE_PrepareHandle *pth) -{ -  (void) cls; -  (void) pth; -  GNUNET_break (0); -} - - -/** - * Execute a wire transfer. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param buf buffer with the prepared execution details - * @param buf_size number of bytes in @a buf - * @param cc function to call upon success - * @param cc_cls closure for @a cc - * @return NULL on error - */ -static struct TALER_WIRE_ExecuteHandle * -template_execute_wire_transfer (void *cls, -                                const char *buf, -                                size_t buf_size, -                                TALER_WIRE_ConfirmationCallback cc, -                                void *cc_cls) -{ -  (void) cls; -  (void) buf; -  (void) buf_size; -  (void) cc; -  (void) cc_cls; -  GNUNET_break (0); -  return NULL; -} - - -/** - * Abort execution of a wire transfer. For example, because we are - * shutting down.  Note that if an execution is aborted, it may or - * may not still succeed. The caller MUST run @e - * execute_wire_transfer again for the same request as soon as - * possilbe, to ensure that the request either ultimately succeeds - * or ultimately fails. Until this has been done, the transaction is - * in limbo (i.e. may or may not have been committed). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param eh execution to cancel - */ -static void -template_execute_wire_transfer_cancel (void *cls, -                                       struct TALER_WIRE_ExecuteHandle *eh) -{ -  (void) cls; -  (void) eh; -  GNUNET_break (0); -} - - -/** - * Query transfer history of an account.  We use the variable-size - * @a start_off to indicate which transfers we are interested in as - * different banking systems may have different ways to identify - * transfers.  The @a start_off value must thus match the value of - * a `row_off` argument previously given to the @a hres_cb.  Use - * NULL to query transfers from the beginning of time (with - * positive @a num_results) or from the latest committed transfers - * (with negative @a num_results). - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param account_section specifies the configuration section which - *        identifies the account for which we should get the history - * @param direction what kinds of wire transfers should be returned - * @param start_off from which row on do we want to get results, use NULL for the latest; exclusive - * @param start_off_len number of bytes in @a start_off; must be `sizeof(uint64_t)`. - * @param num_results how many results do we want; negative numbers to go into the past, - *                    positive numbers to go into the future starting at @a start_row; - *                    must not be zero. - * @param hres_cb the callback to call with the transaction history - * @param hres_cb_cls closure for the above callback - */ -static struct TALER_WIRE_HistoryHandle * -template_get_history (void *cls, -                      const char *account_section, -                      enum TALER_BANK_Direction direction, -                      const void *start_off, -                      size_t start_off_len, -                      int64_t num_results, -                      TALER_WIRE_HistoryResultCallback hres_cb, -                      void *hres_cb_cls) -{ -  (void) cls; -  (void) account_section; -  (void) direction; -  (void) start_off; -  (void) start_off_len; -  (void) num_results; -  (void) hres_cb; -  (void) hres_cb_cls; -  GNUNET_break (0); -  return NULL; -} - - -/** - * Cancel going over the account's history. - * - * @param cls the @e cls of this struct with the plugin-specific state - * @param whh operation to cancel - */ -static void -template_get_history_cancel (void *cls, -                             struct TALER_WIRE_HistoryHandle *whh) -{ -  (void) cls; -  (void) whh; -  GNUNET_break (0); -} - - -/** - * Reject an incoming wire transfer that was obtained from the - * history. This function can be used to transfer funds back to - * the sender if the WTID was malformed (i.e. due to a typo). - * - * Calling `reject_transfer` twice on the same wire transfer should - * be idempotent, i.e. not cause the funds to be wired back twice. - * Furthermore, the transfer should henceforth be removed from the - * results returned by @e get_history. - * - * @param cls plugin's closure - * @param account_section specifies the configuration section which - *        identifies the account to use to reject the transfer - * @param start_off offset of the wire transfer in plugin-specific format - * @param start_off_len number of bytes in @a start_off - * @param rej_cb function to call with the result of the operation - * @param rej_cb_cls closure for @a rej_cb - * @return handle to cancel the operation - */ -static struct TALER_WIRE_RejectHandle * -template_reject_transfer (void *cls, -                          const char *account_section, -                          const void *start_off, -                          size_t start_off_len, -                          TALER_WIRE_RejectTransferCallback rej_cb, -                          void *rej_cb_cls) -{ -  (void) cls; -  (void) account_section; -  (void) start_off; -  (void) start_off_len; -  (void) rej_cb; -  (void) rej_cb_cls; -  GNUNET_break (0); -  return NULL; -} - - -/** - * Cancel ongoing reject operation.  Note that the rejection may still - * proceed. Basically, if this function is called, the rejection may - * have happened or not.  This function is usually used during shutdown - * or system upgrades.  At a later point, the application must call - * @e reject_transfer again for this wire transfer, unless the - * @e get_history shows that the wire transfer no longer exists. - * - * @param cls plugins' closure - * @param rh operation to cancel - * @return closure of the callback of the operation - */ -static void * -template_reject_transfer_cancel (void *cls, -                                 struct TALER_WIRE_RejectHandle *rh) -{ -  (void) cls; -  (void) rh; -  GNUNET_break (0); -  return NULL; -} - - -/** - * Initialize template-wire subsystem. - * - * @param cls a configuration instance - * @return NULL on error, otherwise a `struct TALER_WIRE_Plugin` - */ -void * -libtaler_plugin_wire_template_init (void *cls) -{ -  struct GNUNET_CONFIGURATION_Handle *cfg = cls; -  struct TemplateClosure *tc; -  struct TALER_WIRE_Plugin *plugin; - -  tc = GNUNET_new (struct TemplateClosure); -  tc->cfg = cfg; -  if (GNUNET_OK != -      GNUNET_CONFIGURATION_get_value_string (cfg, -                                             "taler", -                                             "CURRENCY", -                                             &tc->currency)) -  { -    GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, -                               "taler", -                               "CURRENCY"); -    GNUNET_free (tc); -    return NULL; -  } - -  plugin = GNUNET_new (struct TALER_WIRE_Plugin); -  plugin->cls = tc; -  plugin->method = "FIXME-REPLACE-BY-METHOD"; -  plugin->amount_round = &template_amount_round; -  plugin->wire_validate = &template_wire_validate; -  plugin->prepare_wire_transfer = &template_prepare_wire_transfer; -  plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel; -  plugin->execute_wire_transfer = &template_execute_wire_transfer; -  plugin->execute_wire_transfer_cancel = &template_execute_wire_transfer_cancel; -  plugin->get_history = &template_get_history; -  plugin->get_history_cancel = &template_get_history_cancel; -  plugin->reject_transfer = &template_reject_transfer; -  plugin->reject_transfer_cancel = &template_reject_transfer_cancel; -  return plugin; -} - - -/** - * Shutdown Template wire subsystem. - * - * @param cls a `struct TALER_WIRE_Plugin` - * @return NULL (always) - */ -void * -libtaler_plugin_wire_template_done (void *cls) -{ -  struct TALER_WIRE_Plugin *plugin = cls; -  struct TemplateClosure *tc = plugin->cls; - -  GNUNET_free (tc->currency); -  GNUNET_free (tc); -  GNUNET_free (plugin); -  return NULL; -} - - -/* end of plugin_wire_template.c */ diff --git a/src/wire-plugins/test_wire_plugin.c b/src/wire-plugins/test_wire_plugin.c deleted file mode 100644 index 65867113..00000000 --- a/src/wire-plugins/test_wire_plugin.c +++ /dev/null @@ -1,189 +0,0 @@ -/* -  This file is part of TALER -  (C) 2015, 2016, 2017 GNUnet e.V. and Inria - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file wire/test_wire_plugin.c - * @brief Tests for wire plugins - * @author Christian Grothoff - * @author Sree Harsha Totakura <sreeharsha@totakura.in> - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_wire_lib.h" -#include "taler_wire_plugin.h" -#include <gnunet/gnunet_json_lib.h> - - -/** - * Definitions for a test with a plugin. - */ -struct TestBlock -{ - -  /** -   * Name of the plugin to test. -   */ -  const char *plugin_name; - -  /** -   * Amount to give to the rounding function. -   */ -  const char *round_in; - -  /** -   * Expected result from rounding. -   */ -  const char *round_out; - -  /** -   * Currency to give to the plugin. -   */ -  const char *currency; -}; - - -/** - * List of plugins and (unsigned) JSON account definitions - * to use for the tests. - */ -static struct TestBlock tests[] = { -#if HAVE_LIBCURL -  { -    .plugin_name = "taler_bank", -    .round_in = "KUDOS:0.123456", -    .round_out = "KUDOS:0.12", -    .currency = "KUDOS" -  }, -#endif -  { -    NULL, NULL, NULL, NULL -  } -}; - - -/** - * Our configuration. - */ -static struct GNUNET_CONFIGURATION_Handle *cfg; - - -/** - * Run the test. - * - * @param test details of the test - * @param plugin plugin to test - * @return #GNUNET_OK on success - */ -static int -run_test (const struct TestBlock *test, -          struct TALER_WIRE_Plugin *plugin) -{ -  struct GNUNET_HashCode salt; -  struct TALER_Amount in; -  struct TALER_Amount expect; - -  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, -                              &salt, -                              sizeof (salt)); -  GNUNET_assert (GNUNET_OK == -                 TALER_string_to_amount (test->round_in, -                                         &in)); -  GNUNET_assert (GNUNET_OK == -                 TALER_string_to_amount (test->round_out, -                                         &expect)); -  if (GNUNET_OK != -      plugin->amount_round (plugin->cls, -                            &in)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  if (0 != TALER_amount_cmp (&in, &expect)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  if (GNUNET_NO != -      plugin->amount_round (plugin->cls, -                            &in)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  memset (&in, 0, sizeof (in)); -  GNUNET_log_skip (GNUNET_ERROR_TYPE_ERROR, 1); -  if (GNUNET_SYSERR != -      plugin->amount_round (plugin->cls, -                            &in)) -  { -    GNUNET_break (0); -    return GNUNET_SYSERR; -  } -  return GNUNET_OK; -} - - -int -main (int argc, -      const char *const argv[]) -{ -  int ret; -  struct TALER_WIRE_Plugin *plugin; -  const struct TestBlock *test; - -  GNUNET_log_setup ("test-wire-plugin", -                    "WARNING", -                    NULL); -  cfg = GNUNET_CONFIGURATION_create (); -  GNUNET_assert (GNUNET_OK == -                 GNUNET_CONFIGURATION_load (cfg, -                                            "test_wire_plugin.conf")); -  ret = GNUNET_OK; -  for (unsigned int i = 0; NULL != (test = &tests[i])->plugin_name; i++) -  { -    GNUNET_CONFIGURATION_set_value_string (cfg, -                                           "taler", -                                           "CURRENCY", -                                           test->currency); -    plugin = TALER_WIRE_plugin_load (cfg, -                                     test->plugin_name); -    if (NULL == plugin) -    { -      TALER_LOG_ERROR ("Could not load plugin `%s'\n", -                       test->plugin_name); -      return 77; -    } - -    ret = run_test (test, plugin); -    TALER_WIRE_plugin_unload (plugin); -    if (GNUNET_OK != ret) -    { -      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, -                  "%s FAILED\n", -                  test->plugin_name); -      break; -    } -    else -    { -      GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, -                  "%s PASS\n", -                  test->plugin_name); -    } -  } -  GNUNET_CONFIGURATION_destroy (cfg); -  if (GNUNET_OK != ret) -    return 1; -  return 0; -} diff --git a/src/wire-plugins/test_wire_plugin.conf b/src/wire-plugins/test_wire_plugin.conf deleted file mode 100644 index d1d699b0..00000000 --- a/src/wire-plugins/test_wire_plugin.conf +++ /dev/null @@ -1,25 +0,0 @@ -# This file is in the public domain. -# -[account-taler-bank] -# This is the response we give out for the /wire request.  It provides -# wallets with the bank information for transfers to the exchange. -WIRE_JSON = test_wire_plugin_test.json - -# Our bank account URL -URL = payto://x-taler-bank/2 - -# Which wire plugin should we used to access the account? -PLUGIN = taler_bank - - -[account-sepa] -# This is the response we give out for the /wire request.  It provides -# wallets with the bank information for transfers to the exchange. -WIRE_JSON = test_wire_plugin_sepa.json - -# Which wire plugin should we used to access the account? -PLUGIN = ebics - - -[taler] -CURRENCY = "EUR" diff --git a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c deleted file mode 100644 index 79700818..00000000 --- a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c +++ /dev/null @@ -1,365 +0,0 @@ -/* -  This file is part of TALER -  (C) 2015-2018 Taler Systems SA - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> -*/ -/** - * @file wire/test_wire_plugin_transactions_taler-bank.c - * @brief Tests performing actual transactions with the taler-bank wire plugin against FAKEBANK - * @author Christian Grothoff - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_wire_lib.h" -#include "taler_wire_plugin.h" -#include "taler_fakebank_lib.h" -#include <gnunet/gnunet_json_lib.h> - - -/** - * When does the test timeout? Right now, we expect this to be very - * fast. - */ -#define TIMEOUT GNUNET_TIME_UNIT_SECONDS - - -/** - * Destination account to use. - */ -static const char *dest_account = "payto://x-taler-bank/localhost:8088/42"; - -/** - * Origin account, section in the configuration file. - */ -static const char *my_account = "account-test"; - -/** - * Our configuration. - */ -static struct GNUNET_CONFIGURATION_Handle *cfg; - -/** - * Set to #GNUNET_SYSERR if the test failed. - */ -static int global_ret; - -/** - * The 'test' plugin that we are using for the test. - */ -static struct TALER_WIRE_Plugin *plugin; - -/** - * Active preparation handle, or NULL if not active. - */ -static struct TALER_WIRE_PrepareHandle *ph; - -/** - * Active execution handle, or NULL if not active. - */ -static struct TALER_WIRE_ExecuteHandle *eh; - -/** - * Handle to the bank. - */ -static struct TALER_FAKEBANK_Handle *fb; - -/** - * Handle to the history request. - */ -static struct TALER_WIRE_HistoryHandle *hh; - -/** - * Handle to the history-range request (the "legacy" bank API). - */ -static struct TALER_WIRE_HistoryHandle *hhr; - -/** - * Handle for the timeout task. - */ -static struct GNUNET_SCHEDULER_Task *tt; - -/** - * Which serial ID do we expect to get from /history? - */ -static uint64_t serial_target; - -/** - * Wire transfer identifier we are using. - */ -static struct TALER_WireTransferIdentifierRawP wtid; - - -/** - * Function called on shutdown (regular, error or CTRL-C). - * - * @param cls NULL - */ -static void -do_shutdown (void *cls) -{ -  (void) cls; -  TALER_FAKEBANK_stop (fb); -  fb = NULL; -  if (NULL != eh) -  { -    plugin->execute_wire_transfer_cancel (plugin->cls, -                                          eh); -    eh = NULL; -  } -  if (NULL != ph) -  { -    plugin->prepare_wire_transfer_cancel (plugin->cls, -                                          ph); -    ph = NULL; -  } -  if (NULL != hh) -  { -    plugin->get_history_cancel (plugin->cls, -                                hh); -    hh = NULL; -  } - -  if (NULL != hhr) -  { -    plugin->get_history_cancel (plugin->cls, -                                hhr); -    hhr = NULL; -  } - -  if (NULL != tt) -  { -    GNUNET_SCHEDULER_cancel (tt); -    tt = NULL; -  } -  TALER_WIRE_plugin_unload (plugin); -} - - -/** - * Function called on timeout. - * - * @param cls NULL - */ -static void -timeout_cb (void *cls) -{ -  tt = NULL; -  GNUNET_break (0); -  global_ret = GNUNET_SYSERR; -  GNUNET_SCHEDULER_shutdown (); -} - - -/** - * Callbacks of this type are used to serve the result of asking - * the bank for the transaction history. - * - * @param cls closure - * @param ec taler status code - * @param dir direction of the transfer - * @param row_off identification of the position at - *        which we are querying - * @param row_off_size number of bytes in @a row_off - * @param details details about the wire transfer - * @return #GNUNET_OK to continue, #GNUNET_SYSERR to - *         abort iteration - */ -static int -history_result_cb -  (void *cls, -  enum TALER_ErrorCode ec, -  enum TALER_BANK_Direction dir, -  const void *row_off, -  size_t row_off_size, -  const struct TALER_WIRE_TransferDetails *details) -{ -  uint64_t *serialp; -  uint64_t serialh; -  struct TALER_Amount amount; - -  if ( (TALER_BANK_DIRECTION_NONE == dir) && -       (GNUNET_OK == global_ret) ) -  { -    GNUNET_SCHEDULER_shutdown (); -    hh = NULL; -    return GNUNET_OK; -  } -  if (sizeof (uint64_t) != row_off_size) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  serialp = (uint64_t *) row_off; -  serialh = GNUNET_ntohll (*serialp); -  if (serialh != serial_target) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  GNUNET_assert (GNUNET_OK == -                 TALER_string_to_amount ("KUDOS:5.01", -                                         &amount)); -  if (0 != TALER_amount_cmp (&amount, -                             &details->amount)) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  if (0 != GNUNET_memcmp (&wtid, -                          &details->wtid)) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return GNUNET_SYSERR; -  } -  global_ret = GNUNET_OK; -  return GNUNET_OK; -} - - -/** - * Function called with the result from the execute step. - * - * @param cls closure - * @param success #GNUNET_OK on success, - *        #GNUNET_SYSERR on failure - * @param row_id ID of the fresh transaction, - *        in _network_ byte order. - * @param emsg NULL on success, otherwise an error message - */ -static void -confirmation_cb (void *cls, -                 int success, -                 const void *row_id, -                 size_t row_id_size, -                 const char *emsg) -{ -  uint64_t tmp; - -  eh = NULL; -  if (GNUNET_OK != success) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return; -  } -  memcpy (&tmp, -          row_id, -          row_id_size); -  serial_target = GNUNET_ntohll (tmp); -  hh = plugin->get_history (plugin->cls, -                            my_account, -                            TALER_BANK_DIRECTION_BOTH, -                            NULL, -                            0, -                            5, -                            &history_result_cb, -                            NULL); -} - - -/** - * Callback with prepared transaction. - * - * @param cls closure - * @param buf transaction data to persist, NULL on error - * @param buf_size number of bytes in @a buf, 0 on error - */ -static void -prepare_cb (void *cls, -            const char *buf, -            size_t buf_size) -{ -  ph = NULL; -  if (NULL == buf) -  { -    GNUNET_break (0); -    global_ret = GNUNET_SYSERR; -    GNUNET_SCHEDULER_shutdown (); -    return; -  } -  plugin->execute_wire_transfer (plugin->cls, -                                 buf, -                                 buf_size, -                                 &confirmation_cb, -                                 NULL); -} - - -/** - * Run the test. - * - * @param cls NULL - */ -static void -run (void *cls) -{ -  struct TALER_Amount amount; - -  GNUNET_SCHEDULER_add_shutdown (&do_shutdown, -                                 NULL); -  tt = GNUNET_SCHEDULER_add_delayed (TIMEOUT, -                                     &timeout_cb, -                                     NULL); -  GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, -                              &wtid, -                              sizeof (wtid)); -  GNUNET_assert (GNUNET_OK == -                 TALER_string_to_amount ("KUDOS:5.01", -                                         &amount)); -  fb = TALER_FAKEBANK_start (8088); -  ph = plugin->prepare_wire_transfer (plugin->cls, -                                      my_account, -                                      dest_account, -                                      &amount, -                                      "https://exchange.net/", -                                      &wtid, -                                      &prepare_cb, -                                      NULL); -} - - -int -main (int argc, -      const char *const argv[]) -{ - -  GNUNET_log_setup ("test-wire-plugin-transactions-test", -                    "WARNING", -                    NULL); -  cfg = GNUNET_CONFIGURATION_create (); -  GNUNET_assert (GNUNET_OK == -                 GNUNET_CONFIGURATION_load (cfg, -                                            "test_wire_plugin_transactions_taler-bank.conf")); -  global_ret = GNUNET_OK; -  plugin = TALER_WIRE_plugin_load (cfg, -                                   "taler_bank"); -  GNUNET_assert (NULL != plugin); -  GNUNET_SCHEDULER_run (&run, -                        NULL); -  GNUNET_CONFIGURATION_destroy (cfg); -  if (GNUNET_OK != global_ret) -    return 1; -  return 0; -} - - -/* end of test_wire_plugin_transactions_taler-bank.c */ diff --git a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.conf b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.conf deleted file mode 100644 index d6d2e834..00000000 --- a/src/wire-plugins/test_wire_plugin_transactions_taler-bank.conf +++ /dev/null @@ -1,12 +0,0 @@ -# This file is in the public domain. -# -[account-test] -# This is the response we give out for the /wire request.  It provides -# wallets with the bank information for transfers to the exchange. - -TALER_BANK_AUTH_METHOD = NONE - -URL = payto://x-taler-bank/localhost:8088/2 - -[taler] -CURRENCY = "KUDOS" diff --git a/src/wire/Makefile.am b/src/wire/Makefile.am index 6bf38aa2..2a82282a 100644 --- a/src/wire/Makefile.am +++ b/src/wire/Makefile.am @@ -13,7 +13,6 @@ lib_LTLIBRARIES = \  libtalerwire_la_SOURCES = \    payto.c \ -  wire.c \    wire_helper.c  libtalerwire_la_LIBADD = \    -lgnunetutil \ diff --git a/src/wire/payto.c b/src/wire/payto.c index 74154977..0c3fce95 100644 --- a/src/wire/payto.c +++ b/src/wire/payto.c @@ -20,6 +20,7 @@   */  #include "platform.h"  #include "taler_util.h" +#include "taler_bank_service.h"  #include "taler_wire_lib.h"  /** @@ -43,8 +44,8 @@ TALER_WIRE_account_free (struct TALER_Account *acc)    case TALER_PAC_X_TALER_BANK:      GNUNET_free (acc->details.x_taler_bank.hostname);      acc->details.x_taler_bank.hostname = NULL; -    GNUNET_free (acc->details.x_taler_bank.bank_base_url); -    acc->details.x_taler_bank.bank_base_url = NULL; +    GNUNET_free (acc->details.x_taler_bank.account_base_url); +    acc->details.x_taler_bank.account_base_url = NULL;      break;    case TALER_PAC_IBAN:      GNUNET_free (acc->details.iban.number); @@ -410,7 +411,8 @@ parse_payto_x_taler_bank (const char *account_url,    const char *hostname;    const char *account;    const char *q; -  unsigned long long no; +  unsigned int port; +  char *p;  #define PREFIX "payto://x-taler-bank/"    if (0 != strncasecmp (account_url, @@ -422,74 +424,52 @@ parse_payto_x_taler_bank (const char *account_url,                                   (unsigned char) '/')))      return TALER_EC_PAYTO_MALFORMED;    account++; -  if (NULL != (q = strchr (account, -                           (unsigned char) '?'))) +  if (NULL == r_account) +    return TALER_EC_NONE; +  q = strchr (account, +              (unsigned char) '?'); +  if (0 == q) +    q = account + strlen (account); +  r_account->details.x_taler_bank.hostname +    = GNUNET_strndup (hostname, +                      account - hostname); +  port = 443; /* if non given, equals 443.  */ +  if (NULL != (p = strchr (r_account->details.x_taler_bank.hostname, +                           (unsigned char) ':')))    { -    char *s; - -    s = GNUNET_strndup (account, -                        q - account); -    if (1 != sscanf (s, -                     "%llu", -                     &no)) +    p++; +    if (1 != sscanf (p, +                     "%u", +                     &port))      { -      GNUNET_free (s); +      GNUNET_break (0); +      TALER_LOG_ERROR ("Malformed host from payto:// URI\n"); +      GNUNET_free (r_account->details.x_taler_bank.hostname); +      r_account->details.x_taler_bank.hostname = NULL;        return TALER_EC_PAYTO_MALFORMED;      } -    GNUNET_free (s);    } -  else if (1 != sscanf (account, -                        "%llu", -                        &no)) +  if (443 != port)    { -    return TALER_EC_PAYTO_MALFORMED; +    GNUNET_assert +      (GNUNET_SYSERR != GNUNET_asprintf +        (&r_account->details.x_taler_bank.account_base_url, +        "http://%s/%.*s", +        r_account->details.x_taler_bank.hostname, +        (int) (q - account), +        account));    } -  if (no > MAX_ACCOUNT_NO) -    return TALER_EC_PAYTO_MALFORMED; - -  if (NULL != r_account) +  else    { -    long long unsigned port; -    char *p; - -    r_account->details.x_taler_bank.hostname -      = GNUNET_strndup (hostname, -                        account - hostname); -    r_account->details.x_taler_bank.no = no; -    port = 443; /* if non given, equals 443.  */ -    if (NULL != (p = strchr (r_account->details.x_taler_bank.hostname, -                             (unsigned char) ':'))) -    { -      p++; -      if (1 != sscanf (p, -                       "%llu", -                       &port)) -      { -        GNUNET_break (0); -        TALER_LOG_ERROR ("Malformed host from payto:// URI\n"); -        GNUNET_free (r_account->details.x_taler_bank.hostname); -        r_account->details.x_taler_bank.hostname = NULL; -        return TALER_EC_PAYTO_MALFORMED; -      } -    } -    if (443 != port) -    { -      GNUNET_assert -        (GNUNET_SYSERR != GNUNET_asprintf -          (&r_account->details.x_taler_bank.bank_base_url, -          "http://%s", -          r_account->details.x_taler_bank.hostname)); -    } -    else -    { -      GNUNET_assert -        (GNUNET_SYSERR != GNUNET_asprintf -          (&r_account->details.x_taler_bank.bank_base_url, -          "https://%s", -          r_account->details.x_taler_bank.hostname)); -    } -    r_account->type = TALER_PAC_X_TALER_BANK; +    GNUNET_assert +      (GNUNET_SYSERR != GNUNET_asprintf +        (&r_account->details.x_taler_bank.account_base_url, +        "https://%s/%.*s", +        r_account->details.x_taler_bank.hostname, +        (int) (q - account), +        account));    } +  r_account->type = TALER_PAC_X_TALER_BANK;    return TALER_EC_NONE;  } diff --git a/src/wire/wire.c b/src/wire/wire.c deleted file mode 100644 index 60ae9e6e..00000000 --- a/src/wire/wire.c +++ /dev/null @@ -1,149 +0,0 @@ -/* -  This file is part of TALER -  (C) 2015, 2016, 2017, 2018 GNUnet e.V. - -  TALER is free software; you can redistribute it and/or modify it under the -  terms of the GNU General Public License as published by the Free Software -  Foundation; either version 3, or (at your option) any later version. - -  TALER is distributed in the hope that it will be useful, but WITHOUT ANY -  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -  A PARTICULAR PURPOSE.  See the GNU General Public License for more details. - -  You should have received a copy of the GNU General Public License along with -  TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/> -*/ - -/** - * @file wire/wire.c - * @brief Functions for loading wire plugins - * @author Christian Grothoff <christian@grothoff.org> - */ -#include "platform.h" -#include "taler_util.h" -#include "taler_wire_lib.h" - - -/** - * A wire plugin that we have loaded. - */ -struct WirePlugin -{ -  /** -   * We keep these in a DLL. -   */ -  struct WirePlugin *next; - -  /** -   * We keep these in a DLL. -   */ -  struct WirePlugin *prev; - -  /** -   * Type of this wire plugin. -   */ -  char *type; - -  /** -   * Wire plugin -   */ -  struct TALER_WIRE_Plugin *plugin; - -  /** -   * Reference counter for the plugin. -   */ -  unsigned int rc; -}; - - -/** - * Head of the DLL of loaded wire plugins. - */ -static struct WirePlugin *wp_head; - -/** - * Tail of the DLL of loaded wire plugins. - */ -static struct WirePlugin *wp_tail; - - -/** - * Load a WIRE plugin. - * - * @param cfg configuration to use - * @param plugin_name name of the plugin to load - * @return the plugin object pointer, or NULL upon errors. - */ -struct TALER_WIRE_Plugin * -TALER_WIRE_plugin_load (const struct GNUNET_CONFIGURATION_Handle *cfg, -                        const char *plugin_name) -{ -  char *lib_name; -  struct TALER_WIRE_Plugin *plugin; -  struct WirePlugin *wp; - -  for (wp = wp_head; NULL != wp; wp = wp->next) -    if (0 == strcasecmp (plugin_name, -                         wp->type)) -    { -      wp->rc++; -      return wp->plugin; -    } -  (void) GNUNET_asprintf (&lib_name, -                          "libtaler_plugin_wire_%s", -                          plugin_name); -  plugin = GNUNET_PLUGIN_load (lib_name, -                               (void *) cfg); -  if (NULL != plugin) -    plugin->library_name = lib_name; -  else -    GNUNET_free (lib_name); -  if (NULL == plugin) -    return NULL; -  wp = GNUNET_new (struct WirePlugin); -  wp->plugin = plugin; -  wp->type = GNUNET_strdup (plugin_name); -  GNUNET_CONTAINER_DLL_insert (wp_head, -                               wp_tail, -                               wp); -  wp->rc = 1; -  return plugin; -} - - -/** - * Unload a WIRE plugin. - * - * @param plugin the plugin to unload - */ -void -TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin) -{ -  struct WirePlugin *wp; -  char *lib_name; - -  if (NULL == plugin) -    return; -  for (wp = wp_head; NULL != wp; wp = wp->next) -  { -    if (plugin == wp->plugin) -    { -      wp->rc--; -      if (0 < wp->rc) -        return; -      GNUNET_CONTAINER_DLL_remove (wp_head, -                                   wp_tail, -                                   wp); -      GNUNET_free (wp->type); -      GNUNET_free (wp); -      break; -    } -  } -  lib_name = plugin->library_name; -  GNUNET_assert (NULL == GNUNET_PLUGIN_unload (lib_name, -                                               plugin)); -  GNUNET_free (lib_name); -} - - -/* end of wire.c */ diff --git a/src/wire/wire_helper.c b/src/wire/wire_helper.c index e6253983..4b7f092a 100644 --- a/src/wire/wire_helper.c +++ b/src/wire/wire_helper.c @@ -20,6 +20,7 @@  /**   * @file wire/wire_helper.c   * @brief Helper functions for dealing with wire formats +   * @author Christian Grothoff <christian@grothoff.org>   */  #include "platform.h" @@ -33,23 +34,6 @@  /** - * Maps wire methods to plugin names. - */ -struct ConversionTable -{ - -  /** -   * Wire method (e.g. 'iban', 'x-taler-bank', ..) -   */ -  const char *method; - -  /** -   * Plugin name, e.g. 'taler_bank', .. -   */ -  const char *plugin_name; -}; - -/**   * Obtain the payment method from a @a payto_url   *   * @param payto_url the URL to parse @@ -76,35 +60,23 @@ TALER_WIRE_payto_get_method (const char *payto_url)  /** - * Get the plugin name from the payment method. + * Round the amount to something that can be + * transferred on the wire.   * - * FIXME: this is ugly, would be better to have - * a way to iterate over all plugins and interrogate - * them as to what wire method(s) they support! - * - * @param method the method implemented by the plugin (for - *  simplicity, we assume 1 method is implemented by 1 plugin). - * @return the plugin name, NULL if not found. + * @param[in,out] amount amount to round down + * @return #GNUNET_OK on success, #GNUNET_NO if rounding was unnecessary, + *         #GNUNET_SYSERR if the amount or currency was invalid   */ -const char * -TALER_WIRE_get_plugin_from_method (const char *method) +int +TALER_WIRE_amount_round (struct TALER_Amount *amount)  { -  static const struct ConversionTable ct[] = { -    {"x-taler-bank", "taler_bank"}, -    {"iban", "taler_bank"}, -    {NULL, NULL} -  }; - -  for (unsigned int i = 0; -       NULL != ct[i].method; -       i++) -  { -    if (0 == strcmp (method, -                     ct[i].method)) -      return ct[i].plugin_name; -  } +  uint32_t delta; -  return NULL; +  delta = amount->fraction % (TALER_AMOUNT_FRAC_BASE / 100); +  if (0 == delta) +    return GNUNET_NO; +  amount->fraction -= delta; +  return GNUNET_OK;  } | 
