summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am2
-rw-r--r--src/auditor/taler-auditor.c73
-rw-r--r--src/auditor/taler-wire-auditor.c455
-rw-r--r--src/auditordb/auditordb-postgres.conf2
-rw-r--r--src/auditordb/plugin_auditordb_postgres.c27
-rw-r--r--src/auditordb/test-auditor-db-postgres.conf2
-rw-r--r--src/bank-lib/Makefile.am4
-rw-r--r--src/bank-lib/bank.conf5
-rw-r--r--src/bank-lib/bank_api_history.c12
-rw-r--r--src/bank-lib/bank_api_parse.c133
-rw-r--r--src/bank-lib/test_bank_api_with_fakebank_new.c5
-rw-r--r--src/bank-lib/test_bank_interpreter.c40
-rw-r--r--src/bank-lib/testing_api_cmd_history.c47
-rw-r--r--src/bank-lib/testing_api_cmd_reject.c4
-rw-r--r--src/benchmark/taler-exchange-benchmark.c4
-rw-r--r--src/benchmark/taler-exchange-benchmark.conf14
-rw-r--r--src/exchange-lib/Makefile.am3
-rw-r--r--src/exchange-lib/exchange_api_deposit.c4
-rw-r--r--src/exchange-lib/exchange_api_reserve.c15
-rw-r--r--src/exchange-lib/exchange_api_wire.c475
-rw-r--r--src/exchange-lib/test_exchange_api.c80
-rw-r--r--src/exchange-lib/test_exchange_api.conf78
-rw-r--r--src/exchange-lib/test_exchange_api_home/.config/taler/account-1.json5
-rw-r--r--src/exchange-lib/test_exchange_api_home/.config/taler/account-2.json5
-rw-r--r--src/exchange-lib/test_exchange_api_home/.config/taler/x-taler-bank.json5
-rw-r--r--src/exchange-lib/test_exchange_api_keys_cherry_picking.conf64
-rw-r--r--src/exchange-lib/test_exchange_api_keys_cherry_picking_extended.conf2
-rw-r--r--src/exchange-lib/test_exchange_api_new.c99
-rw-r--r--src/exchange-lib/testing_api_cmd_deposit.c52
-rw-r--r--src/exchange-lib/testing_api_cmd_exec_wirewatch.c1
-rw-r--r--src/exchange-lib/testing_api_cmd_payback.c41
-rw-r--r--src/exchange-lib/testing_api_cmd_refund.c11
-rw-r--r--src/exchange-lib/testing_api_cmd_track.c64
-rw-r--r--src/exchange-lib/testing_api_cmd_wire.c129
-rw-r--r--src/exchange-lib/testing_api_helpers.c74
-rw-r--r--src/exchange-lib/testing_api_trait_json.c76
-rw-r--r--src/exchange-lib/testing_api_trait_string.c48
-rw-r--r--src/exchange-tools/Makefile.am3
-rw-r--r--src/exchange-tools/exchange-signkeys.conf16
-rw-r--r--src/exchange-tools/taler-exchange-keyup.c66
-rw-r--r--src/exchange-tools/taler-exchange-wire.c182
-rw-r--r--src/exchange/.gitignore1
-rw-r--r--src/exchange/exchange.conf15
-rw-r--r--src/exchange/taler-exchange-aggregator.c319
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c12
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c17
-rw-r--r--src/exchange/taler-exchange-httpd_track_transfer.c18
-rw-r--r--src/exchange/taler-exchange-httpd_validation.c310
-rw-r--r--src/exchange/taler-exchange-httpd_validation.h9
-rw-r--r--src/exchange/taler-exchange-httpd_wire.c17
-rw-r--r--src/exchange/taler-exchange-httpd_wire.h4
-rw-r--r--src/exchange/taler-exchange-wirewatch.c203
-rw-r--r--src/exchange/test-taler-exchange-aggregator-postgres.conf34
-rw-r--r--src/exchange/test-taler-exchange-wirewatch-postgres.conf30
-rw-r--r--src/exchange/test_taler_exchange_aggregator.c26
-rw-r--r--src/exchange/test_taler_exchange_httpd.conf49
-rw-r--r--src/exchange/test_taler_exchange_httpd.data17
-rwxr-xr-xsrc/exchange/test_taler_exchange_httpd.sh4
-rw-r--r--src/exchange/test_taler_exchange_wirewatch.c3
-rw-r--r--src/exchangedb/Makefile.am12
-rw-r--r--src/exchangedb/exchangedb-postgres.conf2
-rw-r--r--src/exchangedb/exchangedb_accounts.c141
-rw-r--r--src/exchangedb/perf_taler_exchangedb.c2
-rw-r--r--src/exchangedb/perf_taler_exchangedb_init.c22
-rw-r--r--src/exchangedb/perf_taler_exchangedb_interpreter.c14
-rw-r--r--src/exchangedb/plugin_exchangedb_common.c8
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c89
-rw-r--r--src/exchangedb/test-exchange-db-postgres.conf2
-rw-r--r--src/exchangedb/test_exchangedb.c98
-rw-r--r--src/include/taler_auditordb_plugin.h6
-rw-r--r--src/include/taler_bank_service.h29
-rw-r--r--src/include/taler_crypto_lib.h49
-rw-r--r--src/include/taler_error_codes.h22
-rw-r--r--src/include/taler_exchange_service.h68
-rw-r--r--src/include/taler_exchangedb_lib.h68
-rw-r--r--src/include/taler_exchangedb_plugin.h51
-rw-r--r--src/include/taler_json_lib.h59
-rw-r--r--src/include/taler_signatures.h27
-rw-r--r--src/include/taler_testing_lib.h38
-rw-r--r--src/include/taler_wire_lib.h36
-rw-r--r--src/include/taler_wire_plugin.h75
-rw-r--r--src/json/Makefile.am4
-rw-r--r--src/json/json_wire.c193
-rw-r--r--src/util/Makefile.am1
-rw-r--r--src/util/crypto_wire.c108
-rw-r--r--src/wire-plugins/Makefile.am101
-rw-r--r--src/wire-plugins/plugin_wire_ebics.c (renamed from src/wire/plugin_wire_sepa.c)493
-rw-r--r--src/wire-plugins/plugin_wire_taler-bank.c (renamed from src/wire/plugin_wire_test.c)1070
-rw-r--r--src/wire-plugins/plugin_wire_template.c (renamed from src/wire/plugin_wire_template.c)149
-rw-r--r--src/wire-plugins/test_ebics_wireformat.c80
-rw-r--r--src/wire-plugins/test_wire_plugin.c (renamed from src/wire/test_wire_plugin.c)97
-rw-r--r--src/wire-plugins/test_wire_plugin.conf (renamed from src/wire/test_wire_plugin.conf)22
-rw-r--r--src/wire-plugins/test_wire_plugin_transactions_taler-bank.c (renamed from src/wire/test_wire_plugin_transactions_test.c)44
-rw-r--r--src/wire-plugins/test_wire_plugin_transactions_taler-bank.conf12
-rw-r--r--src/wire/Makefile.am103
-rw-r--r--src/wire/test_sepa_wireformat.c120
-rw-r--r--src/wire/test_wire_plugin_key.priv1
-rw-r--r--src/wire/test_wire_plugin_sepa.json8
-rw-r--r--src/wire/test_wire_plugin_test.json7
-rw-r--r--src/wire/test_wire_plugin_transactions_test.conf15
-rw-r--r--src/wire/wire-sepa.conf15
-rw-r--r--src/wire/wire-test.conf22
-rw-r--r--src/wire/wire.c76
-rw-r--r--src/wire/wire_helper.c57
104 files changed, 3995 insertions, 3236 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2f158a1da..d2c925545 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,7 +22,7 @@ pkgcfg_DATA = \
EXTRA_DIST = \
taler.conf
-SUBDIRS = include util json $(PQ_DIR) $(BANK_LIB) wire exchangedb exchange exchange-tools auditordb auditor
+SUBDIRS = include util wire json $(PQ_DIR) $(BANK_LIB) wire-plugins exchangedb exchange exchange-tools auditordb auditor
if HAVE_LIBCURL
SUBDIRS += exchange-lib benchmark
else
diff --git a/src/auditor/taler-auditor.c b/src/auditor/taler-auditor.c
index b8f6c624c..f5d185cf0 100644
--- a/src/auditor/taler-auditor.c
+++ b/src/auditor/taler-auditor.c
@@ -761,7 +761,7 @@ handle_reserve_in (void *cls,
uint64_t rowid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
- const json_t *sender_account_details,
+ const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
struct GNUNET_TIME_Absolute execution_date)
@@ -1193,7 +1193,7 @@ handle_reserve_closed (void *cls,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
- const json_t *receiver_account,
+ const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *transfer_details)
{
struct ReserveContext *rc = cls;
@@ -1774,11 +1774,6 @@ struct WireCheckContext
struct GNUNET_TIME_Absolute date;
/**
- * Wire method used for the transfer.
- */
- const char *method;
-
- /**
* Database transaction status.
*/
enum GNUNET_DB_QueryStatus qs;
@@ -2069,8 +2064,8 @@ check_transaction_history (const struct TALER_CoinSpendPublicKeyP *coin_pub,
* @param cls a `struct WireCheckContext`
* @param rowid which row in the table is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param wire_method which wire plugin was used for the transfer?
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param account_details where did we transfer the funds?
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param coin_pub which public key was this payment about
@@ -2082,8 +2077,8 @@ static void
wire_transfer_information_cb (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- const char *wire_method,
const struct GNUNET_HashCode *h_wire,
+ const json_t *account_details,
struct GNUNET_TIME_Absolute exec_time,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -2097,6 +2092,29 @@ wire_transfer_information_cb (void *cls,
struct TALER_EXCHANGEDB_TransactionList *tl;
const struct TALER_CoinPublicInfo *coin;
enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_HashCode hw;
+
+ if (GNUNET_OK !=
+ TALER_JSON_wire_signature_hash (account_details,
+ &hw))
+ {
+ wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ report_row_inconsistency ("aggregation",
+ rowid,
+ "failed to compute hash of given wire data");
+ return;
+ }
+ if (0 !=
+ memcmp (&hw,
+ h_wire,
+ sizeof (struct GNUNET_HashCode)))
+ {
+ wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ report_row_inconsistency ("aggregation",
+ rowid,
+ "database contains wrong hash code for wire details");
+ return;
+ }
/* Obtain coin's transaction history */
qs = edb->get_coin_transactions (edb->cls,
@@ -2183,8 +2201,9 @@ wire_transfer_information_cb (void *cls,
tl);
/* Check other details of wire transfer match */
- if (0 != strcmp (wire_method,
- wcc->method))
+ if (0 != memcmp (h_wire,
+ &wcc->h_wire,
+ sizeof (struct GNUNET_HashCode)))
{
wcc->qs = GNUNET_DB_STATUS_HARD_ERROR;
report_row_inconsistency ("aggregation",
@@ -2360,12 +2379,12 @@ check_wire_out_cb (void *cls,
{
struct AggregationContext *ac = cls;
struct WireCheckContext wcc;
- json_t *method;
struct TALER_WIRE_Plugin *plugin;
const struct TALER_Amount *wire_fee;
struct TALER_Amount final_amount;
struct TALER_Amount exchange_gain;
enum GNUNET_DB_QueryStatus qs;
+ char *method;
/* should be monotonically increasing */
GNUNET_assert (rowid >= pp.last_wire_out_serial_id);
@@ -2376,26 +2395,23 @@ check_wire_out_cb (void *cls,
TALER_B2S (wtid),
TALER_amount2s (amount),
GNUNET_STRINGS_absolute_time_to_string (date));
- wcc.ac = ac;
- method = json_object_get (wire,
- "type");
- if ( (NULL == method) ||
- (! json_is_string (method)) )
+ if (NULL == (method = TALER_JSON_wire_to_method (wire)))
{
report_row_inconsistency ("wire_out",
rowid,
- "specified wire address lacks type");
+ "specified wire address lacks method");
return GNUNET_OK;
}
- wcc.method = json_string_value (method);
+
+ wcc.ac = ac;
wcc.qs = GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
wcc.date = date;
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (amount->currency,
&wcc.total_deposits));
if (GNUNET_OK !=
- TALER_JSON_hash (wire,
- &wcc.h_wire))
+ TALER_JSON_wire_signature_hash (wire,
+ &wcc.h_wire))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -2409,6 +2425,7 @@ check_wire_out_cb (void *cls,
{
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
ac->qs = qs;
+ GNUNET_free (method);
return GNUNET_SYSERR;
}
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != wcc.qs)
@@ -2417,17 +2434,19 @@ check_wire_out_cb (void *cls,
report_row_inconsistency ("wire_out",
rowid,
"audit of associated transactions failed");
+ GNUNET_free (method);
return GNUNET_OK;
}
/* Subtract aggregation fee from total */
wire_fee = get_wire_fee (ac,
- wcc.method,
+ method,
date);
if (NULL == wire_fee)
{
GNUNET_break (0);
ac->qs = GNUNET_DB_STATUS_HARD_ERROR;
+ GNUNET_free (method);
return GNUNET_SYSERR;
}
if (GNUNET_SYSERR ==
@@ -2440,18 +2459,20 @@ check_wire_out_cb (void *cls,
&wcc.total_deposits,
wire_fee,
-1);
+ GNUNET_free (method);
return GNUNET_OK;
}
/* Round down to amount supported by wire method */
plugin = get_wire_plugin (ac,
- wcc.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));
@@ -3408,8 +3429,8 @@ deposit_cb (void *cls,
dr.purpose.size = htonl (sizeof (dr));
dr.h_contract_terms = *h_contract_terms;
if (GNUNET_OK !=
- TALER_JSON_hash (receiver_wire_account,
- &dr.h_wire))
+ TALER_JSON_wire_signature_hash (receiver_wire_account,
+ &dr.h_wire))
{
GNUNET_break (0);
cc->qs = GNUNET_DB_STATUS_HARD_ERROR;
diff --git a/src/auditor/taler-wire-auditor.c b/src/auditor/taler-wire-auditor.c
index 55a2a05fb..d9c2d820b 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 Taler Systems SA
+ 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
@@ -40,6 +40,45 @@
*/
#define GRACE_PERIOD GNUNET_TIME_UNIT_HOURS
+
+/**
+ * Information we keep for each supported account.
+ */
+struct WireAccount
+{
+ /**
+ * Accounts are kept in a DLL.
+ */
+ struct WireAccount *next;
+
+ /**
+ * Plugins are kept in a DLL.
+ */
+ struct WireAccount *prev;
+
+ /**
+ * Handle to the plugin.
+ */
+ struct TALER_WIRE_Plugin *wire_plugin;
+
+ /**
+ * Name of the section that configures this account.
+ */
+ char *section_name;
+
+ /**
+ * We should check for inbound transactions to this account.
+ */
+ int watch_credit;
+
+ /**
+ * We should check for outbound transactions from this account.
+ */
+ int watch_debit;
+
+};
+
+
/**
* Return value from main().
*/
@@ -51,11 +90,6 @@ static int global_ret;
static int restart;
/**
- * Name of the wire plugin to load to access the exchange's bank account.
- */
-static char *wire_plugin;
-
-/**
* Handle to access the exchange's database.
*/
static struct TALER_EXCHANGEDB_Plugin *edb;
@@ -104,11 +138,27 @@ static struct TALER_AUDITORDB_Session *asession;
static struct TALER_MasterPublicKeyP master_pub;
/**
+ * Head of list of wire accounts we still need to look at.
+ */
+static struct WireAccount *wa_head;
+
+/**
+ * Tail of list of wire accounts we still need to look at.
+ */
+static struct WireAccount *wa_tail;
+
+/**
* Handle to the wire plugin for wire operations.
*/
static struct TALER_WIRE_Plugin *wp;
/**
+ * Name of the section that configures the account
+ * we are currently processing (matches #wp).
+ */
+static char *wp_section_name;
+
+/**
* Active wire request for the transaction history.
*/
static struct TALER_WIRE_HistoryHandle *hh;
@@ -289,7 +339,8 @@ free_rii (void *cls,
GNUNET_CONTAINER_multihashmap_remove (in_map,
key,
rii));
- json_decref (rii->details.account_details);
+ GNUNET_free (rii->details.account_url);
+ GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */
GNUNET_free (rii);
return GNUNET_OK;
}
@@ -314,7 +365,8 @@ free_roi (void *cls,
GNUNET_CONTAINER_multihashmap_remove (out_map,
key,
roi));
- json_decref (roi->details.account_details);
+ GNUNET_free (roi->details.account_url);
+ GNUNET_free_non_null (roi->details.wtid_s); /* field not used (yet) */
GNUNET_free (roi);
return GNUNET_OK;
}
@@ -328,6 +380,8 @@ free_roi (void *cls,
static void
do_shutdown (void *cls)
{
+ struct WireAccount *wa;
+
if (NULL != report_row_inconsistencies)
{
json_t *report;
@@ -407,6 +461,20 @@ do_shutdown (void *cls)
TALER_WIRE_plugin_unload (wp);
wp = NULL;
}
+ if (NULL != wp_section_name)
+ {
+ GNUNET_free (wp_section_name);
+ wp_section_name = NULL;
+ }
+ while (NULL != (wa = wa_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wa_head,
+ wa_tail,
+ wa);
+ TALER_WIRE_plugin_unload (wa->wire_plugin);
+ GNUNET_free (wa->section_name);
+ GNUNET_free (wa);
+ }
if (NULL != adb)
{
TALER_AUDITORDB_plugin_unload (adb);
@@ -470,6 +538,7 @@ commit (enum GNUNET_DB_QueryStatus qs)
qs = adb->update_wire_auditor_progress (adb->cls,
asession,
&master_pub,
+ wp_section_name,
&pp,
in_wire_off,
out_wire_off,
@@ -478,6 +547,7 @@ commit (enum GNUNET_DB_QueryStatus qs)
qs = adb->insert_wire_auditor_progress (adb->cls,
asession,
&master_pub,
+ wp_section_name,
&pp,
in_wire_off,
out_wire_off,
@@ -583,37 +653,44 @@ wire_out_cb (void *cls,
amount));
return GNUNET_OK;
}
- if (! json_equal ((json_t *) wire,
- roi->details.account_details))
{
- /* Destination bank account is wrong in actual wire transfer, so
- we should count the wire transfer as entirely spurious, and
- additionally consider the justified wire transfer as missing. */
- report (report_wire_out_inconsistencies,
- json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
- "row", (json_int_t) rowid,
- "amount_wired", TALER_JSON_from_amount (&roi->details.amount),
- "amount_justified", TALER_JSON_from_amount (&zero),
- "wtid", GNUNET_JSON_from_data_auto (wtid),
- "timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
- "diagnostic", "recevier account missmatch"));
- GNUNET_break (GNUNET_OK ==
- TALER_amount_add (&total_bad_amount_out_plus,
- &total_bad_amount_out_plus,
- &roi->details.amount));
- report (report_wire_out_inconsistencies,
- json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
- "row", (json_int_t) rowid,
- "amount_wired", TALER_JSON_from_amount (&zero),
- "amount_justified", TALER_JSON_from_amount (amount),
- "wtid", GNUNET_JSON_from_data_auto (wtid),
- "timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
- "diagnostic", "receiver account missmatch"));
- GNUNET_break (GNUNET_OK ==
- TALER_amount_add (&total_bad_amount_out_minus,
- &total_bad_amount_out_minus,
- amount));
- goto cleanup;
+ char *payto_url;
+
+ payto_url = TALER_JSON_wire_to_payto (wire);
+ if (0 != strcasecmp (payto_url,
+ roi->details.account_url))
+ {
+ /* Destination bank account is wrong in actual wire transfer, so
+ we should count the wire transfer as entirely spurious, and
+ additionally consider the justified wire transfer as missing. */
+ report (report_wire_out_inconsistencies,
+ json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
+ "row", (json_int_t) rowid,
+ "amount_wired", TALER_JSON_from_amount (&roi->details.amount),
+ "amount_justified", TALER_JSON_from_amount (&zero),
+ "wtid", GNUNET_JSON_from_data_auto (wtid),
+ "timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
+ "diagnostic", "recevier account missmatch"));
+ GNUNET_break (GNUNET_OK ==
+ TALER_amount_add (&total_bad_amount_out_plus,
+ &total_bad_amount_out_plus,
+ &roi->details.amount));
+ report (report_wire_out_inconsistencies,
+ json_pack ("{s:I, s:o, s:o, s:o, s:s, s:s}",
+ "row", (json_int_t) rowid,
+ "amount_wired", TALER_JSON_from_amount (&zero),
+ "amount_justified", TALER_JSON_from_amount (amount),
+ "wtid", GNUNET_JSON_from_data_auto (wtid),
+ "timestamp", GNUNET_STRINGS_absolute_time_to_string (date),
+ "diagnostic", "receiver account missmatch"));
+ GNUNET_break (GNUNET_OK ==
+ TALER_amount_add (&total_bad_amount_out_minus,
+ &total_bad_amount_out_minus,
+ amount));
+ GNUNET_free (payto_url);
+ goto cleanup;
+ }
+ GNUNET_free (payto_url);
}
if (0 != TALER_amount_cmp (&roi->details.amount,
amount))
@@ -765,6 +842,16 @@ wire_missing_cb (void *cls,
/**
+ * Start processing the next wire account.
+ * Shuts down if we are done.
+ *
+ * @param cls NULL
+ */
+static void
+process_next_account (void *cls);
+
+
+/**
* Go over the "wire_out" table of the exchange and
* verify that all wire outs are in that table.
*/
@@ -818,9 +905,8 @@ check_exchange_wire_out ()
}
pp.last_timestamp = next_timestamp;
- /* conclude with: */
- commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT);
- GNUNET_SCHEDULER_shutdown ();
+ /* continue with next account: */
+ process_next_account (NULL);
}
@@ -892,7 +978,7 @@ history_debit_cb (void *cls,
roi->details.amount = details->amount;
roi->details.execution_date = details->execution_date;
roi->details.wtid = details->wtid;
- roi->details.account_details = json_incref ((json_t *) details->account_details);
+ roi->details.account_url = GNUNET_strdup (details->account_url);
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (out_map,
&roi->subject_hash,
@@ -936,6 +1022,7 @@ process_debits ()
out_map = GNUNET_CONTAINER_multihashmap_create (1024,
GNUNET_YES);
hh = wp->get_history (wp->cls,
+ wp_section_name,
TALER_BANK_DIRECTION_DEBIT,
out_wire_off,
wire_off_size,
@@ -965,7 +1052,7 @@ process_debits ()
* @param rowid unique serial ID for the refresh session in our DB
* @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 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 execution_date when did we receive the funds
@@ -976,7 +1063,7 @@ reserve_in_cb (void *cls,
uint64_t rowid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
- const json_t *sender_account_details,
+ const char *sender_url,
const void *wire_reference,
size_t wire_reference_size,
struct GNUNET_TIME_Absolute execution_date)
@@ -997,7 +1084,7 @@ reserve_in_cb (void *cls,
memcpy (&rii->details.wtid,
reserve_pub,
sizeof (*reserve_pub));
- rii->details.account_details = json_incref ((json_t *) sender_account_details);
+ rii->details.account_url = GNUNET_strdup (sender_url);
rii->rowid = rowid;
if (GNUNET_OK !=
GNUNET_CONTAINER_multihashmap_put (in_map,
@@ -1011,7 +1098,8 @@ reserve_in_cb (void *cls,
"row", (json_int_t) rowid,
"wire_offset_hash", GNUNET_JSON_from_data_auto (&rii->row_off_hash),
"diagnostic", "duplicate wire offset"));
- json_decref (rii->details.account_details);
+ GNUNET_free (rii->details.account_url);
+ GNUNET_free_non_null (rii->details.wtid_s); /* field not used (yet) */
GNUNET_free (rii);
return GNUNET_OK;
}
@@ -1228,8 +1316,8 @@ history_credit_cb (void *cls,
}
goto cleanup;
}
- if (! json_equal (details->account_details,
- rii->details.account_details))
+ if (0 != strcasecmp (details->account_url,
+ rii->details.account_url))
{
report (report_missattribution_in_inconsistencies,
json_pack ("{s:s, s:o, s:o}",
@@ -1267,6 +1355,167 @@ history_credit_cb (void *cls,
/**
+ * Start processing the next wire account.
+ * Shuts down if we are done.
+ *
+ * @param cls NULL
+ */
+static void
+process_next_account (void *cls)
+{
+ struct WireAccount *wa;
+ enum GNUNET_DB_QueryStatus qs;
+ int ret;
+
+ (void) cls;
+ if (NULL == (wa = wa_head))
+ {
+ commit (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (wa_head,
+ wa_tail,
+ wa);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Starting audit of account `%s'\n",
+ wa->section_name);
+ /* setup globals */
+ if (NULL != wp)
+ TALER_WIRE_plugin_unload (wp);
+ wp = wa->wire_plugin;
+ GNUNET_free_non_null (wp_section_name);
+ wp_section_name = wa->section_name;
+ GNUNET_free (wa);
+
+ ret = adb->start (adb->cls,
+ asession);
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break (0);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ edb->preflight (edb->cls,
+ esession);
+ ret = edb->start (edb->cls,
+ esession,
+ "wire auditor");
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_break (0);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ qsx = adb->get_wire_auditor_progress (adb->cls,
+ asession,
+ &master_pub,
+ wp_section_name,
+ &pp,
+ &in_wire_off,
+ &out_wire_off,
+ &wire_off_size);
+ if (0 > qsx)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsx)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ _("First analysis using this auditor, starting audit from scratch\n"));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _("Resuming audit at %llu/%llu\n"),
+ (unsigned long long) pp.last_reserve_in_serial_id,
+ (unsigned long long) pp.last_wire_out_serial_id);
+ }
+
+ in_map = GNUNET_CONTAINER_multihashmap_create (1024,
+ GNUNET_YES);
+ qs = edb->select_reserves_in_above_serial_id (edb->cls,
+ esession,
+ pp.last_reserve_in_serial_id,
+ &reserve_in_cb,
+ NULL);
+ if (0 > qs)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
+ "No new incoming transactions available, skipping CREDIT phase\n");
+ process_debits ();
+ return;
+ }
+ hh = wp->get_history (wp->cls,
+ wp_section_name,
+ TALER_BANK_DIRECTION_CREDIT,
+ in_wire_off,
+ wire_off_size,
+ INT64_MAX,
+ &history_credit_cb,
+ NULL);
+ if (NULL == hh)
+ {
+ fprintf (stderr,
+ "Failed to obtain bank transaction history\n");
+ commit (GNUNET_DB_STATUS_HARD_ERROR);
+ global_ret = 1;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+}
+
+
+/**
+ * Function called with information about a wire account. Adds the
+ * account to our list for processing (if it is enabled and we can
+ * load the plugin).
+ *
+ * @param cls closure, NULL
+ * @param ai account information
+ */
+static void
+process_account_cb (void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai)
+{
+ struct WireAccount *wa;
+ struct TALER_WIRE_Plugin *wp;
+
+ 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;
+ }
+ 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;
+ GNUNET_CONTAINER_DLL_insert (wa_head,
+ wa_tail,
+ wa);
+}
+
+
+/**
* Main function that will be run.
*
* @param cls closure
@@ -1281,8 +1530,6 @@ run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *c)
{
static const struct TALER_MasterPublicKeyP zeromp;
- enum GNUNET_DB_QueryStatus qs;
- int ret;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Launching auditor\n");
@@ -1390,40 +1637,6 @@ run (void *cls,
GNUNET_SCHEDULER_shutdown ();
return;
}
- wp = TALER_WIRE_plugin_load (cfg,
- wire_plugin);
- if (NULL == wp)
- {
- fprintf (stderr,
- "Failed to load wire plugin `%s'\n",
- wire_plugin);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Starting audit\n");
- ret = adb->start (adb->cls,
- asession);
- if (GNUNET_OK != ret)
- {
- GNUNET_break (0);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- edb->preflight (edb->cls,
- esession);
- ret = edb->start (edb->cls,
- esession,
- "wire auditor");
- if (GNUNET_OK != ret)
- {
- GNUNET_break (0);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
GNUNET_assert (NULL !=
(report_wire_out_inconsistencies = json_array ()));
GNUNET_assert (NULL !=
@@ -1462,71 +1675,9 @@ run (void *cls,
GNUNET_assert (GNUNET_OK ==
TALER_amount_get_zero (currency,
&zero));
-
- qsx = adb->get_wire_auditor_progress (adb->cls,
- asession,
- &master_pub,
- &pp,
- &in_wire_off,
- &out_wire_off,
- &wire_off_size);
- if (0 > qsx)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qsx);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qsx)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- _("First analysis using this auditor, starting audit from scratch\n"));
- }
- else
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- _("Resuming audit at %llu/%llu\n"),
- (unsigned long long) pp.last_reserve_in_serial_id,
- (unsigned long long) pp.last_wire_out_serial_id);
- }
-
- in_map = GNUNET_CONTAINER_multihashmap_create (1024,
- GNUNET_YES);
- qs = edb->select_reserves_in_above_serial_id (edb->cls,
- esession,
- pp.last_reserve_in_serial_id,
- &reserve_in_cb,
- NULL);
- if (0 > qs)
- {
- GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
- if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE,
- "No new incoming transactions available, skipping CREDIT phase\n");
- process_debits ();
- return;
- }
- hh = wp->get_history (wp->cls,
- TALER_BANK_DIRECTION_CREDIT,
- in_wire_off,
- wire_off_size,
- INT64_MAX,
- &history_credit_cb,
- NULL);
- if (NULL == hh)
- {
- fprintf (stderr,
- "Failed to obtain bank transaction history\n");
- commit (GNUNET_DB_STATUS_HARD_ERROR);
- global_ret = 1;
- GNUNET_SCHEDULER_shutdown ();
- return;
- }
+ TALER_EXCHANGEDB_find_accounts (cfg,
+ &process_account_cb,
+ NULL);
}
@@ -1552,12 +1703,6 @@ main (int argc,
"restart",
"restart audit from the beginning (required on first run)",
&restart),
- GNUNET_GETOPT_option_mandatory
- (GNUNET_GETOPT_option_string ('w',
- "wire",
- "PLUGINNAME",
- "name of the wire plugin to use",
- &wire_plugin)),
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/auditordb/auditordb-postgres.conf b/src/auditordb/auditordb-postgres.conf
index 4fe2064f1..9a6d39884 100644
--- a/src/auditordb/auditordb-postgres.conf
+++ b/src/auditordb/auditordb-postgres.conf
@@ -1,3 +1,3 @@
[auditordb-postgres]
# Argument for Postgres for how to connect to the database.
-DB_CONN_STR = "postgres:///taler"
+CONFIG = "postgres:///taler"
diff --git a/src/auditordb/plugin_auditordb_postgres.c b/src/auditordb/plugin_auditordb_postgres.c
index 2f881ae29..13fbbc2f2 100644
--- a/src/auditordb/plugin_auditordb_postgres.c
+++ b/src/auditordb/plugin_auditordb_postgres.c
@@ -231,6 +231,7 @@ postgres_create_tables (void *cls)
")"),
GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS wire_auditor_progress"
"(master_pub BYTEA PRIMARY KEY CHECK (LENGTH(master_pub)=32)"
+ ",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"
",last_timestamp INT8 NOT NULL"
@@ -521,13 +522,14 @@ postgres_prepare (PGconn *db_conn)
GNUNET_PQ_make_prepare ("wire_auditor_progress_insert",
"INSERT INTO wire_auditor_progress "
"(master_pub"
+ ",account_name"
",last_wire_reserve_in_serial_id"
",last_wire_wire_out_serial_id"
",last_timestamp"
",wire_in_off"
",wire_out_off"
- ") VALUES ($1,$2,$3,$4,$5,$6);",
- 6),
+ ") VALUES ($1,$2,$3,$4,$5,$6,$7);",
+ 7),
/* Used in #postgres_update_wire_auditor_progress() */
GNUNET_PQ_make_prepare ("wire_auditor_progress_update",
"UPDATE wire_auditor_progress SET "
@@ -536,8 +538,8 @@ postgres_prepare (PGconn *db_conn)
",last_timestamp=$3"
",wire_in_off=$4"
",wire_out_off=$5"
- " WHERE master_pub=$6",
- 6),
+ " WHERE master_pub=$6 AND account_name=$7",
+ 7),
/* Used in #postgres_get_wire_auditor_progress() */
GNUNET_PQ_make_prepare ("wire_auditor_progress_select",
"SELECT"
@@ -547,8 +549,8 @@ postgres_prepare (PGconn *db_conn)
",wire_in_off"
",wire_out_off"
" FROM wire_auditor_progress"
- " WHERE master_pub=$1;",
- 1),
+ " WHERE master_pub=$1 AND account_name=$2;",
+ 2),
/* Used in #postgres_insert_reserve_info() */
GNUNET_PQ_make_prepare ("auditor_reserves_insert",
"INSERT INTO auditor_reserves "
@@ -1342,6 +1344,7 @@ postgres_get_auditor_progress (void *cls,
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @param pp where is the auditor in processing
* @return transaction status code
*/
@@ -1349,6 +1352,7 @@ static enum GNUNET_DB_QueryStatus
postgres_insert_wire_auditor_progress (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
const struct TALER_AUDITORDB_WireProgressPoint *pp,
const void *in_wire_off,
const void *out_wire_off,
@@ -1356,6 +1360,7 @@ postgres_insert_wire_auditor_progress (void *cls,
{
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),
TALER_PQ_query_param_absolute_time (&pp->last_timestamp),
@@ -1379,6 +1384,7 @@ postgres_insert_wire_auditor_progress (void *cls,
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @param pp where is the auditor in processing
* @return transaction status code
*/
@@ -1386,6 +1392,7 @@ static enum GNUNET_DB_QueryStatus
postgres_update_wire_auditor_progress (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
const struct TALER_AUDITORDB_WireProgressPoint *pp,
const void *in_wire_off,
const void *out_wire_off,
@@ -1400,6 +1407,7 @@ postgres_update_wire_auditor_progress (void *cls,
GNUNET_PQ_query_param_fixed_size (out_wire_off,
wire_off_size),
GNUNET_PQ_query_param_auto_from_type (master_pub),
+ GNUNET_PQ_query_param_string (account_name),
GNUNET_PQ_query_param_end
};
@@ -1415,6 +1423,7 @@ postgres_update_wire_auditor_progress (void *cls,
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @param[out] pp set to where the auditor is in processing
* @return transaction status code
*/
@@ -1422,6 +1431,7 @@ static enum GNUNET_DB_QueryStatus
postgres_get_wire_auditor_progress (void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
struct TALER_AUDITORDB_WireProgressPoint *pp,
void **in_wire_off,
void **out_wire_off,
@@ -1431,6 +1441,7 @@ postgres_get_wire_auditor_progress (void *cls,
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),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -2594,12 +2605,12 @@ libtaler_plugin_auditordb_postgres_init (void *cls)
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"auditordb-postgres",
- "db_conn_str",
+ "CONFIG",
&pg->connection_cfg_str))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"auditordb-postgres",
- "db_conn_str");
+ "CONFIG");
GNUNET_free (pg);
return NULL;
}
diff --git a/src/auditordb/test-auditor-db-postgres.conf b/src/auditordb/test-auditor-db-postgres.conf
index 5c1e7fbc1..fd8ffbfdd 100644
--- a/src/auditordb/test-auditor-db-postgres.conf
+++ b/src/auditordb/test-auditor-db-postgres.conf
@@ -4,4 +4,4 @@ DB = postgres
[auditordb-postgres]
# Argument for Postgres for how to connect to the database.
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am
index abe820a64..9f2740b24 100644
--- a/src/bank-lib/Makefile.am
+++ b/src/bank-lib/Makefile.am
@@ -32,7 +32,8 @@ 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_reject.c \
+ bank_api_parse.c
libtalerbank_la_LIBADD = \
$(top_builddir)/src/json/libtalerjson.la \
@@ -148,6 +149,7 @@ test_bank_api_new_SOURCES = \
test_bank_api_new_LDADD = \
$(top_builddir)/src/exchange-lib/libtalertesting.la \
+ $(top_builddir)/src/json/libtalerjson.la \
libtalerbanktesting.la \
-ltalerexchange \
-lgnunetutil \
diff --git a/src/bank-lib/bank.conf b/src/bank-lib/bank.conf
index f6e4e7fe0..9befeba9e 100644
--- a/src/bank-lib/bank.conf
+++ b/src/bank-lib/bank.conf
@@ -1,8 +1,11 @@
[taler]
currency = KUDOS
+[account-1]
+URL = payto://x-taler-bank/localhost:8081/1
+
[bank]
-http_port = 8081
+HTTP_PORT = 8081
[exchange-wire-test]
bank_url = http://localhost:8081/
diff --git a/src/bank-lib/bank_api_history.c b/src/bank-lib/bank_api_history.c
index d2035e881..17cd9fd07 100644
--- a/src/bank-lib/bank_api_history.c
+++ b/src/bank-lib/bank_api_history.c
@@ -136,10 +136,12 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
GNUNET_JSON_parse_free (hist_spec);
return GNUNET_SYSERR;
}
- td.account_details = json_pack ("{s:s, s:s, s:I}",
- "type", "test",
- "bank_url", hh->bank_base_url,
- "account_number", (json_int_t) other_account);
+ GNUNET_asprintf (&td.account_url,
+ ('/' == hh->bank_base_url[strlen(hh->bank_base_url)-1])
+ ? "payto://x-taler-bank/%s%llu"
+ : "payto://x-taler-bank/%s/%llu",
+ hh->bank_base_url,
+ (unsigned long long) other_account);
hh->hcb (hh->hcb_cls,
MHD_HTTP_OK,
TALER_EC_NONE,
@@ -147,7 +149,7 @@ parse_account_history (struct TALER_BANK_HistoryHandle *hh,
row_id,
&td,
transaction);
- json_decref (td.account_details);
+ GNUNET_free (td.account_url);
GNUNET_JSON_parse_free (hist_spec);
}
return GNUNET_OK;
diff --git a/src/bank-lib/bank_api_parse.c b/src/bank-lib/bank_api_parse.c
new file mode 100644
index 000000000..04cf7b85f
--- /dev/null
+++ b/src/bank-lib/bank_api_parse.c
@@ -0,0 +1,133 @@
+/*
+ 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/bank_api_parse.c
+ * @brief Convenience function to parse authentication configuration
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_bank_service.h"
+
+
+/**
+ * Parse configuration section with bank authentication data.
+ *
+ * @param cfg configuration to parse
+ * @param section the section with the configuration data
+ * @param auth[out] set to the configuration data found
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_BANK_auth_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ struct TALER_BANK_AuthenticationData *auth)
+{
+ const struct {
+ const char *m;
+ enum TALER_BANK_AuthenticationMethod e;
+ } methods[] = {
+ { "NONE", TALER_BANK_AUTH_NONE },
+ { "BASIC", TALER_BANK_AUTH_BASIC },
+ { NULL, TALER_BANK_AUTH_NONE }
+ };
+ char *method;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "TALER_BANK_AUTH_METHOD",
+ &method))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "TALER_BANK_AUTH_METHOD");
+ return GNUNET_SYSERR;
+ }
+ for (unsigned int i=0; NULL != methods[i].m;i++)
+ {
+ if (0 == strcasecmp (method,
+ methods[i].m))
+ {
+ switch (methods[i].e)
+ {
+ case TALER_BANK_AUTH_NONE:
+ auth->method = TALER_BANK_AUTH_NONE;
+ return GNUNET_OK;
+ case TALER_BANK_AUTH_BASIC:
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "USERNAME",
+ &auth->details.basic.username))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "USERNAME");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ section,
+ "PASSWORD",
+ &auth->details.basic.password))
+ {
+ GNUNET_free (auth->details.basic.username);
+ auth->details.basic.username = NULL;
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ section,
+ "USERNAME");
+ return GNUNET_SYSERR;
+ }
+ auth->method = TALER_BANK_AUTH_BASIC;
+ return GNUNET_OK;
+ }
+ }
+ }
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Free memory inside of @a auth (but not auth itself).
+ * Dual to #TALER_BANK_auth_parse_cfg().
+ *
+ * @param auth authentication data to free
+ */
+void
+TALER_BANK_auth_free (struct TALER_BANK_AuthenticationData *auth)
+{
+ switch (auth->method)
+ {
+ case TALER_BANK_AUTH_NONE:
+ break;
+ case TALER_BANK_AUTH_BASIC:
+ if (NULL != auth->details.basic.username)
+ {
+ GNUNET_free (auth->details.basic.username);
+ auth->details.basic.username = NULL;
+ }
+ if (NULL != auth->details.basic.password)
+ {
+ GNUNET_free (auth->details.basic.password);
+ auth->details.basic.password = NULL;
+ }
+ break;
+ }
+}
+
+
+/* end of bank_api_parse.c */
diff --git a/src/bank-lib/test_bank_api_with_fakebank_new.c b/src/bank-lib/test_bank_api_with_fakebank_new.c
index 1a70f5714..002010b29 100644
--- a/src/bank-lib/test_bank_api_with_fakebank_new.c
+++ b/src/bank-lib/test_bank_api_with_fakebank_new.c
@@ -210,9 +210,10 @@ main (int argc,
"DEBUG",
NULL);
if (NULL ==
- (fakebank_url = TALER_TESTING_prepare_fakebank (CONFIG_FILE)))
+ (fakebank_url = TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-1")))
return 77;
-
+
return (GNUNET_OK == TALER_TESTING_setup (&run,
NULL,
CONFIG_FILE,
diff --git a/src/bank-lib/test_bank_interpreter.c b/src/bank-lib/test_bank_interpreter.c
index 40adea54f..e503bd8dc 100644
--- a/src/bank-lib/test_bank_interpreter.c
+++ b/src/bank-lib/test_bank_interpreter.c
@@ -326,15 +326,10 @@ build_history (struct InterpreterState *is,
h[total].direction = TALER_BANK_DIRECTION_CREDIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
- h[total].details.account_details
- = json_pack ("{s:s, s:s, s:I}",
- "type",
- "test",
- "bank_url",
- "http://localhost:8080",
- "account_number",
- (json_int_t) pos->details.admin_add_incoming.debit_account_no);
- GNUNET_assert (NULL != h[total].details.account_details);
+ GNUNET_asprintf (&h[total].details.account_url,
+ "payto://x-taler-bank/%s/%llu",
+ "http://localhost:8080",
+ (unsigned long long) pos->details.admin_add_incoming.debit_account_no);
}
if ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_DEBIT)) &&
(cmd->details.history.account_number ==
@@ -343,15 +338,10 @@ build_history (struct InterpreterState *is,
h[total].direction = TALER_BANK_DIRECTION_DEBIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
- h[total].details.account_details
- = json_pack ("{s:s, s:s, s:I}",
- "type",
- "test",
- "bank_url",
- "http://localhost:8080",
- "account_number",
- (json_int_t) pos->details.admin_add_incoming.credit_account_no);
- GNUNET_assert (NULL != h[total].details.account_details);
+ GNUNET_asprintf (&h[total].details.account_url,
+ "payto://x-taler-bank/%s/%llu",
+ "http://localhost:8080",
+ (unsigned long long) pos->details.admin_add_incoming.credit_account_no);
}
if ( ( (0 != (cmd->details.history.direction & TALER_BANK_DIRECTION_CREDIT)) &&
(cmd->details.history.account_number ==
@@ -398,10 +388,6 @@ print_expected (struct History *h,
"Expected history:\n");
for (uint64_t i=0;i<h_len;i++)
{
- char *acc;
-
- acc = json_dumps (h[i].details.account_details,
- JSON_COMPACT);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"H(%llu): %s%s (serial: %llu, subject: %s, to: %s)\n",
(unsigned long long) i,
@@ -409,9 +395,7 @@ print_expected (struct History *h,
TALER_amount2s (&h[i].details.amount),
(unsigned long long) h[i].row_id,
h[i].details.wire_transfer_subject,
- acc);
- if (NULL != acc)
- free (acc);
+ h[i].details.account_url);
}
}
@@ -429,7 +413,7 @@ free_history (struct History *h,
for (uint64_t off = 0;off<h_len;off++)
{
GNUNET_free (h[off].details.wire_transfer_subject);
- json_decref (h[off].details.account_details);
+ GNUNET_free (h[off].details.account_url);
}
GNUNET_free_non_null (h);
}
@@ -500,8 +484,8 @@ check_result (struct InterpreterState *is,
details->wire_transfer_subject)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
- (1 != json_equal (h[off].details.account_details,
- details->account_details)) )
+ (0 != strcasecmp (h[off].details.account_url,
+ details->account_url)) )
{
GNUNET_break (0);
print_expected (h, total, off);
diff --git a/src/bank-lib/testing_api_cmd_history.c b/src/bank-lib/testing_api_cmd_history.c
index 30090bf8c..e94009fb3 100644
--- a/src/bank-lib/testing_api_cmd_history.c
+++ b/src/bank-lib/testing_api_cmd_history.c
@@ -99,6 +99,7 @@ history_traits (void *cls,
return GNUNET_SYSERR;
}
+
/**
* Test if the /admin/add/incoming transaction at offset @a off
* has been /rejected.
@@ -115,7 +116,8 @@ test_cancelled (struct TALER_TESTING_Interpreter *is,
const struct TALER_TESTING_Command *current_cmd;
current_cmd = &is->commands[off];
- TALER_LOG_INFO ("Is `%s' rejected?\n", current_cmd->label);
+ TALER_LOG_INFO ("Is `%s' rejected?\n",
+ current_cmd->label);
for (unsigned int i=0;i<is->ip;i++)
{
const struct TALER_TESTING_Command *c = &is->commands[i];
@@ -140,6 +142,7 @@ test_cancelled (struct TALER_TESTING_Interpreter *is,
return GNUNET_NO;
}
+
/**
* Free history @a h of length @a h_len.
*
@@ -153,11 +156,12 @@ free_history (struct History *h,
for (uint64_t off = 0;off<h_len;off++)
{
GNUNET_free (h[off].details.wire_transfer_subject);
- json_decref (h[off].details.account_details);
+ GNUNET_free (h[off].details.account_url);
}
GNUNET_free_non_null (h);
}
+
/**
* Log which history we expected.
*
@@ -178,10 +182,6 @@ print_expected (struct History *h,
"Expected history:\n");
for (uint64_t i=0;i<h_len;i++)
{
- char *acc;
-
- acc = json_dumps (h[i].details.account_details,
- JSON_COMPACT);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"H(%llu): %s%s (serial: %llu, subject: %s, to: %s)\n",
(unsigned long long) i,
@@ -189,12 +189,11 @@ print_expected (struct History *h,
TALER_amount2s (&h[i].details.amount),
(unsigned long long) h[i].row_id,
h[i].details.wire_transfer_subject,
- acc);
- if (NULL != acc)
- free (acc);
+ h[i].details.account_url);
}
}
+
/**
* Build history of transactions matching the current
* command in @a is.
@@ -409,15 +408,10 @@ build_history (struct TALER_TESTING_Interpreter *is,
h[total].direction = TALER_BANK_DIRECTION_CREDIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
- h[total].details.account_details
- = json_pack ("{s:s, s:s, s:I}",
- "type",
- "test",
- "bank_url",
- hs->bank_url,
- "account_number",
- (json_int_t) *debit_account_no);
- GNUNET_assert (NULL != h[total].details.account_details);
+ GNUNET_asprintf (&h[total].details.account_url,
+ "payto://x-taler-bank/%s/%llu",
+ hs->bank_url,
+ (unsigned long long) *debit_account_no);
}
if ( (0 != (hs->direction & TALER_BANK_DIRECTION_DEBIT)) &&
(hs->account_no == *debit_account_no))
@@ -425,15 +419,10 @@ build_history (struct TALER_TESTING_Interpreter *is,
h[total].direction = TALER_BANK_DIRECTION_DEBIT;
if (GNUNET_YES == cancelled)
h[total].direction |= TALER_BANK_DIRECTION_CANCEL;
- h[total].details.account_details
- = json_pack ("{s:s, s:s, s:I}",
- "type",
- "test",
- "bank_url",
- hs->bank_url,
- "account_number",
- (json_int_t) *credit_account_no);
- GNUNET_assert (NULL != h[total].details.account_details);
+ GNUNET_asprintf (&h[total].details.account_url,
+ "payto://x-taler-bank/%s/%llu",
+ hs->bank_url,
+ (unsigned long long) *credit_account_no);
}
if ( ( (0 != (hs->direction & TALER_BANK_DIRECTION_CREDIT)) &&
(hs->account_no == *credit_account_no)) ||
@@ -533,8 +522,8 @@ check_result (struct TALER_TESTING_Interpreter *is,
details->wire_transfer_subject)) ||
(0 != TALER_amount_cmp (&h[off].details.amount,
&details->amount)) ||
- (1 != json_equal (h[off].details.account_details,
- details->account_details)) )
+ (0 != strcasecmp (h[off].details.account_url,
+ details->account_url)) )
{
GNUNET_break (0);
print_expected (h, total, off);
diff --git a/src/bank-lib/testing_api_cmd_reject.c b/src/bank-lib/testing_api_cmd_reject.c
index c01c27d87..2eb6d4f9b 100644
--- a/src/bank-lib/testing_api_cmd_reject.c
+++ b/src/bank-lib/testing_api_cmd_reject.c
@@ -127,7 +127,7 @@ reject_run (void *cls,
(GNUNET_OK == TALER_TESTING_GET_TRAIT_ROW_ID
(deposit_cmd, &row_id));
TALER_LOG_INFO ("Account %llu rejects deposit\n",
- *credit_account);
+ (unsigned long long) *credit_account);
rs->rh = TALER_BANK_reject (is->ctx,
rs->bank_url,
&AUTHS[*credit_account -1],
@@ -180,7 +180,7 @@ TALER_TESTING_cmd_bank_reject (const char *label,
rs = GNUNET_new (struct RejectState);
rs->bank_url = bank_url;
rs->deposit_reference = deposit_reference;
-
+
cmd.cls = rs;
cmd.run = &reject_run;
cmd.cleanup = &reject_cleanup;
diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c
index fbdfe825c..3fd31eda7 100644
--- a/src/benchmark/taler-exchange-benchmark.c
+++ b/src/benchmark/taler-exchange-benchmark.c
@@ -895,8 +895,8 @@ spend_coin (struct Coin *coin,
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.h_contract_terms = h_contract_terms;
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (merchant_details,
- &dr.h_wire));
+ TALER_JSON_wire_signature_hash (merchant_details,
+ &dr.h_wire));
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
diff --git a/src/benchmark/taler-exchange-benchmark.conf b/src/benchmark/taler-exchange-benchmark.conf
index 453782c7c..887673850 100644
--- a/src/benchmark/taler-exchange-benchmark.conf
+++ b/src/benchmark/taler-exchange-benchmark.conf
@@ -20,22 +20,20 @@ DB = postgres
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
[exchangedb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
+[account-exchange]
# What is the main website of the bank?
# (Not used unless the aggregator is run.)
-BANK_URL = "http://localhost:8082/"
-# From which account at the 'bank' should outgoing wire transfers be made?
-BANK_ACCOUNT_NUMBER = 2
+URL = "payto://x-taler-bank/localhost:8082/2"
# This is the response we give out for the /wire request. It provides
# wallets with the bank information for transfers to the exchange.
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account.json
+
+[fees-x-taler-bank]
WIRE-FEE-2017 = KUDOS:0.01
WIRE-FEE-2018 = KUDOS:0.01
WIRE-FEE-2019 = KUDOS:0.01
diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am
index 5e0833b31..57c935088 100644
--- a/src/exchange-lib/Makefile.am
+++ b/src/exchange-lib/Makefile.am
@@ -61,6 +61,7 @@ libtalertesting_la_SOURCES = \
testing_api_trait_coin_priv.c \
testing_api_trait_denom_pub.c \
testing_api_trait_denom_sig.c \
+ testing_api_trait_json.c \
testing_api_trait_process.c \
testing_api_trait_reserve_priv.c \
testing_api_trait_number.c \
@@ -69,8 +70,8 @@ libtalertesting_la_SOURCES = \
testing_api_trait_key_peer.c \
testing_api_trait_wtid.c \
testing_api_trait_amount.c
-
libtalertesting_la_LIBADD = \
+ $(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
diff --git a/src/exchange-lib/exchange_api_deposit.c b/src/exchange-lib/exchange_api_deposit.c
index 76e3e4da9..7e499a434 100644
--- a/src/exchange-lib/exchange_api_deposit.c
+++ b/src/exchange-lib/exchange_api_deposit.c
@@ -416,8 +416,8 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
MAH_handle_is_ready (exchange));
/* initialize h_wire */
if (GNUNET_OK !=
- TALER_JSON_hash (wire_details,
- &h_wire))
+ TALER_JSON_wire_signature_hash (wire_details,
+ &h_wire))
{
GNUNET_break (0);
return NULL;
diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c
index 72429d4e8..86a83fdb0 100644
--- a/src/exchange-lib/exchange_api_reserve.c
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -139,7 +139,7 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
if (0 == strcasecmp (type,
"DEPOSIT"))
{
- json_t *wire_account;
+ const char *wire_url;
void *wire_reference;
size_t wire_reference_size;
struct GNUNET_TIME_Absolute timestamp;
@@ -150,8 +150,8 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
&wire_reference_size),
GNUNET_JSON_spec_absolute_time ("timestamp",
&timestamp),
- GNUNET_JSON_spec_json ("sender_account_details",
- &wire_account),
+ GNUNET_JSON_spec_string ("sender_account_url",
+ &wire_url),
GNUNET_JSON_spec_end()
};
@@ -173,7 +173,7 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- rhistory[off].details.in_details.sender_account_details = wire_account;
+ rhistory[off].details.in_details.sender_url = GNUNET_strdup (wire_url);
rhistory[off].details.in_details.wire_reference = wire_reference;
rhistory[off].details.in_details.wire_reference_size = wire_reference_size;
rhistory[off].details.in_details.timestamp = timestamp;
@@ -361,8 +361,8 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
TALER_amount_hton (&rcc.closing_amount,
&amount);
if (GNUNET_OK !=
- TALER_JSON_hash (rhistory[off].details.close_details.receiver_account_details,
- &rcc.h_wire))
+ TALER_JSON_wire_signature_hash (rhistory[off].details.close_details.receiver_account_details,
+ &rcc.h_wire))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -440,8 +440,7 @@ free_rhistory (struct TALER_EXCHANGE_ReserveHistory *rhistory,
{
case TALER_EXCHANGE_RTT_DEPOSIT:
GNUNET_free_non_null (rhistory[i].details.in_details.wire_reference);
- if (NULL != rhistory[i].details.in_details.sender_account_details)
- json_decref (rhistory[i].details.in_details.sender_account_details);
+ GNUNET_free_non_null (rhistory[i].details.in_details.sender_url);
break;
case TALER_EXCHANGE_RTT_WITHDRAWAL:
break;
diff --git a/src/exchange-lib/exchange_api_wire.c b/src/exchange-lib/exchange_api_wire.c
index f1056fdd2..12789b2bc 100644
--- a/src/exchange-lib/exchange_api_wire.c
+++ b/src/exchange-lib/exchange_api_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016 Inria and GNUnet e.V.
+ Copyright (C) 2014-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
@@ -27,6 +27,7 @@
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
+#include "taler_wire_lib.h"
#include "taler_signatures.h"
#include "taler_wire_plugin.h"
#include "exchange_api_handle.h"
@@ -63,66 +64,133 @@ struct TALER_EXCHANGE_WireHandle
*/
void *cb_cls;
+};
+
+
+/**
+ * List of wire fees by method.
+ */
+struct FeeMap
+{
/**
- * Set to the "methods" JSON array returned by the
- * /wire request.
+ * Next entry in list.
*/
- json_t *methods;
+ struct FeeMap *next;
/**
- * Current iteration offset in the @e methods array.
+ * Wire method this fee structure is for.
*/
- unsigned int methods_off;
+ char *method;
+ /**
+ * Array of wire fees, also linked list, but allocated
+ * only once.
+ */
+ struct TALER_EXCHANGE_WireAggregateFees *fee_list;
};
/**
- * Verify that the signature on the "200 OK" response
- * for /wire/METHOD from the exchange is valid.
+ * Frees @a fm.
*
- * @param wh wire handle with key material
- * @param method method to verify the reply for
- * @param json json reply with the signature
- * @return #GNUNET_SYSERR if @a json is invalid,
- * #GNUNET_NO if the method is unknown,
- * #GNUNET_OK if the json is valid
+ * @param fm memory to release
*/
-static int
-verify_wire_method_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh,
- const char *method,
- const json_t *json)
+static void
+free_fees (struct FeeMap *fm)
{
- const struct TALER_EXCHANGE_Keys *key_state;
- struct TALER_WIRE_Plugin *plugin;
- char *lib_name;
- char *emsg;
- enum TALER_ErrorCode ec;
-
- key_state = TALER_EXCHANGE_get_keys (wh->exchange);
- (void) GNUNET_asprintf (&lib_name,
- "libtaler_plugin_wire_%s",
- method);
- plugin = GNUNET_PLUGIN_load (lib_name,
- NULL);
- if (NULL == plugin)
+ while (NULL != fm)
{
- GNUNET_free (lib_name);
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wire transfer method `%s' not supported\n",
- method);
- return GNUNET_NO;
+ struct FeeMap *fe = fm->next;
+
+ GNUNET_free (fm->fee_list);
+ GNUNET_free (fm->method);
+ GNUNET_free (fm);
+ fm = fe;
+ }
+}
+
+
+/**
+ * Parse wire @a fees and return map.
+ *
+ * @param fees json AggregateTransferFee to parse
+ * @return NULL on error
+ */
+static struct FeeMap *
+parse_fees (json_t *fees)
+{
+ struct FeeMap *fm = NULL;
+ const char *key;
+ json_t *fee_array;
+
+ json_object_foreach (fees, key, fee_array) {
+ struct FeeMap *fe = GNUNET_new (struct FeeMap);
+ int len;
+ unsigned int idx;
+ json_t *fee;
+
+ if (0 == (len = json_array_size (fee_array)))
+ {
+ GNUNET_break_op (0);
+ GNUNET_free (fe);
+ continue; /* skip */
+ }
+ fe->method = GNUNET_strdup (key);
+ fe->next = fm;
+ fe->fee_list = GNUNET_new_array (len,
+ struct TALER_EXCHANGE_WireAggregateFees);
+ fm = fe;
+ json_array_foreach (fee_array, idx, fee)
+ {
+ struct TALER_EXCHANGE_WireAggregateFees *wa = &fe->fee_list[idx];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("sig",
+ &wa->master_sig),
+ TALER_JSON_spec_amount ("wire_fee",
+ &wa->wire_fee),
+ TALER_JSON_spec_amount ("closing_fee",
+ &wa->closing_fee),
+ GNUNET_JSON_spec_absolute_time ("start_date",
+ &wa->start_date),
+ GNUNET_JSON_spec_absolute_time ("end_date",
+ &wa->end_date),
+ GNUNET_JSON_spec_end()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (fee,
+ spec,
+ NULL,
+ NULL))
+ {
+ GNUNET_break_op (0);
+ free_fees (fm);
+ return NULL;
+ }
+ if (idx < len)
+ wa->next = &fe->fee_list[idx + 1];
+ }
}
- plugin->library_name = lib_name;
- ec = plugin->wire_validate (plugin->cls,
- json,
- &key_state->master_pub,
- &emsg);
- GNUNET_free_non_null (emsg);
- GNUNET_PLUGIN_unload (lib_name,
- plugin);
- GNUNET_free (lib_name);
- return (TALER_EC_NONE == ec) ? GNUNET_OK : GNUNET_SYSERR;
+ return fm;
+}
+
+
+/**
+ * Find fee by @a method.
+ *
+ * @param fm map to look in
+ * @param method key to look for
+ * @return NULL if fee is not specified in @a fm
+ */
+static const struct TALER_EXCHANGE_WireAggregateFees *
+lookup_fee (const struct FeeMap *fm,
+ const char *method)
+{
+ for (;NULL != fm; fm = fm->next)
+ if (0 == strcasecmp (fm->method,
+ method))
+ return fm->fee_list;
+ return NULL;
}
@@ -140,70 +208,131 @@ handle_wire_finished (void *cls,
const json_t *json)
{
struct TALER_EXCHANGE_WireHandle *wh = cls;
- json_t *keep = NULL;
+ enum TALER_ErrorCode ec;
wh->job = NULL;
+ ec = TALER_EC_NONE;
switch (response_code)
{
case 0:
break;
case MHD_HTTP_OK:
{
- const struct TALER_EXCHANGE_Keys *keys;
- const struct TALER_MasterPublicKeyP *master_pub;
- const char *key;
- json_t *method;
- int ret;
-
- /* We 'keep' methods that we support and that are well-formed;
- we fail (by setting response_code=0) if any method that we do
- support fails to verify. */
- keep = json_object ();
- json_object_foreach ((json_t *) json, key, method) {
- ret = verify_wire_method_signature_ok (wh,
- key,
- method);
- if (GNUNET_SYSERR == ret)
- {
- /* bogus reply */
- GNUNET_break_op (0);
- response_code = 0;
- }
- /* GNUNET_NO: not understood by us, simply skip! */
- if (GNUNET_OK == ret)
- {
- /* supported and valid, keep! */
- json_object_set (keep,
- key,
- method);
- }
- }
- /* check fees */
- keys = TALER_EXCHANGE_get_keys (wh->exchange);
- if (NULL == keys)
- master_pub = NULL;
- else
- master_pub = &keys->master_pub;
+ json_t *accounts;
+ json_t *fees;
+ int num_accounts;
+ struct FeeMap *fm;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("accounts", &accounts),
+ GNUNET_JSON_spec_json ("fees", &fees),
+ GNUNET_JSON_spec_end()
+ };
+
if (GNUNET_OK !=
- TALER_EXCHANGE_wire_get_fees (master_pub,
- keep,
- NULL,
- NULL))
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
{
/* bogus reply */
GNUNET_break_op (0);
response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
+ break;
}
- if (0 != response_code)
+ if (0 == (num_accounts = json_array_size (accounts)))
{
- /* all supported methods were valid, use 'keep' for 'json' */
+ /* bogus reply */
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
break;
}
- /* some supported methods were invalid, release 'keep', preserve
- full 'json' for application-level error handling. */
- json_decref (keep);
- keep = NULL;
- }
+ if (NULL == (fm = parse_fees (fees)))
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ GNUNET_JSON_parse_free (spec);
+ response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
+ break;
+ }
+
+ key_state = TALER_EXCHANGE_get_keys (wh->exchange);
+ /* parse accounts */
+ {
+ struct TALER_EXCHANGE_WireAccount was[num_accounts];
+
+ for (unsigned int i=0;i<num_accounts;i++)
+ {
+ struct TALER_EXCHANGE_WireAccount *wa = &was[i];
+ json_t *account;
+ struct GNUNET_JSON_Specification spec_account[] = {
+ GNUNET_JSON_spec_string ("url", &wa->url),
+ GNUNET_JSON_spec_string ("salt", &wa->salt),
+ GNUNET_JSON_spec_fixed_auto ("master_sig", &wa->master_sig),
+ GNUNET_JSON_spec_end()
+ };
+ char *method;
+
+ account = json_array_get (accounts,
+ i);
+ if (GNUNET_OK !=
+ TALER_JSON_wire_signature_check (account,
+ &key_state->master_pub))
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ response_code = 0;
+ ec = TALER_EC_SERVER_SIGNATURE_INVALID;
+ break;
+ }
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (account,
+ spec_account,
+ NULL, NULL))
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
+ break;
+ }
+ if (NULL == (method = TALER_WIRE_payto_get_method (wa->url)))
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
+ break;
+ }
+ if (NULL == (wa->fees = lookup_fee (fm,
+ method)))
+ {
+ /* bogus reply */
+ GNUNET_break_op (0);
+ response_code = 0;
+ ec = TALER_EC_SERVER_JSON_INVALID;
+ GNUNET_free (method);
+ break;
+ }
+ GNUNET_free (method);
+ } /* end 'for all accounts */
+ if ( (0 != response_code) &&
+ (NULL != wh->cb) )
+ {
+ wh->cb (wh->cb_cls,
+ response_code,
+ TALER_EC_NONE,
+ num_accounts,
+ was);
+ wh->cb = NULL;
+ }
+ } /* end of 'parse accounts */
+ free_fees (fm);
+ GNUNET_JSON_parse_free (spec);
+ } /* end of MHD_HTTP_OK */
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
@@ -226,12 +355,12 @@ handle_wire_finished (void *cls,
response_code = 0;
break;
}
- wh->cb (wh->cb_cls,
- response_code,
- TALER_JSON_get_error_code (json),
- (NULL != keep) ? keep : json);
- if (NULL != keep)
- json_decref (keep);
+ if (NULL != wh->cb)
+ wh->cb (wh->cb_cls,
+ response_code,
+ (0 == response_code) ? ec : TALER_JSON_get_error_code (json),
+ 0,
+ NULL);
TALER_EXCHANGE_wire_cancel (wh);
}
@@ -306,157 +435,9 @@ TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh)
GNUNET_CURL_job_cancel (wh->job);
wh->job = NULL;
}
- if (NULL != wh->methods)
- {
- json_decref (wh->methods);
- wh->methods = NULL;
- }
GNUNET_free (wh->url);
GNUNET_free (wh);
}
-/**
- * Parse wire @a fee and store the result in @a af.
- *
- * @param[out] af where to write the result
- * @param fee json AggregateTransferFee to parse
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
- */
-static int
-parse_json_fees (struct TALER_EXCHANGE_WireAggregateFees *af,
- json_t *fee)
-{
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("sig",
- &af->master_sig),
- TALER_JSON_spec_amount ("wire_fee",
- &af->wire_fee),
- TALER_JSON_spec_amount ("closing_fee",
- &af->closing_fee),
- GNUNET_JSON_spec_absolute_time ("start_date",
- &af->start_date),
- GNUNET_JSON_spec_absolute_time ("end_date",
- &af->end_date),
- GNUNET_JSON_spec_end()
- };
-
- if (GNUNET_OK !=
- GNUNET_JSON_parse (fee,
- spec,
- NULL,
- NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- return GNUNET_OK;
-}
-
-
-/**
- * Check the #TALER_SIGNATURE_MASTER_WIRE_FEES signature.
- *
- * @param af record to check
- * @param wire_method wire method to check against
- * @param master_pub expected signing key
- * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
- */
-static int
-check_sig (const struct TALER_EXCHANGE_WireAggregateFees *af,
- const char *wire_method,
- const struct TALER_MasterPublicKeyP *master_pub)
-{
- struct TALER_MasterWireFeePS wp;
-
- wp.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_FEES);
- wp.purpose.size = htonl (sizeof (wp));
- GNUNET_CRYPTO_hash (wire_method,
- strlen (wire_method) + 1,
- &wp.h_wire_method);
- wp.start_date = GNUNET_TIME_absolute_hton (af->start_date);
- wp.end_date = GNUNET_TIME_absolute_hton (af->end_date);
- TALER_amount_hton (&wp.wire_fee,
- &af->wire_fee);
- TALER_amount_hton (&wp.closing_fee,
- &af->closing_fee);
- return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_FEES,
- &wp.purpose,
- &af->master_sig.eddsa_signature,
- &master_pub->eddsa_pub);
-}
-
-
-/**
- * Obtain information about wire fees encoded in @a obj
- * by wire method.
- *
- * @param master_pub public key to use to verify signatures, NULL to not verify
- * @param obj wire information as encoded in the #TALER_EXCHANGE_WireResultCallback
- * @param cb callback to invoke for the fees
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK in success, #GNUNET_SYSERR if @a obj is ill-formed
- */
-int
-TALER_EXCHANGE_wire_get_fees (const struct TALER_MasterPublicKeyP *master_pub,
- const json_t *obj,
- TALER_EXCHANGE_WireFeeCallback cb,
- void *cb_cls)
-{
- const char *wire_method;
- json_t *value;
-
- json_object_foreach (((json_t *) obj), wire_method, value)
- {
- json_t *fees;
- size_t num_fees;
-
- fees = json_object_get (value, "fees");
- if ( (NULL == fees) ||
- (! json_is_array (fees)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- num_fees = json_array_size (fees);
- if (num_fees > 1024)
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- {
- struct TALER_EXCHANGE_WireAggregateFees af[num_fees + 1];
-
- for (size_t i=0;i<num_fees;i++)
- {
- af[i].next = &af[i+1];
- if (GNUNET_OK !=
- parse_json_fees (&af[i],
- json_array_get (fees,
- i)))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if ( (NULL != master_pub) &&
- (GNUNET_OK !=
- check_sig (&af[i],
- wire_method,
- master_pub)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- }
- af[num_fees - 1].next = NULL;
- if (NULL != cb)
- cb (cb_cls,
- wire_method,
- &af[0]);
- }
- }
- return GNUNET_OK;
-}
-
-
/* end of exchange_api_wire.c */
diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c
index fe3877790..7ca74a227 100644
--- a/src/exchange-lib/test_exchange_api.c
+++ b/src/exchange-lib/test_exchange_api.c
@@ -36,9 +36,12 @@
#define WIRE_TEST 1
/**
- * Is the configuration file is set to include wire format 'sepa'?
+ * Is the configuration file is set to include wire format 'ebics'?
+ * Requires that EBICS /history function is implemented, which it
+ * is currently not. Once it is, set ENABLE_CREDIT to YES in the
+ * configuration and then set this option to 1.
*/
-#define WIRE_SEPA 1
+#define WIRE_EBICS 0
/**
* Account number of the exchange at the bank.
@@ -1539,12 +1542,15 @@ find_pk (const struct TALER_EXCHANGE_Keys *keys,
}
+#if LEGACY
+/* Tests the *old* /wire API, the _modern_ testcase was adapted,
+ but little point in right now adapting the old testcase */
/**
* Function called with information about the wire fees
* for each wire method.
*
* @param cls closure
- * @param wire_method name of the wire method (i.e. "sepa")
+ * @param wire_method name of the wire method (i.e. "ebics")
* @param fees fee structure for this method
*/
static void
@@ -1556,9 +1562,9 @@ check_fee_cb (void *cls,
struct Command *cmd = &is->commands[is->ip];
struct TALER_Amount expected_amount;
- GNUNET_break ( (0 == strcasecmp ("test",
+ GNUNET_break ( (0 == strcasecmp ("x-taler-bank",
wire_method)) ||
- (0 == strcasecmp ("sepa",
+ (0 == strcasecmp ("ebics",
wire_method)) );
if (GNUNET_OK !=
TALER_string_to_amount (cmd->details.wire.expected_fee,
@@ -1582,6 +1588,7 @@ check_fee_cb (void *cls,
fees = fees->next;
}
}
+#endif
/**
@@ -1592,14 +1599,15 @@ check_fee_cb (void *cls,
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param obj the received JSON reply, if successful this should be the wire
- * format details as provided by /wire.
+ * @param accounts_len length of the @a accounts array
+ * @param accounts list of wire accounts of the exchange, NULL on error
*/
static void
wire_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
- const json_t *obj)
+ unsigned int accounts_len,
+ const struct TALER_EXCHANGE_WireAccount *accounts)
{
struct InterpreterState *is = cls;
struct Command *cmd = &is->commands[is->ip];
@@ -1611,7 +1619,9 @@ wire_cb (void *cls,
"Unexpected response code %u to command %s\n",
http_status,
cmd->label);
+#if LEGACY
json_dumpf (obj, stderr, 0);
+#endif
fail (is);
return;
}
@@ -1619,6 +1629,7 @@ wire_cb (void *cls,
{
case MHD_HTTP_OK:
{
+#if LEGACY
json_t *method;
method = json_object_get (obj,
@@ -1646,6 +1657,7 @@ wire_cb (void *cls,
fail (is);
return;
}
+#endif
}
break;
default:
@@ -1760,8 +1772,8 @@ wire_deposits_cb (void *cls,
JSON_REJECT_DUPLICATES,
NULL);
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &hw));
+ TALER_JSON_wire_signature_hash (wire,
+ &hw));
json_decref (wire);
if (0 != memcmp (&hw,
h_wire,
@@ -2331,13 +2343,15 @@ interpreter_run (void *cls)
{
struct TALER_DepositRequestPS dr;
- memset (&dr, 0, sizeof (dr));
+ memset (&dr,
+ 0,
+ sizeof (dr));
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.h_contract_terms = h_contract_terms;
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &dr.h_wire));
+ TALER_JSON_wire_signature_hash (wire,
+ &dr.h_wire));
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dr.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
TALER_amount_hton (&dr.amount_with_fee,
@@ -2581,8 +2595,8 @@ interpreter_run (void *cls)
NULL);
GNUNET_assert (NULL != wire);
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &h_wire));
+ TALER_JSON_wire_signature_hash (wire,
+ &h_wire));
json_decref (wire);
contract_terms = json_loads (ref->details.deposit.contract_terms,
JSON_REJECT_DUPLICATES,
@@ -2640,7 +2654,6 @@ interpreter_run (void *cls)
"taler-exchange-wirewatch",
"taler-exchange-wirewatch",
"-c", "test_exchange_api.conf",
- "-t", "test", /* use Taler's bank/fakebank */
"-T", /* exit when done */
NULL);
if (NULL == cmd->details.run_wirewatch.wirewatch_proc)
@@ -3204,15 +3217,15 @@ run (void *cls)
.label = "wire-test",
/* expecting 'test' method in response */
.expected_response_code = MHD_HTTP_OK,
- .details.wire.format = "test",
+ .details.wire.format = "x-taler-bank",
.details.wire.expected_fee = "EUR:0.01" },
#endif
-#if WIRE_SEPA
+#if WIRE_EBICS
{ .oc = OC_WIRE,
.label = "wire-sepa",
- /* expecting 'sepa' method in response */
+ /* expecting 'ebics' method in response */
.expected_response_code = MHD_HTTP_OK,
- .details.wire.format = "sepa",
+ .details.wire.format = "ebics",
.details.wire.expected_fee = "EUR:0.01" },
#endif
/* *************** end of /wire testing ************** */
@@ -3252,7 +3265,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
/* Try to overdraw funds ... */
@@ -3268,7 +3281,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_FORBIDDEN,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":43 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/43\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
/* Try to double-spend the 5 EUR coin at the same merchant (but different
transaction ID) */
@@ -3277,7 +3290,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_FORBIDDEN,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":1 } ] }" },
/* Try to double-spend the 5 EUR coin at the same merchant (but different
proposal) */
@@ -3286,7 +3299,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_FORBIDDEN,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\":[{ \"name\":\"ice cream\", \"value\":2 } ] }" },
/* ***************** /refresh testing ******************** */
@@ -3316,7 +3329,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:1",
.details.deposit.coin_ref = "refresh-withdraw-coin-1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:1\" } ] }" },
/* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x EUR:0.13) */
@@ -3357,7 +3370,7 @@ run (void *cls)
.details.deposit.amount = "EUR:1",
.details.deposit.coin_ref = "refresh-reveal-1-idempotency",
.details.deposit.coin_idx = 0,
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
/* Test successfully spending coins from the refresh operation:
@@ -3368,7 +3381,7 @@ run (void *cls)
.details.deposit.amount = "EUR:0.1",
.details.deposit.coin_ref = "refresh-reveal-1",
.details.deposit.coin_idx = 4,
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":43 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/43\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"ice cream\", \"value\":3 } ] }" },
/* Test running a failing melt operation (same operation again must fail) */
@@ -3507,7 +3520,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-r1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:5\" } ] }",
.details.deposit.refund_deadline = { 60LL * 1000 * 1000 } /* 60 s */,
},
@@ -3539,7 +3552,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:4.99",
.details.deposit.coin_ref = "withdraw-coin-r1",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"more ice cream\", \"value\":\"EUR:5\" } ] }",
},
/* Run transfers. This will do the transfer as refund deadline was 0 */
@@ -3591,9 +3604,9 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:5",
.details.deposit.coin_ref = "withdraw-coin-rb",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
.details.deposit.contract_terms = "{ \"items\" : [ { \"name\":\"ice cream\", \"value\":\"EUR:5\" } ] }",
.details.deposit.refund_deadline = { 0 },
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }"
},
{ .oc = OC_CHECK_BANK_TRANSFER,
.label = "check_bank_transfer-aai-3b",
@@ -3695,7 +3708,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_OK,
.details.deposit.amount = "EUR:0.5",
.details.deposit.coin_ref = "payback-withdraw-coin-2a",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
{ .oc = OC_REVOKE,
.label = "revoke-2",
@@ -3716,7 +3729,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_NOT_FOUND,
.details.deposit.amount = "EUR:1",
.details.deposit.coin_ref = "payback-withdraw-coin-2b",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"more ice cream\", \"value\":1 } ] }" },
/* Test deposit fails after payback, with proof in payback */
@@ -3727,7 +3740,7 @@ run (void *cls)
.expected_response_code = MHD_HTTP_NOT_FOUND,
.details.deposit.amount = "EUR:0.5",
.details.deposit.coin_ref = "payback-withdraw-coin-2a",
- .details.deposit.wire_details = "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8082/\", \"account_number\":42 }",
+ .details.deposit.wire_details = "{ \"url\":\"payto://x-taler-bank/localhost:8082/42\", \"salt\":\"my salt\" }",
.details.deposit.contract_terms = "{ \"items\": [ { \"name\":\"extra ice cream\", \"value\":1 } ] }" },
@@ -3999,6 +4012,7 @@ main (int argc,
}
while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null"));
fprintf (stderr, "\n");
+
result = GNUNET_NO;
sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, GNUNET_NO, GNUNET_NO);
GNUNET_assert (NULL != sigpipe);
diff --git a/src/exchange-lib/test_exchange_api.conf b/src/exchange-lib/test_exchange_api.conf
index 7d8761f94..8c8bd7ef5 100644
--- a/src/exchange-lib/test_exchange_api.conf
+++ b/src/exchange-lib/test_exchange_api.conf
@@ -9,7 +9,6 @@ TALER_TEST_HOME = test_exchange_api_home/
CURRENCY = EUR
[exchange]
-
# HTTP port the exchange listens to
PORT = 8081
@@ -23,23 +22,58 @@ DB = postgres
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
+# Keep it short so the test runs fast.
+LOOKAHEAD_SIGN = 12 h
+
[exchangedb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
[auditordb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
+
+# Sections starting with "account-" configure the bank accounts
+# of the exchange. The "URL" specifies the account in
+# payto://-format, while the WIRE_JSON specifies the
+# (possibly offline) signed version to be returned in /wire.
+# WIRE_JSON is optional, as not all accounts must be
+# advertised in /wire.
+[account-1]
+# What is the URL of our account?
+URL = "payto://sepa/CH9300762011623852957"
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json
+# Which wire plugin should we used to access the account?
+PLUGIN = ebics
-[exchange-wire-sepa]
-# Enable 'sepa' to test SEPA-specific routines.
-ENABLE = YES
+# ENABLE_CREDIT = YES
+
+[account-2]
+# What is the bank account (with the "Taler Bank" demo system)?
+URL = "payto://x-taler-bank/localhost:8082/2"
# 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
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json
+
+# Which wire plugin should we used to access the account?
+PLUGIN = taler_bank
+
+# Authentication information for basic authentication
+TALER_BANK_AUTH_METHOD = "basic"
+USERNAME = user
+PASSWORD = pass
+
+ENABLE_DEBIT = YES
+
+ENABLE_CREDIT = YES
+
+# Sections starting with "fee-" configure the wire fee for the
+# respective wire method.
+[fees-sepa]
# Fees for the forseeable future...
# If you see this after 2017, update to match the next 10 years...
-WIRE-FEE-2017 = EUR:0.01
WIRE-FEE-2018 = EUR:0.01
WIRE-FEE-2019 = EUR:0.01
WIRE-FEE-2020 = EUR:0.01
@@ -49,8 +83,8 @@ WIRE-FEE-2023 = EUR:0.01
WIRE-FEE-2024 = EUR:0.01
WIRE-FEE-2025 = EUR:0.01
WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
-CLOSING-FEE-2017 = EUR:0.01
CLOSING-FEE-2018 = EUR:0.01
CLOSING-FEE-2019 = EUR:0.01
CLOSING-FEE-2020 = EUR:0.01
@@ -60,18 +94,11 @@ CLOSING-FEE-2023 = EUR:0.01
CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
+CLOSING-FEE-2027 = EUR:0.01
-[exchange_keys]
-# Keep it short so the test runs fast.
-LOOKAHEAD_SIGN = 12 h
-
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
-
+[fees-x-taler-bank]
# Fees for the forseeable future...
# If you see this after 2017, update to match the next 10 years...
-WIRE-FEE-2017 = EUR:0.01
WIRE-FEE-2018 = EUR:0.01
WIRE-FEE-2019 = EUR:0.01
WIRE-FEE-2020 = EUR:0.01
@@ -81,8 +108,8 @@ WIRE-FEE-2023 = EUR:0.01
WIRE-FEE-2024 = EUR:0.01
WIRE-FEE-2025 = EUR:0.01
WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
-CLOSING-FEE-2017 = EUR:0.01
CLOSING-FEE-2018 = EUR:0.01
CLOSING-FEE-2019 = EUR:0.01
CLOSING-FEE-2020 = EUR:0.01
@@ -92,17 +119,10 @@ CLOSING-FEE-2023 = EUR:0.01
CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
+CLOSING-FEE-2027 = EUR:0.01
-# This is the response we give out for the /wire request. It provides
-# wallets with the bank information for transfers to the exchange.
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
-
-# What is the main website of the bank?
-BANK_URL = "http://localhost:8082/"
-# From which account at the 'bank' should outgoing wire transfers be made?
-BANK_ACCOUNT_NUMBER = 2
-
-
+# Sections starting with "coin_" specify which denominations
+# the exchange should support (and their respective fee structure)
[coin_eur_ct_1]
value = EUR:0.01
duration_overlap = 5 minutes
diff --git a/src/exchange-lib/test_exchange_api_home/.config/taler/account-1.json b/src/exchange-lib/test_exchange_api_home/.config/taler/account-1.json
new file mode 100644
index 000000000..48093f2aa
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api_home/.config/taler/account-1.json
@@ -0,0 +1,5 @@
+{
+ "url": "payto://sepa/CH9300762011623852957",
+ "salt": "N83T9J9202WCC8TQFDMJDWEGZNBEKA33C1ZM241VNYH88RZNTHPW509Y1M2YF7Y098R8VRESWQ05H03BK1SPAZCWE54KARDCKT5N8AG",
+ "master_sig": "D4V5GJ998YK7D6N0N56AD0J6MZNFEW6MRZT2CFPVQ5ME3NMQ59AA2007CXYESSFGRN70CNCFM06858QSSENCWTZM8VHEJ93YQ20ZJ1R"
+} \ No newline at end of file
diff --git a/src/exchange-lib/test_exchange_api_home/.config/taler/account-2.json b/src/exchange-lib/test_exchange_api_home/.config/taler/account-2.json
new file mode 100644
index 000000000..85d80de56
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api_home/.config/taler/account-2.json
@@ -0,0 +1,5 @@
+{
+ "url": "payto://x-taler-bank/localhost:8082/2",
+ "salt": "TMXB995ZZVKA02AG4074X3C6XX0BFTHY8XK76EF4BSG5XVDF069FEBN4TCKW9GS7NKZH409GKAVHMQPA3T361MC6VM7J268V3GBH42R",
+ "master_sig": "CK7BGHKYVAT7DMVCN00DQ0761NCTJVESZT69049BCF3SKNJKVHXXEQ5X6FH2HFGHCJ18YA1MGHBD8RRG4W3G4KJWQJDY2CGPGTHDJ2G"
+} \ No newline at end of file
diff --git a/src/exchange-lib/test_exchange_api_home/.config/taler/x-taler-bank.json b/src/exchange-lib/test_exchange_api_home/.config/taler/x-taler-bank.json
new file mode 100644
index 000000000..9445f048e
--- /dev/null
+++ b/src/exchange-lib/test_exchange_api_home/.config/taler/x-taler-bank.json
@@ -0,0 +1,5 @@
+{
+ "url": "payto://x-taler-bank/http://localhost:8082/2",
+ "salt": "WGRD0W7YKD8ZAN960B0JBRARRY0K5FQ4920Q3DJBTYH4GY7W0XNAX1F04R5B1E0RWH1NFG08TM8K1517WNCXTJM9KMH4913Q5XPK0N8",
+ "master_sig": "J4N0KP64MGNEQX9HST9TDWK67152MSHHM9CTZH8GSMKD607BXSAF209AQYDKYT6QJP0NQXYXC1JMM9Z405DJHGV75JFMWP4G6WB6A00"
+} \ No newline at end of file
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf b/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
index 38b952824..7193bf11e 100644
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
+++ b/src/exchange-lib/test_exchange_api_keys_cherry_picking.conf
@@ -23,20 +23,53 @@ DB = postgres
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
+# Keep it short so we can prolong later!
+LOOKAHEAD_SIGN = 60 s
+
+
[exchangedb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
[auditordb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
+
+
+[account-1]
+# This is the response we give out for the /wire request. It provides
+# wallets with the bank information for transfers to the exchange.
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/iban.json
+
+# What is the URL of our bank account? Must match WIRE_RESPONSE above!
+URL = payto://sepa/FIXME
-[exchange-wire-sepa]
-# Enable 'sepa' to test SEPA-specific routines.
-ENABLE = YES
+# Which plugin implements access for this account?
+PLUGIN = "ebics"
+
+[account-2]
# 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
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/x-taler-bank.json
+
+# What is the URL of our bank account? Must match WIRE_RESPONSE above!
+URL = payto://x-taler-bank/http://localhost:8082/2
+
+# Which plugin implements access for this account?
+PLUGIN = "taler_bank"
+
+# Authentication information for basic authentication
+TALER_BANK_AUTH_METHOD = "basic"
+USERNAME = user
+PASSWORD = pass
+
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+
+
+
+[fees-x-taler-bank]
# Fees for the forseeable future...
# If you see this after 2017, update to match the next 10 years...
WIRE-FEE-2017 = EUR:0.01
@@ -61,14 +94,7 @@ CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
-[exchange_keys]
-# Keep it short so we can prolong later!
-LOOKAHEAD_SIGN = 60 s
-
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
-
+[fees-sepa]
# Fees for the forseeable future...
# If you see this after 2017, update to match the next 10 years...
WIRE-FEE-2017 = EUR:0.01
@@ -93,16 +119,6 @@ CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
-# This is the response we give out for the /wire request. It provides
-# wallets with the bank information for transfers to the exchange.
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/test.json
-
-# What is the main website of the bank?
-BANK_URL = "http://localhost:8082/"
-# From which account at the 'bank' should outgoing wire transfers be made?
-BANK_ACCOUNT_NUMBER = 2
-
-
[coin_eur_ct_1]
value = EUR:0.01
duration_overlap = 5 s
diff --git a/src/exchange-lib/test_exchange_api_keys_cherry_picking_extended.conf b/src/exchange-lib/test_exchange_api_keys_cherry_picking_extended.conf
index 3becf3d68..29290c99c 100644
--- a/src/exchange-lib/test_exchange_api_keys_cherry_picking_extended.conf
+++ b/src/exchange-lib/test_exchange_api_keys_cherry_picking_extended.conf
@@ -1,5 +1,5 @@
@INLINE@ test_exchange_api_keys_cherry_picking.conf
-[exchange_keys]
+[exchange]
# Lengthen over original value (60 s)
LOOKAHEAD_SIGN = 100 s
diff --git a/src/exchange-lib/test_exchange_api_new.c b/src/exchange-lib/test_exchange_api_new.c
index c3e1ce85e..a33f8d014 100644
--- a/src/exchange-lib/test_exchange_api_new.c
+++ b/src/exchange-lib/test_exchange_api_new.c
@@ -43,6 +43,14 @@
#define CONFIG_FILE "test_exchange_api.conf"
/**
+ * Is the configuration file is set to include wire format 'ebics'?
+ * Requires that EBICS /history function is implemented, which it
+ * is currently not. Once it is, set ENABLE_CREDIT to YES in the
+ * configuration and then set this option to 1.
+ */
+#define WIRE_EBICS 0
+
+/**
* URL of the fakebank. Obtained from CONFIG_FILE's
* "exchange-wire-test:BANK_URI" option.
*/
@@ -145,23 +153,23 @@ run (void *cls,
CMD_EXEC_WIREWATCH ("wirewatch-1"),
/**
- * Check if 'test' wire method is offered by the exchange.
+ * Check if 'x-taler-bank' wire method is offered by the exchange.
*/
- TALER_TESTING_cmd_wire ("wire-test-1",
+ TALER_TESTING_cmd_wire ("wire-taler-bank-1",
is->exchange,
- "test",
+ "x-taler-bank",
NULL,
MHD_HTTP_OK),
-
+#if WIRE_EBICS
/**
- * Check if 'sepa' wire method is offered by the exchange.
+ * Check if 'ebics' wire method is offered by the exchange.
*/
TALER_TESTING_cmd_wire ("wire-sepa-1",
is->exchange,
- "sepa",
+ "ebics",
NULL,
MHD_HTTP_OK),
-
+#endif
/****** End of "wire" testing ******/
/****** Start of withdraw and spend testing ******/
@@ -188,9 +196,8 @@ run (void *cls,
*/
TALER_TESTING_cmd_deposit
("deposit-simple", is->exchange, "withdraw-coin-1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_OK),
@@ -208,9 +215,8 @@ run (void *cls,
*/
TALER_TESTING_cmd_deposit
("deposit-double-1", is->exchange, "withdraw-coin-1", 0,
- TALER_TESTING_make_wire_details
- ("{\"type\":\"test\",\"account_number\":43}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (43,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
@@ -225,9 +231,8 @@ run (void *cls,
*/
TALER_TESTING_cmd_deposit
("deposit-double-1", is->exchange, "withdraw-coin-1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\", \"account_number\":43}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (43,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
@@ -236,12 +241,11 @@ run (void *cls,
*/
TALER_TESTING_cmd_deposit
("deposit-double-2", is->exchange, "withdraw-coin-1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\", \"account_number\":43}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (43,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
-
+
/****** End of withdraw and spend testing ******/
/****** Start of refresh testing ******/
@@ -254,7 +258,7 @@ run (void *cls,
*/
CMD_TRANSFER_TO_EXCHANGE ("refresh-create-reserve-1",
"EUR:5.01"),
-
+
/**
* Make previous command effective.
*/
@@ -277,9 +281,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("refresh-deposit-partial", is->exchange,
"refresh-withdraw-coin-1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\
\"value\":\"EUR:1\"}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_OK),
@@ -297,7 +300,7 @@ run (void *cls,
TALER_TESTING_cmd_refresh_reveal
("refresh-reveal-1", is->exchange,
"refresh-melt-1", MHD_HTTP_OK),
-
+
/**
* Do it again to check idempotency
*/
@@ -318,9 +321,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("refresh-deposit-refreshed-1a", is->exchange,
"refresh-reveal-1-idempotency", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\
\"value\":3}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_OK),
@@ -331,9 +333,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("refresh-deposit-refreshed-1b", is->exchange,
"refresh-reveal-1", 4,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":43}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (43,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\",\
\"value\":3}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:0.1", MHD_HTTP_OK),
@@ -463,9 +464,8 @@ run (void *cls,
*/
TALER_TESTING_cmd_deposit
("deposit-refund-1", is->exchange, "withdraw-coin-r1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\", \"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\","
"\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_MINUTES, "EUR:5", MHD_HTTP_OK),
@@ -502,9 +502,8 @@ run (void *cls,
* 1 ct deposit fee) */
TALER_TESTING_cmd_deposit
("deposit-refund-2", is->exchange, "withdraw-coin-r1", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\", \"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"more ice cream\","
"\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:4.99", MHD_HTTP_OK),
@@ -555,9 +554,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("deposit-refund-1b", is->exchange, "withdraw-coin-rb", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\", \"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"ice cream\","
"\"value\":\"EUR:5\"}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_OK),
@@ -602,7 +600,7 @@ run (void *cls,
is->exchange,
"payback-create-reserve-1",
"EUR:5",
- MHD_HTTP_OK),
+ MHD_HTTP_OK),
TALER_TESTING_cmd_revoke ("revoke-1", MHD_HTTP_OK,
"payback-withdraw-coin-1",
@@ -648,9 +646,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("payback-deposit-partial", is->exchange,
"payback-withdraw-coin-2a", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:0.5", MHD_HTTP_OK),
@@ -670,9 +667,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("payback-deposit-revoked", is->exchange,
"payback-withdraw-coin-2b", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"more ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:1", MHD_HTTP_NOT_FOUND),
@@ -685,9 +681,8 @@ run (void *cls,
TALER_TESTING_cmd_deposit
("payback-deposit-partial-after-payback", is->exchange,
"payback-withdraw-coin-2a", 0,
- TALER_TESTING_make_wire_details
- ("{ \"type\":\"test\",\"account_number\":42}",
- fakebank_url),
+ TALER_TESTING_make_wire_details (42,
+ fakebank_url),
"{\"items\":[{\"name\":\"extra ice cream\",\"value\":1}]}",
GNUNET_TIME_UNIT_ZERO, "EUR:0.5", MHD_HTTP_NOT_FOUND),
@@ -740,6 +735,7 @@ run (void *cls,
fakebank_url);
}
+
int
main (int argc,
char * const *argv)
@@ -753,7 +749,8 @@ main (int argc,
if (NULL == (fakebank_url
/* Check fakebank port is available and config cares
* about bank url. */
- = TALER_TESTING_prepare_fakebank (CONFIG_FILE)))
+ = TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "account-2")))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
/* @helpers. Run keyup, create tables, ... Note: it
diff --git a/src/exchange-lib/testing_api_cmd_deposit.c b/src/exchange-lib/testing_api_cmd_deposit.c
index 6f66e8ad0..5854bf8ba 100644
--- a/src/exchange-lib/testing_api_cmd_deposit.c
+++ b/src/exchange-lib/testing_api_cmd_deposit.c
@@ -50,9 +50,9 @@ struct DepositState
unsigned int coin_index;
/**
- * JSON string describing the merchant's "wire details".
+ * payto://-URL of the merchant's bank account.
*/
- char *wire_details;
+ json_t *wire_details;
/**
* JSON string describing what a proposal is about.
@@ -126,6 +126,7 @@ deposit_cb (void *cls,
TALER_TESTING_interpreter_next (ds->is);
}
+
/**
* Run the command.
*
@@ -133,7 +134,7 @@ deposit_cb (void *cls,
* @param cmd the command to execute, a /wire one.
* @param i the interpreter state.
*/
-void
+static void
deposit_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
@@ -153,7 +154,6 @@ deposit_run (void *cls,
struct TALER_MerchantPublicKeyP merchant_pub;
struct GNUNET_HashCode h_contract_terms;
json_t *contract_terms;
- json_t *wire;
struct TALER_Amount amount;
ds->is = is;
@@ -166,7 +166,7 @@ deposit_run (void *cls,
if (NULL == coin_cmd)
{
GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
+ TALER_TESTING_interpreter_fail (is);
return;
}
@@ -213,21 +213,6 @@ deposit_run (void *cls,
TALER_JSON_hash (contract_terms,
&h_contract_terms));
json_decref (contract_terms);
-
- wire = json_loads (ds->wire_details,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == wire)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse wire details `%s' at %u/%s\n",
- ds->wire_details,
- is->ip,
- this_cmd->label);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
-
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
&coin_pub.eddsa_pub);
@@ -267,8 +252,9 @@ deposit_run (void *cls,
dr.purpose.purpose = htonl
(TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.h_contract_terms = h_contract_terms;
- GNUNET_assert (GNUNET_OK == TALER_JSON_hash
- (wire, &dr.h_wire));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_wire_signature_hash (ds->wire_details,
+ &dr.h_wire));
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
dr.refund_deadline = GNUNET_TIME_absolute_hton
(refund_deadline);
@@ -286,7 +272,7 @@ deposit_run (void *cls,
(ds->exchange,
&amount,
wire_deadline,
- wire,
+ ds->wire_details,
&h_contract_terms,
&coin_pub,
denom_pub_sig,
@@ -301,21 +287,20 @@ deposit_run (void *cls,
if (NULL == ds->dh)
{
GNUNET_break (0);
- json_decref (wire);
TALER_TESTING_interpreter_fail (is);
return;
}
- json_decref (wire);
return;
}
+
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
-void
+static void
deposit_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
@@ -331,10 +316,11 @@ deposit_cleanup (void *cls,
ds->dh = NULL;
}
- GNUNET_free (ds->wire_details);
+ json_decref (ds->wire_details);
GNUNET_free (ds);
}
+
/**
* Extract information from a command that is useful for other
* commands.
@@ -354,7 +340,7 @@ deposit_traits (void *cls,
unsigned int index)
{
struct DepositState *ds = cls;
- const struct TALER_TESTING_Command *coin_cmd;
+ const struct TALER_TESTING_Command *coin_cmd;
/* Will point to coin cmd internals. */
struct TALER_CoinSpendPrivateKeyP *coin_spent_priv;
@@ -382,7 +368,7 @@ deposit_traits (void *cls,
TALER_TESTING_make_trait_contract_terms (0, ds->contract_terms),
TALER_TESTING_make_trait_peer_key
(0, &ds->merchant_priv.eddsa_priv),
- TALER_TESTING_trait_end ()
+ TALER_TESTING_trait_end ()
};
return TALER_TESTING_get_trait (traits,
@@ -402,8 +388,8 @@ deposit_traits (void *cls,
* coins, this parameter selects which one in that array.
* This value is currently ignored, as only one-coin
* withdrawals are implemented.
- * @param wire_details bank details of the merchant performing the
- * deposit
+ * @param wire_details JSON details of the wire account of the merchant performing the
+ * deposit, reference is captured by this command
* @param contract_terms contract terms to be signed over by the
* coin
* @param refund_deadline refund deadline, zero means 'no refunds'
@@ -419,7 +405,7 @@ TALER_TESTING_cmd_deposit
struct TALER_EXCHANGE_Handle *exchange,
const char *coin_reference,
unsigned int coin_index,
- char *wire_details,
+ json_t *wire_details,
const char *contract_terms,
struct GNUNET_TIME_Relative refund_deadline,
const char *amount,
@@ -427,7 +413,7 @@ TALER_TESTING_cmd_deposit
{
struct TALER_TESTING_Command cmd;
struct DepositState *ds;
-
+
ds = GNUNET_new (struct DepositState);
ds->exchange = exchange;
ds->coin_reference = coin_reference;
diff --git a/src/exchange-lib/testing_api_cmd_exec_wirewatch.c b/src/exchange-lib/testing_api_cmd_exec_wirewatch.c
index 1ff466f56..fd8404bec 100644
--- a/src/exchange-lib/testing_api_cmd_exec_wirewatch.c
+++ b/src/exchange-lib/testing_api_cmd_exec_wirewatch.c
@@ -68,7 +68,6 @@ wirewatch_run (void *cls,
"taler-exchange-wirewatch",
"taler-exchange-wirewatch",
"-c", ws->config_filename,
- "-t", "test", /* use Taler's bank/fakebank */
"-T", /* exit when done */
NULL);
if (NULL == ws->wirewatch_proc)
diff --git a/src/exchange-lib/testing_api_cmd_payback.c b/src/exchange-lib/testing_api_cmd_payback.c
index 3a750e7fc..65665c9c8 100644
--- a/src/exchange-lib/testing_api_cmd_payback.c
+++ b/src/exchange-lib/testing_api_cmd_payback.c
@@ -31,7 +31,7 @@
struct RevokeState
{
- /**
+ /**
* Expected HTTP status code.
*/
unsigned int expected_response_code;
@@ -65,7 +65,7 @@ struct RevokeState
struct PaybackState
{
- /**
+ /**
* Expected HTTP status code.
*/
unsigned int expected_response_code;
@@ -154,7 +154,7 @@ payback_cb (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
-
+
if (GNUNET_OK != TALER_TESTING_get_trait_reserve_priv
(reserve_cmd, 0, &reserve_priv))
{
@@ -201,6 +201,7 @@ payback_cb (void *cls,
TALER_TESTING_interpreter_next (is);
}
+
/**
* Run the command.
*
@@ -208,7 +209,7 @@ payback_cb (void *cls,
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
-void
+static void
payback_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
@@ -230,7 +231,7 @@ payback_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
@@ -238,7 +239,7 @@ payback_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_blinding_key
@@ -246,7 +247,7 @@ payback_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
planchet.coin_priv = *coin_priv;
planchet.blinding_key = *blinding_key;
@@ -256,7 +257,7 @@ payback_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_denom_sig
@@ -264,13 +265,13 @@ payback_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Trying to get '%s..' paid back\n",
TALER_B2S (&denom_pub->h_key));
-
+
ps->ph = TALER_EXCHANGE_payback (ps->exchange,
denom_pub,
coin_sig,
@@ -280,13 +281,14 @@ payback_run (void *cls,
GNUNET_assert (NULL != ps->ph);
}
+
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
-void
+static void
revoke_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
@@ -302,17 +304,18 @@ revoke_cleanup (void *cls,
rs->revoke_proc = NULL;
}
- GNUNET_free (rs->dhks);
+ GNUNET_free_non_null (rs->dhks);
GNUNET_free (rs);
}
+
/**
* Cleanup the state.
*
* @param cls closure, typically a #struct WireState.
* @param cmd the command which is being cleaned up.
*/
-void
+static void
payback_cleanup (void *cls,
const struct TALER_TESTING_Command *cmd)
{
@@ -325,6 +328,7 @@ payback_cleanup (void *cls,
GNUNET_free (ps);
}
+
/**
* Extract information from a command that is useful for other
* commands.
@@ -366,7 +370,7 @@ revoke_traits (void *cls,
* @param cmd the command to execute, a /wire one.
* @param is the interpreter state.
*/
-void
+static void
revoke_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
@@ -384,7 +388,7 @@ revoke_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
GNUNET_assert (GNUNET_OK == TALER_TESTING_get_trait_denom_pub
@@ -395,8 +399,8 @@ revoke_run (void *cls,
TALER_B2S (&denom_pub->h_key));
rs->dhks = GNUNET_STRINGS_data_to_string_alloc
- (&denom_pub->h_key, sizeof (struct GNUNET_HashCode));
-
+ (&denom_pub->h_key, sizeof (struct GNUNET_HashCode));
+
rs->revoke_proc = GNUNET_OS_start_process
(GNUNET_NO,
GNUNET_OS_INHERIT_STD_ALL,
@@ -441,7 +445,7 @@ TALER_TESTING_cmd_payback (const char *label,
{
struct PaybackState *ps;
struct TALER_TESTING_Command cmd;
-
+
ps = GNUNET_new (struct PaybackState);
ps->expected_response_code = expected_response_code;
ps->coin_reference = coin_reference;
@@ -455,6 +459,7 @@ TALER_TESTING_cmd_payback (const char *label,
return cmd;
}
+
/**
* Make a /revoke command.
*
diff --git a/src/exchange-lib/testing_api_cmd_refund.c b/src/exchange-lib/testing_api_cmd_refund.c
index a092ee2d2..35cb20d26 100644
--- a/src/exchange-lib/testing_api_cmd_refund.c
+++ b/src/exchange-lib/testing_api_cmd_refund.c
@@ -139,7 +139,7 @@ refund_run (void *cls,
const struct TALER_TESTING_Command *cmd,
struct TALER_TESTING_Interpreter *is)
{
- struct RefundState *rs = cls;
+ struct RefundState *rs = cls;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin;
const char *contract_terms;
@@ -193,7 +193,7 @@ refund_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
j_contract_terms = json_loads
@@ -201,8 +201,9 @@ refund_run (void *cls,
/* Very unlikely to fail */
GNUNET_assert (NULL != j_contract_terms);
- GNUNET_assert (GNUNET_OK == TALER_JSON_hash
- (j_contract_terms, &h_contract_terms));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_hash (j_contract_terms,
+ &h_contract_terms));
json_decref (j_contract_terms);
@@ -222,7 +223,7 @@ refund_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
rs->rh = TALER_EXCHANGE_refund
diff --git a/src/exchange-lib/testing_api_cmd_track.c b/src/exchange-lib/testing_api_cmd_track.c
index 3f14c5110..638329d69 100644
--- a/src/exchange-lib/testing_api_cmd_track.c
+++ b/src/exchange-lib/testing_api_cmd_track.c
@@ -183,7 +183,7 @@ deposit_wtid_cb
tts->wtid = *wtid;
if (NULL != tts->bank_transfer_reference)
{
- const struct TALER_TESTING_Command *bank_transfer_cmd;
+ const struct TALER_TESTING_Command *bank_transfer_cmd;
char *ws;
ws = GNUNET_STRINGS_data_to_string_alloc (wtid,
@@ -205,7 +205,7 @@ deposit_wtid_cb
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
if (0 != strcmp (ws, transfer_subject))
@@ -248,14 +248,13 @@ track_transaction_run (void *cls,
const struct TALER_TESTING_Command *transaction_cmd;
struct TALER_CoinSpendPrivateKeyP *coin_priv;
struct TALER_CoinSpendPublicKeyP coin_pub;
- const char *wire_details;
const char *contract_terms;
- json_t *j_wire_details;
+ const json_t *wire_details;
json_t *j_contract_terms;
struct GNUNET_HashCode h_wire_details;
struct GNUNET_HashCode h_contract_terms;
const struct GNUNET_CRYPTO_EddsaPrivateKey *merchant_priv;
-
+
tts->is = is;
transaction_cmd = TALER_TESTING_interpreter_lookup_command
(tts->is, tts->transaction_reference);
@@ -264,7 +263,7 @@ track_transaction_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
- return;
+ return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_coin_priv
@@ -272,7 +271,7 @@ track_transaction_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
- return;
+ return;
}
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
@@ -296,31 +295,31 @@ track_transaction_run (void *cls,
}
/* Parse them.. */
- j_wire_details = json_loads
- (wire_details, JSON_REJECT_DUPLICATES, NULL);
j_contract_terms = json_loads
(contract_terms, JSON_REJECT_DUPLICATES, NULL);
-
- if ((NULL == j_wire_details) || (NULL == j_contract_terms))
+
+ if ((NULL == wire_details) || (NULL == j_contract_terms))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
- return;
+ return;
}
/* Should not fail here, json has been parsed already */
GNUNET_assert
- ( (GNUNET_OK == TALER_JSON_hash (j_wire_details,
- &h_wire_details)) &&
- (GNUNET_OK == TALER_JSON_hash (j_contract_terms,
- &h_contract_terms)) );
+ ( (GNUNET_OK ==
+ TALER_JSON_wire_signature_hash (wire_details,
+ &h_wire_details)) &&
+ (GNUNET_OK ==
+ TALER_JSON_hash (j_contract_terms,
+ &h_contract_terms)) );
if (GNUNET_OK != TALER_TESTING_get_trait_peer_key
(transaction_cmd, 0, &merchant_priv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
- return;
+ return;
}
tts->tth = TALER_EXCHANGE_track_transaction
@@ -580,7 +579,7 @@ track_transfer_cb
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
/**
@@ -594,8 +593,7 @@ track_transfer_cb
if (NULL != tts->wire_details_reference)
{
const struct TALER_TESTING_Command *wire_details_cmd;
- const char *wire_details;
- json_t *j_wire_details;
+ const json_t *wire_details;
struct GNUNET_HashCode h_wire_details;
if (NULL == (wire_details_cmd
@@ -615,13 +613,9 @@ track_transfer_cb
return;
}
- j_wire_details = json_loads
- (wire_details, JSON_REJECT_DUPLICATES, NULL);
-
- GNUNET_assert (NULL != j_wire_details);
-
- GNUNET_assert (GNUNET_OK == TALER_JSON_hash
- (j_wire_details, &h_wire_details));
+ GNUNET_assert (GNUNET_OK ==
+ TALER_JSON_wire_signature_hash (wire_details,
+ &h_wire_details));
if (0 != memcmp (&h_wire_details,
h_wire,
@@ -647,7 +641,7 @@ track_transfer_cb
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
- return;
+ return;
}
if (GNUNET_OK != TALER_TESTING_get_trait_amount
@@ -657,7 +651,7 @@ track_transfer_cb
TALER_TESTING_interpreter_fail (is);
return;
}
-
+
GNUNET_assert (GNUNET_OK == TALER_string_to_amount
(total_amount_from_reference_str,
&total_amount_from_reference));
@@ -699,7 +693,7 @@ track_transfer_run (void *cls,
* WTID */
memset (&wtid, 0, sizeof (wtid));
wtid_ptr = &wtid;
-
+
tts->is = is;
if (NULL != tts->wtid_reference)
{
@@ -720,7 +714,7 @@ track_transfer_run (void *cls,
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (tts->is);
- return;
+ return;
}
GNUNET_assert (NULL != wtid_ptr);
}
@@ -756,7 +750,7 @@ TALER_TESTING_cmd_track_transfer_empty
{
struct TrackTransferState *tts;
struct TALER_TESTING_Command cmd;
-
+
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
@@ -769,7 +763,7 @@ TALER_TESTING_cmd_track_transfer_empty
cmd.run = &track_transfer_run;
cmd.cleanup = &track_transfer_cleanup;
- return cmd;
+ return cmd;
}
/**
@@ -801,7 +795,7 @@ TALER_TESTING_cmd_track_transfer
{
struct TrackTransferState *tts;
struct TALER_TESTING_Command cmd;
-
+
tts = GNUNET_new (struct TrackTransferState);
tts->wtid_reference = wtid_reference;
@@ -816,5 +810,5 @@ TALER_TESTING_cmd_track_transfer
cmd.run = &track_transfer_run;
cmd.cleanup = &track_transfer_cleanup;
- return cmd;
+ return cmd;
}
diff --git a/src/exchange-lib/testing_api_cmd_wire.c b/src/exchange-lib/testing_api_cmd_wire.c
index f65daec00..cf8304e29 100644
--- a/src/exchange-lib/testing_api_cmd_wire.c
+++ b/src/exchange-lib/testing_api_cmd_wire.c
@@ -27,6 +27,7 @@
#include "taler_json_lib.h"
#include <gnunet/gnunet_curl_lib.h>
#include "exchange_api_handle.h"
+#include "taler_wire_lib.h"
#include "taler_testing_lib.h"
struct WireState
@@ -71,19 +72,6 @@ struct WireState
/**
- * Check all the expected values have been returned by /wire.
- *
- * @param cls closure
- * @param wire_method name of the wire method (i.e. "sepa")
- * @param fees fee structure for this method
- */
-static void
-check_method_and_fee_cb
- (void *cls,
- const char *wire_method,
- const struct TALER_EXCHANGE_WireAggregateFees *fees);
-
-/**
* Callbacks called with the result(s) of a wire format inquiry
* request to the exchange.
*
@@ -92,23 +80,20 @@ check_method_and_fee_cb
* for successful request; 0 if the exchange's
* reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param obj the received JSON reply, if successful this should
- * be the wire format details as provided by /wire.
+ * @param accounts_len length of the @a accounts array
+ * @param accounts list of wire accounts of the exchange, NULL on error
*/
static void
wire_cb (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
- const json_t *obj)
+ unsigned int accounts_len,
+ const struct TALER_EXCHANGE_WireAccount *accounts)
{
struct WireState *ws = cls;
- struct TALER_TESTING_Command *cmd
- = &ws->is->commands[ws->is->ip];
+ struct TALER_TESTING_Command *cmd = &ws->is->commands[ws->is->ip];
+ struct TALER_Amount expected_fee;
- /**
- * The handle has been free'd by GNUnet curl-lib. FIXME:
- * shouldn't GNUnet nullify it once it frees it?
- */
ws->wh = NULL;
if (ws->expected_response_code != http_status)
{
@@ -117,74 +102,54 @@ wire_cb (void *cls,
return;
}
- if (GNUNET_OK != TALER_EXCHANGE_wire_get_fees
- (&TALER_EXCHANGE_get_keys (ws->exchange)->master_pub,
- obj,
- // will check synchronously.
- &check_method_and_fee_cb,
- ws))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee extraction in command %s failed\n",
- cmd->label);
- json_dumpf (obj, stderr, 0);
- TALER_TESTING_interpreter_fail (ws->is);
- return;
- }
-
- if (ws->method_found != GNUNET_OK)
+ if (MHD_HTTP_OK == http_status)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "/wire does not offer method '%s'\n",
- ws->expected_method);
- TALER_TESTING_interpreter_fail (ws->is);
- return;
- }
- TALER_TESTING_interpreter_next (ws->is);
-}
-
-/**
- * Check all the expected values have been returned by /wire.
- *
- * @param cls closure
- * @param wire_method name of the wire method (i.e. "sepa")
- * @param fees fee structure for this method
- */
-static void
-check_method_and_fee_cb
- (void *cls,
- const char *wire_method,
- const struct TALER_EXCHANGE_WireAggregateFees *fees)
-{
- struct WireState *ws = cls;
- struct TALER_TESTING_Command *cmd
- = &ws->is->commands[ws->is->ip]; // ugly?
- struct TALER_Amount expected_fee;
-
- if (0 == strcmp (ws->expected_method, wire_method))
- ws->method_found = GNUNET_OK;
-
- if ( ws->expected_fee && (ws->method_found == GNUNET_OK) )
- {
- GNUNET_assert (GNUNET_OK == TALER_string_to_amount
- (ws->expected_fee,
- &expected_fee));
- while (NULL != fees)
+ for (unsigned int i=0;i<accounts_len;i++)
{
- if (0 != TALER_amount_cmp (&fees->wire_fee,
- &expected_fee))
+ char *method;
+
+ method = TALER_WIRE_payto_get_method (accounts[i].url);
+ if (0 == strcmp (ws->expected_method,
+ method))
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire fee missmatch to command %s\n",
- cmd->label);
- TALER_TESTING_interpreter_fail (ws->is);
- return;
+ ws->method_found = GNUNET_OK;
+ if (NULL != ws->expected_fee)
+ {
+ GNUNET_assert (GNUNET_OK ==
+ TALER_string_to_amount (ws->expected_fee,
+ &expected_fee));
+ for (const struct TALER_EXCHANGE_WireAggregateFees *waf = accounts[i].fees;
+ NULL != waf;
+ waf = waf->next)
+ {
+ if (0 != TALER_amount_cmp (&waf->wire_fee,
+ &expected_fee))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fee missmatch to command %s\n",
+ cmd->label);
+ TALER_TESTING_interpreter_fail (ws->is);
+ GNUNET_free (method);
+ return;
+ }
+ }
+ }
}
- fees = fees->next;
+ GNUNET_free (method);
+ }
+ if (GNUNET_OK != ws->method_found)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "/wire does not offer method '%s'\n",
+ ws->expected_method);
+ TALER_TESTING_interpreter_fail (ws->is);
+ return;
}
}
+ TALER_TESTING_interpreter_next (ws->is);
}
+
/**
* Run the command.
*
diff --git a/src/exchange-lib/testing_api_helpers.c b/src/exchange-lib/testing_api_helpers.c
index a942b6522..3aff0a3cc 100644
--- a/src/exchange-lib/testing_api_helpers.c
+++ b/src/exchange-lib/testing_api_helpers.c
@@ -416,42 +416,54 @@ TALER_TESTING_url_port_free (const char *url)
return GNUNET_OK;
}
+
/**
- * Allocate and return a piece of wire-details. Mostly, it adds
- * the bank_url to the JSON.
+ * Allocate and return a piece of wire-details. Combines
+ * the @a account_no and the @a bank_url to a
+ * @a payto://-URL and adds some salt to create the JSON.
*
- * @param template the wire-details template.
+ * @param account_no account number
* @param bank_url the bank_url
- *
- * @return the filled out and stringified wire-details. To
- * be manually free'd.
+ * @return JSON describing the account, including the
+ * payto://-URL of the account, must be manually decref'd
*/
-char *
-TALER_TESTING_make_wire_details (const char *template,
+json_t *
+TALER_TESTING_make_wire_details (unsigned long long account_no,
const char *bank_url)
{
- json_t *jtemplate;
-
- GNUNET_assert (NULL != (jtemplate = json_loads
- (template, JSON_REJECT_DUPLICATES, NULL)));
- GNUNET_assert (0 == json_object_set
- (jtemplate, "bank_url", json_string (bank_url)));
- return json_dumps (jtemplate, JSON_COMPACT);
+ char *payto;
+ json_t *ret;
+
+ GNUNET_asprintf (&payto,
+ "payto://x-taler-bank/%s/%llu",
+ bank_url,
+ account_no);
+ ret = json_pack ("{s:s, s:s}",
+ "url", payto,
+ "salt", "test-salt (must be constant for aggregation tests)");
+ GNUNET_free (payto);
+ return ret;
}
+
/**
* Prepare launching a fakebank. Check that the configuration
* file has the right option, and that the port is available.
* If everything is OK, return the configured URL of the fakebank.
*
* @param config_filename configuration file to use
+ * @param config_section which account to use (must match x-taler-bank)
* @return NULL on error, fakebank URL otherwise
*/
char *
-TALER_TESTING_prepare_fakebank (const char *config_filename)
+TALER_TESTING_prepare_fakebank (const char *config_filename,
+ const char *config_section)
{
struct GNUNET_CONFIGURATION_Handle *cfg;
+ char *payto_url;
char *fakebank_url;
+ const char *start;
+ const char *end;
cfg = GNUNET_CONFIGURATION_create ();
if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg,
@@ -459,17 +471,37 @@ TALER_TESTING_prepare_fakebank (const char *config_filename)
return NULL;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "BANK_URL",
- &fakebank_url))
+ config_section,
+ "URL",
+ &payto_url))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- "exchange-wire-test",
- "BANK_URL");
+ config_section,
+ "URL");
GNUNET_CONFIGURATION_destroy (cfg);
return NULL;
}
GNUNET_CONFIGURATION_destroy (cfg);
+ if (0 != strncasecmp (payto_url,
+ "payto://x-taler-bank/",
+ strlen ("payto://x-taler-bank/")))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_WARNING,
+ config_section,
+ "URL",
+ "expected `x-taler-bank' payto://-URL");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ GNUNET_free (payto_url);
+ return NULL;
+ }
+ start = &payto_url [strlen ("payto://x-taler-bank/")];
+ end = strchr (start,
+ (unsigned char) '/');
+ if (NULL == end)
+ end = &start[strlen (start)];
+ fakebank_url = GNUNET_strndup (start,
+ end - start);
+ GNUNET_free (payto_url);
if (GNUNET_OK !=
TALER_TESTING_url_port_free (fakebank_url))
{
diff --git a/src/exchange-lib/testing_api_trait_json.c b/src/exchange-lib/testing_api_trait_json.c
new file mode 100644
index 000000000..40dddbfa3
--- /dev/null
+++ b/src/exchange-lib/testing_api_trait_json.c
@@ -0,0 +1,76 @@
+/*
+ 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 exchange-lib/testing_api_trait_json.c
+ * @brief offers JSON traits.
+ * @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_WIRE_DETAILS "wire-details"
+
+/**
+ * Obtain wire details from @a cmd.
+ *
+ * @param cmd command to extract trait from
+ * @param index always (?) zero, as one command sticks
+ * to one bank account
+ * @param wire_details[out] where to write the wire details.
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_TESTING_get_trait_wire_details
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const json_t **wire_details)
+{
+ return cmd->traits (cmd->cls,
+ (void **) wire_details,
+ TALER_TESTING_TRAIT_WIRE_DETAILS,
+ index);
+}
+
+/**
+ * Offer wire details in a trait.
+ *
+ * @param index always (?) zero, as one command sticks
+ * to one bank account
+ * @param wire_details wire details to offer
+ * @return the trait, to be put in the traits array of the command
+ */
+struct TALER_TESTING_Trait
+TALER_TESTING_make_trait_wire_details
+ (unsigned int index,
+ const json_t *wire_details)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
+ .ptr = (const json_t *) wire_details
+ };
+ return ret;
+}
+
+/* end of testing_api_trait_json.c */
diff --git a/src/exchange-lib/testing_api_trait_string.c b/src/exchange-lib/testing_api_trait_string.c
index 1b1b42219..fb5af93e5 100644
--- a/src/exchange-lib/testing_api_trait_string.c
+++ b/src/exchange-lib/testing_api_trait_string.c
@@ -30,7 +30,6 @@
#include "taler_signatures.h"
#include "taler_testing_lib.h"
-#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details"
#define TALER_TESTING_TRAIT_CONTRACT_TERMS "contract-terms"
#define TALER_TESTING_TRAIT_TRANSFER_SUBJECT "transfer-subject"
#define TALER_TESTING_TRAIT_AMOUNT "amount"
@@ -81,49 +80,6 @@ TALER_TESTING_make_trait_contract_terms
/**
- * Obtain wire details from @a cmd.
- *
- * @param cmd command to extract trait from
- * @param index always (?) zero, as one command sticks
- * to one bank account
- * @param wire_details[out] where to write the wire details.
- * @return #GNUNET_OK on success
- */
-int
-TALER_TESTING_get_trait_wire_details
- (const struct TALER_TESTING_Command *cmd,
- unsigned int index,
- const char **wire_details)
-{
- return cmd->traits (cmd->cls,
- (void **) wire_details,
- TALER_TESTING_TRAIT_WIRE_DETAILS,
- index);
-}
-
-/**
- * Offer wire details in a trait.
- *
- * @param index always (?) zero, as one command sticks
- * to one bank account
- * @param wire_details wire details to offer
- * @return the trait, to be put in the traits array of the command
- */
-struct TALER_TESTING_Trait
-TALER_TESTING_make_trait_wire_details
- (unsigned int index,
- const char *wire_details)
-{
- struct TALER_TESTING_Trait ret = {
- .index = index,
- .trait_name = TALER_TESTING_TRAIT_WIRE_DETAILS,
- .ptr = (const void *) wire_details
- };
- return ret;
-}
-
-
-/**
* Obtain a transfer subject from @a cmd.
*
* @param cmd command to extract trait from
@@ -289,7 +245,7 @@ TALER_TESTING_make_trait_order_id
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_ORDER_ID,
- .ptr = (const void *) order_id
+ .ptr = (const void *) order_id
};
return ret;
}
@@ -333,7 +289,7 @@ TALER_TESTING_make_trait_rejected
struct TALER_TESTING_Trait ret = {
.index = index,
.trait_name = TALER_TESTING_TRAIT_REJECTED,
- .ptr = (const void *) rejected
+ .ptr = (const void *) rejected
};
return ret;
}
diff --git a/src/exchange-tools/Makefile.am b/src/exchange-tools/Makefile.am
index 8d00415c8..2c1ff0f4d 100644
--- a/src/exchange-tools/Makefile.am
+++ b/src/exchange-tools/Makefile.am
@@ -4,7 +4,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include
pkgcfgdir = $(prefix)/share/taler/config.d/
pkgcfg_DATA = \
- exchange-signkeys.conf \
coins.conf
if USE_COVERAGE
@@ -34,6 +33,8 @@ taler_exchange_wire_SOURCES = \
taler-exchange-wire.c
taler_exchange_wire_LDADD = \
$(LIBGCRYPT_LIBS) \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/exchangedb/libtalerexchangedb.la \
$(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetjson \
diff --git a/src/exchange-tools/exchange-signkeys.conf b/src/exchange-tools/exchange-signkeys.conf
deleted file mode 100644
index 3146f09b2..000000000
--- a/src/exchange-tools/exchange-signkeys.conf
+++ /dev/null
@@ -1,16 +0,0 @@
-# General data for signing keys.
-[exchange_keys]
-
-# how long is one signkey valid?
-signkey_duration = 4 weeks
-
-# how long are the signatures with the signkey valid?
-legal_duration = 2 years
-
-# how long do we generate denomination and signing keys
-# ahead of time?
-lookahead_sign = 32 weeks 1 day
-
-# how long do we provide to clients denomination and signing keys
-# ahead of time?
-lookahead_provide = 4 weeks 1 day
diff --git a/src/exchange-tools/taler-exchange-keyup.c b/src/exchange-tools/taler-exchange-keyup.c
index 5e069af5b..9842a37a8 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-2017 GNUnet e.V.
+ Copyright (C) 2014-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
@@ -499,23 +499,23 @@ exchange_keys_update_signkeys ()
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (kcfg,
- "exchange_keys",
+ "exchange",
"signkey_duration",
&signkey_duration))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange_keys",
+ "exchange",
"signkey_duration");
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (kcfg,
- "exchange_keys",
+ "exchange",
"legal_duration",
&legal_duration))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "exchange_keys",
+ "exchange",
"legal_duration",
"fails to specify valid timeframe");
return GNUNET_SYSERR;
@@ -523,7 +523,7 @@ exchange_keys_update_signkeys ()
if (signkey_duration.rel_value_us > legal_duration.rel_value_us)
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "exchange_keys",
+ "exchange",
"legal_duration",
"must be longer than signkey_duration");
return GNUNET_SYSERR;
@@ -926,10 +926,13 @@ create_wire_fee_for_method (void *cls,
if (GNUNET_OK != *ret)
return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Setting up wire fees for `%s'\n",
+ wiremethod);
last_date = GNUNET_TIME_absolute_add (lookahead_sign_stamp,
max_duration_spend);
GNUNET_asprintf (&section,
- "exchange-wire-%s",
+ "fees-%s",
wiremethod);
GNUNET_asprintf (&fn,
"%s%s.fee",
@@ -1049,6 +1052,43 @@ create_wire_fee_for_method (void *cls,
* Output the wire fee structure. Must be run after #max_duration_spend
* was initialized.
*
+ * @param cls pointer to `int`, set to #GNUNET_SYSERR on error
+ * @param ai information about enabled accounts
+ */
+static void
+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);
+}
+
+
+/**
+ * Output the wire fee structure. Must be run after #max_duration_spend
+ * was initialized.
+ *
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
static int
@@ -1057,9 +1097,9 @@ create_wire_fees ()
int ret;
ret = GNUNET_OK;
- TALER_WIRE_find_enabled (kcfg,
- &create_wire_fee_for_method,
- &ret);
+ TALER_EXCHANGEDB_find_accounts (kcfg,
+ &create_wire_fee_by_account,
+ &ret);
return ret;
}
@@ -1305,12 +1345,12 @@ run (void *cls,
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_time (kcfg,
- "exchange_keys",
+ "exchange",
"lookahead_sign",
&lookahead_sign))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange_keys",
+ "exchange",
"lookahead_sign");
global_ret = 1;
return;
@@ -1318,7 +1358,7 @@ run (void *cls,
if (0 == lookahead_sign.rel_value_us)
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
- "exchange_keys",
+ "exchange",
"lookahead_sign",
_("must not be zero"));
global_ret = 1;
diff --git a/src/exchange-tools/taler-exchange-wire.c b/src/exchange-tools/taler-exchange-wire.c
index 60244f154..390c0e5e3 100644
--- a/src/exchange-tools/taler-exchange-wire.c
+++ b/src/exchange-tools/taler-exchange-wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2015, 2016, 2017 Inria
+ Copyright (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
@@ -24,6 +24,8 @@
#include "taler_crypto_lib.h"
#include "taler_util.h"
#include "taler_wire_lib.h"
+#include "taler_json_lib.h"
+#include "taler_exchangedb_lib.h"
#include "taler_signatures.h"
@@ -33,24 +35,64 @@
static char *masterkeyfile;
/**
- * Account holder information in JSON format.
+ * Private key for signing.
*/
-static json_t *account_holder;
+static struct TALER_MasterPrivateKeyP master_priv;
/**
- * Which wire method is this for?
+ * Return value from main().
*/
-static char *method;
+static int global_ret;
-/**
- * Where to write the result.
- */
-static char *output_filename;
/**
- * Return value from main().
+ * Function called with information about a wire account. Signs
+ * the account's wire details and writes out the JSON file to disk.
+ *
+ * @param cls closure
+ * @param ai account information
*/
-static int global_ret;
+static void
+sign_account_data (void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai)
+{
+ json_t *wire;
+ char *json_out;
+ FILE *out;
+
+ if (GNUNET_NO == ai->credit_enabled)
+ return;
+ if (NULL == ai->wire_response_filename)
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ ai->section_name,
+ "WIRE_RESPONSE");
+ global_ret = 1;
+ return;
+ }
+ wire = TALER_JSON_wire_signature_make (ai->payto_url,
+ &master_priv);
+ json_out = json_dumps (wire,
+ JSON_INDENT(2));
+ json_decref (wire);
+ GNUNET_assert (NULL != json_out);
+
+ out = fopen (ai->wire_response_filename,
+ "w+");
+ if (NULL == out)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "fopen",
+ ai->wire_response_filename);
+ global_ret = 1;
+ return;
+ }
+ fprintf (out,
+ "%s",
+ json_out);
+ fclose (out);
+ free (json_out);
+}
/**
@@ -68,11 +110,6 @@ run (void *cls,
const struct GNUNET_CONFIGURATION_Handle *cfg)
{
struct GNUNET_CRYPTO_EddsaPrivateKey *eddsa_priv;
- struct TALER_MasterPrivateKeyP key;
- struct TALER_MasterSignatureP sig;
- char *json_out;
- struct GNUNET_HashCode salt;
- struct TALER_WIRE_Plugin *plugin;
if ( (NULL == masterkeyfile) &&
(GNUNET_OK !=
@@ -86,7 +123,8 @@ run (void *cls,
global_ret = 1;
return;
}
- if (GNUNET_YES != GNUNET_DISK_file_test (masterkeyfile))
+ if (GNUNET_YES !=
+ GNUNET_DISK_file_test (masterkeyfile))
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Exchange master private key `%s' does not exist yet, creating it!\n",
masterkeyfile);
@@ -99,97 +137,11 @@ run (void *cls,
global_ret = 1;
return;
}
- if (NULL == method)
- {
- json_t *test;
- const char *m;
-
- test = json_object_get(account_holder,
- "type");
- if ( (NULL == test) ||
- (NULL == (m = json_string_value (test))))
- {
- fprintf (stderr,
- "Required -t argument missing\n");
- global_ret = 1;
- return;
- }
- method = GNUNET_strdup (m);
- }
- else
- {
- json_object_set_new (account_holder,
- "type",
- json_string (method));
- }
- key.eddsa_priv = *eddsa_priv;
- GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
- &salt,
- sizeof (salt));
- plugin = TALER_WIRE_plugin_load (cfg,
- method);
- if (NULL == plugin)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Wire transfer method `%s' not supported\n",
- method);
- GNUNET_free (method);
- global_ret = 1;
- return;
- }
- GNUNET_free (method);
- if (GNUNET_OK !=
- plugin->sign_wire_details (plugin->cls,
- account_holder,
- &key,
- &salt,
- &sig))
- {
- /* sign function should have logged applicable errors */
- json_decref (account_holder);
- TALER_WIRE_plugin_unload (plugin);
- global_ret = 1;
- return;
- }
- TALER_WIRE_plugin_unload (plugin);
+ master_priv.eddsa_priv = *eddsa_priv;
+ TALER_EXCHANGEDB_find_accounts (cfg,
+ &sign_account_data,
+ NULL);
GNUNET_free (eddsa_priv);
-
- /* add signature and salt to JSON message */
- json_object_set_new (account_holder,
- "salt",
- GNUNET_JSON_from_data (&salt,
- sizeof (salt)));
- json_object_set_new (account_holder,
- "sig",
- GNUNET_JSON_from_data (&sig,
- sizeof (sig)));
-
- /* dump result to stdout */
- json_out = json_dumps (account_holder,
- JSON_INDENT(2));
- json_decref (account_holder);
- GNUNET_assert (NULL != json_out);
-
- if (NULL != output_filename)
- {
- if (NULL != stdout)
- fclose (stdout);
- stdout = fopen (output_filename,
- "w+");
- if (NULL == stdout)
- {
- fprintf (stderr,
- "Failed to open `%s': %s\n",
- output_filename,
- STRERROR (errno));
- return;
- }
- }
- fprintf (stdout,
- "%s",
- json_out);
- fflush (stdout);
- free (json_out);
}
@@ -206,27 +158,11 @@ main (int argc,
char *const *argv)
{
const struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_mandatory
- (GNUNET_JSON_getopt ('j',
- "json",
- "JSON",
- "account information in JSON format",
- &account_holder)),
GNUNET_GETOPT_option_filename ('m',
"master-key",
"FILENAME",
"master key file (private key)",
&masterkeyfile),
- GNUNET_GETOPT_option_string ('t',
- "type",
- "METHOD",
- "which wire transfer method (i.e. 'test' or 'sepa') is this for?",
- &method),
- GNUNET_GETOPT_option_filename ('o',
- "output",
- "FILENAME",
- "where to write the result",
- &output_filename),
GNUNET_GETOPT_OPTION_END
};
diff --git a/src/exchange/.gitignore b/src/exchange/.gitignore
index e54fe4932..b0fe0a0f6 100644
--- a/src/exchange/.gitignore
+++ b/src/exchange/.gitignore
@@ -6,3 +6,4 @@ taler-exchange-reservemod
taler-exchange-httpd
taler-exchange-wirewatch
test_taler_exchange_wirewatch-postgres
+test_taler_exchange_httpd_home/.config/taler/account-1.json
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index 39c496ec5..5b9ff9be3 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -36,3 +36,18 @@ PORT = 8081
# Required for wire transfers as we need to include it in the wire
# transfers to enable tracking.
BASE_URL = http://localhost:8081/
+
+
+# how long is one signkey valid?
+SIGNKEY_DURATION = 4 weeks
+
+# how long are the signatures with the signkey valid?
+LEGAL_DURATION = 2 years
+
+# how long do we generate denomination and signing keys
+# ahead of time?
+LOOKAHEAD_SIGN = 32 weeks 1 day
+
+# how long do we provide to clients denomination and signing keys
+# ahead of time?
+LOOKAHEAD_PROVIDE = 4 weeks 1 day
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index 49cbb2b93..fa76cfb03 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, 2017 GNUnet e.V.
+ Copyright (C) 2016-2018 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,19 +30,19 @@
/**
- * Information we keep for each loaded wire plugin.
+ * Information we keep for each supported account.
*/
-struct WirePlugin
+struct WireAccount
{
/**
- * Plugins are kept in a DLL.
+ * Accounts are kept in a DLL.
*/
- struct WirePlugin *next;
+ struct WireAccount *next;
/**
* Plugins are kept in a DLL.
*/
- struct WirePlugin *prev;
+ struct WireAccount *prev;
/**
* Handle to the plugin.
@@ -50,14 +50,14 @@ struct WirePlugin
struct TALER_WIRE_Plugin *wire_plugin;
/**
- * Name of the plugin.
+ * Wire transfer fee structure.
*/
- char *type;
+ struct TALER_EXCHANGEDB_AggregateFees *af;
/**
- * Wire transfer fee structure.
+ * Name of the section that configures this account.
*/
- struct TALER_EXCHANGEDB_AggregateFees *af;
+ char *section_name;
};
@@ -82,7 +82,7 @@ struct WirePrepareData
/**
* Wire plugin used for this preparation.
*/
- struct WirePlugin *wp;
+ struct WireAccount *wa;
/**
* Row ID of the transfer.
@@ -149,9 +149,9 @@ struct AggregationUnit
json_t *wire;
/**
- * Wire plugin to be used for the preparation.
+ * Wire account to be used for the preparation.
*/
- struct WirePlugin *wp;
+ struct WireAccount *wa;
/**
* Database session for all of our transactions.
@@ -200,12 +200,12 @@ struct CloseTransferContext
/**
* Wire transfer method.
*/
- char *type;
+ char *method;
/**
- * Wire plugin used for closing the reserve.
+ * Wire account used for closing the reserve.
*/
- struct WirePlugin *wp;
+ struct WireAccount *wa;
};
@@ -238,12 +238,12 @@ static struct TALER_EXCHANGEDB_Plugin *db_plugin;
/**
* Head of list of loaded wire plugins.
*/
-static struct WirePlugin *wp_head;
+static struct WireAccount *wa_head;
/**
* Tail of list of loaded wire plugins.
*/
-static struct WirePlugin *wp_tail;
+static struct WireAccount *wa_tail;
/**
* Next task to run, if any.
@@ -290,49 +290,22 @@ static int reserves_idle;
static unsigned int aggregation_limit = TALER_EXCHANGEDB_MATCHING_DEPOSITS_LIMIT;
-/**
- * Extract wire plugin type from @a wire address
- *
- * @param wire a wire address
- * @return NULL if @a wire is ill-formed
- */
-const char *
-extract_type (const json_t *wire)
-{
- const char *type;
- json_t *t;
-
- t = json_object_get (wire, "type");
- if (NULL == t)
- {
- GNUNET_break (0);
- return NULL;
- }
- type = json_string_value (t);
- if (NULL == type)
- {
- GNUNET_break (0);
- return NULL;
- }
- return type;
-}
-
/**
* Advance the "af" pointer in @a wp to point to the
* currently valid record.
*
- * @param wp wire transfer fee data structure to update
+ * @param wa wire transfer fee data structure to update
* @param now timestamp to update fees to
*/
static void
-advance_fees (struct WirePlugin *wp,
+advance_fees (struct WireAccount *wa,
struct GNUNET_TIME_Absolute now)
{
struct TALER_EXCHANGEDB_AggregateFees *af;
/* First, try to see if we have current fee information in memory */
- af = wp->af;
+ af = wa->af;
while ( (NULL != af) &&
(af->end_date.abs_value_us < now.abs_value_us) )
{
@@ -341,7 +314,7 @@ advance_fees (struct WirePlugin *wp,
GNUNET_free (af);
af = n;
}
- wp->af = af;
+ wa->af = af;
}
@@ -354,28 +327,28 @@ advance_fees (struct WirePlugin *wp,
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
-update_fees (struct WirePlugin *wp,
+update_fees (struct WireAccount *wa,
struct GNUNET_TIME_Absolute now,
struct TALER_EXCHANGEDB_Session *session)
{
enum GNUNET_DB_QueryStatus qs;
- advance_fees (wp,
+ advance_fees (wa,
now);
- if (NULL != wp->af)
+ if (NULL != wa->af)
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
/* Let's try to load it from disk... */
- wp->af = TALER_EXCHANGEDB_fees_read (cfg,
- wp->type);
- advance_fees (wp,
+ wa->af = TALER_EXCHANGEDB_fees_read (cfg,
+ wa->wire_plugin->method);
+ advance_fees (wa,
now);
- for (struct TALER_EXCHANGEDB_AggregateFees *p = wp->af;
+ for (struct TALER_EXCHANGEDB_AggregateFees *p = wa->af;
NULL != p;
p = p->next)
{
qs = db_plugin->insert_wire_fee (db_plugin->cls,
session,
- wp->type,
+ wa->wire_plugin->method,
p->start_date,
p->end_date,
&p->wire_fee,
@@ -383,53 +356,94 @@ update_fees (struct WirePlugin *wp,
&p->master_sig);
if (qs < 0)
{
- TALER_EXCHANGEDB_fees_free (wp->af);
- wp->af = NULL;
+ TALER_EXCHANGEDB_fees_free (wa->af);
+ wa->af = NULL;
return qs;
}
}
- if (NULL != wp->af)
+ if (NULL != wa->af)
return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to find current wire transfer fees for `%s'\n",
- wp->type);
+ wa->wire_plugin->method);
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
}
/**
- * Find the wire plugin for the given wire address.
+ * Find the wire plugin for the given payto:// URL
*
- * @param type wire plugin type we need a plugin for
+ * @param method wire method we need an account for
* @return NULL on error
*/
-static struct WirePlugin *
-find_plugin (const char *type)
+static struct WireAccount *
+find_account_by_method (const char *method)
{
- struct WirePlugin *wp;
+ for (struct WireAccount *wa = wa_head; NULL != wa; wa = wa->next)
+ if (0 == strcmp (method,
+ wa->wire_plugin->method))
+ return wa;
+ return NULL;
+}
+
- if (NULL == type)
+/**
+ * Find the wire plugin for the given payto:// URL
+ *
+ * @param url wire address we need an account for
+ * @return NULL on error
+ */
+static struct WireAccount *
+find_account_by_url (const char *url)
+{
+ char *method;
+ struct WireAccount *wa;
+
+ method = TALER_WIRE_payto_get_method (url);
+ if (NULL == method)
+ {
+ fprintf (stderr,
+ "Invalid payto:// URL `%s'\n",
+ url);
return NULL;
- for (wp = wp_head; NULL != wp; wp = wp->next)
- if (0 == strcmp (type,
- wp->type))
- return wp;
- wp = GNUNET_new (struct WirePlugin);
- wp->wire_plugin = TALER_WIRE_plugin_load (cfg,
- type);
- if (NULL == wp->wire_plugin)
+ }
+ wa = find_account_by_method (method);
+ GNUNET_free (method);
+ return wa;
+}
+
+
+/**
+ * Function called with information about a wire account. Adds the
+ * account to our list (if it is enabled and we can load the plugin).
+ *
+ * @param cls closure, NULL
+ * @param ai account information
+ */
+static void
+add_account_cb (void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai)
+{
+ struct WireAccount *wa;
+
+ (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)
{
fprintf (stderr,
"Failed to load wire plugin for `%s'\n",
- type);
- GNUNET_free (wp);
- return NULL;
+ ai->plugin_name);
+ GNUNET_free (wa);
+ return;
}
- wp->type = GNUNET_strdup (type);
- GNUNET_CONTAINER_DLL_insert (wp_head,
- wp_tail,
- wp);
- return wp;
+ wa->section_name = GNUNET_strdup (ai->section_name);
+ GNUNET_CONTAINER_DLL_insert (wa_head,
+ wa_tail,
+ wa);
}
@@ -471,7 +485,7 @@ shutdown_task (void *cls)
{
if (NULL != wpd->eh)
{
- wpd->wp->wire_plugin->execute_wire_transfer_cancel (wpd->wp->wire_plugin->cls,
+ wpd->wa->wire_plugin->execute_wire_transfer_cancel (wpd->wa->wire_plugin->cls,
wpd->eh);
wpd->eh = NULL;
}
@@ -484,7 +498,7 @@ shutdown_task (void *cls)
{
if (NULL != au->ph)
{
- au->wp->wire_plugin->prepare_wire_transfer_cancel (au->wp->wire_plugin->cls,
+ au->wa->wire_plugin->prepare_wire_transfer_cancel (au->wa->wire_plugin->cls,
au->ph);
au->ph = NULL;
}
@@ -494,29 +508,29 @@ shutdown_task (void *cls)
}
if (NULL != ctc)
{
- ctc->wp->wire_plugin->prepare_wire_transfer_cancel (ctc->wp->wire_plugin->cls,
+ 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->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
}
TALER_EXCHANGEDB_plugin_unload (db_plugin);
{
- struct WirePlugin *wp;
+ struct WireAccount *wa;
- while (NULL != (wp = wp_head))
+ while (NULL != (wa = wa_head))
{
- GNUNET_CONTAINER_DLL_remove (wp_head,
- wp_tail,
- wp);
- TALER_WIRE_plugin_unload (wp->wire_plugin);
- TALER_EXCHANGEDB_fees_free (wp->af);
- GNUNET_free (wp->type);
- GNUNET_free (wp);
+ GNUNET_CONTAINER_DLL_remove (wa_head,
+ wa_tail,
+ wa);
+ TALER_WIRE_plugin_unload (wa->wire_plugin);
+ TALER_EXCHANGEDB_fees_free (wa->af);
+ GNUNET_free (wa->section_name);
+ GNUNET_free (wa);
}
}
GNUNET_CONFIGURATION_destroy (cfg);
@@ -568,7 +582,16 @@ exchange_serve_process_config ()
TALER_EXCHANGEDB_plugin_unload (db_plugin);
return GNUNET_SYSERR;
}
-
+ TALER_EXCHANGEDB_find_accounts (cfg,
+ &add_account_cb,
+ NULL);
+ if (NULL == wa_head)
+ {
+ fprintf (stderr,
+ "No wire accounts configured for debit!\n");
+ TALER_EXCHANGEDB_plugin_unload (db_plugin);
+ return GNUNET_SYSERR;
+ }
return GNUNET_OK;
}
@@ -677,16 +700,13 @@ deposit_cb (void *cls,
}
GNUNET_assert (NULL == au->wire);
- au->wire = json_incref ((json_t *) wire);
- if (GNUNET_OK !=
- TALER_JSON_hash (au->wire,
- &au->h_wire))
+ if (NULL == (au->wire = json_incref ((json_t *) wire)))
{
GNUNET_break (0);
- json_decref (au->wire);
- au->wire = NULL;
return GNUNET_DB_STATUS_HARD_ERROR;
}
+ TALER_JSON_wire_signature_hash (wire,
+ &au->h_wire);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&au->wtid,
sizeof (au->wtid));
@@ -695,15 +715,20 @@ deposit_cb (void *cls,
TALER_B2S (&au->wtid),
TALER_amount2s (amount_with_fee),
(unsigned long long) row_id);
+ {
+ char *url;
- au->wp = find_plugin (extract_type (au->wire));
- if (NULL == au->wp)
+ url = TALER_JSON_wire_to_payto (au->wire);
+ au->wa = find_account_by_url (url);
+ GNUNET_free (url);
+ }
+ if (NULL == au->wa)
return GNUNET_DB_STATUS_HARD_ERROR;
/* make sure we have current fees */
au->execution_time = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&au->execution_time);
- qs = update_fees (au->wp,
+ qs = update_fees (au->wa,
au->execution_time,
au->session);
if (qs <= 0)
@@ -713,7 +738,7 @@ deposit_cb (void *cls,
GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs);
return qs;
}
- au->wire_fee = au->wp->af->wire_fee;
+ au->wire_fee = au->wa->af->wire_fee;
qs = db_plugin->insert_aggregation_tracking (db_plugin->cls,
au->session,
@@ -942,7 +967,7 @@ prepare_close_cb (void *cls,
db_plugin->rollback (db_plugin->cls,
ctc->session);
/* start again */
- GNUNET_free (ctc->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
@@ -953,7 +978,7 @@ prepare_close_cb (void *cls,
/* Commit our intention to execute the wire transfer! */
qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
ctc->session,
- ctc->type,
+ ctc->method,
buf,
buf_size);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -963,7 +988,7 @@ prepare_close_cb (void *cls,
ctc->session);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (ctc->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return;
@@ -975,7 +1000,7 @@ prepare_close_cb (void *cls,
/* start again */
task = GNUNET_SCHEDULER_add_now (&run_aggregation,
NULL);
- GNUNET_free (ctc->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return;
@@ -983,7 +1008,7 @@ prepare_close_cb (void *cls,
/* finally commit */
(void) commit_or_warn (ctc->session);
- GNUNET_free (ctc->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -1029,7 +1054,7 @@ static enum GNUNET_DB_QueryStatus
expired_reserve_cb (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *left,
- const json_t *account_details,
+ const char *account_details,
struct GNUNET_TIME_Absolute expiration_date)
{
struct ExpiredReserveContext *erc = cls;
@@ -1040,24 +1065,15 @@ expired_reserve_cb (void *cls,
const struct TALER_Amount *closing_fee;
int ret;
enum GNUNET_DB_QueryStatus qs;
- const char *type;
- struct WirePlugin *wp;
+ struct WireAccount *wa;
GNUNET_assert (NULL == ctc);
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
/* lookup wire plugin */
- type = extract_type (account_details);
- if (NULL == type)
- {
- GNUNET_break (0);
- global_ret = GNUNET_SYSERR;
- GNUNET_SCHEDULER_shutdown ();
- return GNUNET_DB_STATUS_HARD_ERROR;
- }
- wp = find_plugin (type);
- if (NULL == wp)
+ wa = find_account_by_url (account_details);
+ if (NULL == wa)
{
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
@@ -1066,7 +1082,7 @@ expired_reserve_cb (void *cls,
}
/* lookup `closing_fee` */
- qs = update_fees (wp,
+ qs = update_fees (wa,
now,
session);
if (qs <= 0)
@@ -1079,7 +1095,7 @@ expired_reserve_cb (void *cls,
GNUNET_SCHEDULER_shutdown ();
return qs;
}
- closing_fee = &wp->af->closing_fee;
+ closing_fee = &wa->af->closing_fee;
/* calculate transfer amount */
ret = TALER_amount_subtract (&amount_without_fee,
@@ -1124,7 +1140,7 @@ expired_reserve_cb (void *cls,
{
/* success, perform wire transfer */
if (GNUNET_SYSERR ==
- wp->wire_plugin->amount_round (wp->wire_plugin->cls,
+ wa->wire_plugin->amount_round (wa->wire_plugin->cls,
&amount_without_fee))
{
GNUNET_break (0);
@@ -1133,11 +1149,12 @@ expired_reserve_cb (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR;
}
ctc = GNUNET_new (struct CloseTransferContext);
- ctc->wp = wp;
+ ctc->wa = wa;
ctc->session = session;
- ctc->type = GNUNET_strdup (type);
+ ctc->method = TALER_WIRE_payto_get_method (account_details);
ctc->ph
- = wp->wire_plugin->prepare_wire_transfer (wp->wire_plugin->cls,
+ = wa->wire_plugin->prepare_wire_transfer (wa->wire_plugin->cls,
+ wa->section_name,
account_details,
&amount_without_fee,
exchange_base_url,
@@ -1149,7 +1166,7 @@ expired_reserve_cb (void *cls,
GNUNET_break (0);
global_ret = GNUNET_SYSERR;
GNUNET_SCHEDULER_shutdown ();
- GNUNET_free (ctc->type);
+ GNUNET_free (ctc->method);
GNUNET_free (ctc);
ctc = NULL;
return GNUNET_DB_STATUS_HARD_ERROR;
@@ -1398,7 +1415,7 @@ run_aggregation (void *cls)
&au->total_amount,
&au->wire_fee)) ||
(GNUNET_SYSERR ==
- au->wp->wire_plugin->amount_round (au->wp->wire_plugin->cls,
+ au->wa->wire_plugin->amount_round (au->wa->wire_plugin->cls,
&au->final_amount)) ||
( (0 == au->final_amount.value) &&
(0 == au->final_amount.fraction) ) )
@@ -1479,22 +1496,28 @@ run_aggregation (void *cls)
TALER_B2S (&au->merchant_pub));
GNUNET_free (amount_s);
}
- au->ph = au->wp->wire_plugin->prepare_wire_transfer (au->wp->wire_plugin->cls,
- au->wire,
- &au->final_amount,
- exchange_base_url,
- &au->wtid,
- &prepare_cb,
- au);
+ {
+ 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);
+ GNUNET_free (url);
+ }
if (NULL == au->ph)
{
- GNUNET_break (0); /* why? how to best recover? */
+ /* something went very wrong, likely bad configuration,
+ abort */
db_plugin->rollback (db_plugin->cls,
session);
cleanup_au ();
- /* start again */
- task = GNUNET_SCHEDULER_add_now (&run_aggregation,
- NULL);
+ GNUNET_SCHEDULER_shutdown ();
return;
}
/* otherwise we continue with #prepare_cb(), see below */
@@ -1536,7 +1559,7 @@ prepare_cb (void *cls,
/* Commit our intention to execute the wire transfer! */
qs = db_plugin->wire_prepare_data_insert (db_plugin->cls,
session,
- au->wp->type,
+ au->wa->wire_plugin->method,
buf,
buf_size);
/* Commit the WTID data to 'wire_out' to finally satisfy aggregation
@@ -1711,8 +1734,8 @@ wire_prepare_cb (void *cls,
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Starting wire transfer %llu\n",
(unsigned long long) rowid);
- wpd->wp = find_plugin (wire_method);
- if (NULL == wpd->wp)
+ wpd->wa = find_account_by_method (wire_method);
+ if (NULL == wpd->wa)
{
/* Should really never happen here, as when we get
here the plugin should be in the cache. */
@@ -1725,7 +1748,7 @@ wire_prepare_cb (void *cls,
wpd = NULL;
return;
}
- wpd->eh = wpd->wp->wire_plugin->execute_wire_transfer (wpd->wp->wire_plugin->cls,
+ wpd->eh = wpd->wa->wire_plugin->execute_wire_transfer (wpd->wa->wire_plugin->cls,
buf,
buf_size,
&wire_confirm_cb,
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 277430b2d..8bf47717e 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -402,9 +402,12 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
&json);
if (GNUNET_SYSERR == res)
return MHD_NO;
- if ( (GNUNET_NO == res) || (NULL == json) )
+ if ( (GNUNET_NO == res) ||
+ (NULL == json) )
return MHD_YES;
- memset (&deposit, 0, sizeof (deposit));
+ memset (&deposit,
+ 0,
+ sizeof (deposit));
res = TEH_PARSE_json_data (connection,
json,
spec);
@@ -426,7 +429,6 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
if (TALER_EC_NONE !=
(ec = TEH_json_validate_wireformat (wire,
- GNUNET_NO,
&emsg)))
{
GNUNET_JSON_parse_free (spec);
@@ -446,8 +448,8 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
"timestamp");
}
if (GNUNET_OK !=
- TALER_JSON_hash (wire,
- &my_h_wire))
+ TALER_JSON_wire_signature_hash (wire,
+ &my_h_wire))
{
TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
GNUNET_JSON_parse_free (spec);
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index c7874ed15..99ee08a80 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -148,7 +148,7 @@ TEH_RESPONSE_reply_json (struct MHD_Connection *connection,
JSON_INDENT(2));
if (NULL == json_str)
{
- GNUNET_break (0);
+ GNUNET_assert (0);
return MHD_NO;
}
json_len = strlen (json_str);
@@ -733,10 +733,10 @@ TEH_RESPONSE_compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHisto
ret |= 1;
GNUNET_assert (0 ==
json_array_append_new (json_history,
- json_pack ("{s:s, s:o, s:O, s:o, s:o}",
+ json_pack ("{s:s, s:o, s:s, s:o, s:o}",
"type", "DEPOSIT",
"timestamp", GNUNET_JSON_from_time_abs (pos->details.bank->execution_date),
- "sender_account_details", pos->details.bank->sender_account_details,
+ "sender_account_url", pos->details.bank->sender_account_details,
"wire_reference", GNUNET_JSON_from_data (pos->details.bank->wire_reference,
pos->details.bank->wire_reference_size),
"amount", TALER_JSON_from_amount (&pos->details.bank->amount))));
@@ -858,14 +858,9 @@ TEH_RESPONSE_compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHisto
TALER_amount_hton (&rcc.closing_fee,
&pos->details.closing->closing_fee);
rcc.reserve_pub = pos->details.closing->reserve_pub;
- if (GNUNET_OK !=
- TALER_JSON_hash (pos->details.closing->receiver_account_details,
- &rcc.h_wire))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
+ GNUNET_CRYPTO_hash (pos->details.closing->receiver_account_details,
+ strlen (pos->details.closing->receiver_account_details) + 1,
+ &rcc.h_wire);
rcc.wtid = pos->details.closing->wtid;
if (GNUNET_OK !=
TEH_KS_sign (&rcc.purpose,
diff --git a/src/exchange/taler-exchange-httpd_track_transfer.c b/src/exchange/taler-exchange-httpd_track_transfer.c
index 493febc21..429c86f35 100644
--- a/src/exchange/taler-exchange-httpd_track_transfer.c
+++ b/src/exchange/taler-exchange-httpd_track_transfer.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2017 GNUnet e.V.
+ Copyright (C) 2014-2018 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
@@ -28,6 +28,7 @@
#include "taler-exchange-httpd_keystate.h"
#include "taler-exchange-httpd_track_transfer.h"
#include "taler-exchange-httpd_responses.h"
+#include "taler_wire_lib.h"
/**
@@ -236,8 +237,8 @@ struct WtidTransactionContext
* @param cls our context for transmission
* @param rowid which row in the DB is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param wire_method which wire plugin was used
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param wire where the funds were sent
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param coin_pub which public key was this payment about
@@ -248,8 +249,8 @@ static void
handle_transaction_data (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- const char *wire_method,
const struct GNUNET_HashCode *h_wire,
+ const json_t *wire,
struct GNUNET_TIME_Absolute exec_time,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -259,15 +260,22 @@ handle_transaction_data (void *cls,
struct WtidTransactionContext *ctx = cls;
struct TALER_Amount delta;
struct TEH_TrackTransferDetail *wdd;
+ char *wire_method;
if (GNUNET_SYSERR == ctx->is_valid)
return;
+ if (NULL == (wire_method = TALER_JSON_wire_to_method (wire)))
+ {
+ GNUNET_break (0);
+ ctx->is_valid = GNUNET_SYSERR;
+ return;
+ }
if (GNUNET_NO == ctx->is_valid)
{
ctx->merchant_pub = *merchant_pub;
ctx->h_wire = *h_wire;
ctx->exec_time = exec_time;
- ctx->wire_method = GNUNET_strdup (wire_method);
+ ctx->wire_method = wire_method;
ctx->is_valid = GNUNET_YES;
if (GNUNET_OK !=
TALER_amount_subtract (&ctx->total,
@@ -292,8 +300,10 @@ handle_transaction_data (void *cls,
{
GNUNET_break (0);
ctx->is_valid = GNUNET_SYSERR;
+ GNUNET_free (wire_method);
return;
}
+ GNUNET_free (wire_method);
if (GNUNET_OK !=
TALER_amount_subtract (&delta,
deposit_value,
diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c
index bef6aec59..7daa18aa7 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 GNUnet e.V.
+ Copyright (C) 2016, 2017, 2018 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
@@ -24,6 +24,8 @@
#include "taler-exchange-httpd.h"
#include "taler-exchange-httpd_validation.h"
#include "taler-exchange-httpd_wire.h"
+#include "taler_exchangedb_lib.h"
+#include "taler_json_lib.h"
#include "taler_wire_lib.h"
@@ -44,17 +46,13 @@ struct Plugin
struct Plugin *prev;
/**
- * Type of the wireformat.
- */
- char *type;
-
- /**
* Pointer to the plugin.
*/
struct TALER_WIRE_Plugin *plugin;
};
+
/**
* Head of DLL of wire plugins.
*/
@@ -65,50 +63,162 @@ static struct Plugin *wire_head;
*/
static struct Plugin *wire_tail;
+/**
+ * Array of wire methods supported by this exchange.
+ */
+static json_t *wire_accounts_array;
+
+/**
+ * Object mapping wire methods to the respective fee structure.
+ */
+static json_t *wire_fee_object;
+
/**
- * Load plugin @a name.
+ * Load wire fees for @a method.
+ *
+ * @param method wire method to load fee structure for
+ * @return #GNUNET_OK on success
+ */
+static int
+load_fee (const char *method)
+{
+ json_t *fees;
+
+ if (NULL != json_object_get (wire_fee_object,
+ method))
+ return GNUNET_OK; /* already have them */
+ fees = TEH_WIRE_get_fees (method);
+ if (NULL == fees)
+ return GNUNET_SYSERR;
+ /* Add fees to #wire_fee_object */
+ GNUNET_assert (-1 !=
+ json_object_set_new (wire_fee_object,
+ method,
+ fees));
+ return GNUNET_OK;
+}
+
+
+/**
+ * Initialize account; checks if @ai has /wire information, and if so,
+ * adds the /wire information (if included) to our responses. Also, if
+ * the account is debitable, we try to load the plugin.
*
* @param cls pointer to `int` to set to #GNUNET_SYSERR on errors
* @param name name of the plugin to load
*/
static void
-load_plugin (void *cls,
- const char *name)
+load_account (void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai)
{
int *ret = cls;
- struct Plugin *p;
- json_t *fees;
- p = GNUNET_new (struct Plugin);
- p->type = GNUNET_strdup (name);
- p->plugin = TALER_WIRE_plugin_load (cfg,
- name);
- if (NULL == p->plugin)
+ if ( (NULL != ai->wire_response_filename) &&
+ (GNUNET_YES == ai->credit_enabled) )
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to load plugin %s\n",
- name);
- GNUNET_free (p->type);
- GNUNET_free (p);
- *ret = GNUNET_SYSERR;
- return;
+ json_t *wire_s;
+ json_error_t error;
+ char *url;
+ char *method;
+
+ if (NULL == (wire_s = json_load_file (ai->wire_response_filename,
+ JSON_REJECT_DUPLICATES,
+ &error)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to parse `%s': %s at %d:%d (%d)\n",
+ ai->wire_response_filename,
+ error.text,
+ error.line,
+ error.column,
+ error.position);
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ if (NULL == (url = TALER_JSON_wire_to_payto (wire_s)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire response file `%s' lacks `url' entry\n",
+ ai->wire_response_filename);
+ json_decref (wire_s);
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ if (0 != strcasecmp (url,
+ ai->payto_url))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "URL in Wire response file `%s' does not match URL in configuration!\n",
+ ai->wire_response_filename);
+ json_decref (wire_s);
+ GNUNET_free (url);
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ GNUNET_free (url);
+ if (GNUNET_OK !=
+ TALER_JSON_wire_signature_check (wire_s,
+ &TEH_master_public_key))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid signature in `%s'\n",
+ ai->wire_response_filename);
+ json_decref (wire_s);
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ method = TALER_WIRE_payto_get_method (ai->payto_url);
+ if (GNUNET_OK ==
+ load_fee (method))
+ {
+ GNUNET_assert (-1 !=
+ json_array_append_new (wire_accounts_array,
+ wire_s));
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Wire fees not specified for `%s', ignoring plugin %s\n",
+ method,
+ ai->plugin_name);
+ *ret = GNUNET_SYSERR;
+ }
+ GNUNET_free (method);
}
- fees = TEH_WIRE_get_fees (name);
- if (NULL == fees)
+
+ if (GNUNET_YES == ai->debit_enabled)
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Disabling method `%s' as wire transfer fees are not given correctly\n",
- name);
- GNUNET_free (p->type);
- GNUNET_free (p);
- *ret = GNUNET_SYSERR;
- return;
+ 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))
+ {
+ 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);
+ *ret = GNUNET_SYSERR;
+ return;
+ }
+ GNUNET_CONTAINER_DLL_insert (wire_head,
+ wire_tail,
+ p);
}
- json_decref (fees);
- GNUNET_CONTAINER_DLL_insert (wire_head,
- wire_tail,
- p);
}
@@ -124,9 +234,11 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
int ret;
ret = GNUNET_OK;
- TALER_WIRE_find_enabled (cfg,
- &load_plugin,
- &ret);
+ wire_accounts_array = json_array ();
+ wire_fee_object = json_object ();
+ TALER_EXCHANGEDB_find_accounts (cfg,
+ &load_account,
+ &ret);
if (NULL == wire_head)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -153,9 +265,12 @@ TEH_VALIDATION_done ()
wire_tail,
p);
TALER_WIRE_plugin_unload (p->plugin);
- GNUNET_free (p->type);
GNUNET_free (p);
}
+ json_decref (wire_fee_object);
+ wire_fee_object = NULL;
+ json_decref (wire_accounts_array);
+ wire_accounts_array = NULL;
}
@@ -164,109 +279,74 @@ TEH_VALIDATION_done ()
* a wire address.
*
* @param wire the JSON wire format object
- * @param ours #GNUNET_YES if the signature should match our master key
* @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,
- int ours,
char **emsg)
{
- const char *stype;
+ const char *payto_url;
json_error_t error;
- struct Plugin *p;
+ char *method;
*emsg = NULL;
if (0 != json_unpack_ex ((json_t *) wire,
&error, 0,
"{s:s}",
- "type", &stype))
+ "url", &payto_url))
{
GNUNET_asprintf (emsg,
- "No `type' specified in the wire details\n");
+ "No `url' specified in the wire details\n");
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_MISSING;
}
- for (p=wire_head; NULL != p; p = p->next)
- if (0 == strcasecmp (p->type,
- stype))
- return p->plugin->wire_validate (p->plugin->cls,
- wire,
- (GNUNET_YES == ours)
- ? &TEH_master_public_key
- : NULL,
- emsg);
+ 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",
- stype);
+ method);
+ GNUNET_free (method);
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE_UNSUPPORTED;
}
/**
- * Obtain JSON of the supported wire methods for a given
- * account name prefix.
+ * Obtain JSON response for /wire
*
- * @return JSON array with the supported validation methods
+ * @return JSON array with the supported validation methods, NULL on error
*/
json_t *
-TEH_VALIDATION_get_wire_methods ()
+TEH_VALIDATION_get_wire_response ()
{
- json_t *methods;
- char *account_name;
- char *emsg;
- enum TALER_ErrorCode ec;
-
- methods = json_object ();
- for (struct Plugin *p=wire_head;NULL != p;p = p->next)
- {
- struct TALER_WIRE_Plugin *plugin = p->plugin;
- json_t *method;
- json_t *fees;
-
- GNUNET_asprintf (&account_name,
- "exchange-wire-%s",
- p->type);
- method = plugin->get_wire_details (plugin->cls,
- cfg,
- account_name);
- if (TALER_EC_NONE !=
- (ec = TEH_json_validate_wireformat (method,
- GNUNET_YES,
- &emsg)))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Disabling method `%s' as details are ill-formed: %s (%d)\n",
- p->type,
- emsg,
- ec);
- GNUNET_free (emsg);
- json_decref (method);
- method = NULL;
- }
- fees = TEH_WIRE_get_fees (p->type);
- if (NULL == fees)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Disabling method `%s' as wire transfer fees are not given correctly\n",
- p->type);
- json_decref (method);
- method = NULL;
- }
- else
- {
- json_object_set_new (method,
- "fees",
- fees);
- }
-
- if (NULL != method)
- json_object_set_new (methods,
- p->type,
- method);
- GNUNET_free (account_name);
- }
- return methods;
+ if ( (0 == json_array_size (wire_accounts_array)) ||
+ (0 == json_object_size (wire_fee_object)) )
+ return NULL;
+ return json_pack ("{s:O, s:O}",
+ "accounts", wire_accounts_array,
+ "fees", wire_fee_object);
}
diff --git a/src/exchange/taler-exchange-httpd_validation.h b/src/exchange/taler-exchange-httpd_validation.h
index d910da74f..a0d0795ff 100644
--- a/src/exchange/taler-exchange-httpd_validation.h
+++ b/src/exchange/taler-exchange-httpd_validation.h
@@ -47,24 +47,21 @@ TEH_VALIDATION_done (void);
* a wire address.
*
* @param wire the JSON wire format object
- * @param ours #GNUNET_YES if the signature should match our master key
* @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,
- int ours,
char **emsg);
/**
- * Obtain JSON of the supported wire methods for a given
- * account name prefix.
+ * Obtain JSON response for /wire
*
- * @return JSON array with the supported validation methods
+ * @return JSON object with the supported wire transfer options, NULL on error
*/
json_t *
-TEH_VALIDATION_get_wire_methods (void);
+TEH_VALIDATION_get_wire_response (void);
#endif
diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c
index 69b800ff8..bbbf3fb48 100644
--- a/src/exchange/taler-exchange-httpd_wire.c
+++ b/src/exchange/taler-exchange-httpd_wire.c
@@ -74,20 +74,20 @@ fees_to_json (struct TALER_EXCHANGEDB_AggregateFees *af)
/**
- * Obtain fee structure for @a wire_plugin_name wire transfers.
+ * Obtain fee structure for @a method wire transfers.
*
- * @param wire_plugin_name name of the plugin to load fees for
+ * @param method method to load fees for
* @return JSON object (to be freed by caller) with fee structure
*/
json_t *
-TEH_WIRE_get_fees (const char *wire_plugin_name)
+TEH_WIRE_get_fees (const char *method)
{
struct TALER_EXCHANGEDB_AggregateFees *af;
json_t *j;
struct GNUNET_TIME_Absolute now;
af = TALER_EXCHANGEDB_fees_read (cfg,
- wire_plugin_name);
+ method);
now = GNUNET_TIME_absolute_get ();
while ( (NULL != af) &&
(af->end_date.abs_value_us < now.abs_value_us) )
@@ -101,7 +101,7 @@ TEH_WIRE_get_fees (const char *wire_plugin_name)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to find current wire transfer fees for `%s'\n",
- wire_plugin_name);
+ method);
return NULL;
}
j = fees_to_json (af);
@@ -143,9 +143,8 @@ TEH_WIRE_handler_wire (struct TEH_RequestHandler *rh,
int
TEH_WIRE_init ()
{
- wire_methods = TEH_VALIDATION_get_wire_methods ();
- if ( (NULL == wire_methods) ||
- (0 == json_object_size (wire_methods)) )
+ wire_methods = TEH_VALIDATION_get_wire_response ();
+ if (NULL == wire_methods)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to find properly configured wire transfer method\n");
@@ -156,7 +155,7 @@ TEH_WIRE_init ()
/**
- * Initialize libgcrypt.
+ * Clean up wire subsystem.
*/
void __attribute__ ((destructor))
TEH_wire_cleanup ()
diff --git a/src/exchange/taler-exchange-httpd_wire.h b/src/exchange/taler-exchange-httpd_wire.h
index 72dd2198f..48f82beff 100644
--- a/src/exchange/taler-exchange-httpd_wire.h
+++ b/src/exchange/taler-exchange-httpd_wire.h
@@ -39,11 +39,11 @@ TEH_WIRE_init (void);
/**
* Obtain fee structure for @a wire_plugin_name wire transfers.
*
- * @param wire_plugin_name name of the plugin to load fees for
+ * @param method method to load fees for
* @return JSON object (to be freed by caller) with fee structure
*/
json_t *
-TEH_WIRE_get_fees (const char *wire_plugin_name);
+TEH_WIRE_get_fees (const char *method);
/**
diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c
index e0985366d..cabfac7f4 100644
--- a/src/exchange/taler-exchange-wirewatch.c
+++ b/src/exchange/taler-exchange-wirewatch.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016, 2017 GNUnet e.V.
+ Copyright (C) 2016, 2017, 2018 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
@@ -54,9 +54,58 @@ struct RejectContext
/**
- * Handle to the plugin.
+ * Information we keep for each supported account.
*/
-static struct TALER_WIRE_Plugin *wire_plugin;
+struct WireAccount
+{
+ /**
+ * Accounts are kept in a DLL.
+ */
+ struct WireAccount *next;
+
+ /**
+ * Plugins are kept in a DLL.
+ */
+ struct WireAccount *prev;
+
+ /**
+ * Handle to the plugin.
+ */
+ struct TALER_WIRE_Plugin *wire_plugin;
+
+ /**
+ * Name of the section that configures this account.
+ */
+ char *section_name;
+
+ /**
+ * Are we running from scratch and should re-process all transactions
+ * for this account?
+ */
+ int reset_mode;
+
+ /**
+ * Until when is processing this wire plugin delayed?
+ */
+ struct GNUNET_TIME_Absolute delayed_until;
+
+};
+
+
+/**
+ * Head of list of loaded wire plugins.
+ */
+static struct WireAccount *wa_head;
+
+/**
+ * Tail of list of loaded wire plugins.
+ */
+static struct WireAccount *wa_tail;
+
+/**
+ * Wire plugin we are currently using.
+ */
+static struct WireAccount *wa_pos;
/**
* Which currency is used by this exchange?
@@ -91,11 +140,6 @@ static void *last_row_off;
static size_t last_row_off_size;
/**
- * Which wire plugin are we watching?
- */
-static char *type;
-
-/**
* Should we delay the next request to the wire plugin a bit?
*/
static int delay;
@@ -134,6 +178,8 @@ static struct TALER_WIRE_RejectHandle *rt;
static void
shutdown_task (void *cls)
{
+ struct WireAccount *wa;
+
if (NULL != task)
{
GNUNET_SCHEDULER_cancel (task);
@@ -141,23 +187,31 @@ shutdown_task (void *cls)
}
if (NULL != hh)
{
- wire_plugin->get_history_cancel (wire_plugin->cls,
- hh);
+ wa_pos->wire_plugin->get_history_cancel (wa_pos->wire_plugin->cls,
+ hh);
hh = NULL;
}
if (NULL != rt)
{
char *wtid_s;
- wtid_s = wire_plugin->reject_transfer_cancel (wire_plugin->cls,
- rt);
+ 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;
- TALER_WIRE_plugin_unload (wire_plugin);
- wire_plugin = NULL;
+ while (NULL != (wa = wa_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (wa_head,
+ wa_tail,
+ wa);
+ TALER_WIRE_plugin_unload (wa->wire_plugin);
+ 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;
@@ -165,6 +219,41 @@ shutdown_task (void *cls)
/**
+ * Function called with information about a wire account. Adds the
+ * account to our list (if it is enabled and we can load the plugin).
+ *
+ * @param cls closure, NULL
+ * @param ai account information
+ */
+static void
+add_account_cb (void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai)
+{
+ struct WireAccount *wa;
+
+ (void) cls;
+ if (GNUNET_YES != ai->credit_enabled)
+ 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)
+ {
+ fprintf (stderr,
+ "Failed to load wire plugin for `%s'\n",
+ ai->plugin_name);
+ GNUNET_free (wa);
+ return;
+ }
+ wa->section_name = GNUNET_strdup (ai->section_name);
+ GNUNET_CONTAINER_DLL_insert (wa_head,
+ wa_tail,
+ wa);
+}
+
+
+/**
* Parse configuration parameters for the exchange server into the
* corresponding global variables.
*
@@ -173,12 +262,6 @@ shutdown_task (void *cls)
static int
exchange_serve_process_config ()
{
- if (NULL == type)
- {
- fprintf (stderr,
- "Option `-t' to specify wire plugin is mandatory.\n");
- return GNUNET_SYSERR;
- }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"taler",
@@ -206,17 +289,16 @@ exchange_serve_process_config ()
"Failed to initialize DB subsystem\n");
return GNUNET_SYSERR;
}
- if (NULL ==
- (wire_plugin = TALER_WIRE_plugin_load (cfg,
- type)))
+ TALER_EXCHANGEDB_find_accounts (cfg,
+ &add_account_cb,
+ NULL);
+ if (NULL == wa_head)
{
fprintf (stderr,
- "Failed to load wire plugin for `%s'\n",
- type);
+ "No wire accounts configured for credit!\n");
TALER_EXCHANGEDB_plugin_unload (db_plugin);
return GNUNET_SYSERR;
}
-
return GNUNET_OK;
}
@@ -292,12 +374,11 @@ history_cb (void *cls,
struct TALER_ReservePublicKeyP reserve_pub;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Got history callback, direction %u!\n", (unsigned int) dir);
-
+ "Got history callback, direction %u!\n",
+ (unsigned int) dir);
if (TALER_BANK_DIRECTION_NONE == dir)
{
hh = NULL;
-
if (TALER_EC_NONE != ec)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -309,18 +390,27 @@ history_cb (void *cls,
qs = db_plugin->commit (db_plugin->cls,
session);
if ( (GNUNET_YES == delay) &&
- (test_mode) )
+ (test_mode) &&
+ (NULL == wa_pos->next) )
{
GNUNET_SCHEDULER_shutdown ();
return GNUNET_OK;
}
if (GNUNET_YES == delay)
- task = GNUNET_SCHEDULER_add_delayed (DELAY,
- &find_transfers,
- NULL);
- else
- task = GNUNET_SCHEDULER_add_now (&find_transfers,
- NULL);
+ {
+ wa_pos->delayed_until
+ = GNUNET_TIME_relative_to_absolute (DELAY);
+ GNUNET_free_non_null (last_row_off);
+ last_row_off = NULL;
+ last_row_off_size = 0;
+ wa_pos = wa_pos->next;
+ if (NULL == wa_pos)
+ wa_pos = wa_head;
+ GNUNET_assert (NULL != wa_pos);
+ }
+ task = GNUNET_SCHEDULER_add_at (wa_pos->delayed_until,
+ &find_transfers,
+ NULL);
return GNUNET_OK; /* will be ignored anyway */
}
if (NULL != details->wtid_s)
@@ -344,11 +434,12 @@ history_cb (void *cls,
rtc = GNUNET_new (struct RejectContext);
rtc->session = session;
rtc->wtid_s = GNUNET_strdup (details->wtid_s);
- rt = wire_plugin->reject_transfer (wire_plugin->cls,
- row_off,
- row_off_size,
- &reject_cb,
- rtc);
+ rt = wa_pos->wire_plugin->reject_transfer (wa_pos->wire_plugin->cls,
+ wa_pos->section_name,
+ row_off,
+ row_off_size,
+ &reject_cb,
+ rtc);
return GNUNET_SYSERR; /* will continue later... */
}
@@ -366,7 +457,8 @@ history_cb (void *cls,
&reserve_pub,
&details->amount,
details->execution_date,
- details->account_details,
+ details->account_url,
+ wa_pos->section_name,
row_off,
row_off_size);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -434,10 +526,11 @@ find_transfers (void *cls)
GNUNET_SCHEDULER_shutdown ();
return;
}
- if (! reset_mode)
+ if (! wa_pos->reset_mode)
{
qs = db_plugin->get_latest_reserve_in_reference (db_plugin->cls,
session,
+ wa_pos->section_name,
&last_row_off,
&last_row_off_size);
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -456,17 +549,19 @@ find_transfers (void *cls)
return;
}
}
+ wa_pos->reset_mode = GNUNET_NO;
GNUNET_assert ( (NULL == last_row_off) ||
( (NULL != last_row_off) &&
(0 != last_row_off_size) ) );
delay = GNUNET_YES;
- hh = wire_plugin->get_history (wire_plugin->cls,
- TALER_BANK_DIRECTION_CREDIT,
- last_row_off,
- last_row_off_size,
- 1024,
- &history_cb,
- session);
+ 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,
+ 1024,
+ &history_cb,
+ session);
if (NULL == hh)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -501,7 +596,8 @@ run (void *cls,
global_ret = 1;
return;
}
-
+ wa_pos = wa_head;
+ GNUNET_assert (NULL != wa_pos);
task = GNUNET_SCHEDULER_add_now (&find_transfers,
NULL);
GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
@@ -521,11 +617,6 @@ main (int argc,
char *const *argv)
{
struct GNUNET_GETOPT_CommandLineOption options[] = {
- GNUNET_GETOPT_option_string ('t',
- "type",
- "PLUGINNAME",
- "which wire plugin to use",
- &type),
GNUNET_GETOPT_option_flag ('T',
"test",
"run in test mode and exit when idle",
diff --git a/src/exchange/test-taler-exchange-aggregator-postgres.conf b/src/exchange/test-taler-exchange-aggregator-postgres.conf
index a5f35196b..c2c8aef1d 100644
--- a/src/exchange/test-taler-exchange-aggregator-postgres.conf
+++ b/src/exchange/test-taler-exchange-aggregator-postgres.conf
@@ -16,7 +16,8 @@ PORT = 8081
# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
-# Expected base URL of the exchange.
+# Expected base URL of the exchange. Used in wire transfers for
+# the tracking API.
BASE_URL = "https://exchange.taler.net/"
[exchangedb]
@@ -31,16 +32,24 @@ IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
[exchangedb-postgres]
#The connection string the plugin has to use for connecting to the database
-DB_CONN_STR = postgres:///talercheck
+CONFIG = postgres:///talercheck
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
+[account-1]
+
+# What is the account URL?
+URL = "payto://x-taler-bank/localhost:8082/3"
+
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json
+PLUGIN = "taler_bank"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+TALER_BANK_AUTH_METHOD = NONE
+
+[fees-x-taler-bank]
# Fees for the forseeable future...
-# If you see this after 2017, update to match the next 10 years...
-WIRE-FEE-2017 = EUR:0.01
+# If you see this after 2018, update to match the next 10 years...
WIRE-FEE-2018 = EUR:0.01
WIRE-FEE-2019 = EUR:0.01
WIRE-FEE-2020 = EUR:0.01
@@ -50,8 +59,8 @@ WIRE-FEE-2023 = EUR:0.01
WIRE-FEE-2024 = EUR:0.01
WIRE-FEE-2025 = EUR:0.01
WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
-CLOSING-FEE-2017 = EUR:0.01
CLOSING-FEE-2018 = EUR:0.01
CLOSING-FEE-2019 = EUR:0.01
CLOSING-FEE-2020 = EUR:0.01
@@ -61,11 +70,4 @@ CLOSING-FEE-2023 = EUR:0.01
CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
-
-
-# What is the main website of the bank?
-BANK_URL = "http://localhost:8082/"
-
-# From which account at the 'bank' should outgoing
-# wire transfers be made?
-EXCHANGE_ACCOUNT_NUMBER = 3
+CLOSING-FEE-2027 = EUR:0.01
diff --git a/src/exchange/test-taler-exchange-wirewatch-postgres.conf b/src/exchange/test-taler-exchange-wirewatch-postgres.conf
index cc614fc83..7f8cc4793 100644
--- a/src/exchange/test-taler-exchange-wirewatch-postgres.conf
+++ b/src/exchange/test-taler-exchange-wirewatch-postgres.conf
@@ -33,16 +33,23 @@ IDLE_RESERVE_EXPIRATION_TIME = 5 s
[exchangedb-postgres]
#The connection string the plugin has to use for connecting to the database
-DB_CONN_STR = postgres:///talercheck
+CONFIG = postgres:///talercheck
+[account-1]
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
+# What is the account URL?
+URL = "payto://x-taler-bank/localhost:8082/3"
+
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json
+PLUGIN = "taler_bank"
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+TALER_BANK_AUTH_METHOD = NONE
+
+[fees-x-taler-bank]
# Fees for the forseeable future...
-# If you see this after 2017, update to match the next 10 years...
-WIRE-FEE-2017 = EUR:0.01
+# If you see this after 2018, update to match the next 10 years...
WIRE-FEE-2018 = EUR:0.01
WIRE-FEE-2019 = EUR:0.01
WIRE-FEE-2020 = EUR:0.01
@@ -52,8 +59,8 @@ WIRE-FEE-2023 = EUR:0.01
WIRE-FEE-2024 = EUR:0.01
WIRE-FEE-2025 = EUR:0.01
WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
-CLOSING-FEE-2017 = EUR:0.01
CLOSING-FEE-2018 = EUR:0.01
CLOSING-FEE-2019 = EUR:0.01
CLOSING-FEE-2020 = EUR:0.01
@@ -63,11 +70,4 @@ CLOSING-FEE-2023 = EUR:0.01
CLOSING-FEE-2024 = EUR:0.01
CLOSING-FEE-2025 = EUR:0.01
CLOSING-FEE-2026 = EUR:0.01
-
-
-# What is the main website of the bank?
-BANK_URL = "http://localhost:8082/"
-
-# From which account at the 'bank' should outgoing
-# wire transfers be made?
-EXCHANGE_ACCOUNT_NUMBER = 3
+CLOSING-FEE-2027 = EUR:0.01
diff --git a/src/exchange/test_taler_exchange_aggregator.c b/src/exchange/test_taler_exchange_aggregator.c
index 0335bcd44..f22e63815 100644
--- a/src/exchange/test_taler_exchange_aggregator.c
+++ b/src/exchange/test_taler_exchange_aggregator.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2016, 2017 Inria and GNUnet e.V.
+ (C) 2016, 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
@@ -403,7 +403,9 @@ do_deposit (struct Command *cmd)
struct TALER_MerchantPrivateKeyP merchant_priv;
int ret;
- memset (&deposit, 0, sizeof (deposit));
+ memset (&deposit,
+ 0,
+ sizeof (deposit));
/* we derive the merchant's private key from the
name, to ensure that the same name always
results in the same key pair. */
@@ -432,13 +434,21 @@ do_deposit (struct Command *cmd)
}
fake_coin (&deposit.coin);
/* Build JSON for wire details */
- deposit.receiver_wire_account = json_pack ("{s:s, s:s, s:I}",
- "type", "test",
- "bank_url", "http://localhost:8082/",
- "account_number", (json_int_t) cmd->details.deposit.merchant_account);
+ {
+ char *str;
+
+ GNUNET_asprintf (&str,
+ "payto://x-taler-bank/localhost:8082/%llu",
+ (unsigned long long) cmd->details.deposit.merchant_account);
+ deposit.receiver_wire_account
+ = json_pack ("{s:s, s:s}",
+ "salt", "this-is-a-salt-value",
+ "url", str);
+ GNUNET_free (str);
+ }
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (deposit.receiver_wire_account,
- &deposit.h_wire));
+ TALER_JSON_wire_signature_hash (deposit.receiver_wire_account,
+ &deposit.h_wire));
deposit.timestamp = GNUNET_TIME_absolute_get ();
GNUNET_TIME_round_abs (&deposit.timestamp);
deposit.wire_deadline = GNUNET_TIME_relative_to_absolute (cmd->details.deposit.wire_deadline);
diff --git a/src/exchange/test_taler_exchange_httpd.conf b/src/exchange/test_taler_exchange_httpd.conf
index 7df8d9b22..743dbfede 100644
--- a/src/exchange/test_taler_exchange_httpd.conf
+++ b/src/exchange/test_taler_exchange_httpd.conf
@@ -30,18 +30,49 @@ IDLE_RESERVE_EXPIRATION_TIME = 4 weeks
[exchangedb-postgres]
-DB_CONN_STR = "postgres:///talercheck"
+CONFIG = "postgres:///talercheck"
-[exchange-wire-test]
-# Enable 'test' for testing of the actual coin operations.
-ENABLE = YES
+[account-1]
# What is the main website of the bank?
-BANK_URL = "http://localhost:8082/"
-
-# From which account at the 'bank' should outgoing
-# wire transfers be made?
-EXCHANGE_ACCOUNT_NUMBER = 3
+URL = "payto://x-taler-bank/localhost:8082/3"
+
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json
+
+PLUGIN = "taler_bank"
+
+ENABLE_DEBIT = YES
+
+ENABLE_CREDIT = YES
+
+TALER_BANK_AUTH_METHOD = NONE
+
+
+# Wire fees are specified by wire method, NOT by wire plugin.
+[fees-x-taler-bank]
+# Fees for the forseeable future...
+# If you see this after 2018, update to match the next 10 years...
+WIRE-FEE-2018 = EUR:0.01
+WIRE-FEE-2019 = EUR:0.01
+WIRE-FEE-2020 = EUR:0.01
+WIRE-FEE-2021 = EUR:0.01
+WIRE-FEE-2022 = EUR:0.01
+WIRE-FEE-2023 = EUR:0.01
+WIRE-FEE-2024 = EUR:0.01
+WIRE-FEE-2025 = EUR:0.01
+WIRE-FEE-2026 = EUR:0.01
+WIRE-FEE-2027 = EUR:0.01
+
+CLOSING-FEE-2018 = EUR:0.01
+CLOSING-FEE-2019 = EUR:0.01
+CLOSING-FEE-2020 = EUR:0.01
+CLOSING-FEE-2021 = EUR:0.01
+CLOSING-FEE-2022 = EUR:0.01
+CLOSING-FEE-2023 = EUR:0.01
+CLOSING-FEE-2024 = EUR:0.01
+CLOSING-FEE-2025 = EUR:0.01
+CLOSING-FEE-2026 = EUR:0.01
+CLOSING-FEE-2027 = EUR:0.01
# Coins for the tests.
diff --git a/src/exchange/test_taler_exchange_httpd.data b/src/exchange/test_taler_exchange_httpd.data
index f88f42063..48fd8eec2 100644
--- a/src/exchange/test_taler_exchange_httpd.data
+++ b/src/exchange/test_taler_exchange_httpd.data
@@ -1,5 +1,5 @@
# This file is part of TALER
-# Copyright (C) 2015 GNUnet e.V.
+# Copyright (C) 2015, 2018 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
@@ -23,21 +23,6 @@
# Note that neither element may contain any spaces!
#
#
-# Bad amount:
-/admin/add/incoming {"reserve_pub":"7RZBZ86677QMASD2KAYGEPD246C7B7RC6P101FNTG6ZK8X61A620","amount":"1","execution_date":"\/Date(1435934428788)\/","wire":{"empty":"empty"}}
-#
-# Bad wire format:
-/admin/add/incoming {"reserve_pub":"6VRFYZRVHJ434BV3J018MS6H7Q1V5Q6YECNMEF9G4WKB8QJQCAX0","amount":{"currency":"EUR","value":10,"fraction":3},"execution_date":"\/Date(1436258333286)\/","wire":{"empty":"empty"}}
-#
-# Malformed JSON (ill-balanced quotes around 'amount')
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0",amount":{"currency":"EUR","value":5,"fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
-#
-# Bad amount (value not a string)
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":{"currency":"EUR","value":"5","fraction":3},"execution_date":"\/Date(1436271156447)\/","wire":{"type":"test","IBAN":0,"name":"Jack","BIC":999,"edate":"\/Date(1436271156447)\/","r":50}}
-#
-# Bad amount (overall amount is a string)
-/admin/add/incoming {"reserve_pub":"BSEFVVNZ4C3724BPVKTJMQMD73HQREA5FWSS1C1BZ36ZFF2WBTK0","amount":"{\"currency\":\"EUR\",\"value\":5,\"fraction\":3}","execution_date":"\/Date(1436271156447)\/","wire":{"type":"test"}}
-#
# Bogus denomination key
/deposit {"f":{"currency":"EUR","value":5,"fraction":0},"h_contract_terms":"NRT9E07FYT147V4VCDG0102P0YX0FZ11ZRG90F4X1HDV95M0J64ZVE4XQGNN9MJ3B5K3JX6TJ181KNGRYSZSTYZ5PQHBM1F9QKQ5B50","wire":{"bank":"dest bank","type":"TEST","account":42},"timestamp":"/Date(1436823947)/","coin_pub":"2KCPBGZ77VGJT4DG99EZAY0GQ5TJ89DF53FWYR5RFRTK0CCXRMFG","denom_pub":"51B7ARKCD5HJTTV5F4G0M818E9SP280A40G2GVH04CR30E9S6GVK2DHM8S234C236CR32C9N8RW44E9M712KAH1R60VM2CJ16RT3GGA18RR36CA575144DJ58CTK0E9M8D2M2E9S8GTKGH1Q8S0KACT174S3AD2670R4ADJ664W32C1N8N23CHA58MSK6DJ26WSMAD1P8H132CHP8GWKAG9K8RS46GJ6890M6GT28GSK4GJ66X2KCCA168RM4GA67113GDA28RR4AGA36RVK6GA460VKJDT58CVK6HA488R48E9R6D2KEH258N246HHJ850K4H9R8N0KEC9N68SM2EA48RR3JEA284SM6C9M6D130D228MSK6H1J6MSKCH1K8CR38CJ48MV36GJ38513CE9P60TM6CA56D1K8HHQ75244DA26WW4CG9M8MW3JE9M7133JGH354520818CMG26C1H60R30C935452081918G2J2G0","coin_sig":"W1TDFCSW5XQX9ZF4QPVP3JAJFYA7G4X6SY2B49KRNTDMA685M9YNFETV4610RFKZMSQ3RBRCYBJQH1ZQSMTDMW9W8X6C9SGPCA5ST0R","H_wire":"YQED9FDYPKK2QQYB3FS19Y15ZMKBAXJP2C73CXASAF1KM6ZYY723TEJ3HBR6D864A7X5W58G92QJ0A9PFMZNB81ZP9NJAQQCCABM4RG","ub_sig":"51SPJSSDESGPR80A40M74WV140520818ECG26DSQ8913AC1S7513EC9G6914AE228H236HHR68VKCCSK650MAGSM6GV3GCHP6D330H1R8GVKJD9P68W46H9Q8GVK8HA6752M2CSN8N248DHJ8H346E9J8RS4CDA28D33ECJ38S33JC9R6MRM8D9G74WM8HA668T44H1N6RT44GHS8CSK8H1G6D346C9J6CS3EC1N8H2M4HA38CSK2D246CW4CD1P70VMAD1Q891K8H1M64TK6C258MRM6G9R88RM6E2488WK2CSQ6GW3GH9N64RKGH2375136GA66533GCSJ65344CHH84W38HHP75330DA58RSKJCJ364SK0C1R8GVK6DSP61134HA48GT4CE1J6MW36C9G891K2GT68GTMCCSQ890M8E1P88R44DA174VK4E135452081918G2J2G0","merchant_pub":"4032W2ZXFW000KRJQDH3CZR00000000004000030P6YG1NR50000","refund_deadline":"/Date(0)/"}
#
diff --git a/src/exchange/test_taler_exchange_httpd.sh b/src/exchange/test_taler_exchange_httpd.sh
index 7cd2e2762..9c9ef40e1 100755
--- a/src/exchange/test_taler_exchange_httpd.sh
+++ b/src/exchange/test_taler_exchange_httpd.sh
@@ -25,7 +25,9 @@ unset XDG_DATA_HOME
unset XDG_CONFIG_HOME
#
# Setup keys.
-taler-exchange-keyup -c test_taler_exchange_httpd.conf
+taler-exchange-keyup -c test_taler_exchange_httpd.conf || exit 1
+# Setup wire accounts.
+taler-exchange-wire -c test_taler_exchange_httpd.conf || exit 1
# Run Exchange HTTPD (in background)
taler-exchange-httpd -c test_taler_exchange_httpd.conf -i &
# Give HTTP time to start
diff --git a/src/exchange/test_taler_exchange_wirewatch.c b/src/exchange/test_taler_exchange_wirewatch.c
index 69502d9d4..8c1210da2 100644
--- a/src/exchange/test_taler_exchange_wirewatch.c
+++ b/src/exchange/test_taler_exchange_wirewatch.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2016, 2017 Inria and GNUnet e.V.
+ (C) 2016, 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
@@ -499,7 +499,6 @@ interpreter (void *cls)
"taler-exchange-wirewatch",
"taler-exchange-wirewatch",
"-c", config_filename,
- "-t", "test",
"-T", /* run in test mode, exit instead of looping */
NULL);
if (NULL == cmd->details.wirewatch.wirewatch_proc)
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index 66299d786..03322f8c5 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -42,6 +42,7 @@ lib_LTLIBRARIES = \
libtalerexchangedb.la
libtalerexchangedb_la_SOURCES = \
+ exchangedb_accounts.c \
exchangedb_auditorkeys.c \
exchangedb_denomkeys.c \
exchangedb_fees.c \
@@ -111,7 +112,8 @@ test_exchangedb_postgres_LDADD = \
$(top_builddir)/src/json/libtalerjson.la \
$(top_srcdir)/src/util/libtalerutil.la \
$(top_srcdir)/src/pq/libtalerpq.la \
- -lgnunetutil -ljansson
+ -ljansson \
+ -lgnunetutil
test_perf_taler_exchangedb_SOURCES = \
test_perf_taler_exchangedb.c \
@@ -121,8 +123,8 @@ test_perf_taler_exchangedb_LDADD = \
libtalerexchangedb.la \
$(top_srcdir)/src/util/libtalerutil.la \
$(top_srcdir)/src/pq/libtalerpq.la \
- -ljansson \
- -lgnunetutil
+ -lgnunetutil \
+ -ljansson
perf_exchangedb_SOURCES = \
perf_taler_exchangedb.c \
@@ -132,8 +134,8 @@ perf_exchangedb_LDADD = \
libtalerexchangedb.la \
$(top_srcdir)/src/util/libtalerutil.la \
$(top_srcdir)/src/pq/libtalerpq.la \
- -ljansson \
- -lgnunetutil
+ -lgnunetutil \
+ -ljansson
EXTRA_test_exchangedb_postgres_DEPENDENCIES = \
diff --git a/src/exchangedb/exchangedb-postgres.conf b/src/exchangedb/exchangedb-postgres.conf
index 3de7474ff..5ebd656c8 100644
--- a/src/exchangedb/exchangedb-postgres.conf
+++ b/src/exchangedb/exchangedb-postgres.conf
@@ -1,2 +1,2 @@
[exchangedb-postgres]
-DB_CONN_STR = "postgres:///taler"
+CONFIG = "postgres:///taler"
diff --git a/src/exchangedb/exchangedb_accounts.c b/src/exchangedb/exchangedb_accounts.c
new file mode 100644
index 000000000..275e92674
--- /dev/null
+++ b/src/exchangedb/exchangedb_accounts.c
@@ -0,0 +1,141 @@
+/*
+ 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 exchangedb/exchangedb_accounts.c
+ * @brief Logic to parse account information from the configuration
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "taler_exchangedb_lib.h"
+
+
+/**
+ * Closure of #check_for_account.
+ */
+struct FindAccountContext
+{
+ /**
+ * Configuration we are usign.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Callback to invoke.
+ */
+ TALER_EXCHANGEDB_AccountCallback 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_account (void *cls,
+ const char *section)
+{
+ struct FindAccountContext *ctx = cls;
+ char *plugin_name;
+ char *payto_url;
+ char *wire_response_filename;
+ struct TALER_EXCHANGEDB_AccountInfo ai;
+
+ if (0 != strncasecmp (section,
+ "account-",
+ strlen ("account-")))
+ return;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
+ section,
+ "URL",
+ &payto_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ section,
+ "URL");
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
+ section,
+ "PLUGIN",
+ &plugin_name))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
+ section,
+ "PLUGIN");
+ GNUNET_free (payto_url);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (ctx->cfg,
+ section,
+ "WIRE_RESPONSE",
+ &wire_response_filename))
+ wire_response_filename = NULL;
+ ai.section_name = section;
+ ai.plugin_name = plugin_name;
+ ai.payto_url = payto_url;
+ ai.wire_response_filename = wire_response_filename;
+ ai.debit_enabled = (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (ctx->cfg,
+ section,
+ "ENABLE_DEBIT"));
+ ai.credit_enabled = (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (ctx->cfg,
+ section,
+ "ENABLE_CREDIT"));
+ ctx->cb (ctx->cb_cls,
+ &ai);
+ GNUNET_free (payto_url);
+ GNUNET_free (plugin_name);
+ GNUNET_free_non_null (wire_response_filename);
+}
+
+
+/**
+ * Parse the configuration to find account information.
+ *
+ * @param cfg configuration to use
+ * @param cb callback to invoke
+ * @param cb_cls closure for @a cb
+ */
+void
+TALER_EXCHANGEDB_find_accounts (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ TALER_EXCHANGEDB_AccountCallback cb,
+ void *cb_cls)
+{
+ struct FindAccountContext ctx;
+
+ ctx.cfg = cfg;
+ ctx.cb = cb;
+ ctx.cb_cls = cb_cls;
+ GNUNET_CONFIGURATION_iterate_sections (cfg,
+ &check_for_account,
+ &ctx);
+}
+
+/* end of exchangedb_accounts.c */
diff --git a/src/exchangedb/perf_taler_exchangedb.c b/src/exchangedb/perf_taler_exchangedb.c
index e2591c88b..5cde719c1 100644
--- a/src/exchangedb/perf_taler_exchangedb.c
+++ b/src/exchangedb/perf_taler_exchangedb.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016 Inria and GNUnet e.V.
+ Copyright (C) 2014-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
diff --git a/src/exchangedb/perf_taler_exchangedb_init.c b/src/exchangedb/perf_taler_exchangedb_init.c
index 4efec3911..789aaea00 100644
--- a/src/exchangedb/perf_taler_exchangedb_init.c
+++ b/src/exchangedb/perf_taler_exchangedb_init.c
@@ -204,6 +204,7 @@ PERF_TALER_EXCHANGEDB_reserve_free (struct PERF_TALER_EXCHANGEDB_Reserve *reserv
/**
* Generate a dummy deposit for testing purposes
+ *
* @param dki the denomination key used to sign the key
*/
struct TALER_EXCHANGEDB_Deposit *
@@ -214,19 +215,12 @@ PERF_TALER_EXCHANGEDB_deposit_init (const struct PERF_TALER_EXCHANGEDB_Coin *coi
struct TALER_MerchantPublicKeyP merchant_pub;
struct GNUNET_HashCode h_contract_terms;
struct GNUNET_HashCode h_wire;
- const char wire[] = "{"
- "\"type\":\"SEPA\","
- "\"IBAN\":\"DE67830654080004822650\","
- "\"NAME\":\"GNUNET E.\","
- "\"BIC\":\"GENODEF1SRL\""
- "}";
struct GNUNET_TIME_Absolute timestamp;
struct GNUNET_TIME_Absolute refund_deadline;
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
- GNUNET_assert (NULL !=
- (deposit = GNUNET_malloc (sizeof (struct TALER_EXCHANGEDB_Deposit) + sizeof (wire))));
+ deposit = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
&h_contract_terms);
GNUNET_CRYPTO_hash_create_random (GNUNET_CRYPTO_QUALITY_WEAK,
@@ -253,9 +247,8 @@ PERF_TALER_EXCHANGEDB_deposit_init (const struct PERF_TALER_EXCHANGEDB_Coin *coi
eddsa_prv = GNUNET_CRYPTO_eddsa_key_create ();
GNUNET_assert(NULL != eddsa_prv);
- GNUNET_CRYPTO_eddsa_key_get_public (
- eddsa_prv,
- &merchant_pub.eddsa_pub);
+ GNUNET_CRYPTO_eddsa_key_get_public (eddsa_prv,
+ &merchant_pub.eddsa_pub);
GNUNET_free (eddsa_prv);
}
timestamp = GNUNET_TIME_absolute_get ();
@@ -280,7 +273,10 @@ PERF_TALER_EXCHANGEDB_deposit_init (const struct PERF_TALER_EXCHANGEDB_Coin *coi
deposit->csig = csig;
deposit->h_contract_terms = h_contract_terms;
deposit->h_wire = h_wire;
- deposit->receiver_wire_account = json_loads (wire, 0, NULL);
+ deposit->receiver_wire_account
+ = json_pack ("{s:s, s:s}",
+ "url", "payto://sepa/DE67830654080004822650",
+ "salt", "this-is-a-salt-value");
deposit->timestamp = timestamp;
deposit->refund_deadline = refund_deadline;
deposit->amount_with_fee = amount_with_fee;
@@ -301,7 +297,7 @@ PERF_TALER_EXCHANGEDB_deposit_copy (const struct TALER_EXCHANGEDB_Deposit *depos
copy = GNUNET_new (struct TALER_EXCHANGEDB_Deposit);
*copy = *deposit;
- json_incref (copy->receiver_wire_account);
+ copy->receiver_wire_account = json_incref (deposit->receiver_wire_account);
copy->coin.denom_pub.rsa_public_key =
GNUNET_CRYPTO_rsa_public_key_dup (deposit->coin.denom_pub.rsa_public_key);
copy->coin.denom_sig.rsa_signature =
diff --git a/src/exchangedb/perf_taler_exchangedb_interpreter.c b/src/exchangedb/perf_taler_exchangedb_interpreter.c
index 8a81befdb..43891e55f 100644
--- a/src/exchangedb/perf_taler_exchangedb_interpreter.c
+++ b/src/exchangedb/perf_taler_exchangedb_interpreter.c
@@ -1243,19 +1243,18 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
unsigned int reserve_index;
int ret;
struct PERF_TALER_EXCHANGEDB_Reserve *reserve;
- json_t *sndr;
+ char *sndr;
uint32_t uid;
struct GNUNET_TIME_Absolute now;
reserve_index = state->cmd[state->i].details.insert_reserve.index_reserve;
reserve = state->cmd[reserve_index].exposed.data.reserve;
- sndr = json_pack ("{s:i}",
- "account",
- (int) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
- UINT32_MAX));
+ GNUNET_asprintf (&sndr,
+ "payto://x-taler-test/localhost:8080/%u",
+ (unsigned int) GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ UINT32_MAX));
uid = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
UINT32_MAX);
- GNUNET_assert (NULL != sndr);
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
ret = state->plugin->reserves_in_insert (state->plugin->cls,
@@ -1264,10 +1263,11 @@ interpret (struct PERF_TALER_EXCHANGEDB_interpreter_state *state)
&reserve->reserve.balance,
now,
sndr,
+ "account-1",
&uid,
sizeof (uid));
GNUNET_assert (GNUNET_SYSERR != ret);
- json_decref (sndr);
+ GNUNET_free (sndr);
}
break;
diff --git a/src/exchangedb/plugin_exchangedb_common.c b/src/exchangedb/plugin_exchangedb_common.c
index e4b832491..8344974b4 100644
--- a/src/exchangedb/plugin_exchangedb_common.c
+++ b/src/exchangedb/plugin_exchangedb_common.c
@@ -42,8 +42,7 @@ common_free_reserve_history (void *cls,
{
case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
bt = rh->details.bank;
- if (NULL != bt->sender_account_details)
- json_decref (bt->sender_account_details);
+ GNUNET_free_non_null (bt->sender_account_details);
GNUNET_free_non_null (bt->wire_reference);
GNUNET_free (bt);
break;
@@ -61,8 +60,7 @@ common_free_reserve_history (void *cls,
break;
case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
closing = rh->details.closing;
- if (NULL != closing->receiver_account_details)
- json_decref (closing->receiver_account_details);
+ GNUNET_free_non_null (closing->receiver_account_details);
GNUNET_free (closing);
break;
}
@@ -92,7 +90,7 @@ common_free_coin_transaction_list (void *cls,
switch (list->type)
{
case TALER_EXCHANGEDB_TT_DEPOSIT:
- json_decref (list->details.deposit->receiver_wire_account);
+ GNUNET_free_non_null (list->details.deposit->receiver_wire_account);
if (NULL != list->details.deposit->coin.denom_pub.rsa_public_key)
GNUNET_CRYPTO_rsa_public_key_free (list->details.deposit->coin.denom_pub.rsa_public_key);
if (NULL != list->details.deposit->coin.denom_sig.rsa_signature)
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 6c6330556..140bceb2e 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -127,6 +127,7 @@ postgres_drop_tables (void *cls)
PGconn *conn;
int ret;
+ /* FIXME: use GNUNET_PQ_connect_with_cfg instead? */
conn = GNUNET_PQ_connect (pc->connection_cfg_str);
if (NULL == conn)
return GNUNET_SYSERR;
@@ -218,12 +219,13 @@ postgres_create_tables (void *cls)
",credit_frac INT4 NOT NULL"
",credit_curr VARCHAR("TALER_CURRENCY_LEN_STR") NOT NULL"
",sender_account_details TEXT NOT NULL"
+ ",exchange_account_section TEXT NOT NULL"
",execution_date INT8 NOT NULL"
",PRIMARY KEY (reserve_pub, wire_reference)"
");"),
/* Create indices on reserves_in */
GNUNET_PQ_make_try_execute ("CREATE INDEX reserves_in_execution_index"
- " ON reserves_in (execution_date);"),
+ " ON reserves_in (exchange_account_section,execution_date);"),
/* This table contains the data for wire transfers the exchange has
executed to close a reserve. */
GNUNET_PQ_make_execute("CREATE TABLE IF NOT EXISTS reserves_close "
@@ -433,6 +435,7 @@ postgres_create_tables (void *cls)
PGconn *conn;
int ret;
+ /* FIXME: use GNUNET_PQ_connect_with_cfg instead? */
conn = GNUNET_PQ_connect (pc->connection_cfg_str);
if (NULL == conn)
return GNUNET_SYSERR;
@@ -585,21 +588,23 @@ postgres_prepare (PGconn *db_conn)
",credit_val"
",credit_frac"
",credit_curr"
+ ",exchange_account_section"
",sender_account_details"
",execution_date"
") VALUES "
- "($1, $2, $3, $4, $5, $6, $7) "
+ "($1, $2, $3, $4, $5, $6, $7, $8) "
"ON CONFLICT DO NOTHING;",
- 7),
+ 8),
/* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
transactions for reserves with serial id '\geq' the given parameter */
GNUNET_PQ_make_prepare ("reserves_in_get_latest_wire_reference",
"SELECT"
" wire_reference"
" FROM reserves_in"
+ " WHERE exchange_account_section=$1"
" ORDER BY reserve_in_serial_id DESC"
" LIMIT 1;",
- 0),
+ 1),
/* Used in postgres_select_reserves_in_above_serial_id() to obtain inbound
transactions for reserves with serial id '\geq' the given parameter */
GNUNET_PQ_make_prepare ("audit_reserves_in_get_transactions_incr",
@@ -1509,6 +1514,7 @@ postgres_get_session (void *cls)
return session;
}
}
+ /* FIXME: use GNUNET_PQ_connect_with_cfg instead? */
db_conn = GNUNET_PQ_connect (pc->connection_cfg_str);
if (NULL == db_conn)
return NULL;
@@ -1836,7 +1842,9 @@ reserves_update (void *cls,
* @param reserve_pub public key of the reserve
* @param balance the amount that has to be added to the reserve
* @param execution_time when was the amount added
- * @param sender_account_details account information for the sender
+ * @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
* @return transaction status code
@@ -1847,7 +1855,8 @@ postgres_reserves_in_insert (void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *balance,
struct GNUNET_TIME_Absolute execution_time,
- const json_t *sender_account_details,
+ const char *sender_account_details,
+ const char *exchange_account_section,
const void *wire_reference,
size_t wire_reference_size)
{
@@ -1900,7 +1909,7 @@ postgres_reserves_in_insert (void *cls,
as a foreign key. */
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
- TALER_PQ_query_param_json (sender_account_details),
+ GNUNET_PQ_query_param_string (sender_account_details),
TALER_PQ_query_param_amount (balance),
TALER_PQ_query_param_absolute_time (&expiry),
GNUNET_PQ_query_param_end
@@ -1929,7 +1938,8 @@ postgres_reserves_in_insert (void *cls,
GNUNET_PQ_query_param_fixed_size (wire_reference,
wire_reference_size),
TALER_PQ_query_param_amount (balance),
- TALER_PQ_query_param_json (sender_account_details),
+ GNUNET_PQ_query_param_string (exchange_account_section),
+ GNUNET_PQ_query_param_string (sender_account_details),
TALER_PQ_query_param_absolute_time (&execution_time),
GNUNET_PQ_query_param_end
};
@@ -1976,6 +1986,8 @@ postgres_reserves_in_insert (void *cls,
*
* @param cls the @e cls of this struct with the plugin-specific state
* @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
* @return transaction status code
@@ -1983,10 +1995,12 @@ postgres_reserves_in_insert (void *cls,
static enum GNUNET_DB_QueryStatus
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)
{
struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (exchange_account_name),
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
@@ -2222,8 +2236,8 @@ add_bank_to_exchange (void *cls,
&bt->amount),
TALER_PQ_result_spec_absolute_time ("execution_date",
&bt->execution_date),
- TALER_PQ_result_spec_json ("sender_account_details",
- &bt->sender_account_details),
+ GNUNET_PQ_result_spec_string ("sender_account_details",
+ &bt->sender_account_details),
GNUNET_PQ_result_spec_end
};
@@ -2389,8 +2403,8 @@ add_exchange_to_bank (void *cls,
&closing->closing_fee),
TALER_PQ_result_spec_absolute_time ("execution_date",
&closing->execution_date),
- TALER_PQ_result_spec_json ("receiver_account",
- &closing->receiver_account_details),
+ GNUNET_PQ_result_spec_string ("receiver_account",
+ &closing->receiver_account_details),
GNUNET_PQ_result_spec_auto_from_type ("wtid",
&closing->wtid),
GNUNET_PQ_result_spec_end
@@ -2710,7 +2724,7 @@ postgres_get_ready_deposit (void *cls,
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
&coin_pub),
TALER_PQ_result_spec_json ("wire",
- &wire),
+ &wire),
GNUNET_PQ_result_spec_end
};
enum GNUNET_DB_QueryStatus qs;
@@ -3811,7 +3825,7 @@ add_coin_deposit (void *cls,
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
&deposit->h_wire),
TALER_PQ_result_spec_json ("wire",
- &deposit->receiver_wire_account),
+ &deposit->receiver_wire_account),
GNUNET_PQ_result_spec_auto_from_type ("coin_sig",
&deposit->csig),
GNUNET_PQ_result_spec_end
@@ -4178,8 +4192,6 @@ handle_wt_result (void *cls,
struct TALER_Amount amount_with_fee;
struct TALER_Amount deposit_fee;
json_t *wire;
- json_t *t;
- const char *wire_method;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_uint64 ("aggregation_serial_id", &rowid),
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms", &h_contract_terms),
@@ -4202,25 +4214,11 @@ handle_wt_result (void *cls,
ctx->status = GNUNET_SYSERR;
return;
}
- t = json_object_get (wire, "type");
- if (NULL == t)
- {
- GNUNET_break (0);
- ctx->status = GNUNET_SYSERR;
- return;
- }
- wire_method = json_string_value (t);
- if (NULL == wire_method)
- {
- GNUNET_break (0);
- ctx->status = GNUNET_SYSERR;
- return;
- }
ctx->cb (ctx->cb_cls,
rowid,
&merchant_pub,
- wire_method,
&h_wire,
+ wire,
exec_time,
&h_contract_terms,
&coin_pub,
@@ -4580,14 +4578,14 @@ reserve_expired_cb (void *cls,
for (unsigned int i=0;i<num_results;i++)
{
struct GNUNET_TIME_Absolute exp_date;
- json_t *account_details;
+ char *account_details;
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_Amount remaining_balance;
struct GNUNET_PQ_ResultSpec rs[] = {
TALER_PQ_result_spec_absolute_time ("expiration_date",
&exp_date),
- TALER_PQ_result_spec_json ("account_details",
- &account_details),
+ GNUNET_PQ_result_spec_string ("account_details",
+ &account_details),
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
&reserve_pub),
TALER_PQ_result_spec_amount ("current_balance",
@@ -4674,7 +4672,7 @@ postgres_insert_reserve_closed (void *cls,
struct TALER_EXCHANGEDB_Session *session,
const struct TALER_ReservePublicKeyP *reserve_pub,
struct GNUNET_TIME_Absolute execution_date,
- const json_t *receiver_account,
+ const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee)
@@ -4684,7 +4682,7 @@ postgres_insert_reserve_closed (void *cls,
GNUNET_PQ_query_param_auto_from_type (reserve_pub),
TALER_PQ_query_param_absolute_time (&execution_date),
GNUNET_PQ_query_param_auto_from_type (wtid),
- TALER_PQ_query_param_json (receiver_account),
+ GNUNET_PQ_query_param_string (receiver_account),
TALER_PQ_query_param_amount (amount_with_fee),
TALER_PQ_query_param_amount (closing_fee),
GNUNET_PQ_query_param_end
@@ -4946,6 +4944,7 @@ postgres_gc (void *cls)
long_ago = GNUNET_TIME_absolute_subtract (now,
GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
10));
+ /* FIXME: use GNUNET_PQ_connect_with_cfg instead? */
conn = GNUNET_PQ_connect (pc->connection_cfg_str);
if (NULL == conn)
return GNUNET_SYSERR;
@@ -5421,7 +5420,7 @@ reserves_in_serial_helper_cb (void *cls,
{
struct TALER_ReservePublicKeyP reserve_pub;
struct TALER_Amount credit;
- json_t *sender_account_details;
+ char *sender_account_details;
struct GNUNET_TIME_Absolute execution_date;
uint64_t rowid;
void *wire_reference;
@@ -5436,8 +5435,8 @@ reserves_in_serial_helper_cb (void *cls,
&credit),
TALER_PQ_result_spec_absolute_time("execution_date",
&execution_date),
- TALER_PQ_result_spec_json ("sender_account_details",
- &sender_account_details),
+ GNUNET_PQ_result_spec_string ("sender_account_details",
+ &sender_account_details),
GNUNET_PQ_result_spec_uint64 ("reserve_in_serial_id",
&rowid),
GNUNET_PQ_result_spec_end
@@ -5943,7 +5942,7 @@ reserve_closed_serial_helper_cb (void *cls,
{
uint64_t rowid;
struct TALER_ReservePublicKeyP reserve_pub;
- json_t *receiver_account;
+ char *receiver_account;
struct TALER_WireTransferIdentifierRawP wtid;
struct TALER_Amount amount_with_fee;
struct TALER_Amount closing_fee;
@@ -5957,8 +5956,8 @@ reserve_closed_serial_helper_cb (void *cls,
&execution_date),
GNUNET_PQ_result_spec_auto_from_type ("wtid",
&wtid),
- TALER_PQ_result_spec_json ("receiver_account",
- &receiver_account),
+ GNUNET_PQ_result_spec_string ("receiver_account",
+ &receiver_account),
TALER_PQ_result_spec_amount ("amount",
&amount_with_fee),
TALER_PQ_result_spec_amount ("closing_fee",
@@ -6271,7 +6270,7 @@ missing_wire_cb (void *cls,
TALER_PQ_result_spec_amount ("amount_with_fee",
&amount),
TALER_PQ_result_spec_json ("wire",
- &wire),
+ &wire),
TALER_PQ_result_spec_absolute_time ("wire_deadline",
&deadline),
GNUNET_PQ_result_spec_auto_from_type ("tiny",
@@ -6380,12 +6379,12 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"exchangedb-postgres",
- "db_conn_str",
+ "CONFIG",
&pg->connection_cfg_str))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"exchangedb-postgres",
- "db_conn_str");
+ "CONFIG");
GNUNET_free (pg);
return NULL;
}
diff --git a/src/exchangedb/test-exchange-db-postgres.conf b/src/exchangedb/test-exchange-db-postgres.conf
index 926e2997e..d0afc535e 100644
--- a/src/exchangedb/test-exchange-db-postgres.conf
+++ b/src/exchangedb/test-exchange-db-postgres.conf
@@ -5,7 +5,7 @@ DB = postgres
[exchangedb-postgres]
#The connection string the plugin has to use for connecting to the database
-DB_CONN_STR = postgres:///talercheck
+CONFIG = postgres:///talercheck
[exchangedb]
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index 36f0cce4e..a112af248 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2017 GNUnet e.V.
+ Copyright (C) 2014-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
@@ -703,8 +703,8 @@ static void
cb_wt_never (void *cls,
uint64_t serial_id,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- const char *wire_method,
const struct GNUNET_HashCode *h_wire,
+ const json_t *wire,
struct GNUNET_TIME_Absolute exec_time,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -747,8 +747,8 @@ static void
cb_wt_check (void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- const char *wire_method,
const struct GNUNET_HashCode *h_wire,
+ const json_t *wire,
struct GNUNET_TIME_Absolute exec_time,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -759,8 +759,9 @@ cb_wt_check (void *cls,
GNUNET_assert (0 == memcmp (merchant_pub,
&merchant_pub_wt,
sizeof (struct TALER_MerchantPublicKeyP)));
- GNUNET_assert (0 == strcmp (wire_method,
- "SEPA"));
+ GNUNET_assert (0 == strcmp (json_string_value (json_object_get (wire,
+ "url")),
+ "payto://sepa/DE67830654080004822650"));
GNUNET_assert (0 == memcmp (h_wire,
&h_wire_wt,
sizeof (struct GNUNET_HashCode)));
@@ -842,8 +843,8 @@ deposit_cb (void *cls,
deposit_rowid = rowid;
if (NULL != wire)
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &h_wire));
+ TALER_JSON_wire_signature_hash (wire,
+ &h_wire));
if ( (0 != memcmp (merchant_pub,
&deposit->merchant_pub,
sizeof (struct TALER_MerchantPublicKeyP))) ||
@@ -960,7 +961,7 @@ audit_reserve_in_cb (void *cls,
uint64_t rowid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
- const json_t *sender_account_details,
+ const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
struct GNUNET_TIME_Absolute execution_date)
@@ -1156,8 +1157,6 @@ test_wire_fees (struct TALER_EXCHANGEDB_Session *session)
}
-static json_t *wire_out_account;
-
static struct TALER_Amount wire_out_amount;
@@ -1204,11 +1203,11 @@ test_wire_out (struct TALER_EXCHANGEDB_Session *session,
const struct TALER_EXCHANGEDB_Deposit *deposit)
{
auditor_row_cnt = 0;
- memset (&wire_out_wtid, 42, sizeof (wire_out_wtid));
+ memset (&wire_out_wtid,
+ 42,
+ sizeof (wire_out_wtid));
wire_out_date = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&wire_out_date);
- wire_out_account = json_loads ("{ \"account\":\"1\" }", 0, NULL);
- GNUNET_assert (NULL != wire_out_account);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1",
&wire_out_amount));
@@ -1262,13 +1261,25 @@ test_wire_out (struct TALER_EXCHANGEDB_Session *session,
/* Now let's fix the transient constraint violation by
putting in the WTID into the wire_out table */
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->store_wire_transfer_out (plugin->cls,
- session,
- wire_out_date,
- &wire_out_wtid,
- wire_out_account,
- &wire_out_amount));
+ {
+ json_t *wire_out_account;
+
+ wire_out_account = json_pack ("{s:s,s:s}",
+ "url", "payto://x-taler-bank/localhost:8080/1",
+ "salt", "this-is-my-salt");
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ plugin->store_wire_transfer_out (plugin->cls,
+ session,
+ wire_out_date,
+ &wire_out_wtid,
+ wire_out_account,
+ &wire_out_amount))
+ {
+ json_decref (wire_out_account);
+ FAILIF (1);
+ }
+ json_decref (wire_out_account);
+ }
/* And now the commit should still succeed! */
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->commit (plugin->cls,
@@ -1365,8 +1376,8 @@ wire_missing_cb (void *cls,
if (NULL != wire)
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &h_wire));
+ TALER_JSON_wire_signature_hash (wire,
+ &h_wire));
else
memset (&h_wire,
0,
@@ -1500,16 +1511,8 @@ run (void *cls)
struct TALER_EXCHANGEDB_TransactionList *tl;
struct TALER_EXCHANGEDB_TransactionList *tlp;
json_t *wire;
- json_t *sndr;
+ const char *sndr = "payto://x-taler-bank/localhost:8080/1";
unsigned int matched;
- const char * const json_wire_str =
- "{ \"type\":\"SEPA\", \
-\"IBAN\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"wire_transfer_deadline\":\"1449930207000\", \
-\"r\":123456789, \
-\"address\": \"foobar\"}";
unsigned int cnt;
void *rr;
size_t rr_size;
@@ -1518,9 +1521,11 @@ run (void *cls)
dkp = NULL;
rh = NULL;
- wire = NULL;
session = NULL;
deposit.coin.denom_sig.rsa_signature = NULL;
+ wire = json_pack ("{s:s, s:s}",
+ "url", "payto://sepa/DE67830654080004822650",
+ "salt", "this-is-a-salt-value");
ZR_BLK (&cbc);
ZR_BLK (&cbc2);
if (NULL ==
@@ -1576,11 +1581,10 @@ run (void *cls)
&amount_with_fee));
result = 4;
- sndr = json_loads ("{ \"account\":\"1\" }", 0, NULL);
- GNUNET_assert (NULL != sndr);
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
plugin->get_latest_reserve_in_reference (plugin->cls,
session,
+ "account-1",
&rr,
&rr_size));
now = GNUNET_TIME_absolute_get ();
@@ -1592,11 +1596,13 @@ run (void *cls)
&value,
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);
@@ -1617,23 +1623,25 @@ run (void *cls)
&value,
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);
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);
- json_decref (sndr);
FAILIF (GNUNET_OK !=
check_reserve (session,
&reserve_pub,
@@ -1731,7 +1739,6 @@ run (void *cls)
TALER_amount_add (&amount_with_fee,
&value,
&value));
- sndr = json_loads ("{ \"account\":\"1\" }", 0, NULL);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":0.000010",
&fee_closing));
@@ -1753,7 +1760,6 @@ run (void *cls)
0,
value.currency));
- json_decref (sndr);
result = 7;
qs = plugin->get_reserve_history (plugin->cls,
session,
@@ -1840,17 +1846,18 @@ run (void *cls)
FAILIF (3 != auditor_row_cnt);
/* Tests for deposits */
- memset (&deposit, 0, sizeof (deposit));
+ memset (&deposit,
+ 0,
+ sizeof (deposit));
RND_BLK (&deposit.coin.coin_pub);
deposit.coin.denom_pub = dkp->pub;
deposit.coin.denom_sig = cbc.sig;
RND_BLK (&deposit.csig);
RND_BLK (&deposit.merchant_pub);
RND_BLK (&deposit.h_contract_terms);
- wire = json_loads (json_wire_str, 0, NULL);
GNUNET_assert (GNUNET_OK ==
- TALER_JSON_hash (wire,
- &deposit.h_wire));
+ TALER_JSON_wire_signature_hash (wire,
+ &deposit.h_wire));
deposit.receiver_wire_account = wire;
deposit.amount_with_fee = value;
deposit.deposit_fee = fee_deposit;
@@ -1897,7 +1904,8 @@ run (void *cls)
session,
&deposit.h_wire,
&deposit.merchant_pub,
- &deposit_cb, &deposit,
+ &deposit_cb,
+ &deposit,
2));
sleep (2); /* giv deposit time to be ready */
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@@ -2179,8 +2187,9 @@ run (void *cls)
result = 0;
drop:
- if (NULL != wire)
- json_decref (wire);
+ if (0 != result)
+ plugin->rollback (plugin->cls,
+ session);
if (NULL != rh)
plugin->free_reserve_history (plugin->cls,
rh);
@@ -2196,6 +2205,7 @@ run (void *cls)
if (NULL != cbc2.sig.rsa_signature)
GNUNET_CRYPTO_rsa_signature_free (cbc2.sig.rsa_signature);
dkp = NULL;
+ json_decref (wire);
TALER_EXCHANGEDB_plugin_unload (plugin);
plugin = NULL;
}
diff --git a/src/include/taler_auditordb_plugin.h b/src/include/taler_auditordb_plugin.h
index 80974cca0..cc583e8e7 100644
--- a/src/include/taler_auditordb_plugin.h
+++ b/src/include/taler_auditordb_plugin.h
@@ -382,6 +382,7 @@ struct TALER_AUDITORDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @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
@@ -392,6 +393,7 @@ struct TALER_AUDITORDB_Plugin
(*insert_wire_auditor_progress)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
const struct TALER_AUDITORDB_WireProgressPoint *pp,
const void *in_wire_off,
const void *out_wire_off,
@@ -405,6 +407,7 @@ struct TALER_AUDITORDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @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
@@ -415,6 +418,7 @@ struct TALER_AUDITORDB_Plugin
(*update_wire_auditor_progress)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
const struct TALER_AUDITORDB_WireProgressPoint *pp,
const void *in_wire_off,
const void *out_wire_off,
@@ -428,6 +432,7 @@ struct TALER_AUDITORDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @param session connection to use
* @param master_pub master key of the exchange
+ * @param account_name name of the wire account we are auditing
* @param[out] pp set to where the auditor is 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
@@ -438,6 +443,7 @@ struct TALER_AUDITORDB_Plugin
(*get_wire_auditor_progress)(void *cls,
struct TALER_AUDITORDB_Session *session,
const struct TALER_MasterPublicKeyP *master_pub,
+ const char *account_name,
struct TALER_AUDITORDB_WireProgressPoint *pp,
void **in_wire_off,
void **out_wire_off,
diff --git a/src/include/taler_bank_service.h b/src/include/taler_bank_service.h
index bfa050336..1cad5710a 100644
--- a/src/include/taler_bank_service.h
+++ b/src/include/taler_bank_service.h
@@ -217,9 +217,9 @@ struct TALER_BANK_TransferDetails
char *wire_transfer_subject;
/**
- * The other account that was involved
+ * payto://-URL of the other account that was involved
*/
- json_t *account_details;
+ char *account_url;
};
@@ -347,4 +347,29 @@ void
TALER_BANK_reject_cancel (struct TALER_BANK_RejectHandle *rh);
+/**
+ * Convenience method for parsing configuration section with bank
+ * authentication data. The section must contain an option
+ * "METHOD", plus other options that depend on the METHOD specified.
+ *
+ * @param cfg configuration to parse
+ * @param section the section with the configuration data
+ * @param auth[out] set to the configuration data found
+ * @return #GNUNET_OK on success
+ */
+int
+TALER_BANK_auth_parse_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const char *section,
+ struct TALER_BANK_AuthenticationData *auth);
+
+
+/**
+ * Free memory inside of @a auth (but not auth itself).
+ * Dual to #TALER_BANK_auth_parse_cfg().
+ *
+ * @param auth authentication data to free
+ */
+void
+TALER_BANK_auth_free (struct TALER_BANK_AuthenticationData *auth);
+
#endif /* _TALER_BANK_SERVICE_H */
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index d45e7bb28..b22c55ce3 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2017 Taler Systems SA
+ Copyright (C) 2014-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
@@ -730,4 +730,51 @@ TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
const struct TALER_Amount *amount_with_fee);
+/* **************** /wire account offline signing **************** */
+
+
+/**
+ * Compute the hash of the given wire details. The resulting
+ * hash is what is put into the contract.
+ *
+ * @param payto_url bank account
+ * @param salt salt used to eliminate brute-force inversion
+ * @param hc[out] set to the hash
+ */
+void
+TALER_wire_signature_hash (const char *payto_url,
+ const char *salt,
+ struct GNUNET_HashCode *hc);
+
+/**
+ * Check the signature in @a wire_s.
+ *
+ * @param payto_url URL that is signed
+ * @param salt the salt used to salt the @a payto_url when hashing
+ * @param master_pub master public key of the exchange
+ * @param master_sig signature of the exchange
+ * @return #GNUNET_OK if signature is valid
+ */
+int
+TALER_wire_signature_check (const char *payto_url,
+ const char *salt,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const struct TALER_MasterSignatureP *master_sig);
+
+
+/**
+ * Create a signed wire statement for the given account.
+ *
+ * @param payto_url account specification
+ * @param salt the salt used to salt the @a payto_url when hashing
+ * @param master_priv private key to sign with
+ * @param master_sig[out] where to write the signature
+ */
+void
+TALER_wire_signature_make (const char *payto_url,
+ const char *salt,
+ const struct TALER_MasterPrivateKeyP *master_priv,
+ struct TALER_MasterSignatureP *master_sig);
+
+
#endif
diff --git a/src/include/taler_error_codes.h b/src/include/taler_error_codes.h
index 1a20889d8..dbde04df1 100644
--- a/src/include/taler_error_codes.h
+++ b/src/include/taler_error_codes.h
@@ -165,7 +165,15 @@ enum TALER_ErrorCode
*/
TALER_EC_INTERNAL_LOGIC_ERROR = 1011,
+ /**
+ * The method specified in a payto:// URL is not one we expected.
+ */
+ TALER_EC_PAYTO_WRONG_METHOD = 1012,
+ /**
+ * The PAYTO URL is malformed.
+ */
+ TALER_EC_PAYTO_MALFORMED = 1013,
/* ********** request-specific error codes ************* */
@@ -1535,6 +1543,20 @@ enum TALER_ErrorCode
*/
TALER_EC_TEST_RSA_SIGN_ERROR = 4005,
+
+ /**
+ * The JSON in the server's response was malformed. This response
+ * is provided with HTTP status code of 0.
+ */
+ TALER_EC_SERVER_JSON_INVALID = 5000,
+
+ /**
+ * A signature in the server's response was malformed. This response
+ * is provided with HTTP status code of 0.
+ */
+ TALER_EC_SERVER_SIGNATURE_INVALID = 5001,
+
+
/* *************** Taler BANK/FAKEBANK error codes *************** */
/**
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index 30ea4ce66..22ca049eb 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -472,40 +472,32 @@ struct TALER_EXCHANGE_WireAggregateFees
/**
- * Function called with information about the wire fees
- * for each wire method.
- *
- * @param cls closure
- * @param wire_method name of the wire method (i.e. "sepa")
- * @param fees fee structure for this method
+ * Information about a wire account of the exchange.
*/
-typedef void
-(*TALER_EXCHANGE_WireFeeCallback)(void *cls,
- const char *wire_method,
- const struct TALER_EXCHANGE_WireAggregateFees *fees);
+struct TALER_EXCHANGE_WireAccount
+{
+ /**
+ * payto://-URL of the exchange.
+ */
+ const char *url;
+ /**
+ * Salt used to generate @e master_sig.
+ */
+ const char *salt;
-/**
- * Obtain information about wire fees encoded in @a obj
- * by wire method.
- *
- * @param master_pub public key to use to verify signatures, NULL to not verify
- * @param obj wire information as encoded in the #TALER_EXCHANGE_WireResultCallback
- * @param cb callback to invoke for the fees
- * @param cb_cls closure for @a cb
- * @return #GNUNET_OK in success, #GNUNET_SYSERR if @a obj is ill-formed
- */
-int
-TALER_EXCHANGE_wire_get_fees (const struct TALER_MasterPublicKeyP *master_pub,
- const json_t *obj,
- TALER_EXCHANGE_WireFeeCallback cb,
- void *cb_cls);
+ /**
+ * Signature of the exchange over the account (was checked by the API).
+ */
+ struct TALER_MasterSignatureP master_sig;
+ /**
+ * Linked list of wire fees the exchange charges for
+ * accounts of the wire method matching @e url.
+ */
+ const struct TALER_EXCHANGE_WireAggregateFees *fees;
-/**
- * @brief A Wire format inquiry handle
- */
-struct TALER_EXCHANGE_WireHandle;
+};
/**
@@ -519,15 +511,21 @@ struct TALER_EXCHANGE_WireHandle;
* @param http_status HTTP response code, #MHD_HTTP_OK (200) for successful request;
* 0 if the exchange's reply is bogus (fails to follow the protocol)
* @param ec taler-specific error code, #TALER_EC_NONE on success
- * @param obj the received JSON reply, if successful this should be the wire
- * format details as provided by /wire, or NULL if the
- * reply was not in JSON format.
+ * @param accounts_len length of the @a accounts array
+ * @param accounts list of wire accounts of the exchange, NULL on error
*/
typedef void
(*TALER_EXCHANGE_WireResultCallback) (void *cls,
unsigned int http_status,
enum TALER_ErrorCode ec,
- const json_t *obj);
+ unsigned int accounts_len,
+ const struct TALER_EXCHANGE_WireAccount *accounts);
+
+
+/**
+ * @brief A Wire format inquiry handle
+ */
+struct TALER_EXCHANGE_WireHandle;
/**
@@ -843,9 +841,9 @@ struct TALER_EXCHANGE_ReserveHistory
*/
struct {
/**
- * Sender account information for the incoming transfer.
+ * Sender account payto://-URL of the incoming transfer.
*/
- json_t *sender_account_details;
+ char *sender_url;
/**
* Information that uniquely identifies the wire transfer.
diff --git a/src/include/taler_exchangedb_lib.h b/src/include/taler_exchangedb_lib.h
index e4284c27f..b89dd087d 100644
--- a/src/include/taler_exchangedb_lib.h
+++ b/src/include/taler_exchangedb_lib.h
@@ -406,4 +406,72 @@ TALER_EXCHANGEDB_fees_write (const char *filename,
void
TALER_EXCHANGEDB_fees_free (struct TALER_EXCHANGEDB_AggregateFees *af);
+
+/**
+ * Information about an account from the configuration.
+ */
+struct TALER_EXCHANGEDB_AccountInfo
+{
+ /**
+ * Section in the configuration file that specifies the
+ * account. Must start with "account-".
+ */
+ const char *section_name;
+
+ /**
+ * Name of the wire plugin that should be used to access
+ * the account.
+ */
+ const char *plugin_name;
+
+ /**
+ * payto://-URL of the account.
+ */
+ const char *payto_url;
+
+ /**
+ * Filename containing the signed /wire response, or NULL
+ * if not given.
+ */
+ const char *wire_response_filename;
+
+ /**
+ * #GNUNET_YES if this account is enabed to be debited
+ * by the taler-exchange-aggregator.
+ */
+ int debit_enabled;
+
+ /**
+ * #GNUNET_YES if this account is enabed to be credited by wallets
+ * and needs to be watched by the taler-exchange-wirewatch.
+ * Also, the account will only be included in /wire if credit
+ * is enabled.
+ */
+ int credit_enabled;
+};
+
+
+/**
+ * Function called with information about a wire account.
+ *
+ * @param cls closure
+ * @param ai account information
+ */
+typedef void
+(*TALER_EXCHANGEDB_AccountCallback)(void *cls,
+ const struct TALER_EXCHANGEDB_AccountInfo *ai);
+
+/**
+ * Parse the configuration to find account information.
+ *
+ * @param cfg configuration to use
+ * @param cb callback to invoke
+ * @param cb_cls closure for @a cb
+ */
+void
+TALER_EXCHANGEDB_find_accounts (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ TALER_EXCHANGEDB_AccountCallback cb,
+ void *cb_cls);
+
+
#endif
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 33677559a..0d6f9cd90 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -21,7 +21,6 @@
*/
#ifndef TALER_EXCHANGEDB_PLUGIN_H
#define TALER_EXCHANGEDB_PLUGIN_H
-
#include <jansson.h>
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_db_lib.h>
@@ -52,9 +51,10 @@ struct TALER_EXCHANGEDB_BankTransfer
struct GNUNET_TIME_Absolute execution_date;
/**
- * Detailed wire information about the sending account.
+ * Detailed wire information about the sending account
+ * in "payto://" format.
*/
- json_t *sender_account_details;
+ char *sender_account_details;
/**
* Data uniquely identifying the wire transfer (wire transfer-type specific)
@@ -97,9 +97,10 @@ struct TALER_EXCHANGEDB_ClosingTransfer
struct GNUNET_TIME_Absolute execution_date;
/**
- * Detailed wire information about the receiving account.
+ * Detailed wire information about the receiving account
+ * in payto://-format.
*/
- json_t *receiver_account_details;
+ char *receiver_account_details;
/**
* Detailed wire transfer information that uniquely identifies the
@@ -361,6 +362,7 @@ struct TALER_EXCHANGEDB_Deposit
/**
* Detailed information about the receiver for executing the transaction.
+ * Includes URL in payto://-format and salt.
*/
json_t *receiver_wire_account;
@@ -638,7 +640,8 @@ struct TALER_EXCHANGEDB_Session;
* @param h_contract_terms hash of the proposal data known to merchant and customer
* @param wire_deadline by which the merchant adviced that he would like the
* wire transfer to be executed
- * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits()
+ * @param receiver_wire_account wire details for the merchant, includes
+ * 'url' in payto://-format; NULL from iterate_matching_deposits()
* @return transaction status code, #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT to continue to iterate
*/
typedef enum GNUNET_DB_QueryStatus
@@ -687,7 +690,8 @@ typedef void
* to get a refund
* @param wire_deadline by which the merchant adviced that he would like the
* wire transfer to be executed
- * @param receiver_wire_account wire details for the merchant, NULL from iterate_matching_deposits()
+ * @param receiver_wire_account wire details for the merchant including 'url' in payto://-format;
+ * NULL from iterate_matching_deposits()
* @param done flag set if the deposit was already executed (or not)
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@@ -837,7 +841,7 @@ typedef int
* @param rowid unique serial ID for the refresh session in our DB
* @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 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 execution_date when did we receive the funds
@@ -848,7 +852,7 @@ typedef int
uint64_t rowid,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *credit,
- const json_t *sender_account_details,
+ const char *sender_account_details,
const void *wire_reference,
size_t wire_reference_size,
struct GNUNET_TIME_Absolute execution_date);
@@ -923,8 +927,8 @@ typedef void
* @param cls closure
* @param rowid which row in the table is the information from (for diagnostics)
* @param merchant_pub public key of the merchant (should be same for all callbacks with the same @e cls)
- * @param wire_method which wire plugin was used for the transfer?
* @param h_wire hash of wire transfer details of the merchant (should be same for all callbacks with the same @e cls)
+ * @param account_details which account did the transfer go to?
* @param exec_time execution time of the wire transfer (should be same for all callbacks with the same @e cls)
* @param h_contract_terms which proposal was this payment about
* @param coin_pub which public key was this payment about
@@ -935,8 +939,8 @@ typedef void
(*TALER_EXCHANGEDB_WireTransferDataCallback)(void *cls,
uint64_t rowid,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- const char *wire_method,
const struct GNUNET_HashCode *h_wire,
+ const json_t *account_details,
struct GNUNET_TIME_Absolute exec_time,
const struct GNUNET_HashCode *h_contract_terms,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@@ -952,7 +956,7 @@ typedef void
* @param rowid identifier of the respective row in the database
* @param date timestamp of the wire transfer (roughly)
* @param wtid wire transfer subject
- * @param wire wire transfer details of the receiver
+ * @param wire wire transfer details of the receiver, including "url" in payto://-format
* @param amount amount that was wired
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
@@ -1019,7 +1023,7 @@ typedef int
* @param amount_with_fee how much did we debit the reserve
* @param closing_fee how much did we charge for closing the reserve
* @param reserve_pub public key of the reserve
- * @param receiver_account where did we send the funds
+ * @param receiver_account where did we send the funds, in payto://-format
* @param wtid identifier used for the wire transfer
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
@@ -1030,7 +1034,7 @@ typedef int
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee,
const struct TALER_ReservePublicKeyP *reserve_pub,
- const json_t *receiver_account,
+ const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid);
@@ -1040,7 +1044,7 @@ typedef int
* @param cls closure
* @param reserve_pub public key of the reserve
* @param left amount left in the reserve
- * @param account_details information about the reserve's bank account
+ * @param account_details information about the reserve's bank account, in payto://-format
* @param expiration_date when did the reserve expire
* @return transaction status code to pass on
*/
@@ -1048,7 +1052,7 @@ typedef enum GNUNET_DB_QueryStatus
(*TALER_EXCHANGEDB_ReserveExpiredCallback)(void *cls,
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *left,
- const json_t *account_details,
+ const char *account_details,
struct GNUNET_TIME_Absolute expiration_date);
@@ -1082,7 +1086,7 @@ typedef void
* @param rowid deposit table row of the coin's deposit
* @param coin_pub public key of the coin
* @param amount value of the deposit, including fee
- * @param wire where should the funds be wired
+ * @param wire where should the funds be wired, including 'url' in payto://-format
* @param deadline what was the requested wire transfer deadline
* @param tiny did the exchange defer this transfer because it is too small?
* @param done did the exchange claim that it made a transfer?
@@ -1259,7 +1263,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param reserve_pub public key of the reserve
* @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
+ * @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
* @return transaction status code
@@ -1270,7 +1274,8 @@ struct TALER_EXCHANGEDB_Plugin
const struct TALER_ReservePublicKeyP *reserve_pub,
const struct TALER_Amount *balance,
struct GNUNET_TIME_Absolute execution_time,
- const json_t *sender_account_details,
+ const char *sender_account_details,
+ const char *exchange_account_name,
const void *wire_reference,
size_t wire_reference_size);
@@ -1287,6 +1292,7 @@ struct TALER_EXCHANGEDB_Plugin
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);
@@ -1781,7 +1787,7 @@ struct TALER_EXCHANGEDB_Plugin
* @param session database connection
* @param reserve_pub which reserve is this about?
* @param execution_date when did we perform the transfer?
- * @param receiver_account to which account do we transfer?
+ * @param receiver_account to which account do we transfer, in payto://-format
* @param wtid identifier for the wire transfer
* @param amount_with_fee amount we charged to the reserve
* @param closing_fee how high is the closing fee
@@ -1792,7 +1798,7 @@ struct TALER_EXCHANGEDB_Plugin
struct TALER_EXCHANGEDB_Session *session,
const struct TALER_ReservePublicKeyP *reserve_pub,
struct GNUNET_TIME_Absolute execution_date,
- const json_t *receiver_account,
+ const char *receiver_account,
const struct TALER_WireTransferIdentifierRawP *wtid,
const struct TALER_Amount *amount_with_fee,
const struct TALER_Amount *closing_fee);
@@ -1869,7 +1875,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param session database connection
* @param date time of the wire transfer
* @param wtid subject of the wire transfer
- * @param wire_account details about the receiver account of the wire transfer
+ * @param wire_account details about the receiver account of the wire transfer,
+ * including 'url' in payto://-format
* @param amount amount that was transmitted
* @return transaction status code
*/
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index 6d019ecca..0504ddfb8 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -126,6 +126,65 @@ enum TALER_ErrorCode
TALER_JSON_get_error_code (const json_t *json);
+/* **************** /wire account offline signing **************** */
+
+/**
+ * Compute the hash of the given wire details. The resulting
+ * hash is what is put into the contract.
+ *
+ * @param wire_s wire details to hash
+ * @param hc[out] set to the hash
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if @a wire_s is malformed
+ */
+int
+TALER_JSON_wire_signature_hash (const json_t *wire_s,
+ struct GNUNET_HashCode *hc);
+
+/**
+ * Check the signature in @a wire_s.
+ *
+ * @param wire_s signed wire information of an exchange
+ * @param master_pub master public key of the exchange
+ * @return #GNUNET_OK if signature is valid
+ */
+int
+TALER_JSON_wire_signature_check (const json_t *wire_s,
+ const struct TALER_MasterPublicKeyP *master_pub);
+
+
+/**
+ * Create a signed wire statement for the given account.
+ *
+ * @param payto_url account specification
+ * @param master_priv private key to sign with, NULL to not sign
+ */
+json_t *
+TALER_JSON_wire_signature_make (const char *payto_url,
+ const struct TALER_MasterPrivateKeyP *master_priv);
+
+
+/**
+ * Obtain the wire method associated with the given
+ * wire account details. @a wire_s must contain a payto://-URL
+ * under 'url'.
+ *
+ * @return NULL on error
+ */
+char *
+TALER_JSON_wire_to_method (const json_t *wire_s);
+
+
+/**
+ * Obtain the payto://-URL associated with the given
+ * wire account details. @a wire_s must contain a payto://-URL
+ * under 'url'.
+ *
+ * @return NULL on error
+ */
+char *
+TALER_JSON_wire_to_payto (const json_t *wire_s);
+
+
#endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.h */
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index c281d21fd..f1148beb8 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -62,18 +62,6 @@
#define TALER_SIGNATURE_MASTER_DENOMINATION_KEY_VALIDITY 1025
/**
- * Signature where the Exchange confirms its SEPA details in
- * the /wire response.
- */
-#define TALER_SIGNATURE_MASTER_SEPA_DETAILS 1026
-
-/**
- * Signature where the Exchange confirms its TEST details in
- * the /wire response.
- */
-#define TALER_SIGNATURE_MASTER_TEST_DETAILS 1027
-
-/**
* Fees charged per (aggregate) wire transfer to the merchant.
*/
#define TALER_SIGNATURE_MASTER_WIRE_FEES 1028
@@ -83,6 +71,12 @@
*/
#define TALER_SIGNATURE_MASTER_DENOMINATION_KEY_REVOKED 1029
+/**
+ * Signature where the Exchange confirms its SEPA details in
+ * the /wire response.
+ */
+#define TALER_SIGNATURE_MASTER_WIRE_DETAILS 1030
+
/*********************************************/
/* Exchange online signatures (with signing key) */
/*********************************************/
@@ -891,16 +885,15 @@ struct TALER_MasterWireDetailsPS
{
/**
- * Purpose is #TALER_SIGNATURE_MASTER_SEPA_DETAILS or
- * #TALER_SIGNATURE_MASTER_TEST_DETAILS.
+ * Purpose is #TALER_SIGNATURE_MASTER_WIRE_DETAILS.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/**
- * Hash over the account holder's name, IBAN and BIC
- * code (all as 0-terminated strings).
+ * Hash over the account holder's payto:// URL and
+ * the salt, as done by #TALER_wire_signature_hash().
*/
- struct GNUNET_HashCode h_sepa_details GNUNET_PACKED;
+ struct GNUNET_HashCode h_wire_details GNUNET_PACKED;
};
diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h
index 3914208f1..dce92ceae 100644
--- a/src/include/taler_testing_lib.h
+++ b/src/include/taler_testing_lib.h
@@ -66,20 +66,22 @@
#define TALER_TESTING_MAKE_TRAIT_ROW_ID(data) \
TALER_TESTING_make_trait_uint64 (3, data)
+
/**
- * Allocate and return a piece of wire-details. Mostly, it adds
- * the bank_url to the JSON.
+ * Allocate and return a piece of wire-details. Combines
+ * the @a account_no and the @a bank_url to a
+ * @a payto://-URL and adds some salt to create the JSON.
*
- * @param template the wire-details template.
+ * @param account_no account number
* @param bank_url the bank_url
- *
- * @return the filled out and stringified wire-details. To
- * be manually free'd.
+ * @return JSON describing the account, including the
+ * payto://-URL of the account, must be manually decref'd
*/
-char *
-TALER_TESTING_make_wire_details (const char *template,
+json_t *
+TALER_TESTING_make_wire_details (unsigned long long account_no,
const char *bank_url);
+
/**
* Find denomination key matching the given amount.
*
@@ -130,10 +132,12 @@ TALER_TESTING_url_port_free (const char *url);
* If everything is OK, return the configured URL of the fakebank.
*
* @param config_filename configuration file to use
+ * @param config_section which account to use (must match x-taler-bank)
* @return NULL on error, fakebank URL otherwise
*/
char *
-TALER_TESTING_prepare_fakebank (const char *config_filename);
+TALER_TESTING_prepare_fakebank (const char *config_filename,
+ const char *config_section);
/* ******************* Generic interpreter logic ************ */
@@ -613,8 +617,8 @@ TALER_TESTING_cmd_status (const char *label,
* coins, this parameter selects which one in that array
* This value is currently ignored, as only one-coin
* withdrawals are implemented.
- * @param wire_details bank details of the merchant performing the
- * deposit
+ * @param wire_details JSON including payto://-URL of the merchant performing the
+ * deposit, reference is captured by this command
* @param contract_terms contract terms to be signed over by the
* coin
* @param refund_deadline refund deadline
@@ -625,12 +629,12 @@ TALER_TESTING_cmd_status (const char *label,
* @return the deposit command to be run by the interpreter
*/
struct TALER_TESTING_Command
-TALER_TESTING_cmd_deposit
+TALER_TESTING_cmd_deposit
(const char *label,
struct TALER_EXCHANGE_Handle *exchange,
const char *coin_reference,
unsigned int coin_index,
- char *wire_details,
+ json_t *wire_details,
const char *contract_terms,
struct GNUNET_TIME_Relative refund_deadline,
const char *amount,
@@ -1209,7 +1213,7 @@ int
TALER_TESTING_get_trait_wire_details
(const struct TALER_TESTING_Command *cmd,
unsigned int index,
- const char **wire_details);
+ const json_t **wire_details);
/**
@@ -1223,7 +1227,7 @@ TALER_TESTING_get_trait_wire_details
struct TALER_TESTING_Trait
TALER_TESTING_make_trait_wire_details
(unsigned int index,
- const char *wire_details);
+ const json_t *wire_details);
/**
* Obtain a private key from a "peer". Used e.g. to obtain
@@ -1300,11 +1304,11 @@ TALER_TESTING_get_trait_transfer_subject
/**
- * Offer wire details in a trait.
+ * Offer wire wire transfer subject in a trait.
*
* @param index always (?) zero, as one command sticks
* to one bank account
- * @param wire_details wire details to offer
+ * @param transfer_subject wire transfer subject to offer
* @return the trait, to be put in the traits array of the command
*/
struct TALER_TESTING_Trait
diff --git a/src/include/taler_wire_lib.h b/src/include/taler_wire_lib.h
index 68c36e889..0cf38d6d1 100644
--- a/src/include/taler_wire_lib.h
+++ b/src/include/taler_wire_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ Copyright (C) 2016,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
@@ -26,6 +26,16 @@
/**
+ * Obtain the payment method from a @a payto_url
+ *
+ * @param payto_url the URL to parse
+ * @return NULL on error (malformed @a payto_url)
+ */
+char *
+TALER_WIRE_payto_get_method (const char *payto_url);
+
+
+/**
* Load a WIRE plugin.
*
* @param cfg configuration to use
@@ -45,28 +55,4 @@ 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/include/taler_wire_plugin.h b/src/include/taler_wire_plugin.h
index c0e29609f..2758d2d2e 100644
--- a/src/include/taler_wire_plugin.h
+++ b/src/include/taler_wire_plugin.h
@@ -22,7 +22,6 @@
#define TALER_WIRE_PLUGIN_H
#include <gnunet/gnunet_util_lib.h>
-#include <jansson.h>
#include "taler_util.h"
#include "taler_error_codes.h"
#include "taler_bank_service.h" /* for `enum TALER_BANK_Direction` and `struct TALER_BANK_TransferDetails` */
@@ -72,9 +71,9 @@ struct TALER_WIRE_TransferDetails
char *wtid_s;
/**
- * The other account that was involved
+ * payto://-URL of the other account that was involved
*/
- json_t *account_details;
+ char *account_url;
};
@@ -161,6 +160,13 @@ struct TALER_WIRE_Plugin
char *library_name;
/**
+ * Which wire method (payto://METHOD/") is supported by this plugin?
+ * For example, "sepa" or "x-taler-bank".
+ */
+ 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
* payment, but SEPA only supports 0.01 EUR. This function would
@@ -177,62 +183,27 @@ struct TALER_WIRE_Plugin
/**
- * Obtain wire transfer details in the plugin-specific format
- * from the configuration.
- *
- * @param cls closure
- * @param cfg configuration with details about wire accounts
- * @param account_name which section in the configuration should we parse
- * @return NULL if @a cfg fails to have valid wire details for @a account_name
- */
- json_t *
- (*get_wire_details)(void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *account_name);
-
-
- /**
- * Sign wire transfer details in the plugin-specific format.
- *
- * @param cls closure
- * @param in wire transfer details in JSON format
- * @param key private signing key to use
- * @param salt salt to add
- * @param[out] sig where to write the signature
- * @return #GNUNET_OK on success
- */
- int
- (*sign_wire_details)(void *cls,
- const json_t *in,
- const struct TALER_MasterPrivateKeyP *key,
- const struct GNUNET_HashCode *salt,
- struct TALER_MasterSignatureP *sig);
-
-
- /**
- * Check if the given wire format JSON object is correctly formatted
+ * 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 wire the JSON wire format object
- * @param master_pub public key of the exchange to verify against
- * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
- * error message must be freed by the caller using GNUNET_free()
+ * @param account_url the payto:// URL
* @return #TALER_EC_NONE if correctly formatted
*/
enum TALER_ErrorCode
(*wire_validate) (void *cls,
- const json_t *wire,
- const struct TALER_MasterPublicKeyP *master_pub,
- char **emsg);
+ const char *account_url);
/**
* Prepare for exeuction of a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
- * @param wire valid wire account information
+ * @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 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
@@ -240,13 +211,15 @@ struct TALER_WIRE_Plugin
*/
struct TALER_WIRE_PrepareHandle *
(*prepare_wire_transfer) (void *cls,
- const json_t *wire,
+ 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.
@@ -305,6 +278,8 @@ struct TALER_WIRE_Plugin
* (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
@@ -316,6 +291,7 @@ struct TALER_WIRE_Plugin
*/
struct TALER_WIRE_HistoryHandle *
(*get_history) (void *cls,
+ const char *account_section,
enum TALER_BANK_Direction direction,
const void *start_off,
size_t start_off_len,
@@ -323,6 +299,7 @@ struct TALER_WIRE_Plugin
TALER_WIRE_HistoryResultCallback hres_cb,
void *hres_cb_cls);
+
/**
* Cancel going over the account's history.
*
@@ -345,6 +322,8 @@ struct TALER_WIRE_Plugin
* 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
@@ -353,11 +332,13 @@ struct TALER_WIRE_Plugin
*/
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);
+
/**
* Cancel ongoing reject operation. Note that the rejection may still
* proceed. Basically, if this function is called, the rejection may
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index d26f731ac..4b40e94b4 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -11,12 +11,14 @@ lib_LTLIBRARIES = \
libtalerjson_la_SOURCES = \
json.c \
- json_helper.c
+ json_helper.c \
+ json_wire.c
libtalerjson_la_LDFLAGS = \
-version-info 1:0:1 \
-export-dynamic -no-undefined
libtalerjson_la_LIBADD = \
-lgnunetjson \
+ $(top_builddir)/src/wire/libtalerwire.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil \
-ljansson \
diff --git a/src/json/json_wire.c b/src/json/json_wire.c
new file mode 100644
index 000000000..f0bd17578
--- /dev/null
+++ b/src/json/json_wire.c
@@ -0,0 +1,193 @@
+/*
+ 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 json/json_wire.c
+ * @brief helper functions to generate or check /wire replies
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include "taler_util.h"
+#include "taler_json_lib.h"
+#include "taler_wire_lib.h"
+
+
+/**
+ * Compute the hash of the given wire details. The resulting
+ * hash is what is put into the contract.
+ *
+ * @param wire_s wire details to hash
+ * @param hc[out] set to the hash
+ * @return #GNUNET_OK on success, #GNUNET_SYSERR if @a wire_s is malformed
+ */
+int
+TALER_JSON_wire_signature_hash (const json_t *wire_s,
+ struct GNUNET_HashCode *hc)
+{
+ const char *payto_url;
+ const char *salt;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("url", &payto_url),
+ GNUNET_JSON_spec_string ("salt", &salt),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (wire_s,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ TALER_wire_signature_hash (payto_url,
+ salt,
+ hc);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Check the signature in @a wire_s.
+ *
+ * @param wire_s signed wire information of an exchange
+ * @param master_pub master public key of the exchange
+ * @return #GNUNET_OK if signature is valid
+ */
+int
+TALER_JSON_wire_signature_check (const json_t *wire_s,
+ const struct TALER_MasterPublicKeyP *master_pub)
+{
+ const char *payto_url;
+ const char *salt;
+ struct TALER_MasterSignatureP master_sig;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("url", &payto_url),
+ GNUNET_JSON_spec_string ("salt", &salt),
+ GNUNET_JSON_spec_fixed_auto ("master_sig", &master_sig),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (wire_s,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ return TALER_wire_signature_check (payto_url,
+ salt,
+ master_pub,
+ &master_sig);
+}
+
+
+/**
+ * Create a signed wire statement for the given account.
+ *
+ * @param payto_url account specification
+ * @param master_priv private key to sign with, NULL to not sign
+ */
+json_t *
+TALER_JSON_wire_signature_make (const char *payto_url,
+ const struct TALER_MasterPrivateKeyP *master_priv)
+{
+ struct TALER_MasterSignatureP master_sig;
+ struct GNUNET_HashCode salt;
+ char *salt_str;
+ json_t *ret;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &salt,
+ sizeof (salt));
+ salt_str = GNUNET_STRINGS_data_to_string_alloc (&salt,
+ sizeof (salt));
+ if (NULL != master_priv)
+ {
+ TALER_wire_signature_make (payto_url,
+ salt_str,
+ master_priv,
+ &master_sig);
+ ret = json_pack ("{s:s, s:s, s:o}",
+ "url", payto_url,
+ "salt", salt_str,
+ "master_sig", GNUNET_JSON_from_data_auto (&master_sig));
+ }
+ else
+ {
+ ret = json_pack ("{s:s, s:s}",
+ "url", payto_url,
+ "salt", salt_str);
+ }
+ GNUNET_free (salt_str);
+ return ret;
+}
+
+
+/**
+ * Obtain the wire method associated with the given
+ * wire account details. @a wire_s must contain a payto://-URL
+ * under 'url'.
+ *
+ * @return NULL on error
+ */
+char *
+TALER_JSON_wire_to_payto (const json_t *wire_s)
+{
+ json_t *payto_o;
+ const char *payto_str;
+
+ payto_o = json_object_get (wire_s,
+ "url");
+ if ( (NULL == payto_o) ||
+ (NULL == (payto_str = json_string_value (payto_o))) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed wire record encountered: lacks payto://-url\n");
+ return NULL;
+ }
+ return GNUNET_strdup (payto_str);
+}
+
+
+/**
+ * Obtain the wire method associated with the given
+ * wire account details. @a wire_s must contain a payto://-URL
+ * under 'url'.
+ *
+ * @return NULL on error
+ */
+char *
+TALER_JSON_wire_to_method (const json_t *wire_s)
+{
+ json_t *payto_o;
+ const char *payto_str;
+
+ payto_o = json_object_get (wire_s,
+ "url");
+ if ( (NULL == payto_o) ||
+ (NULL == (payto_str = json_string_value (payto_o))) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fatally malformed wire record encountered: lacks payto://-url\n");
+ return NULL;
+ }
+ return TALER_WIRE_payto_get_method (payto_str);
+}
+
+
+/* end of json_wire.c */
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 4f9a6367d..89b31ebba 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -43,6 +43,7 @@ libtalerutil_wallet_la_LDFLAGS = \
libtalerutil_la_SOURCES = \
amount.c \
crypto.c \
+ crypto_wire.c \
util.c \
os_installation.c
diff --git a/src/util/crypto_wire.c b/src/util/crypto_wire.c
new file mode 100644
index 000000000..494573ffa
--- /dev/null
+++ b/src/util/crypto_wire.c
@@ -0,0 +1,108 @@
+/*
+ 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 util/crypto_wire.c
+ * @brief functions for making and verifying /wire account signatures
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "taler_crypto_lib.h"
+#include "taler_signatures.h"
+
+/**
+ * Compute the hash of the given wire details. The resulting
+ * hash is what is put into the contract.
+ *
+ * @param payto_url bank account
+ * @param salt salt used to eliminate brute-force inversion
+ * @param hc[out] set to the hash
+ */
+void
+TALER_wire_signature_hash (const char *payto_url,
+ const char *salt,
+ struct GNUNET_HashCode *hc)
+{
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (hc,
+ sizeof (*hc),
+ salt,
+ strlen (salt) + 1,
+ payto_url,
+ strlen (payto_url) + 1,
+ "wire-signature",
+ strlen ("wire-signature"),
+ NULL, 0));
+}
+
+
+/**
+ * Check the signature in @a wire_s.
+ *
+ * @param payto_url URL that is signed
+ * @param salt the salt used to salt the @a payto_url when hashing
+ * @param master_pub master public key of the exchange
+ * @param master_sig signature of the exchange
+ * @return #GNUNET_OK if signature is valid
+ */
+int
+TALER_wire_signature_check (const char *payto_url,
+ const char *salt,
+ const struct TALER_MasterPublicKeyP *master_pub,
+ const struct TALER_MasterSignatureP *master_sig)
+{
+ struct TALER_MasterWireDetailsPS wd;
+
+ wd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_DETAILS);
+ wd.purpose.size = htonl (sizeof (wd));
+ TALER_wire_signature_hash (payto_url,
+ salt,
+ &wd.h_wire_details);
+ return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS,
+ &wd.purpose,
+ &master_sig->eddsa_signature,
+ &master_pub->eddsa_pub);
+}
+
+
+/**
+ * Create a signed wire statement for the given account.
+ *
+ * @param payto_url account specification
+ * @param salt the salt used to salt the @a payto_url when hashing
+ * @param master_priv private key to sign with
+ * @param master_sig[out] where to write the signature
+ */
+void
+TALER_wire_signature_make (const char *payto_url,
+ const char *salt,
+ const struct TALER_MasterPrivateKeyP *master_priv,
+ struct TALER_MasterSignatureP *master_sig)
+{
+ struct TALER_MasterWireDetailsPS wd;
+
+ wd.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_WIRE_DETAILS);
+ wd.purpose.size = htonl (sizeof (wd));
+ TALER_wire_signature_hash (payto_url,
+ salt,
+ &wd.h_wire_details);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv,
+ &wd.purpose,
+ &master_sig->eddsa_signature));
+}
+
+
+/* end of crypto_wire.c */
diff --git a/src/wire-plugins/Makefile.am b/src/wire-plugins/Makefile.am
new file mode 100644
index 000000000..9f6029d7f
--- /dev/null
+++ b/src/wire-plugins/Makefile.am
@@ -0,0 +1,101 @@
+# 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 \
+ test_wire_plugin_key.priv \
+ test_wire_plugin_test.json \
+ test_wire_plugin_sepa.json
+
+plugindir = $(libdir)/taler
+
+plugin_LTLIBRARIES = \
+ libtaler_plugin_wire_ebics.la \
+ libtaler_plugin_wire_taler_bank.la
+
+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/util/libtalerutil.la \
+ -lgnunetcurl \
+ -lgnunetutil $(XLIB)
+
+
+libtaler_plugin_wire_ebics_la_SOURCES = \
+ plugin_wire_ebics.c
+libtaler_plugin_wire_ebics_la_LIBADD = \
+ $(LTLIBINTL)
+libtaler_plugin_wire_ebics_la_LDFLAGS = \
+ $(TALER_PLUGIN_LDFLAGS) \
+ $(top_builddir)/src/json/libtalerjson.la \
+ $(top_builddir)/src/util/libtalerutil.la \
+ -lgnunetjson \
+ -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_ebics_wireformat \
+ test_wire_plugin \
+ test_wire_plugin_transactions_taler_bank
+
+check_PROGRAMS= \
+ test_ebics_wireformat \
+ test_wire_plugin \
+ test_wire_plugin_transactions_taler_bank
+
+
+test_ebics_wireformat_SOURCES = \
+ test_ebics_wireformat.c
+test_ebics_wireformat_LDADD = \
+ -lgnunetutil \
+ $(top_builddir)/src/wire/libtalerwire.la \
+ $(top_builddir)/src/util/libtalerutil.la
+
+
+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/plugin_wire_sepa.c b/src/wire-plugins/plugin_wire_ebics.c
index 416acac7c..9aad9df08 100644
--- a/src/wire/plugin_wire_sepa.c
+++ b/src/wire-plugins/plugin_wire_ebics.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016, 2017 GNUnet e.V. & Inria
+ Copyright (C) 2016, 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
@@ -15,7 +15,7 @@
*/
/**
- * @file plugin_wire_sepa.c
+ * @file plugin_wire_ebics.c
* @brief wire plugin for transfers using SEPA/EBICS
* @author Florian Dold
* @author Christian Grothoff
@@ -31,7 +31,7 @@
* Type of the "cls" argument given to each of the functions in
* our API.
*/
-struct SepaClosure
+struct EbicsClosure
{
/**
@@ -39,6 +39,11 @@ struct SepaClosure
*/
char *currency;
+ /**
+ * Configuration we use to lookup account information.
+ */
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
};
@@ -54,10 +59,10 @@ struct SepaClosure
* #GNUNET_SYSERR if the amount or currency was invalid
*/
static int
-sepa_amount_round (void *cls,
- struct TALER_Amount *amount)
+ebics_amount_round (void *cls,
+ struct TALER_Amount *amount)
{
- struct SepaClosure *sc = cls;
+ struct EbicsClosure *sc = cls;
uint32_t delta;
if (NULL == sc->currency)
@@ -81,7 +86,7 @@ sepa_amount_round (void *cls,
/**
* Entry in the country table.
*/
-struct table_entry
+struct CountryTableEntry
{
/**
* 2-Character international country code.
@@ -100,7 +105,7 @@ struct table_entry
/**
* List of country codes.
*/
-static const struct table_entry country_table[] =
+static const struct CountryTableEntry country_table[] =
{
{ "AE", "U.A.E." },
{ "AF", "Afghanistan" },
@@ -259,8 +264,8 @@ static int
cmp_country_code (const void *ptr1,
const void *ptr2)
{
- const struct table_entry *cc1 = ptr1;
- const struct table_entry *cc2 = ptr2;
+ const struct CountryTableEntry *cc1 = ptr1;
+ const struct CountryTableEntry *cc2 = ptr2;
return strncmp (cc1->code,
cc2->code,
@@ -280,20 +285,21 @@ validate_iban (const char *iban)
{
char cc[2];
char ibancpy[35];
- struct table_entry cc_entry;
+ struct CountryTableEntry cc_entry;
unsigned int len;
char *nbuf;
- unsigned int i;
- unsigned int j;
unsigned long long dividend;
unsigned long long remainder;
int nread;
int ret;
+ unsigned int i;
+ unsigned int j;
len = strlen (iban);
if (len > 34)
{
- GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "IBAN number too long to be valid\n");
return GNUNET_NO;
}
strncpy (cc, iban, 2);
@@ -305,11 +311,14 @@ validate_iban (const char *iban)
if (NULL ==
bsearch (&cc_entry,
country_table,
- sizeof (country_table) / sizeof (struct table_entry),
- sizeof (struct table_entry),
+ sizeof (country_table) / sizeof (struct CountryTableEntry),
+ sizeof (struct CountryTableEntry),
&cmp_country_code))
{
- GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Country code `%c%c' not supported\n",
+ cc[0],
+ cc[1]);
return GNUNET_NO;
}
nbuf = GNUNET_malloc ((len * 2) + 1);
@@ -354,309 +363,89 @@ validate_iban (const char *iban)
GNUNET_free (nbuf);
if (1 == remainder)
return GNUNET_YES;
- GNUNET_break_op (0); /* checksum wrong */
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "IBAN checksum wrong\n");
return GNUNET_NO;
}
/**
- * Compute purpose for signing.
- *
- * @param sepa_name name of the account holder
- * @param iban bank account number in IBAN format
- * @param bic bank identifier
- * @param[out] wsd purpose to be signed
+ * Information about an account extracted from a payto://-URL.
*/
-static void
-compute_purpose (const char *sepa_name,
- const char *iban,
- const char *bic,
- struct TALER_MasterWireDetailsPS *wsd)
+struct Account
{
- struct GNUNET_HashContext *hc;
-
- wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
- wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SEPA_DETAILS);
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- "sepa",
- strlen ("sepa") + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- sepa_name,
- strlen (sepa_name) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- iban,
- strlen (iban) + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- bic,
- strlen (bic) + 1);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &wsd->h_sepa_details);
-}
-
-
-/**
- * Verify that the signature in the @a json for /wire/sepa is valid.
- *
- * @param json json reply with the signature
- * @param master_pub public key of the exchange to verify against
- * @return #GNUNET_SYSERR if @a json is invalid,
- * #GNUNET_NO if the method is unknown,
- * #GNUNET_OK if the json is valid
- */
-static int
-verify_wire_sepa_signature_ok (const json_t *json,
- const struct TALER_MasterPublicKeyP *master_pub)
-{
- struct TALER_MasterSignatureP exchange_sig;
- struct TALER_MasterWireDetailsPS mp;
- const char *name;
- const char *iban;
- const char *bic;
- struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("sig", &exchange_sig),
- GNUNET_JSON_spec_string ("name", &name),
- GNUNET_JSON_spec_string ("iban", &iban),
- GNUNET_JSON_spec_string ("bic", &bic),
- GNUNET_JSON_spec_end()
- };
+ /**
+ * The IBAN number.
+ */
+ char *iban;
- if (NULL == master_pub)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Skipping signature check as master public key not given\n");
- return GNUNET_OK;
- }
- if (GNUNET_OK !=
- GNUNET_JSON_parse (json, spec,
- NULL, NULL))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- compute_purpose (name,
- iban,
- bic,
- &mp);
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SEPA_DETAILS,
- &mp.purpose,
- &exchange_sig.eddsa_signature,
- &master_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (spec);
- return GNUNET_SYSERR;
- }
- GNUNET_JSON_parse_free (spec);
- return GNUNET_OK;
-}
+};
/**
- * Check if the given wire format JSON object is correctly formatted
+ * Parse payto:// account URL (only account information,
+ * wire subject and amount are ignored).
*
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wire the JSON wire format object
- * @param master_pub public key of the exchange to verify against
- * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
- * error message must be freed by the caller using GNUNET_free()
- * @return #TALER_EC_NONE if correctly formatted
+ * @param account_url URL to parse
+ * @param account[out] set to information, can be NULL
+ * @return #TALER_EC_NONE if @a account_url is well-formed
*/
static enum TALER_ErrorCode
-sepa_wire_validate (void *cls,
- const json_t *wire,
- const struct TALER_MasterPublicKeyP *master_pub,
- char **emsg)
+parse_payto (const char *account_url,
+ struct Account *account)
{
- json_error_t error;
- const char *type;
const char *iban;
- const char *name;
- const char *bic;
-
- *emsg = NULL;
- if (0 != json_unpack_ex
- ((json_t *) wire,
- &error, 0,
- "{"
- "s:s," /* type: sepa */
- "s:s," /* iban: IBAN */
- "s:s," /* name: beneficiary name */
- "s:s" /* bic: beneficiary bank's BIC */
- "}",
- "type", &type,
- "iban", &iban,
- "name", &name,
- "bic", &bic))
- {
- char *dump;
-
- dump = json_dumps (wire, 0);
- GNUNET_asprintf (emsg,
- "JSON parsing failed at %s:%u: %s (%s): %s\n",
- __FILE__, __LINE__,
- error.text,
- error.source,
- dump);
- free (dump);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
- }
- if (0 != strcasecmp (type,
- "sepa"))
+ const char *q;
+ char *result;
+
+#define PREFIX "payto://sepa/"
+ if (0 != strncasecmp (account_url,
+ PREFIX,
+ strlen (PREFIX)))
+ return TALER_EC_PAYTO_WRONG_METHOD;
+ iban = &account_url[strlen (PREFIX)];
+ q = strchr (iban,
+ '?');
+ if (NULL != q)
{
- GNUNET_asprintf (emsg,
- "Transfer type `%s' invalid for SEPA wire plugin\n",
- type);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE;
+ result = GNUNET_strndup (iban,
+ q - iban);
}
- if (1 != validate_iban (iban))
+ else
{
- GNUNET_asprintf (emsg,
- "IBAN `%s' invalid\n",
- iban);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
+ result = GNUNET_strdup (iban);
}
- /* FIXME: don't parse again, integrate properly... */
if (GNUNET_OK !=
- verify_wire_sepa_signature_ok (wire,
- master_pub))
+ validate_iban (result))
{
- GNUNET_asprintf (emsg,
- "Signature using public key `%s' invalid\n",
- TALER_B2S (master_pub));
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
+ GNUNET_free (result);
+ return TALER_EC_PAYTO_MALFORMED;
}
- return TALER_EC_NONE;
-}
-
-
-/**
- * Obtain wire transfer details in the plugin-specific format
- * from the configuration.
- *
- * @param cls closure
- * @param cfg configuration with details about wire accounts
- * @param account_name which section in the configuration should we parse
- * @return NULL if @a cfg fails to have valid wire details for @a account_name
- */
-static json_t *
-sepa_get_wire_details (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *account_name)
-{
- char *sepa_wire_file;
- json_error_t err;
- json_t *ret;
- char *emsg;
-
- /* Fetch reply */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- account_name,
- "SEPA_RESPONSE_FILE",
- &sepa_wire_file))
+ if (NULL != account)
{
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
- account_name,
- "SEPA_RESPONSE_FILE");
- return NULL;
+ account->iban = result;
}
- ret = json_load_file (sepa_wire_file,
- JSON_REJECT_DUPLICATES,
- &err);
- if (NULL == ret)
+ else
{
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse JSON in %s: %s (%s:%u)\n",
- sepa_wire_file,
- err.text,
- err.source,
- err.line);
- GNUNET_free (sepa_wire_file);
- return NULL;
+ GNUNET_free (result);
}
- if (TALER_EC_NONE !=
- sepa_wire_validate (cls,
- ret,
- NULL,
- &emsg))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to validate SEPA data in %s: %s\n",
- sepa_wire_file,
- emsg);
- GNUNET_free (emsg);
- GNUNET_free (sepa_wire_file);
- json_decref (ret);
- return NULL;
- }
- GNUNET_free (sepa_wire_file);
- return ret;
+ return TALER_EC_NONE;
}
/**
- * Sign wire transfer details in the plugin-specific format.
+ * Check if the given payto:// URL is correctly formatted for this plugin
*
- * @param cls closure
- * @param in wire transfer details in JSON format
- * @param key private signing key to use
- * @param salt salt to add
- * @param[out] sig where to write the signature
- * @return #GNUNET_OK on success
+ * @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 int
-sepa_sign_wire_details (void *cls,
- const json_t *in,
- const struct TALER_MasterPrivateKeyP *key,
- const struct GNUNET_HashCode *salt,
- struct TALER_MasterSignatureP *sig)
+static enum TALER_ErrorCode
+ebics_wire_validate (void *cls,
+ const char *account_url)
{
- struct TALER_MasterWireDetailsPS wsd;
- const char *sepa_name;
- const char *iban;
- const char *bic;
- const char *type;
- json_error_t err;
-
- if (0 !=
- json_unpack_ex ((json_t *) in,
- &err,
- 0 /* flags */,
- "{s:s, s:s, s:s, s:s}",
- "type", &type,
- "name", &sepa_name,
- "iban", &iban,
- "bic", &bic))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to unpack JSON: %s (at %u)\n",
- err.text,
- err.position);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp (type,
- "sepa"))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "`type' must be `sepa' for SEPA wire details\n");
- return GNUNET_SYSERR;
- }
- if (1 != validate_iban (iban))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "IBAN invalid in SEPA wire details\n");
- return GNUNET_SYSERR;
- }
- compute_purpose (sepa_name,
- iban,
- bic,
- &wsd);
- GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
- &wsd.purpose,
- &sig->eddsa_signature);
- return GNUNET_OK;
+ return parse_payto (account_url,
+ NULL);
}
@@ -673,13 +462,14 @@ sepa_sign_wire_details (void *cls,
* @return NULL on failure
*/
static struct TALER_WIRE_PrepareHandle *
-sepa_prepare_wire_transfer (void *cls,
- const json_t *wire,
- const struct TALER_Amount *amount,
- const char *exchange_base_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_WIRE_PrepareTransactionCallback psc,
- void *psc_cls)
+ebics_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 psc,
+ void *psc_cls)
{
GNUNET_break (0); // FIXME: not implemented
return NULL;
@@ -694,7 +484,7 @@ sepa_prepare_wire_transfer (void *cls,
* @param pth preparation to cancel
*/
static void
-sepa_prepare_wire_transfer_cancel (void *cls,
+ebics_prepare_wire_transfer_cancel (void *cls,
struct TALER_WIRE_PrepareHandle *pth)
{
GNUNET_break (0); // FIXME: not implemented
@@ -712,11 +502,11 @@ sepa_prepare_wire_transfer_cancel (void *cls,
* @return NULL on error
*/
static struct TALER_WIRE_ExecuteHandle *
-sepa_execute_wire_transfer (void *cls,
- const char *buf,
- size_t buf_size,
- TALER_WIRE_ConfirmationCallback cc,
- void *cc_cls)
+ebics_execute_wire_transfer (void *cls,
+ const char *buf,
+ size_t buf_size,
+ TALER_WIRE_ConfirmationCallback cc,
+ void *cc_cls)
{
GNUNET_break (0); // FIXME: not implemented
return NULL;
@@ -736,8 +526,8 @@ sepa_execute_wire_transfer (void *cls,
* @param eh execution to cancel
*/
static void
-sepa_execute_wire_transfer_cancel (void *cls,
- struct TALER_WIRE_ExecuteHandle *eh)
+ebics_execute_wire_transfer_cancel (void *cls,
+ struct TALER_WIRE_ExecuteHandle *eh)
{
GNUNET_break (0); // FIXME: not implemented
}
@@ -754,6 +544,8 @@ sepa_execute_wire_transfer_cancel (void *cls,
* (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)`.
@@ -764,13 +556,14 @@ sepa_execute_wire_transfer_cancel (void *cls,
* @param hres_cb_cls closure for the above callback
*/
static struct TALER_WIRE_HistoryHandle *
-sepa_get_history (void *cls,
- 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)
+ebics_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)
{
GNUNET_break (0);
return NULL;
@@ -784,8 +577,8 @@ sepa_get_history (void *cls,
* @param whh operation to cancel
*/
static void
-sepa_get_history_cancel (void *cls,
- struct TALER_WIRE_HistoryHandle *whh)
+ebics_get_history_cancel (void *cls,
+ struct TALER_WIRE_HistoryHandle *whh)
{
GNUNET_break (0);
}
@@ -843,6 +636,8 @@ timeout_reject (void *cls)
* 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
@@ -850,11 +645,12 @@ timeout_reject (void *cls)
* @return handle to cancel the operation
*/
static struct TALER_WIRE_RejectHandle *
-sepa_reject_transfer (void *cls,
- const void *start_off,
- size_t start_off_len,
- TALER_WIRE_RejectTransferCallback rej_cb,
- void *rej_cb_cls)
+ebics_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_RejectHandle *rh;
@@ -881,8 +677,8 @@ sepa_reject_transfer (void *cls,
* @return closure of the callback of the operation
*/
static void *
-sepa_reject_transfer_cancel (void *cls,
- struct TALER_WIRE_RejectHandle *rh)
+ebics_reject_transfer_cancel (void *cls,
+ struct TALER_WIRE_RejectHandle *rh)
{
void *ret = rh->rej_cb_cls;
@@ -893,63 +689,60 @@ sepa_reject_transfer_cancel (void *cls,
/**
- * Initialize sepa-wire subsystem.
+ * Initialize ebics-wire subsystem.
*
* @param cls a configuration instance
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
*/
void *
-libtaler_plugin_wire_sepa_init (void *cls)
+libtaler_plugin_wire_ebics_init (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct SepaClosure *sc;
+ struct EbicsClosure *sc;
struct TALER_WIRE_Plugin *plugin;
- sc = GNUNET_new (struct SepaClosure);
- if (NULL != cfg)
+ sc = GNUNET_new (struct EbicsClosure);
+ sc->cfg = cfg;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler",
+ "CURRENCY",
+ &sc->currency))
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "taler",
- "CURRENCY",
- &sc->currency))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "taler",
- "CURRENCY");
- GNUNET_free (sc);
- return NULL;
- }
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "taler",
+ "CURRENCY");
+ GNUNET_free (sc);
+ return NULL;
}
plugin = GNUNET_new (struct TALER_WIRE_Plugin);
plugin->cls = sc;
- plugin->amount_round = &sepa_amount_round;
- plugin->get_wire_details = &sepa_get_wire_details;
- plugin->sign_wire_details = &sepa_sign_wire_details;
- plugin->wire_validate = &sepa_wire_validate;
- plugin->prepare_wire_transfer = &sepa_prepare_wire_transfer;
- plugin->prepare_wire_transfer_cancel = &sepa_prepare_wire_transfer_cancel;
- plugin->execute_wire_transfer = &sepa_execute_wire_transfer;
- plugin->execute_wire_transfer_cancel = &sepa_execute_wire_transfer_cancel;
- plugin->get_history = &sepa_get_history;
- plugin->get_history_cancel = &sepa_get_history_cancel;
- plugin->reject_transfer = &sepa_reject_transfer;
- plugin->reject_transfer_cancel = &sepa_reject_transfer_cancel;
+ plugin->method = "sepa";
+ plugin->amount_round = &ebics_amount_round;
+ plugin->wire_validate = &ebics_wire_validate;
+ plugin->prepare_wire_transfer = &ebics_prepare_wire_transfer;
+ plugin->prepare_wire_transfer_cancel = &ebics_prepare_wire_transfer_cancel;
+ plugin->execute_wire_transfer = &ebics_execute_wire_transfer;
+ plugin->execute_wire_transfer_cancel = &ebics_execute_wire_transfer_cancel;
+ plugin->get_history = &ebics_get_history;
+ plugin->get_history_cancel = &ebics_get_history_cancel;
+ plugin->reject_transfer = &ebics_reject_transfer;
+ plugin->reject_transfer_cancel = &ebics_reject_transfer_cancel;
return plugin;
}
/**
- * Shutdown Sepa wire subsystem.
+ * Shutdown Ebics wire subsystem.
*
* @param cls a `struct TALER_WIRE_Plugin`
* @return NULL (always)
*/
void *
-libtaler_plugin_wire_sepa_done (void *cls)
+libtaler_plugin_wire_ebics_done (void *cls)
{
struct TALER_WIRE_Plugin *plugin = cls;
- struct SepaClosure *sc = plugin->cls;
+ struct EbicsClosure *sc = plugin->cls;
GNUNET_free_non_null (sc->currency);
GNUNET_free (sc);
@@ -957,4 +750,4 @@ libtaler_plugin_wire_sepa_done (void *cls)
return NULL;
}
-/* end of plugin_wire_sepa.c */
+/* end of plugin_wire_ebics.c */
diff --git a/src/wire/plugin_wire_test.c b/src/wire-plugins/plugin_wire_taler-bank.c
index 11feaea7e..2d2235343 100644
--- a/src/wire/plugin_wire_test.c
+++ b/src/wire-plugins/plugin_wire_taler-bank.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2017 Taler Systems SA
+ 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
@@ -15,12 +15,13 @@
*/
/**
- * @file plugin_wire_test.c
- * @brief plugin for the "test" wire method
+ * @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_bank_service.h"
#include "taler_signatures.h"
#include <gnunet/gnunet_curl_lib.h>
@@ -29,10 +30,15 @@
#include <microhttpd.h>
/**
+ * Maximum legal 'value' for an account number, based on IEEE double (for JavaScript compatibility).
+ */
+#define MAX_ACCOUNT_NO (1LLU << 52)
+
+/**
* Type of the "cls" argument given to each of the functions in
* our API.
*/
-struct TestClosure
+struct TalerBankClosure
{
/**
@@ -41,16 +47,6 @@ struct TestClosure
char *currency;
/**
- * URL of our bank.
- */
- char *bank_url;
-
- /**
- * Authentication information.
- */
- struct TALER_BANK_AuthenticationData auth;
-
- /**
* Handle to the context for sending funds to the bank.
*/
struct GNUNET_CURL_Context *ctx;
@@ -61,16 +57,15 @@ struct TestClosure
struct GNUNET_CURL_RescheduleContext *rc;
/**
- * Number of the account that the exchange has at the bank for
- * transfers.
+ * Configuration we use to lookup account information.
*/
- unsigned long long exchange_account_no;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
};
/**
- * Handle returned by #test_prepare_wire_transfer.
+ * Handle returned by #taler_bank_prepare_wire_transfer.
*/
struct TALER_WIRE_PrepareHandle
{
@@ -81,14 +76,25 @@ struct TALER_WIRE_PrepareHandle
struct GNUNET_SCHEDULER_Task *task;
/**
- * Test closure we run in.
+ * 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.
*/
- struct TestClosure *tc;
+ char *origin_account_url;
/**
- * Wire data for the transfer.
+ * Which account should be credited?
*/
- json_t *wire;
+ char *destination_account_url;
/**
* Base URL to use for the exchange.
@@ -120,7 +126,7 @@ struct TALER_WIRE_PrepareHandle
/**
- * Handle returned by #test_execute_wire_transfer.
+ * Handle returned by #taler_bank_execute_wire_transfer.
*/
struct TALER_WIRE_ExecuteHandle
{
@@ -142,7 +148,6 @@ struct TALER_WIRE_ExecuteHandle
};
-
/**
* 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
@@ -155,10 +160,10 @@ struct TALER_WIRE_ExecuteHandle
* #GNUNET_SYSERR if the amount or currency was invalid
*/
static int
-test_amount_round (void *cls,
- struct TALER_Amount *amount)
+taler_bank_amount_round (void *cls,
+ struct TALER_Amount *amount)
{
- struct TestClosure *tc = cls;
+ struct TalerBankClosure *tc = cls;
uint32_t delta;
if (NULL == tc->currency)
@@ -174,7 +179,7 @@ test_amount_round (void *cls,
GNUNET_break (0);
return GNUNET_SYSERR;
}
- /* 'test' method supports 1/100 of the unit currency, i.e. 0.01 CUR */
+ /* '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;
@@ -184,209 +189,99 @@ test_amount_round (void *cls,
/**
- * Compute purpose for signing.
- *
- * @param account number of the account
- * @param bank_url URL of the bank
- * @param[out] wsd purpose to be signed
+ * Information about an account extracted from a payto://-URL.
*/
-static void
-compute_purpose (uint64_t account,
- const char *bank_url,
- struct TALER_MasterWireDetailsPS *wsd)
+struct Account
{
- struct GNUNET_HashContext *hc;
- uint64_t n = GNUNET_htonll (account);
-
- wsd->purpose.size = htonl (sizeof (struct TALER_MasterWireDetailsPS));
- wsd->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_TEST_DETAILS);
- hc = GNUNET_CRYPTO_hash_context_start ();
- GNUNET_CRYPTO_hash_context_read (hc,
- "test",
- strlen ("test") + 1);
- GNUNET_CRYPTO_hash_context_read (hc,
- &n,
- sizeof (n));
- GNUNET_CRYPTO_hash_context_read (hc,
- bank_url,
- strlen (bank_url) + 1);
- GNUNET_CRYPTO_hash_context_finish (hc,
- &wsd->h_sepa_details);
-}
+ /**
+ * Hostname of the bank (possibly including port).
+ */
+ char *hostname;
+
+ /**
+ * Bank account number.
+ */
+ unsigned long long no;
+};
/**
- * Check if the given wire format JSON object is correctly formatted.
- * Right now, the only thing we require is a field
- * "account_number" which must contain a positive 53-bit integer.
+ * Parse payto:// account URL (only account information,
+ * wire subject and amount are ignored).
*
- * @param cls the @e cls of this struct with the plugin-specific state
- * @param wire the JSON wire format object
- * @param master_pub public key of the exchange to verify against
- * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
- * error message must be freed by the caller using GNUNET_free()
- * @return #TALER_EC_NONE if correctly formatted
+ * @param account_url URL to parse
+ * @param account[out] set to information, can be NULL
+ * @return #TALER_EC_NONE if @a account_url is well-formed
*/
static enum TALER_ErrorCode
-test_wire_validate (void *cls,
- const json_t *wire,
- const struct TALER_MasterPublicKeyP *master_pub,
- char **emsg)
+parse_payto (const char *account_url,
+ struct Account *r_account)
{
- struct TestClosure *tc = cls;
- json_error_t error;
- json_int_t account_no;
- const char *bank_url;
- const char *sig_s;
- struct TALER_MasterWireDetailsPS wsd;
- struct TALER_MasterSignatureP sig;
-
- *emsg = NULL;
- if (0 !=
- json_unpack_ex ((json_t *) wire,
- &error,
- 0,
- "{s:I, s:s}",
- "account_number", &account_no,
- "bank_url", &bank_url))
- {
- char *dump;
-
- dump = json_dumps (wire, 0);
- GNUNET_asprintf (emsg,
- "JSON parsing failed at %s:%u: %s (%s): %s\n",
- __FILE__, __LINE__,
- error.text,
- error.source,
- dump);
- free (dump);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_JSON;
- }
- if ( (account_no < 0) ||
- (account_no > (1LL << 53)) )
- {
- GNUNET_asprintf (emsg,
- "Account number %llu outside of permitted range\n",
- account_no);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
- }
- if ( (NULL != tc->bank_url) &&
- (0 != strcmp (bank_url,
- tc->bank_url)) )
+ const char *hostname;
+ const char *account;
+ const char *q;
+ unsigned long long no;
+
+#define PREFIX "payto://x-taler-bank/"
+ if (0 != strncasecmp (account_url,
+ PREFIX,
+ strlen (PREFIX)))
+ return TALER_EC_PAYTO_WRONG_METHOD;
+ hostname = &account_url[strlen (PREFIX)];
+ if (NULL == (account = strchr (hostname,
+ (unsigned char) '/')))
+ return TALER_EC_PAYTO_MALFORMED;
+ account++;
+ if (NULL != (q = strchr (account,
+ (unsigned char) '?')))
{
- GNUNET_asprintf (emsg,
- "Wire specifies bank URL `%s', but this exchange only supports `%s'\n",
- bank_url,
- tc->bank_url);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_BANK;
- }
- if (NULL == master_pub)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Skipping signature check as master public key not given\n");
- return TALER_EC_NONE;
- }
- if (0 !=
- json_unpack_ex ((json_t *) wire,
- &error,
- 0,
- "{s:s}",
- "sig", &sig_s))
- {
- GNUNET_asprintf (emsg,
- "Signature check required, but signature is missing\n");
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
+ char *s;
+
+ s = GNUNET_strndup (account,
+ q - account);
+ if (1 != sscanf (s,
+ "%llu",
+ &no))
+ {
+ GNUNET_free (s);
+ return TALER_EC_PAYTO_MALFORMED;
+ }
+ GNUNET_free (s);
}
- compute_purpose (account_no,
- bank_url,
- &wsd);
- if (GNUNET_OK !=
- GNUNET_STRINGS_string_to_data (sig_s,
- strlen (sig_s),
- &sig,
- sizeof (sig)))
+ else
{
- GNUNET_break (0);
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
+ if (1 != sscanf (account,
+ "%llu",
+ &no))
+ return TALER_EC_PAYTO_MALFORMED;
}
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_TEST_DETAILS,
- &wsd.purpose,
- &sig.eddsa_signature,
- &master_pub->eddsa_pub))
+ if (no > MAX_ACCOUNT_NO)
+ return TALER_EC_PAYTO_MALFORMED;
+ if (NULL != r_account)
{
- GNUNET_asprintf (emsg,
- "Signature using public key `%s' invalid\n",
- TALER_B2S (master_pub));
- return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_SIGNATURE;
+ r_account->hostname = GNUNET_strndup (hostname,
+ account - hostname);
+ r_account->no = no;
}
return TALER_EC_NONE;
}
/**
- * Obtain wire transfer details in the plugin-specific format
- * from the configuration.
+ * Check if the given payto:// URL is correctly formatted.
*
- * @param cls closure
- * @param cfg configuration with details about wire accounts
- * @param account_name which section in the configuration should we parse
- * @return NULL if @a cfg fails to have valid wire details for @a account_name
+ * @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 json_t *
-test_get_wire_details (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *account_name)
+static enum TALER_ErrorCode
+taler_bank_wire_validate (void *cls,
+ const char *account_url)
{
- struct TestClosure *tc = cls;
- char *test_wire_file;
- json_error_t err;
- json_t *ret;
- char *emsg;
+ (void) cls;
- /* Fetch reply */
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_filename (cfg,
- account_name,
- "TEST_RESPONSE_FILE",
- &test_wire_file))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- account_name,
- "TEST_RESPONSE_FILE");
- return NULL;
- }
- ret = json_load_file (test_wire_file,
- JSON_REJECT_DUPLICATES,
- &err);
- if (NULL == ret)
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse JSON in %s: %s (%s:%u)\n",
- test_wire_file,
- err.text,
- err.source,
- err.line);
- GNUNET_free (test_wire_file);
- return NULL;
- }
- if (TALER_EC_NONE !=
- test_wire_validate (tc,
- ret,
- NULL,
- &emsg))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to validate TEST wire data in %s: %s\n",
- test_wire_file,
- emsg);
- GNUNET_free (emsg);
- GNUNET_free (test_wire_file);
- json_decref (ret);
- return NULL;
- }
- GNUNET_free (test_wire_file);
- return ret;
+ return parse_payto (account_url,
+ NULL);
}
@@ -407,9 +302,15 @@ struct BufFormatP
*/
struct TALER_AmountNBO amount;
- /* followed by serialized 'wire' JSON data (0-terminated) */
+ /* followed by 0-terminated origin account URL */
- /* followed by 0-terminated base 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
@@ -423,12 +324,14 @@ GNUNET_NETWORK_STRUCT_END
* @param pth preparation to cancel
*/
static void
-test_prepare_wire_transfer_cancel (void *cls,
- struct TALER_WIRE_PrepareHandle *pth)
+taler_bank_prepare_wire_transfer_cancel (void *cls,
+ struct TALER_WIRE_PrepareHandle *pth)
{
if (NULL != pth->task)
GNUNET_SCHEDULER_cancel (pth->task);
- json_decref (pth->wire);
+ 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);
}
@@ -444,52 +347,111 @@ static void
do_prepare (void *cls)
{
struct TALER_WIRE_PrepareHandle *pth = cls;
- char *wire_enc;
- size_t len_w;
+ 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' */
- wire_enc = json_dumps (pth->wire,
- JSON_COMPACT | JSON_SORT_KEYS);
- if (NULL == wire_enc)
+ len_o = strlen (pth->origin_account_url) + 1;
+ len_i = strlen (pth->destination_account_url) + 1;
+ len_b = strlen (pth->exchange_base_url) + 1;
+ switch (pth->auth.method)
{
- GNUNET_break (0);
- pth->ptc (pth->ptc_cls,
- NULL,
- 0);
- test_prepare_wire_transfer_cancel (NULL,
- pth);
- return;
+ case TALER_BANK_AUTH_NONE:
+ len_au = 0;
+ len_ap = 0;
+ 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;
}
- len_w = strlen (wire_enc) + 1;
- len_b = strlen (pth->exchange_base_url) + 1;
bf.wtid = pth->wtid;
TALER_amount_hton (&bf.amount,
&pth->amount);
{
- char buf[sizeof (struct BufFormatP) + len_w + len_b];
+ 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)],
- wire_enc,
- len_w);
- memcpy (&buf[sizeof (struct BufFormatP) + len_w],
+ 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));
}
- free (wire_enc); /* not using GNUNET_free(),
- as this one is allocated by libjansson */
- test_prepare_wire_transfer_cancel (NULL,
- pth);
+ 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 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 !=
+ parse_payto (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;
+ }
+ GNUNET_free (account_url);
+ return GNUNET_OK;
}
@@ -501,7 +463,9 @@ do_prepare (void *cls)
* the work.
*
* @param cls the @e cls of this struct with the plugin-specific state
- * @param wire valid wire account information
+ * @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
@@ -510,31 +474,84 @@ do_prepare (void *cls)
* @return NULL on failure
*/
static struct TALER_WIRE_PrepareHandle *
-test_prepare_wire_transfer (void *cls,
- const json_t *wire,
- const struct TALER_Amount *amount,
- const char *exchange_base_url,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- TALER_WIRE_PrepareTransactionCallback ptc,
- void *ptc_cls)
+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 TestClosure *tc = cls;
+ struct TalerBankClosure *tc = cls;
struct TALER_WIRE_PrepareHandle *pth;
- char *emsg;
+ char *origin_account_url;
+ struct Account a_in;
+ struct Account a_out;
+ /* Check that payto:// URLs are valid */
+ if (TALER_EC_NONE !=
+ parse_payto (destination_account_url,
+ &a_out))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "payto://-URL `%s' is invalid!\n",
+ destination_account_url);
+ 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");
+ GNUNET_free (a_out.hostname);
+ return NULL;
+ }
if (TALER_EC_NONE !=
- test_wire_validate (tc,
- wire,
- NULL,
- &emsg))
+ parse_payto (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);
+ GNUNET_free (a_out.hostname);
+ return NULL;
+ }
+
+ /* Make sure the bank is the same! */
+ if (0 != strcasecmp (a_in.hostname,
+ a_out.hostname))
{
- GNUNET_break_op (0);
- GNUNET_free (emsg);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "x-taler-bank hostname missmatch: `%s' != `%s'\n",
+ a_in.hostname,
+ a_out.hostname);
+ GNUNET_free (a_in.hostname);
+ GNUNET_free (a_out.hostname);
return NULL;
}
+ GNUNET_free (a_in.hostname);
+ GNUNET_free (a_out.hostname);
+
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);
+ return NULL;
+ }
+
pth->tc = tc;
- pth->wire = json_incref ((json_t *) wire);
+ 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;
@@ -599,61 +616,6 @@ execute_cb (void *cls,
/**
- * Sign wire transfer details in the plugin-specific format.
- *
- * @param cls closure
- * @param in wire transfer details in JSON format
- * @param key private signing key to use
- * @param salt salt to add
- * @param[out] sig where to write the signature
- * @return #GNUNET_OK on success
- */
-static int
-test_sign_wire_details (void *cls,
- const json_t *in,
- const struct TALER_MasterPrivateKeyP *key,
- const struct GNUNET_HashCode *salt,
- struct TALER_MasterSignatureP *sig)
-{
- struct TALER_MasterWireDetailsPS wsd;
- const char *bank_url;
- const char *type;
- json_int_t account;
- json_error_t err;
-
- if (0 !=
- json_unpack_ex ((json_t *) in,
- &err,
- 0 /* flags */,
- "{s:s, s:s, s:I}",
- "type", &type,
- "bank_url", &bank_url,
- "account_number", &account))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Failed to unpack JSON: %s (at %u)\n",
- err.text,
- err.position);
- return GNUNET_SYSERR;
- }
- if (0 != strcmp (type,
- "test"))
- {
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "`type' must be `test' for test wire details\n");
- return GNUNET_SYSERR;
- }
- compute_purpose (account,
- bank_url,
- &wsd);
- GNUNET_CRYPTO_eddsa_sign (&key->eddsa_priv,
- &wsd.purpose,
- &sig->eddsa_signature);
- return GNUNET_OK;
-}
-
-
-/**
* Execute a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -664,22 +626,24 @@ test_sign_wire_details (void *cls,
* @return NULL on error
*/
static struct TALER_WIRE_ExecuteHandle *
-test_execute_wire_transfer (void *cls,
- const char *buf,
- size_t buf_size,
- TALER_WIRE_ConfirmationCallback cc,
- void *cc_cls)
+taler_bank_execute_wire_transfer (void *cls,
+ const char *buf,
+ size_t buf_size,
+ TALER_WIRE_ConfirmationCallback cc,
+ void *cc_cls)
{
- struct TestClosure *tc = cls;
+ struct TalerBankClosure *tc = cls;
struct TALER_WIRE_ExecuteHandle *eh;
- json_t *wire;
- json_error_t error;
struct TALER_Amount amount;
- json_int_t account_no;
+ struct Account origin_account;
+ struct Account destination_account;
struct BufFormatP bf;
- char *emsg;
- const char *json_s;
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)
@@ -694,37 +658,76 @@ test_execute_wire_transfer (void *cls,
GNUNET_break (0);
return NULL;
}
- json_s = &buf[sizeof (struct BufFormatP)];
- exchange_base_url = &json_s[strlen (json_s) + 1];
- if (exchange_base_url > &buf[buf_size - 1])
- {
- GNUNET_break (0);
- return NULL;
- }
memcpy (&bf,
buf,
sizeof (bf));
TALER_amount_ntoh (&amount,
&bf.amount);
- wire = json_loads (json_s,
- JSON_REJECT_DUPLICATES,
- NULL);
- if (NULL == wire)
+ origin_account_url = &buf[sizeof (struct BufFormatP)];
+ left = buf_size - sizeof (struct BufFormatP);
+ slen = strlen (origin_account_url) + 1;
+ 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.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.username) + 1;
+ GNUNET_assert (left >= slen);
+ left -= slen;
+ if (0 != left)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ }
+
+ if (TALER_EC_NONE !=
+ parse_payto (origin_account_url,
+ &origin_account))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (TALER_EC_NONE !=
+ parse_payto (destination_account_url,
+ &destination_account))
{
GNUNET_break (0);
return NULL;
}
- GNUNET_assert (TALER_EC_NONE ==
- test_wire_validate (tc,
- wire,
- NULL,
- &emsg));
- if (0 !=
- json_unpack_ex (wire,
- &error,
- 0,
- "{s:I}",
- "account_number", &account_no))
+ if (0 != strcasecmp (origin_account.hostname,
+ destination_account.hostname))
{
GNUNET_break (0);
return NULL;
@@ -736,17 +739,16 @@ test_execute_wire_transfer (void *cls,
wire_s = GNUNET_STRINGS_data_to_string_alloc (&bf.wtid,
sizeof (bf.wtid));
eh->aaih = TALER_BANK_admin_add_incoming (tc->ctx,
- tc->bank_url,
- &tc->auth,
+ origin_account.hostname,
+ &auth,
exchange_base_url,
wire_s,
&amount,
- (uint64_t) tc->exchange_account_no,
- (uint64_t) account_no,
+ (uint64_t) origin_account.no,
+ (uint64_t) destination_account.no,
&execute_cb,
eh);
GNUNET_free (wire_s);
- json_decref (wire);
if (NULL == eh->aaih)
{
GNUNET_break (0);
@@ -770,8 +772,8 @@ test_execute_wire_transfer (void *cls,
* @param eh execution to cancel
*/
static void
-test_execute_wire_transfer_cancel (void *cls,
- struct TALER_WIRE_ExecuteHandle *eh)
+taler_bank_execute_wire_transfer_cancel (void *cls,
+ struct TALER_WIRE_ExecuteHandle *eh)
{
TALER_BANK_admin_add_incoming_cancel (eh->aaih);
GNUNET_free (eh);
@@ -779,7 +781,7 @@ test_execute_wire_transfer_cancel (void *cls,
/**
- * Handle for a #test_get_history() request.
+ * Handle for a #taler_bank_get_history() request.
*/
struct TALER_WIRE_HistoryHandle
{
@@ -799,10 +801,35 @@ struct TALER_WIRE_HistoryHandle
*/
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)
+{
+ 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`
@@ -839,7 +866,8 @@ bhist_cb (void *cls,
wd.amount = details->amount;
wd.execution_date = details->execution_date;
subject = GNUNET_strdup (details->wire_transfer_subject);
- space = strchr (subject, (int) ' ');
+ space = strchr (subject,
+ (unsigned char) ' ');
if (NULL != space)
{
/* Space separates the actual wire transfer subject from the
@@ -867,8 +895,7 @@ bhist_cb (void *cls,
wd.wtid_s = NULL;
}
GNUNET_free (subject);
- wd.account_details = details->account_details;
-
+ wd.account_url = details->account_url;
if ( (NULL != whh->hres_cb) &&
(GNUNET_OK !=
whh->hres_cb (whh->hres_cb_cls,
@@ -878,7 +905,7 @@ bhist_cb (void *cls,
sizeof (bserial_id),
&wd)) )
whh->hres_cb = NULL;
- break;
+ return; /* do NOT yet clean up! */
}
case MHD_HTTP_NO_CONTENT:
if (NULL != whh->hres_cb)
@@ -888,7 +915,6 @@ bhist_cb (void *cls,
NULL,
0,
NULL);
- GNUNET_free (whh);
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@@ -902,9 +928,11 @@ bhist_cb (void *cls,
NULL,
0,
NULL);
- GNUNET_free (whh);
break;
}
+ whh->hh = NULL;
+ taler_bank_get_history_cancel (NULL,
+ whh);
}
@@ -915,12 +943,14 @@ bhist_cb (void *cls,
* 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
+ * 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 from which row on do we want to get results, use NULL for the lataler_bank; 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;
@@ -929,18 +959,20 @@ bhist_cb (void *cls,
* @param hres_cb_cls closure for the above callback
*/
static struct TALER_WIRE_HistoryHandle *
-test_get_history (void *cls,
- 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)
+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 TestClosure *tc = cls;
+ struct TalerBankClosure *tc = cls;
struct TALER_WIRE_HistoryHandle *whh;
const uint64_t *start_off_b64;
uint64_t start_row;
+ struct Account account;
if (0 == num_results)
{
@@ -956,11 +988,12 @@ test_get_history (void *cls,
(sizeof (uint64_t) != start_off_len) )
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Wire plugin 'test' got start offset of wrong size (%llu instead of %llu)\n",
- (unsigned long long) start_off_len, (unsigned long long) sizeof (uint64_t));
+ "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,
+ * wrote a wrong value to it. Instead of completely stopping to work,
* we just scan from the beginning. */
start_off = NULL;
}
@@ -973,14 +1006,28 @@ test_get_history (void *cls,
start_off_b64 = start_off;
start_row = GNUNET_ntohll (*start_off_b64);
}
+ if (GNUNET_OK !=
+ parse_account_cfg (tc->cfg,
+ account_section,
+ &account))
+ return NULL;
whh = GNUNET_new (struct TALER_WIRE_HistoryHandle);
+ if (GNUNET_OK !=
+ TALER_BANK_auth_parse_cfg (tc->cfg,
+ account_section,
+ &whh->auth))
+ {
+ GNUNET_free (whh);
+ return NULL;
+ }
+
whh->hres_cb = hres_cb;
whh->hres_cb_cls = hres_cb_cls;
whh->hh = TALER_BANK_history (tc->ctx,
- tc->bank_url,
- &tc->auth,
- (uint64_t) tc->exchange_account_no,
+ account.hostname,
+ &whh->auth,
+ (uint64_t) account.no,
direction,
start_row,
num_results,
@@ -989,30 +1036,17 @@ test_get_history (void *cls,
if (NULL == whh->hh)
{
GNUNET_break (0);
- GNUNET_free (whh);
+ taler_bank_get_history_cancel (NULL,
+ whh);
+ GNUNET_free (account.hostname);
return NULL;
}
-
+ GNUNET_free (account.hostname);
return whh;
}
/**
- * 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
-test_get_history_cancel (void *cls,
- struct TALER_WIRE_HistoryHandle *whh)
-{
- TALER_BANK_history_cancel (whh->hh);
- GNUNET_free (whh);
-}
-
-
-/**
* Context for a rejection operation.
*/
struct TALER_WIRE_RejectHandle
@@ -1031,6 +1065,11 @@ struct TALER_WIRE_RejectHandle
* Handle for the reject operation.
*/
struct TALER_BANK_RejectHandle *brh;
+
+ /**
+ * Authentication information to use.
+ */
+ struct TALER_BANK_AuthenticationData auth;
};
@@ -1059,6 +1098,32 @@ reject_cb (void *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.
+ *
+ * @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;
+
+ 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).
@@ -1069,6 +1134,8 @@ reject_cb (void *cls,
* 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
@@ -1076,15 +1143,17 @@ reject_cb (void *cls,
* @return handle to cancel the operation
*/
static struct TALER_WIRE_RejectHandle *
-test_reject_transfer (void *cls,
- const void *start_off,
- size_t start_off_len,
- TALER_WIRE_RejectTransferCallback rej_cb,
- void *rej_cb_cls)
+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 TestClosure *tc = cls;
+ struct TalerBankClosure *tc = cls;
const uint64_t *rowid_b64 = start_off;
struct TALER_WIRE_RejectHandle *rh;
+ struct Account account;
if (sizeof (uint64_t) != start_off_len)
{
@@ -1092,178 +1161,109 @@ test_reject_transfer (void *cls,
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;
rh->brh = TALER_BANK_reject (tc->ctx,
- tc->bank_url,
- &tc->auth,
- (uint64_t) tc->exchange_account_no,
+ account.hostname,
+ &rh->auth,
+ (uint64_t) account.no,
GNUNET_ntohll (*rowid_b64),
&reject_cb,
rh);
if (NULL == rh->brh)
{
- GNUNET_free (rh);
+ (void) taler_bank_reject_transfer_cancel (tc,
+ rh);
+ GNUNET_free (account.hostname);
return NULL;
}
+ GNUNET_free (account.hostname);
return 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 *
-test_reject_transfer_cancel (void *cls,
- struct TALER_WIRE_RejectHandle *rh)
-{
- void *ret = rh->rej_cb_cls;
-
- if (NULL != rh->brh)
- TALER_BANK_reject_cancel (rh->brh);
- GNUNET_free (rh);
- return ret;
-}
-
-
-/**
- * Initialize test-wire subsystem.
+ * Initialize taler_bank-wire subsystem.
*
* @param cls a configuration instance
* @return NULL on error, otherwise a `struct TALER_WIRE_Plugin`
*/
void *
-libtaler_plugin_wire_test_init (void *cls)
+libtaler_plugin_wire_taler_bank_init (void *cls)
{
struct GNUNET_CONFIGURATION_Handle *cfg = cls;
- struct TestClosure *tc;
+ struct TalerBankClosure *tc;
struct TALER_WIRE_Plugin *plugin;
- char *user;
- char *pass;
- tc = GNUNET_new (struct TestClosure);
- if (NULL != cfg)
+ tc = GNUNET_new (struct TalerBankClosure);
+ tc->cfg = cfg;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg,
+ "taler",
+ "CURRENCY",
+ &tc->currency))
{
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "BANK_URL",
- &tc->bank_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "BANK_URL");
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_number (cfg,
- "exchange-wire-test",
- "EXCHANGE_ACCOUNT_NUMBER",
- &tc->exchange_account_no))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "EXCHANGE_ACCOUNT_NUMBER");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- 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->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "USERNAME",
- &user))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "USERNAME");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- return NULL;
- }
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-test",
- "PASSWORD",
- &pass))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-test",
- "PASSWORD");
- GNUNET_free (tc->bank_url);
- GNUNET_free (tc);
- GNUNET_free (user);
- return NULL;
- }
- tc->auth.method = TALER_BANK_AUTH_BASIC;
- tc->auth.details.basic.username = user;
- tc->auth.details.basic.password = pass;
- 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->bank_url);
- GNUNET_free (tc->auth.details.basic.username);
- GNUNET_free (tc->auth.details.basic.password);
- GNUNET_free (tc);
- return NULL;
- }
+ 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->amount_round = &test_amount_round;
- plugin->get_wire_details = &test_get_wire_details;
- plugin->sign_wire_details = &test_sign_wire_details;
- plugin->wire_validate = &test_wire_validate;
- plugin->prepare_wire_transfer = &test_prepare_wire_transfer;
- plugin->prepare_wire_transfer_cancel = &test_prepare_wire_transfer_cancel;
- plugin->execute_wire_transfer = &test_execute_wire_transfer;
- plugin->execute_wire_transfer_cancel = &test_execute_wire_transfer_cancel;
- plugin->get_history = &test_get_history;
- plugin->get_history_cancel = &test_get_history_cancel;
- plugin->reject_transfer = &test_reject_transfer;
- plugin->reject_transfer_cancel = &test_reject_transfer_cancel;
+ 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 Test wire subsystem.
+ * Shutdown taler-bank wire subsystem.
*
* @param cls a `struct TALER_WIRE_Plugin`
* @return NULL (always)
*/
void *
-libtaler_plugin_wire_test_done (void *cls)
+libtaler_plugin_wire_taler_bank_done (void *cls)
{
struct TALER_WIRE_Plugin *plugin = cls;
- struct TestClosure *tc = plugin->cls;
+ struct TalerBankClosure *tc = plugin->cls;
if (NULL != tc->ctx)
{
@@ -1275,28 +1275,10 @@ libtaler_plugin_wire_test_done (void *cls)
GNUNET_CURL_gnunet_rc_destroy (tc->rc);
tc->rc = NULL;
}
- switch (tc->auth.method)
- {
- case TALER_BANK_AUTH_NONE:
- break;
- case TALER_BANK_AUTH_BASIC:
- if (NULL != tc->auth.details.basic.username)
- {
- GNUNET_free (tc->auth.details.basic.username);
- tc->auth.details.basic.username = NULL;
- }
- if (NULL != tc->auth.details.basic.password)
- {
- GNUNET_free (tc->auth.details.basic.password);
- tc->auth.details.basic.password = NULL;
- }
- break;
- }
GNUNET_free_non_null (tc->currency);
- GNUNET_free_non_null (tc->bank_url);
GNUNET_free (tc);
GNUNET_free (plugin);
return NULL;
}
-/* end of plugin_wire_test.c */
+/* end of plugin_wire_taler-bank.c */
diff --git a/src/wire/plugin_wire_template.c b/src/wire-plugins/plugin_wire_template.c
index 06e70c2a8..6fadb88ce 100644
--- a/src/wire/plugin_wire_template.c
+++ b/src/wire-plugins/plugin_wire_template.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2016 GNUnet e.V.
+ 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
@@ -33,14 +33,14 @@ struct TemplateClosure
{
/**
- * URL of the bank for sending funds to the bank.
+ * Which currency do we support?
*/
- char *bank_url;
+ char *currency;
/**
- * Which currency do we support?
+ * Which configuration do we use to lookup accounts?
*/
- char *currency;
+ struct GNUNET_CONFIGURATION_Handle *cfg;
};
@@ -74,42 +74,17 @@ template_amount_round (void *cls,
/**
- * Obtain wire transfer details in the plugin-specific format
- * from the configuration.
- *
- * @param cls closure
- * @param cfg configuration with details about wire accounts
- * @param account_name which section in the configuration should we parse
- * @return NULL if @a cfg fails to have valid wire details for @a account_name
- */
-static json_t *
-template_get_wire_details (void *cls,
- const struct GNUNET_CONFIGURATION_Handle *cfg,
- const char *account_name)
-{
- GNUNET_break (0);
- return NULL;
-}
-
-
-/**
- * Check if the given wire format JSON object is correctly formatted
+ * 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 wire the JSON wire format object
- * @param master_pub public key of the exchange to verify against
- * @param[out] emsg set to an error message, unless we return #TALER_EC_NONE;
- * error message must be freed by the caller using GNUNET_free()
+ * @param account_url the payto:// URL
* @return #TALER_EC_NONE if correctly formatted
*/
static enum TALER_ErrorCode
template_wire_validate (void *cls,
- const json_t *wire,
- const struct TALER_MasterPublicKeyP *master_pub,
- char **emsg)
+ const char *account_url)
{
- GNUNET_asprintf (emsg,
- "Not implemented");
+ GNUNET_break (0);
return TALER_EC_NOT_IMPLEMENTED;
}
@@ -118,7 +93,9 @@ template_wire_validate (void *cls,
* Prepare for exeuction of a wire transfer.
*
* @param cls the @e cls of this struct with the plugin-specific state
- * @param wire valid wire account information
+ * @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
@@ -128,7 +105,8 @@ template_wire_validate (void *cls,
*/
static struct TALER_WIRE_PrepareHandle *
template_prepare_wire_transfer (void *cls,
- const json_t *wire,
+ 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,
@@ -178,28 +156,6 @@ template_execute_wire_transfer (void *cls,
/**
- * Sign wire transfer details in the plugin-specific format.
- *
- * @param cls closure
- * @param in wire transfer details in JSON format
- * @param key private signing key to use
- * @param salt salt to add
- * @param[out] sig where to write the signature
- * @return #GNUNET_OK on success
- */
-static int
-template_sign_wire_details (void *cls,
- const json_t *in,
- const struct TALER_MasterPrivateKeyP *key,
- const struct GNUNET_HashCode *salt,
- struct TALER_MasterSignatureP *sig)
-{
- GNUNET_break (0);
- return GNUNET_SYSERR;
-}
-
-
-/**
* 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
@@ -230,6 +186,8 @@ template_execute_wire_transfer_cancel (void *cls,
* (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)`.
@@ -241,6 +199,7 @@ template_execute_wire_transfer_cancel (void *cls,
*/
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,
@@ -268,6 +227,59 @@ template_get_history_cancel (void *cls,
/**
+ * 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)
+{
+ 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)
+{
+ GNUNET_break (0);
+ return NULL;
+}
+
+
+/**
* Initialize template-wire subsystem.
*
* @param cls a configuration instance
@@ -281,19 +293,7 @@ libtaler_plugin_wire_template_init (void *cls)
struct TALER_WIRE_Plugin *plugin;
tc = GNUNET_new (struct TemplateClosure);
-
- if (GNUNET_OK !=
- GNUNET_CONFIGURATION_get_value_string (cfg,
- "exchange-wire-template",
- "bank_url",
- &tc->bank_url))
- {
- GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
- "exchange-wire-template",
- "bank_url");
- GNUNET_free (tc);
- return NULL;
- }
+ tc->cfg = cfg;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_string (cfg,
"taler",
@@ -303,16 +303,14 @@ libtaler_plugin_wire_template_init (void *cls)
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler",
"CURRENCY");
- GNUNET_free (tc->bank_url);
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->get_wire_details = &template_get_wire_details;
- plugin->sign_wire_details = &template_sign_wire_details;
plugin->wire_validate = &template_wire_validate;
plugin->prepare_wire_transfer = &template_prepare_wire_transfer;
plugin->prepare_wire_transfer_cancel = &template_prepare_wire_transfer_cancel;
@@ -320,6 +318,8 @@ libtaler_plugin_wire_template_init (void *cls)
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;
}
@@ -336,7 +336,6 @@ libtaler_plugin_wire_template_done (void *cls)
struct TALER_WIRE_Plugin *plugin = cls;
struct TemplateClosure *tc = plugin->cls;
- GNUNET_free (tc->bank_url);
GNUNET_free (tc->currency);
GNUNET_free (tc);
GNUNET_free (plugin);
diff --git a/src/wire-plugins/test_ebics_wireformat.c b/src/wire-plugins/test_ebics_wireformat.c
new file mode 100644
index 000000000..46989d503
--- /dev/null
+++ b/src/wire-plugins/test_ebics_wireformat.c
@@ -0,0 +1,80 @@
+/*
+ This file is part of TALER
+ (C) 2015, 2016, 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_ebics_wireformat.c
+ * @brief Tests for SEPA format validation by the EBICS plugin
+ * @author Sree Harsha Totakura <sreeharsha@totakura.in>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_wire_lib.h"
+
+
+/**
+ * Valid SEPA data
+ */
+static const char *valid_wire_str = "payto://sepa/DE67830654080004822650";
+
+/**
+ * IBAN has wrong country code
+ */
+static const char *invalid_wire_str = "payto://sepa/XX67830654080004822650";
+
+/**
+ * IBAN has wrong checksum
+ */
+static const char *invalid_wire_str2 = "payto://sepa/DE67830654080004822651";
+
+/**
+ * Unsupported wireformat type
+ */
+static const char *unsupported_wire_str = "payto://sega/DE67830654080004822650";
+
+
+int
+main (int argc,
+ const char *const argv[])
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ struct TALER_WIRE_Plugin *plugin;
+
+ GNUNET_log_setup ("test-sepa-wireformats",
+ "WARNING",
+ NULL);
+ cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_CONFIGURATION_set_value_string (cfg,
+ "taler",
+ "currency",
+ "EUR");
+ plugin = TALER_WIRE_plugin_load (cfg,
+ "ebics");
+ GNUNET_assert (NULL != plugin);
+ GNUNET_assert (TALER_EC_NONE !=
+ plugin->wire_validate (plugin->cls,
+ unsupported_wire_str));
+ GNUNET_assert (TALER_EC_NONE !=
+ plugin->wire_validate (plugin->cls,
+ invalid_wire_str));
+ GNUNET_assert (TALER_EC_NONE !=
+ plugin->wire_validate (plugin->cls,
+ invalid_wire_str2));
+ GNUNET_assert (TALER_EC_NONE ==
+ plugin->wire_validate (plugin->cls,
+ valid_wire_str));
+ TALER_WIRE_plugin_unload (plugin);
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return 0;
+}
diff --git a/src/wire/test_wire_plugin.c b/src/wire-plugins/test_wire_plugin.c
index f5dba01aa..0e149dde7 100644
--- a/src/wire/test_wire_plugin.c
+++ b/src/wire-plugins/test_wire_plugin.c
@@ -24,7 +24,6 @@
#include "taler_wire_lib.h"
#include "taler_wire_plugin.h"
#include <gnunet/gnunet_json_lib.h>
-#include <jansson.h>
/**
@@ -38,11 +37,6 @@ struct TestBlock {
const char *plugin_name;
/**
- * JSON template expected by the plugin for an account definition.
- */
- const char *json_proto;
-
- /**
* Amount to give to the rounding function.
*/
const char *round_in;
@@ -54,7 +48,7 @@ struct TestBlock {
/**
* Currency to give to the plugin.
- */
+ */
const char *currency;
};
@@ -65,36 +59,24 @@ struct TestBlock {
*/
static struct TestBlock tests[] = {
{
- .plugin_name = "sepa",
- .json_proto = "{ \"type\":\"sepa\", \"iban\":\"DE67830654080004822650\", \"name\":\"GNUnet e.V.\", \"bic\":\"GENODEF1SLR\" }",
+ .plugin_name = "ebics",
.round_in = "EUR:0.123456",
.round_out = "EUR:0.12",
.currency = "EUR"
},
{
- .plugin_name = "test",
- .json_proto = "{ \"type\":\"test\", \"bank_url\":\"http://localhost/\", \"account_number\":42 }",
+ .plugin_name = "taler_bank",
.round_in = "KUDOS:0.123456",
.round_out = "KUDOS:0.12",
.currency = "KUDOS"
},
{
- NULL, NULL, NULL, NULL, NULL
+ NULL, NULL, NULL, NULL
}
};
/**
- * Private key used to sign wire details.
- */
-static struct TALER_MasterPrivateKeyP priv_key;
-
-/**
- * Public key matching #priv_key.
- */
-static struct TALER_MasterPublicKeyP pub_key;
-
-/**
* Our configuration.
*/
static struct GNUNET_CONFIGURATION_Handle *cfg;
@@ -105,73 +87,19 @@ static struct GNUNET_CONFIGURATION_Handle *cfg;
*
* @param test details of the test
* @param plugin plugin to test
- * @param wire wire details for testing
* @return #GNUNET_OK on success
*/
static int
run_test (const struct TestBlock *test,
- struct TALER_WIRE_Plugin *plugin,
- json_t *wire)
+ struct TALER_WIRE_Plugin *plugin)
{
struct GNUNET_HashCode salt;
- struct TALER_MasterSignatureP sig;
- json_t *lwire;
struct TALER_Amount in;
struct TALER_Amount expect;
- char *emsg;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
&salt,
sizeof (salt));
- if (GNUNET_OK !=
- plugin->sign_wire_details (plugin->cls,
- wire,
- &priv_key,
- &salt,
- &sig))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- json_object_set_new (wire,
- "salt",
- GNUNET_JSON_from_data (&salt,
- sizeof (salt)));
- json_object_set_new (wire,
- "sig",
- GNUNET_JSON_from_data (&sig,
- sizeof (sig)));
- if (TALER_EC_NONE !=
- plugin->wire_validate (plugin->cls,
- wire,
- &pub_key,
- &emsg))
- {
- GNUNET_break (0);
- GNUNET_free (emsg);
- return GNUNET_SYSERR;
- }
- /* load wire details from file */
- lwire = plugin->get_wire_details (plugin->cls,
- cfg,
- test->plugin_name);
- if (NULL == lwire)
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
- if (TALER_EC_NONE !=
- plugin->wire_validate (plugin->cls,
- lwire,
- &pub_key,
- &emsg))
- {
- GNUNET_break (0);
- GNUNET_free (emsg);
- json_decref (lwire);
- return GNUNET_SYSERR;
- }
- json_decref (lwire);
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (test->round_in,
&in));
@@ -214,12 +142,9 @@ int
main (int argc,
const char *const argv[])
{
- json_t *wire;
int ret;
struct TALER_WIRE_Plugin *plugin;
const struct TestBlock *test;
- unsigned int i;
- struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
GNUNET_log_setup ("test-wire-plugin",
"WARNING",
@@ -228,13 +153,8 @@ main (int argc,
GNUNET_assert (GNUNET_OK ==
GNUNET_CONFIGURATION_load (cfg,
"test_wire_plugin.conf"));
- pk = GNUNET_CRYPTO_eddsa_key_create_from_file ("test_wire_plugin_key.priv");
- priv_key.eddsa_priv = *pk;
- GNUNET_free (pk);
- GNUNET_CRYPTO_eddsa_key_get_public (&priv_key.eddsa_priv,
- &pub_key.eddsa_pub);
ret = GNUNET_OK;
- for (i=0;NULL != (test = &tests[i])->plugin_name;i++)
+ for (unsigned int i=0;NULL != (test = &tests[i])->plugin_name;i++)
{
GNUNET_CONFIGURATION_set_value_string (cfg,
"taler",
@@ -243,10 +163,7 @@ main (int argc,
plugin = TALER_WIRE_plugin_load (cfg,
test->plugin_name);
GNUNET_assert (NULL != plugin);
- wire = json_loads (test->json_proto, 0, NULL);
- GNUNET_assert (NULL != wire);
- ret = run_test (test, plugin, wire);
- json_decref (wire);
+ ret = run_test (test, plugin);
TALER_WIRE_plugin_unload (plugin);
if (GNUNET_OK != ret)
{
diff --git a/src/wire/test_wire_plugin.conf b/src/wire-plugins/test_wire_plugin.conf
index 90b4f0749..d1d699b0f 100644
--- a/src/wire/test_wire_plugin.conf
+++ b/src/wire-plugins/test_wire_plugin.conf
@@ -1,21 +1,25 @@
# This file is in the public domain.
#
-[test]
+[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.
-TEST_RESPONSE_FILE = test_wire_plugin_test.json
+WIRE_JSON = test_wire_plugin_test.json
-[sepa]
+# 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.
-SEPA_RESPONSE_FILE = test_wire_plugin_sepa.json
+WIRE_JSON = test_wire_plugin_sepa.json
+# Which wire plugin should we used to access the account?
+PLUGIN = ebics
-[exchange-wire-test]
-# For transfers made by the exchange, we need to know
-# the URL of the bank (where the /admin/add/incoming API
-# is avaialble).
-BANK_URL = http://localhost/
[taler]
CURRENCY = "EUR"
diff --git a/src/wire/test_wire_plugin_transactions_test.c b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c
index ccfde1b40..06aef8aa1 100644
--- a/src/wire/test_wire_plugin_transactions_test.c
+++ b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2015, 2016, 2017 GNUnet e.V. and Inria
+ (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
@@ -14,8 +14,8 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
- * @file wire/test_wire_plugin_transactions_test.c
- * @brief Tests performing actual transactions with the TEST wire plugin against FAKEBANK
+ * @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"
@@ -24,7 +24,6 @@
#include "taler_wire_plugin.h"
#include "taler_fakebank_lib.h"
#include <gnunet/gnunet_json_lib.h>
-#include <jansson.h>
/**
@@ -35,21 +34,14 @@
/**
- * Input for the wire transfer details.
+ * Destination account to use.
*/
-static const char *json_proto =
- "{ \"type\":\"test\", \"bank_url\":\"http://localhost:8088/\", \"account_number\":42 }";
-
+static const char *dest_account = "payto://x-taler-bank/localhost:8088/42";
/**
- * Private key used to sign wire details.
+ * Origin account, section in the configuration file.
*/
-static struct TALER_MasterPrivateKeyP priv_key;
-
-/**
- * Public key matching #priv_key.
- */
-static struct TALER_MasterPublicKeyP pub_key;
+static const char *my_account = "account-test";
/**
* Our configuration.
@@ -250,6 +242,7 @@ confirmation_cb (void *cls,
}
serial_target = serial_id;
hh = plugin->get_history (plugin->cls,
+ my_account,
TALER_BANK_DIRECTION_BOTH,
NULL, 0,
5,
@@ -294,7 +287,6 @@ prepare_cb (void *cls,
static void
run (void *cls)
{
- json_t *wire;
struct TALER_Amount amount;
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
@@ -308,18 +300,15 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount ("KUDOS:5.01",
&amount));
- wire = json_loads (json_proto,
- 0,
- NULL);
fb = TALER_FAKEBANK_start (8088);
ph = plugin->prepare_wire_transfer (plugin->cls,
- wire,
+ my_account,
+ dest_account,
&amount,
"https://exchange.net/",
&wtid,
&prepare_cb,
NULL);
- json_decref (wire);
}
@@ -327,23 +316,16 @@ int
main (int argc,
const char *const argv[])
{
- struct GNUNET_CRYPTO_EddsaPrivateKey *pk;
-
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_test.conf"));
- pk = GNUNET_CRYPTO_eddsa_key_create_from_file ("test_wire_plugin_key.priv");
- priv_key.eddsa_priv = *pk;
- GNUNET_free (pk);
- GNUNET_CRYPTO_eddsa_key_get_public (&priv_key.eddsa_priv,
- &pub_key.eddsa_pub);
+ "test_wire_plugin_transactions_taler-bank.conf"));
global_ret = GNUNET_OK;
plugin = TALER_WIRE_plugin_load (cfg,
- "test");
+ "taler_bank");
GNUNET_assert (NULL != plugin);
GNUNET_SCHEDULER_run (&run,
NULL);
@@ -353,4 +335,4 @@ main (int argc,
return 0;
}
-/* end of test_wire_plugin_transactions_test.c */
+/* 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
new file mode 100644
index 000000000..d6d2e8346
--- /dev/null
+++ b/src/wire-plugins/test_wire_plugin_transactions_taler-bank.conf
@@ -0,0 +1,12 @@
+# 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 5f651461e..9fcf877f9 100644
--- a/src/wire/Makefile.am
+++ b/src/wire/Makefile.am
@@ -8,114 +8,15 @@ endif
pkgcfgdir = $(prefix)/share/taler/config.d/
-pkgcfg_DATA = \
- wire-sepa.conf \
- wire-test.conf
-
-
-EXTRA_DIST = \
- wire-sepa.conf \
- wire-test.conf \
- test_wire_plugin.conf \
- test_wire_plugin_transactions_test.conf \
- test_wire_plugin_key.priv \
- test_wire_plugin_test.json \
- test_wire_plugin_sepa.json
-
-plugindir = $(libdir)/taler
-
-plugin_LTLIBRARIES = \
- libtaler_plugin_wire_sepa.la \
- libtaler_plugin_wire_test.la
-
-noinst_LTLIBRARIES = \
- libtaler_plugin_wire_template.la
-
lib_LTLIBRARIES = \
libtalerwire.la
-
-libtaler_plugin_wire_test_la_SOURCES = \
- plugin_wire_test.c
-libtaler_plugin_wire_test_la_LIBADD = \
- $(LTLIBINTL)
-libtaler_plugin_wire_test_la_LDFLAGS = \
- $(TALER_PLUGIN_LDFLAGS) \
- $(top_builddir)/src/bank-lib/libtalerbank.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetcurl \
- -lgnunetutil $(XLIB)
-
-
-libtaler_plugin_wire_sepa_la_SOURCES = \
- plugin_wire_sepa.c
-libtaler_plugin_wire_sepa_la_LIBADD = \
- $(LTLIBINTL)
-libtaler_plugin_wire_sepa_la_LDFLAGS = \
- $(TALER_PLUGIN_LDFLAGS) \
- $(top_builddir)/src/json/libtalerjson.la \
- $(top_builddir)/src/util/libtalerutil.la \
- -lgnunetjson \
- -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)
-
-
libtalerwire_la_SOURCES = \
- wire.c
+ wire.c \
+ wire_helper.c
libtalerwire_la_LIBADD = \
-lgnunetutil \
$(XLIB)
libtalerwire_la_LDFLAGS = \
-version-info 1:0:0 \
-export-dynamic -no-undefined
-
-
-AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH;
-
-TESTS = \
- test_sepa_wireformat \
- test_wire_plugin
-
-check_PROGRAMS= \
- test_sepa_wireformat \
- test_wire_plugin \
- test_wire_plugin_transactions_test
-
-
-test_sepa_wireformat_SOURCES = \
- test_sepa_wireformat.c
-test_sepa_wireformat_LDADD = \
- -lgnunetutil \
- -ljansson \
- libtalerwire.la \
- $(top_builddir)/src/util/libtalerutil.la
-
-
-test_wire_plugin_SOURCES = \
- test_wire_plugin.c
-test_wire_plugin_LDADD = \
- -lgnunetjson \
- -lgnunetutil \
- -ljansson \
- libtalerwire.la \
- $(top_builddir)/src/util/libtalerutil.la
-
-
-test_wire_plugin_transactions_test_SOURCES = \
- test_wire_plugin_transactions_test.c
-test_wire_plugin_transactions_test_LDADD = \
- -lgnunetjson \
- -lgnunetutil \
- -ljansson \
- libtalerwire.la \
- $(top_builddir)/src/bank-lib/libtalerfakebank.la \
- $(top_builddir)/src/util/libtalerutil.la
diff --git a/src/wire/test_sepa_wireformat.c b/src/wire/test_sepa_wireformat.c
deleted file mode 100644
index 07a3784c6..000000000
--- a/src/wire/test_sepa_wireformat.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- This file is part of TALER
- (C) 2015, 2016 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/test_sepa_wireformat.c
- * @brief Tests for JSON SEPA format validation
- * @author Sree Harsha Totakura <sreeharsha@totakura.in>
- */
-
-#include "platform.h"
-#include "taler_util.h"
-#include "taler_wire_lib.h"
-
-
-/* Valid SEPA data */
-static const char * const valid_wire_str =
- "{ \"type\":\"SEPA\", \
-\"iban\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"salt\":\"123456789\", \
-\"address\": \"foobar\"}";
-
-/* IBAN has wrong country code */
-static const char * const invalid_wire_str =
- "{ \"type\":\"SEPA\", \
-\"iban\":\"XX67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"salt\":\"123456789\", \
-\"address\": \"foobar\"}";
-
-/* IBAN has wrong checksum */
-static const char * const invalid_wire_str2 =
- "{ \"type\":\"SEPA\", \
-\"iban\":\"DE67830654080004822651\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"salt\":\"123456789\", \
-\"address\": \"foobar\"}";
-
-/* Unsupported wireformat type */
-static const char * const unsupported_wire_str =
- "{ \"type\":\"unsupported\", \
-\"iban\":\"DE67830654080004822650\", \
-\"name\":\"GNUnet e.V.\", \
-\"bic\":\"GENODEF1SLR\", \
-\"salt\":\"123456789\", \
-\"address\": \"foobar\"}";
-
-
-int
-main(int argc,
- const char *const argv[])
-{
- json_t *wire;
- char *emsg;
- json_error_t error;
- int ret;
- struct GNUNET_CONFIGURATION_Handle *cfg;
- struct TALER_WIRE_Plugin *plugin;
-
- GNUNET_log_setup ("test-sepa-wireformats",
- "WARNING",
- NULL);
- cfg = GNUNET_CONFIGURATION_create ();
- GNUNET_CONFIGURATION_set_value_string (cfg,
- "taler",
- "currency",
- "EUR");
- plugin = TALER_WIRE_plugin_load (cfg,
- "sepa");
- GNUNET_assert (NULL != plugin);
- (void) memset(&error, 0, sizeof(error));
- GNUNET_assert (NULL != (wire = json_loads (unsupported_wire_str, 0, NULL)));
- GNUNET_assert (TALER_EC_NONE != plugin->wire_validate (NULL,
- wire,
- NULL,
- &emsg));
- GNUNET_free (emsg);
- json_decref (wire);
- GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str, 0, NULL)));
- GNUNET_assert (TALER_EC_NONE != plugin->wire_validate (NULL,
- wire,
- NULL,
- &emsg));
- GNUNET_free (emsg);
- json_decref (wire);
- GNUNET_assert (NULL != (wire = json_loads (invalid_wire_str2, 0, NULL)));
- GNUNET_assert (TALER_EC_NONE != plugin->wire_validate (NULL,
- wire,
- NULL,
- &emsg));
- GNUNET_free (emsg);
- json_decref (wire);
- GNUNET_assert (NULL != (wire = json_loads (valid_wire_str, 0, &error)));
- ret = plugin->wire_validate (NULL,
- wire,
- NULL,
- &emsg);
- json_decref (wire);
- TALER_WIRE_plugin_unload (plugin);
- GNUNET_CONFIGURATION_destroy (cfg);
- if (TALER_EC_NONE != ret)
- return 1;
- return 0;
-}
diff --git a/src/wire/test_wire_plugin_key.priv b/src/wire/test_wire_plugin_key.priv
deleted file mode 100644
index 26b4f26f6..000000000
--- a/src/wire/test_wire_plugin_key.priv
+++ /dev/null
@@ -1 +0,0 @@
-?Sgb@Js; %aKȉs_Hў \ No newline at end of file
diff --git a/src/wire/test_wire_plugin_sepa.json b/src/wire/test_wire_plugin_sepa.json
deleted file mode 100644
index 175345f0c..000000000
--- a/src/wire/test_wire_plugin_sepa.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "salt": "32V01R7K4T02S74PZZMVXRQ1K7FR948RBNB9BJ5Z101HEQFH7CW7J82006GY3BPTGQ4FM775PSSRD3K9MY97HSNVVCGEVBPVSAQ2710",
- "type": "sepa",
- "iban": "DE67830654080004822650",
- "sig": "K48GPPM715ZXX0DC597WESD5ECT3R0B3TAFQMB68SBF4K5CZ5KCE9NESN1JX412SPZ82PSV7JAPVJFXDDTZ63YV4295S5RC28E4221G",
- "name": "GNUnet e.V.",
- "bic": "GENODEF1SLR"
-} \ No newline at end of file
diff --git a/src/wire/test_wire_plugin_test.json b/src/wire/test_wire_plugin_test.json
deleted file mode 100644
index e5a0c3329..000000000
--- a/src/wire/test_wire_plugin_test.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "type": "test",
- "bank_url": "http://localhost/",
- "sig": "KX1CMHNFH1WE10244AEF07AXHJCF9PZDZVNZBC9P4EJEQ1MH1Y3C2TWF08VTQMK4N5TCV0V1VTGWSV0WB8TB9YQRZW87F5A6KCEZ81R",
- "account_number": 42,
- "salt": "EZV905MQPVAZEMGC6SEZQF2Z75P6ZKTN8TX00JHN11S7J81DQ78G8Z551K6TGR9WHPP0JW1X9J9X9CVRY48JTHBCP6Q4XKJ6R2G18G0"
-}
diff --git a/src/wire/test_wire_plugin_transactions_test.conf b/src/wire/test_wire_plugin_transactions_test.conf
deleted file mode 100644
index 42fb51b79..000000000
--- a/src/wire/test_wire_plugin_transactions_test.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-# This file is in the public domain.
-#
-[test]
-# This is the response we give out for the /wire request. It provides
-# wallets with the bank information for transfers to the exchange.
-TEST_RESPONSE_FILE = test_wire_plugin_test.json
-
-[exchange-wire-test]
-# For transfers made by the exchange, we need to know
-# the URL of the bank (where the /admin/add/incoming API
-# is avaialble).
-BANK_URL= http://localhost:8088/
-
-[taler]
-CURRENCY = "KUDOS"
diff --git a/src/wire/wire-sepa.conf b/src/wire/wire-sepa.conf
deleted file mode 100644
index eb43d3dcc..000000000
--- a/src/wire/wire-sepa.conf
+++ /dev/null
@@ -1,15 +0,0 @@
-# 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
-
-# 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}/exchange/wire/sepa.json
-
-[exchange-wire-outgoing-sepa]
-# This section should contain the options required for making outgoing
-# SEPA transfers. Not yet supported (need libebics).
diff --git a/src/wire/wire-test.conf b/src/wire/wire-test.conf
deleted file mode 100644
index 7ee217ee1..000000000
--- a/src/wire/wire-test.conf
+++ /dev/null
@@ -1,22 +0,0 @@
-# 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
-
-# This is the response we give out for the /wire request. It provides
-# wallets with the bank information for transfers to the exchange.
-TEST_RESPONSE_FILE = ${TALER_CONFIG_HOME}/exchange/wire/test.json
-
-# We need to know the exchange's account number at the bank.
-EXCHANGE_ACCOUNT_NUMBER = 2
-
-# For accessing transfers, we need to know
-# the URL of the bank (where the /history API is available).
-# BANK_URL = https://bank.demo.taler.net/
-
-# Authentication information for basic authentication
-USERNAME = user
-PASSWORD = pass
diff --git a/src/wire/wire.c b/src/wire/wire.c
index 58180b7b1..aeb8689e6 100644
--- a/src/wire/wire.c
+++ b/src/wire/wire.c
@@ -146,80 +146,4 @@ 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 = &section[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 */
diff --git a/src/wire/wire_helper.c b/src/wire/wire_helper.c
new file mode 100644
index 000000000..34d40e11e
--- /dev/null
+++ b/src/wire/wire_helper.c
@@ -0,0 +1,57 @@
+/*
+ This file is part of TALER
+ (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 wire/wire_helper.c
+ * @brief Helper functions for dealing with wire formats
+ * @author Christian Grothoff <christian@grothoff.org>
+ */
+#include "platform.h"
+#include "taler_util.h"
+#include "taler_wire_lib.h"
+
+/**
+ * Prefix of PAYTO URLs.
+ */
+#define PAYTO "payto://"
+
+
+/**
+ * Obtain the payment method from a @a payto_url
+ *
+ * @param payto_url the URL to parse
+ * @return NULL on error (malformed @a payto_url)
+ */
+char *
+TALER_WIRE_payto_get_method (const char *payto_url)
+{
+ const char *start;
+ const char *end;
+
+ if (0 != strncmp (payto_url,
+ PAYTO,
+ strlen (PAYTO)))
+ return NULL;
+ start = &payto_url[strlen(PAYTO)];
+ end = strchr (start,
+ (unsigned char) '/');
+ if (NULL == end)
+ return NULL;
+ return GNUNET_strndup (start,
+ end - start);
+}
+
+/* end of wire_helper.c */