From 4d2faa5ec92213efc4ee40f707ab0ad3615e5433 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 3 Mar 2017 19:23:34 +0100 Subject: [PATCH] changing wire plugin specification from [exchange]WIREFORMAT to [exchange-wire-PLUGIN]enable=YES/NO --- src/benchmark/taler-exchange-benchmark.conf | 9 +- src/exchange-lib/test_exchange_api.conf | 13 +- src/exchange/exchange.conf | 4 - ...st-taler-exchange-aggregator-postgres.conf | 8 +- src/exchange/test_taler_exchange_httpd.conf | 8 +- src/exchangedb/exchangedb.conf | 7 + src/exchangedb/exchangedb_fees.c | 243 ++++++++++++++++++ src/exchangedb/test_exchangedb_fees.c | 46 ++++ src/include/taler_wire_lib.h | 24 ++ src/wire/wire-sepa.conf | 6 + src/wire/wire-test.conf | 6 + src/wire/wire.c | 78 +++++- 12 files changed, 426 insertions(+), 26 deletions(-) create mode 100644 src/exchangedb/exchangedb_fees.c create mode 100644 src/exchangedb/test_exchangedb_fees.c diff --git a/src/benchmark/taler-exchange-benchmark.conf b/src/benchmark/taler-exchange-benchmark.conf index 16a26d8ae..a77df46a2 100644 --- a/src/benchmark/taler-exchange-benchmark.conf +++ b/src/benchmark/taler-exchange-benchmark.conf @@ -11,11 +11,6 @@ CURRENCY = KUDOS [exchange] -# Wire format supported by the exchange -# We use 'test' for testing of the actual -# coin operations, and 'sepa' to test SEPA-specific routines. -WIREFORMAT = test - # HTTP port the exchange listens to PORT = 8081 # How to access our database @@ -27,6 +22,9 @@ MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG [exchangedb-postgres] DB_CONN_STR = "postgres:///talercheck" +[exchange-wire-test] +# Enable 'test' for testing of the actual coin operations. +ENABLE = YES [exchange-wire-outgoing-test] # What is the main website of the bank? @@ -88,4 +86,3 @@ fee_deposit = KUDOS:0.00 fee_refresh = KUDOS:0.00 fee_refund = KUDOS:0.00 rsa_keysize = 1024 - diff --git a/src/exchange-lib/test_exchange_api.conf b/src/exchange-lib/test_exchange_api.conf index 83be7c410..76ade18fe 100644 --- a/src/exchange-lib/test_exchange_api.conf +++ b/src/exchange-lib/test_exchange_api.conf @@ -10,11 +10,6 @@ CURRENCY = EUR [exchange] -# Wire format supported by the exchange -# We use 'test' for testing of the actual -# coin operations, and 'sepa' to test SEPA-specific routines. -WIREFORMAT = test sepa - # HTTP port the exchange listens to PORT = 8081 @@ -31,11 +26,19 @@ BASE_URL = "https://exchange.com/" [exchangedb-postgres] DB_CONN_STR = "postgres:///talercheck" +[exchange-wire-sepa] +# Enable 'sepa' to test SEPA-specific routines. +ENABLE = YES + [exchange-wire-incoming-sepa] # This is the response we give out for the /wire request. It provides # wallets with the bank information for transfers to the exchange. SEPA_RESPONSE_FILE = ${TALER_CONFIG_HOME}/sepa.json +[exchange-wire-test] +# Enable 'test' for testing of the actual coin operations. +ENABLE = YES + [exchange-wire-incoming-test] # This is the response we give out for the /wire request. It provides # wallets with the bank information for transfers to the exchange. diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf index a226d4149..4c10b31aa 100644 --- a/src/exchange/exchange.conf +++ b/src/exchange/exchange.conf @@ -7,10 +7,6 @@ # in respective subdirectories.) KEYDIR = ${TALER_DATA_HOME}/exchange/live-keys/ -# Wire format supported by the exchange. We use 'test' for testing of -# the actual coin operations. -# WIREFORMAT = test - # Master public key used to sign the exchange's various keys # MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG diff --git a/src/exchange/test-taler-exchange-aggregator-postgres.conf b/src/exchange/test-taler-exchange-aggregator-postgres.conf index 7bcadc157..4aa74b037 100644 --- a/src/exchange/test-taler-exchange-aggregator-postgres.conf +++ b/src/exchange/test-taler-exchange-aggregator-postgres.conf @@ -10,11 +10,6 @@ CURRENCY = EUR # The DB plugin to use DB = postgres -# Wire format supported by the exchange -# We use 'test' for testing of the actual -# coin operations. -WIREFORMAT = test - # HTTP port the exchange listens to PORT = 8081 @@ -30,6 +25,9 @@ BASE_URL = "https://exchange.taler.net/" DB_CONN_STR = postgres:///talercheck +[exchange-wire-test] +# Enable 'test' for testing of the actual coin operations. +ENABLE = YES [exchange-wire-outgoing-test] # What is the main website of the bank? diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf index e1c30615b..945031dd1 100644 --- a/src/exchange/test_taler_exchange_httpd.conf +++ b/src/exchange/test_taler_exchange_httpd.conf @@ -9,11 +9,6 @@ CURRENCY = EUR [exchange] -# Wire format supported by the exchange -# We use 'test' for testing of the actual -# coin operations. -WIREFORMAT = test - # HTTP port the exchange listens to PORT = 8081 @@ -27,6 +22,9 @@ DB = postgres [exchangedb-postgres] DB_CONN_STR = "postgres:///talercheck" +[exchange-wire-test] +# Enable 'test' for testing of the actual coin operations. +ENABLE = YES [exchange-wire-outgoing-test] # What is the main website of the bank? diff --git a/src/exchangedb/exchangedb.conf b/src/exchangedb/exchangedb.conf index 19277ed23..4640507dc 100644 --- a/src/exchangedb/exchangedb.conf +++ b/src/exchangedb/exchangedb.conf @@ -5,3 +5,10 @@ [exchangedb] # Where do we expect to find information about auditors? AUDITOR_BASE_DIR = ${TALER_DATA_HOME}/auditors/ + +# Where do we expect to find information about wire transfer fees +# for aggregate payments? These are the amounts we charge (subtract) +# the merchant per wire transfer. The directory is expected to +# contain files "$METHOD.fee" with the cost structure, where +# $METHOD corresponds to a wire transfer method. +WIREFEE_BASE_DIR = ${TALER_DATA_HOME}/wirefees/ diff --git a/src/exchangedb/exchangedb_fees.c b/src/exchangedb/exchangedb_fees.c new file mode 100644 index 000000000..938b61c19 --- /dev/null +++ b/src/exchangedb/exchangedb_fees.c @@ -0,0 +1,243 @@ +/* + This file is part of TALER + Copyright (C) 2017 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 +*/ +/** + * @file exchangedb/exchangedb_fees.c + * @brief Logic to read/write/convert aggregation wire fees (not other fees!) + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_exchangedb_lib.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Structure for wire fees on disk. + */ +struct TALER_WireFeeDiskP +{ + + /** + * Wire fee details. + */ + struct TALER_MasterWireFeePS wf; + + + /** + * Signature affirming the above fee structure. + */ + struct TALER_MasterSignatureP master_sig; + +}; + +GNUNET_NETWORK_STRUCT_END + + +/** + * Convert @a wd disk format to host format. + * + * @param wd aggregate fees, disk format + * @return fees in host format + */ +static struct TALER_EXCHANGEDB_AggregateFees * +wd2af (const struct TALER_WireFeeDiskP *wd) +{ + struct TALER_EXCHANGEDB_AggregateFees *af; + + af = GNUNET_new (struct TALER_EXCHANGEDB_AggregateFees); + af->start_date = GNUNET_TIME_absolute_ntoh (wd->wf.start_date); + af->end_date = GNUNET_TIME_absolute_ntoh (wd->wf.end_date); + TALER_amount_ntoh (&af->wire_fee, + &wd->wf.wire_fee); + af->master_sig = wd->master_sig; + return af; +} + + +/** + * Read the current fee structure from disk. + * + * @param cfg configuration to use + * @param wireplugin name of the wire plugin to read fees for + * @return sorted list of aggregation fees, NULL on error + */ +struct TALER_EXCHANGEDB_AggregateFees * +TALER_EXCHANGEDB_fees_read (const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *wireplugin) +{ + char *wirefee_base_dir; + char *fn; + struct GNUNET_DISK_FileHandle *fh; + struct TALER_WireFeeDiskP wd; + struct TALER_EXCHANGEDB_AggregateFees *af; + struct TALER_EXCHANGEDB_AggregateFees *endp; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "exchangedb", + "WIREFEE_BASE_DIR", + &wirefee_base_dir)) + return NULL; + GNUNET_asprintf (&fn, + "%s" DIR_SEPARATOR_STR "%s.fee", + wirefee_base_dir, + wireplugin); + GNUNET_free (wirefee_base_dir); + fh = GNUNET_DISK_file_open (fn, + GNUNET_DISK_OPEN_READ, + GNUNET_DISK_PERM_NONE); + GNUNET_free (fn); + if (NULL == fh) + return NULL; + + af = NULL; + endp = NULL; + while (sizeof (wd) == + GNUNET_DISK_file_read (fh, + &wd, + sizeof (wd))) + { + struct TALER_EXCHANGEDB_AggregateFees *n; + + n = wd2af (&wd); + if ( ( (NULL == af) || + (endp->end_date.abs_value_us == n->start_date.abs_value_us) ) && + (n->start_date.abs_value_us < n->end_date.abs_value_us) ) + { + /* append to list */ + if (NULL != endp) + endp->next = n; + else + af = n; + endp = n; + } + else + { + /* We expect file to be in chronological order! */ + GNUNET_break (0); + GNUNET_DISK_file_close (fh); + GNUNET_free (n); + TALER_EXCHANGEDB_fees_free (af); + return NULL; + } + } + GNUNET_DISK_file_close (fh); + return af; +} + + +/** + * Convert @a af to @a wf. + * + * @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 (struct TALER_EXCHANGEDB_AggregateFees *af, + struct TALER_MasterWireFeePS *wf) +{ + (void) GNUNET_TIME_round_abs (&af->start_date); + (void) GNUNET_TIME_round_abs (&af->end_date); + wf->purpose.size = htonl (sizeof (*wf)); + wf->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES); + wf->start_date = GNUNET_TIME_absolute_hton (af->start_date); + wf->end_date = GNUNET_TIME_absolute_hton (af->end_date); + TALER_amount_hton (&wf->wire_fee, + &af->wire_fee); +} + + +/** + * Write given fee structure to disk. + * + * @param filename where to write the fees + * @param af fee structure to write + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +int +TALER_EXCHANGEDB_fees_write (const char *filename, + struct TALER_EXCHANGEDB_AggregateFees *af) +{ + struct GNUNET_DISK_FileHandle *fh; + struct TALER_WireFeeDiskP wd; + struct TALER_EXCHANGEDB_AggregateFees *last; + + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (filename)) + return GNUNET_SYSERR; + + fh = GNUNET_DISK_file_open (filename, + GNUNET_DISK_OPEN_WRITE | + GNUNET_DISK_OPEN_TRUNCATE | + GNUNET_DISK_OPEN_CREATE, + GNUNET_DISK_PERM_USER_READ | + GNUNET_DISK_PERM_USER_WRITE); + if (NULL == fh) + return GNUNET_SYSERR; + + last = NULL; + while (NULL != af) + { + if ( ( (NULL != last) && + (last->end_date.abs_value_us != af->start_date.abs_value_us) ) || + (af->start_date.abs_value_us >= af->end_date.abs_value_us) ) + { + /* @a af malformed, refusing to write file that will be rejected */ + GNUNET_break (0); + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_file_close (fh)); + return GNUNET_SYSERR; + } + TALER_EXCHANGEDB_fees_2_wf (af, + &wd.wf); + wd.master_sig = af->master_sig; + af = af->next; + if (sizeof (wd) != + GNUNET_DISK_file_write (fh, + &wd, + sizeof (wd))) + { + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_file_close (fh)); + return GNUNET_SYSERR; + } + } + GNUNET_assert (GNUNET_OK == + GNUNET_DISK_file_close (fh)); + return GNUNET_OK; +} + + +/** + * Free @a af data structure + * + * @param af list to free + */ +void +TALER_EXCHANGEDB_fees_free (struct TALER_EXCHANGEDB_AggregateFees *af) +{ + struct TALER_EXCHANGEDB_AggregateFees *next; + + while (NULL != af) + { + next = af->next; + GNUNET_free (af); + af = next; + } +} + + +/* end of exchangedb_fees.c */ diff --git a/src/exchangedb/test_exchangedb_fees.c b/src/exchangedb/test_exchangedb_fees.c new file mode 100644 index 000000000..e23879ead --- /dev/null +++ b/src/exchangedb/test_exchangedb_fees.c @@ -0,0 +1,46 @@ +/* + This file is part of TALER + Copyright (C) 2017 Inria & 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 +*/ +/** + * @file exchangedb/test_exchangedb_fees.c + * @brief test cases for functions in exchangedb/exchangedb_fees.c + * @author Christian Grothoff + */ +#include "platform.h" +#include "gnunet/gnunet_util_lib.h" +#include "taler_signatures.h" +#include "taler_exchangedb_lib.h" + + +int +main (int argc, + const char *const argv[]) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + int ret; + + ret = 1; + GNUNET_log_setup ("test-exchangedb-fees", + "WARNING", + NULL); + cfg = GNUNET_CONFIGURATION_create (); + + GNUNET_CONFIGURATION_set_value_string (cfg, + "exchangedb", + "AUDITOR_BASE_DIR", + tmpdir); + ret = 0; + return ret; +} diff --git a/src/include/taler_wire_lib.h b/src/include/taler_wire_lib.h index b67f620f4..68c36e889 100644 --- a/src/include/taler_wire_lib.h +++ b/src/include/taler_wire_lib.h @@ -45,4 +45,28 @@ void TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin); +/** + * Signature of a function to be called on each enabled + * wire plugin. + * + * @param cls closure + * @param name name of the enabled plugin + */ +typedef void +(*TALER_WIRE_EnabledCallback)(void *cls, + const char *name); + + +/** + * Check which wire plugins are enabled in @a cfg and call @a cb for each one. + * + * @param cfg configuration to use + * @param cb callback to invoke + * @param cb_cls closure for @a cb + */ +void +TALER_WIRE_find_enabled (const struct GNUNET_CONFIGURATION_Handle *cfg, + TALER_WIRE_EnabledCallback cb, + void *cb_cls); + #endif diff --git a/src/wire/wire-sepa.conf b/src/wire/wire-sepa.conf index b7c09153f..88d2ac03c 100644 --- a/src/wire/wire-sepa.conf +++ b/src/wire/wire-sepa.conf @@ -1,5 +1,11 @@ +# This file is in the public domain. +# # Configuration for SEPA wire plugin. +[exchange-wire-sepa] +# Set to "YES" to activate the 'sepa' plugin. +ENABLE = NO + [exchange-wire-incoming-sepa] # This is the response we give out for the /wire request. It provides # wallets with the bank information for transfers to the exchange. diff --git a/src/wire/wire-test.conf b/src/wire/wire-test.conf index fc03f1b83..fcc156426 100644 --- a/src/wire/wire-test.conf +++ b/src/wire/wire-test.conf @@ -1,5 +1,11 @@ # This file is in the public domain. # +# Configuration for TEST wire plugin. +# +[exchange-wire-test] +# Set to "YES" to activate the 'test' plugin. +ENABLE = NO + [exchange-wire-incoming-test] # This is the response we give out for the /wire request. It provides # wallets with the bank information for transfers to the exchange. diff --git a/src/wire/wire.c b/src/wire/wire.c index 4d53b0d0b..c799334f9 100644 --- a/src/wire/wire.c +++ b/src/wire/wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2015, 2016 GNUnet e.V. + (C) 2015, 2016, 2017 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 @@ -69,4 +69,80 @@ TALER_WIRE_plugin_unload (struct TALER_WIRE_Plugin *plugin) } +/** + * Closure of #check_for_wire. + */ +struct FindEnabledWireContext +{ + /** + * Configuration we are usign. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Callback to invoke. + */ + TALER_WIRE_EnabledCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; +}; + + +/** + * Check if @a section begins with "exchange-wire-", and if + * so if the "ENABLE" option is set to "YES". If both are + * true, call the callback from the context with the + * rest of the section name. + * + * @param cls our `struct FindEnabledWireContext` + * @param section name of a section in the configuration + */ +static void +check_for_wire (void *cls, + const char *section) +{ + struct FindEnabledWireContext *ctx = cls; + const char *name; + + if (0 != strncasecmp (section, + "exchange-wire-", + strlen ("exchange-wire-"))) + return; + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (ctx->cfg, + section, + "ENABLE")) + return; + name = §ion[strlen ("exchange-wire-")]; + ctx->cb (ctx->cb_cls, + name); +} + + +/** + * Check which wire plugins are enabled in @a cfg and call @a cb for each one. + * + * @param cfg configuration to use + * @param cb callback to invoke + * @param cb_cls closure for @a cb + */ +void +TALER_WIRE_find_enabled (const struct GNUNET_CONFIGURATION_Handle *cfg, + TALER_WIRE_EnabledCallback cb, + void *cb_cls) +{ + struct FindEnabledWireContext ctx; + + ctx.cfg = cfg; + ctx.cb = cb; + ctx.cb_cls = cb_cls; + GNUNET_CONFIGURATION_iterate_sections (cfg, + &check_for_wire, + &ctx); +} + + /* end of wire.c */