summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2018-04-02 14:24:45 +0200
committerChristian Grothoff <christian@grothoff.org>2018-04-02 14:29:44 +0200
commitcb55c1a3af9f56a6da38e5589e72df0b70d355b1 (patch)
tree5f9a3af7d9073249f77ce56c690844a6cb27c3e7
parent7a20062bafed42f937c5388aed09042aad7014c0 (diff)
downloadexchange-cb55c1a3af9f56a6da38e5589e72df0b70d355b1.tar.gz
exchange-cb55c1a3af9f56a6da38e5589e72df0b70d355b1.tar.bz2
exchange-cb55c1a3af9f56a6da38e5589e72df0b70d355b1.zip
Changing configuration structure to enable multiple accounts.
This change enables using multiple wire plugins at the same time. Also, we now distinguish between the wire plugin (i.e. EBICS or taler_bank) and the wire method (i.e. SEPA or x-taler-bank) that the wire plugin is implementing. The "taler-bank" wire method was renamed from "test" to "x-taler-bank". This also changes the format of the /wire response of the exchange, as we now need to return multiple accounts. Note that wire fees are specified per wire method, not per wire account. taler-exchange-keyup now automatically signs all of the /wire responses in the location specified by the configuration. Account identification in wire plugins was changed to use payto://-URLs instead of method-specific JSON fields. Signing and validation of /wire responses was moved from each wire plugin to a generic validation method in libtalerutil (crypto) or libtalerjson (for JSON-formatted inputs). Convenience methods were added to generate JSON for wire accounts (salting, signing). Various section and option names were adjusted to streamline the configuration and make it more consistent overall. Documentation was updated as well.
-rw-r--r--.gitignore7
-rw-r--r--configure.ac1
-rw-r--r--contrib/exchange-template/config/exchange-common.conf103
-rw-r--r--doc/taler-exchange-wire.112
-rw-r--r--doc/taler-exchange.texi220
-rw-r--r--doc/taler.conf.5191
-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
110 files changed, 4387 insertions, 3378 deletions
diff --git a/.gitignore b/.gitignore
index daf85892..7acf2dcf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -59,10 +59,11 @@ src/exchange-tools/taler-exchange-wire
src/exchangedb/perf-exchangedb
src/benchmark/taler-exchange-benchmark
src/benchmark/test_benchmark_home/.local/share/taler/exchange/live-keys/
+src/benchmark/test_benchmark_home/.local/share/taler/exchange/wirefees/
src/json/test_json
-src/wire/test_sepa_wireformat
-src/wire/test_wire_plugin
-src/wire/test_wire_plugin_transactions_test
+src/wire-plugins/test_ebics_wireformat
+src/wire-plugins/test_wire_plugin
+src/wire-plugins/test_wire_plugin_transactions_taler_bank
src/pq/test_pq
src/util/test_amount
src/util/test_crypto
diff --git a/configure.ac b/configure.ac
index 0f760e2e..fedc2cd5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -536,5 +536,6 @@ AC_CONFIG_FILES([Makefile
src/util/Makefile
src/util/taler-config
src/wire/Makefile
+ src/wire-plugins/Makefile
])
AC_OUTPUT
diff --git a/contrib/exchange-template/config/exchange-common.conf b/contrib/exchange-template/config/exchange-common.conf
index 47782651..425bb92b 100644
--- a/contrib/exchange-template/config/exchange-common.conf
+++ b/contrib/exchange-template/config/exchange-common.conf
@@ -17,27 +17,98 @@ TESTRUN = YES
[exchangedb-postgres]
DB_CONN_STR = "postgres:///talercheck"
+[auditordb-postgres]
+DB_CONN_STR = "postgres:///talercheck"
-[exchange-wire-sepa]
-# Change here to enable SEPA wire transfers.
-ENABLE = NO
-# Response for /wire
-SEPA_RESPONSE_FILE = "sepa.json"
+# Provide account information
+[account-1]
+# Accounts must have a payto:// URL
+URL = payto://METHOD/DETAILS
+
+# To be included in /wire, accounts must have a signed wire file
+# Must match URL.
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-1.json
+
+# For access to the account, we need to know the plugin.
+PLUGIN = "ebics"
-[exchange-wire-outgoing-sepa]
-# TBD
+# TBD: authentication data.
+# Accounts need to be enabled for the aggregator to debit them.
+ENABLE_DEBIT = NO
-[exchange-wire-test]
-# Change here to disable TEST wire transfers.
-ENABLE = YES
+# Accounts need to be enabled for the wirewatcher to look for credits into them.
+ENABLE_CREDIT = YES
+
+[account-2]
+URL = payto://x-taler-wire/bank/2
# Response for /wire
-TEST_RESPONSE_FILE = "test.json"
+# Must match URL.
+WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json
+
+PLUGIN = taler_bank
+
+# We also may need authentication data.
+TALER_BANK_AUTH_METHOD = "none" # or basic
+# TALER_BANK_USERNAME = user
+# TALER_BANK_PASSWORD = pass
+
+# Accounts need to be enabled for the aggregator to debit them.
+ENABLE_DEBIT = YES
+
+# Accounts need to be enabled for the wirewatcher to look for credits into them.
+ENABLE_CREDIT = YES
+
+
+# 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
+
+[fees-sepa]
+# 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
-# What is the main website of the bank?
-BANK_URL = "https://bank/"
-# Into which account at the 'bank' should incoming
-# wire transfers be made?
-BANK_ACCOUNT_NUMBER = 2
+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
diff --git a/doc/taler-exchange-wire.1 b/doc/taler-exchange-wire.1
index 546d8eb7..256daab7 100644
--- a/doc/taler-exchange-wire.1
+++ b/doc/taler-exchange-wire.1
@@ -1,4 +1,4 @@
-.TH TALER\-EXCHANGE\-WIRE 1 "Apr 2, 2016" "GNU Taler"
+.TH TALER\-EXCHANGE\-WIRE 1 "Mar 18, 2018" "GNU Taler"
.SH NAME
taler\-exchange\-wire \- Create the master-key signed responses to /wire.
@@ -13,18 +13,8 @@ taler\-exchange\-wire \- Create the master-key signed responses to /wire.
.SH OPTIONS
.B
-.IP "\-j JSON, \-\-json=JSON"
-Gives JSON with all of the relevant account details in a method-specific format.
-.B
-.IP "\-t METHOD, \-\-type=METHOD"
-Specifies the wire transfer method to use. Common are 'test' and 'sepa'.
-.B
.IP "\-m MASTERKEYFILE, \-\-master=MASTERKEYFILE"
Specifies the name of the file containing the exchange's master key.
-.B
-.IP "\-o FILENAME, \-\-output=FILENAME"
-Where to write the SEPA_RESPONSE_FILE.
-.B
.IP "\-h, \-\-help"
Print short help on options.
.B
diff --git a/doc/taler-exchange.texi b/doc/taler-exchange.texi
index 9f5fd103..72efe391 100644
--- a/doc/taler-exchange.texi
+++ b/doc/taler-exchange.texi
@@ -13,7 +13,7 @@ This manual is for the GNU Taler Exchange
(version @value{VERSION}, @value{UPDATED}),
a payment service provider for GNU Taler.
-Copyright @copyright{} 2014-2017 GNUnet e.V. and INRIA
+Copyright @copyright{} 2014-2018 Taler Systems SA
@quotation
Permission is granted to copy, distribute and/or modify this document
@@ -260,7 +260,7 @@ GNU libunistring @geq{} 0.9.3
libcurl @geq{} 7.26 (or libgnurl @geq{} 7.26)
@item
-GNU libmicrohttpd @geq{} 0.9.52
+GNU libmicrohttpd @geq{} 0.9.59
@item
GNU libgcrypt @geq{} 1.6
@@ -354,6 +354,8 @@ description of some of the options.
The exchange works with three types of keys:
+@c FIXME: explain better!
+
@itemize
@item
@@ -366,34 +368,18 @@ The exchange works with three types of keys:
@cite{denomination keys} (see section @cite{Coins})
@end itemize
-@cite{master key}: in section @cite{[exchange]}, edit the two following values:
-
+@c FIXME: text here.
@itemize
-
@item
-@cite{master_priv_file}: Path to the exchange's master private file.
+@cite{MASTER_PRIV_FILE}: Path to the exchange's master private file.
@item
-@cite{master_public_key}: Must specify the exchange's master public key.
+@cite{MASTER_PUBLIC_KEY}: Must specify the exchange's master public key.
@end itemize
-@cite{sign keys}: the following two options under
-@cite{[exchange_keys]} section control @cite{sign keys}:
-
-@itemize
-
-@item
-@cite{signkey_duration}: How long should one signing key be used?
-@item
-@cite{lookahead_sign}: How much time we want to cover with our
-@cite{signkeys}? Note that if @cite{signkey_duration} is bigger than
-@cite{lookahead_sign}, @cite{taler-exchange-keyup} will generate a
-quantity of @cite{signkeys} which is sufficient to cover all the
-gap. See keys-duration.
-@end itemize
@node Serving
@@ -436,99 +422,148 @@ option @cite{currency} in section @cite{[taler]}.
@node Bank account
@section Bank account
-@menu
-* Wiremethod-test::
-* Wiremethod-sepa::
-@end menu
+To configure a bank account in Taler, we need to furnish four
+pieces of information:
+@itemize
+@item
+ The @code{payto://} URL of the bank account, which uniquely idenfies
+ the account. Examples for such URLs include
+ @code{payto://sepa/CH9300762011623852957} for a bank account
+ in the single European payment area (SEPA) or
+ @code{payto://x-taler-bank/localhost:8080/2} for the 2nd bank
+ account a the Taler bank demonstrator running at @code{localhost}
+ on port 8080. The first part of the URL following @code{payto://}
+ (``sepa'' or ``x-taler-bank'') is called the wire method.
+@item
+ A matching wire plugin that implements a protocol to interact
+ with the banking system. For example, the EBICS plugin can
+ be used for SEPA transfers, or the ``taler-bank'' plugin can
+ interact with the Taler bank demonstrator. A wire plugin
+ only supports one particular wire method. Thus, you must make
+ sure to pick a plugin that supports the wire method used in the
+ URL.
+@item
+ A file containing the signed JSON-encoded bank account details
+ for the /wire API. This is necessary as Taler supports offline
+ signing for bank accounts for additional security.
+@item
+ Finally, the plugin needs to be provided resources for
+ authentication to the respective banking service. The format
+ in which the authentication information must be provided
+ depends on the wire plugin.
+@end itemize
-@node Wiremethod-test
-@subsection Wiremethod-test
+You can configure multiple accounts for an exchange by creating
+sections starting with ``account-'' for the section name. You can
+ENABLE for each account whether it should be used, and for what
+(incoming or outgoing wire transfers):
-To enable the wire transfer method ``test'', you need to set
-``ENABLE=YES'' in section @cite{[exchange-wire-test]}.
+@setsyntax ini
+@example
+
+[account-1]
+URL = "payto://sepa/CH9300762011623852957"
+WIRE_RESPONSE = $@{TALER_CONFIG_HOME@}/account-1.json
+PLUGIN = ebics
-The bank account where the exchange gets money from customers is
-configured under the section @cite{[exchange-wire-test]}. It must
-contain the options ``EXCHANGE_ACCOUNT_NO'' and ``BANK_URL''.
-For basic authentication, it must additionally contain the
-``USERNAME'' and ``PASSWORD'' of the exchange's account at the bank.
+# Use for exchange-aggregator (outgoing transfers)
+ENABLE_DEBIT = YES
+# Use for exchange-wirewatch (and listed in /wire)
+ENABLE_CREDIT = YES
-For incoming transfers, the section must additional contain the
-option: @cite{test_response_file}, which takes
-the path to a text file containing the exchange's bank account details
-in JSON format.
+# ... add authentication options here
+@end example
-The command line tool @cite{taler-exchange-wire} is used to create such a file.
-For example, the utility may be invoked as follows:
+The command line tool @cite{taler-exchange-wire} is used to create
+the @code{account-1.json} file.
+For example, the utility may be invoked as follows to create
+all of the WIRE_RESPONSE files (in the locations specified by the configuration):
@example
-$ taler-exchange-wire -j '@{"name": "The Exchange", "account_number":
-10, "bank_url": "https://bank.demo.taler.net", "type": "test"@}' -t
-test -o exchange.json
+$ taler-exchange-wire
@end example
-Note that the value given to option @cite{-t} must match the value in
-the JSON's field @code{"type"}.
-
The generated file will be echoed by the exchange when serving
/wire@footnote{https://api.taler.net/api-exchange.html#wire-req}
requests.
-@node Wiremethod-sepa
-@subsection Wiremethod-sepa
+@menu
+* Wire plugin ``taler_bank''::
+* Wire plugin ``ebics''::
+* Wire fee structure::
+@end menu
-To enable the wire transfer method ``sepa'', you need to set
-``ENABLE=YES'' in section @cite{[exchange-wire-sepa]}.
+@node Wire plugin ``taler_bank''
+@subsection Wire plugin ``taler_bank''
+@cindex x-taler-bank
+@cindex taler_bank plugin
+The @code{taler_bank} plugin implements the wire method ``x-taler-bank''.
-This section contains only one option: @cite{sepa_response_file},
-which takes the path to a text file containing the exchange's bank
-account details in JSON format.
+The format of the @code{payto://} URL is @code{payto://x-taler-bank/HOSTNAME:PORT},
+possibly followed by other parameters like the amount and wire transfer subject
+as per the @code{payto://} standard.
-The command line tool @cite{taler-exchange-wire} is used to create such a file.
-For example, the utility may be invoked as follows:
+For basic authentication, the @code{taler_bank} plugin only supports
+simple password-based authentication. For this, the configuration
+must contain the ``USERNAME'' and ``PASSWORD'' of the respective
+account at the bank.
+@setsyntax ini
@example
-$ taler-exchange-wire -j '@{"name": "The Exchange", "account_number":
-10, "bank_url": "https://bank.demo.taler.net", "type": "sepa"@}' -t
-sepa -o exchange.json
+[account-2]
+URL = "payto://test/localhost:8080"
+USERNAME = exchange
+PASSWORD = super-secure
@end example
-Note that the value given to option @cite{-t} must match the value in the JSON's field @code{"type"}.
-
-The generated file will be echoed by the exchange when serving
-/wire@footnote{https://api.taler.net/api-exchange.html#wire-req}
-requests.
-
-This exchange's outgoing bank account is used to give money to merchants, after
-successful
-deposits@footnote{https://api.taler.net/api-exchange.html#deposit-par}
-operations. The outgoing bank account is configured by the following
-options under @cite{[exchange-wire-outgoing-sepa]}: (NOT YET SUPPORTED).
-@quotation
-
-
-@itemize
+@node Wire plugin ``ebics''
+@subsection Wire plugin ``ebics''
-@item
-@cite{exchange_account_numer}: which bank account number has the exchange
+The ``ebics'' wire plugin is not fully implemented and today
+does not support actual wire transfers.
-@item
-@cite{bank_url}: base URL of the bank hosting the exchange bank account
-@end itemize
-@end quotation
@cartouche
@quotation Note
-The rationale behind having two bank accounts is that the exchange operator, as a security
+The rationale behind having multiple bank accounts is that the exchange operator, as a security
measure, may want to instruct the bank that the incoming bank account is only supposed to
@emph{receive} money.
@end quotation
@end cartouche
+@node Wire fee structure
+@subsection Wire fee structure
+@cindex wire fee
+@cindex fee
+
+For each wire method (``sepa'' or ``x-taler-wire'', but not per plugin!) the
+exchange configuration must specify applicable wire fees. This is done
+in configuration sections of the format @code{fee-METHOD}. There are two
+types of fees, simple wire fees and closing fees. Wire fees apply whenever
+the aggregator transfers funds to a merchant. Closing fees apply whenever
+the exchange closes a reserve (sending back funds to the customer). The
+fees must be constant for a full year, which is specified as part of the name
+of the option.
+
+@setsyntax ini
+@example
+[fee-iban]
+WIRE-FEE-2018 = EUR:0.01
+WIRE-FEE-2019 = EUR:0.01
+CLOSING-FEE-2018 = EUR:0.01
+CLOSING-FEE-2019 = EUR:0.01
+
+[fee-x-taler-bank]
+WIRE-FEE-2018 = KUDOS:0.01
+WIRE-FEE-2019 = KUDOS:0.01
+CLOSING-FEE-2018 = KUDOS:0.01
+CLOSING-FEE-2019 = KUDOS:0.01
+@end example
+
@node Database
@section Database
@@ -546,18 +581,18 @@ possible in two ways:
via an environment variable: @cite{TALER_EXCHANGEDB_POSTGRES_CONFIG}.
@item
-via configuration option @cite{db_conn_str}, under section @cite{[exchangedb-BACKEND]}. For example, the demo exchange is configured as follows:
+via configuration option @cite{CONFIG}, under section @cite{[exchangedb-BACKEND]}. For example, the demo exchange is configured as follows:
@end itemize
@setsyntax ini
@example
[exchange]
...
-db = postgres
+DB = postgres
...
[exchangedb-postgres]
-db_conn_str = postgres:///talerdemo
+CONFIG = postgres:///talerdemo
@end example
@node Coins denomination keys
@@ -639,6 +674,25 @@ key will get a starting time of @cite{t}, and the @cite{j}-th key will
get a starting time of @cite{x + duration_withdraw}, where @cite{x} is
the starting time of the @cite{(j-1)}-th key.
+To change these settings, edit the following
+values in section @cite{[exchange]}:
+
+@itemize
+@item
+@cite{SIGNKEY_DURATION}: How long should one signing key be used?
+
+@item
+@cite{LOOKAHEAD_SIGN}: How much time we want to cover with our
+signing keys? Note that if @cite{SIGNKEY_DURATION} is bigger than
+@cite{LOOKAHEAD_SIGN}, @code{taler-exchange-keyup} will generate a
+quantity of signing keys which is sufficient to cover all the
+gap.
+@end itemize
+
+@c FIXME: LEGAL_DURATION not covered!
+@c FIXME: LOOKAHEAD_PROVIDE not covered!
+
+
@node Deployment
@chapter Deployment
diff --git a/doc/taler.conf.5 b/doc/taler.conf.5
index 40a9506e..07d13f19 100644
--- a/doc/taler.conf.5
+++ b/doc/taler.conf.5
@@ -1,4 +1,4 @@
-.TH TALER.CONF 5 "Apr 11, 2016" "GNU Taler"
+.TH TALER.CONF 5 "Mar 20, 2018" "GNU Taler"
.SH NAME
taler.conf \- Taler configuration file.
@@ -10,46 +10,174 @@ taler.conf \- Taler configuration file.
The basic structure of the configuration file is the following. The file is split into sections. Every section begins with "[SECTIONNAME]" and contains a number of options of the form "OPTION=VALUE". Empty lines and lines beginning with a "#" are treated as comments. Files containing default values for many of the options described below are installed under $TALER\_PREFIX/share/taler/config.d/. The configuration file given with \-c to Taler binaries overrides these defaults.
-.SH EXCHANGE OPTIONS
+.SH GLOBAL OPTIONS
-The following options are from the "[exchange]" section and used by most exchange tools:
+The following options are from the "[taler]" section and used by virtually all Taler components.
.IP CURRENCY
Name of the currency, i.e. "EUR" for Euro.
+
+The "[PATHS]" section is special in that it contains paths that can be referenced using "$" in other configuration values that specify filenames. For Taler, it commonly contains the following paths:
+
+.IP TALER_HOME
+ Home directory of the user, usually "${HOME}". Can be overwritten by testcases by setting ${TALER_TEST_HOME}.
+.IP TALER_DATA_HOME
+ Where should Taler store its long-term data. Usually "${TALER_HOME}/.local/share/taler/"
+.IP TALER_CONFIG_HOME
+ Where is the Taler configuration kept. Usually "${TALER_HOME}/.config/taler/"
+.IP TALER_CACHE_HOME
+ Where should Taler store cached data. Usually "${TALER_HOME}/.cache/taler/"
+.IP TALER_RUNTIME_DIR
+ Where should Taler store system runtime data (like UNIX domain sockets). Usually "${TMP}/taler-system-runtime".
+
+.SH EXCHANGE OPTIONS
+
+The following options are from the "[exchange]" section and used by most exchange tools:
+
.IP DB
Plugin to use for the database, i.e. "postgres"
.IP PORT
Port on which the HTTP server listens, i.e. 8080.
.IP MASTER_PUBLIC_KEY
Crockford Base32-encoded master public key, public version of the exchange\'s long\-time offline signing key.
+.IP MASTER_PRIV_FILE
+ Location of the master private key on disk. Only used by tools that can be run offline (as the master key is for offline signing).
+.IP BASE_URL
+ Specifies the base URL under which the exchange can be reached. Added to wire transfers to enable tracking by merchants.
+.IP SIGNKEY_DURATION
+ For how long is a signing key valid?
+.IP LEGAL_DURATION
+ For how long are signatures with signing keys legally valid?
+.IP LOOKAHEAD_SIGN
+ How long do we generate denomination and signing keys ahead of time?
+.IP LOOKAHEAD_PROVIDE
+ How long into the future do we provide signing and denomination keys to clients?
+
-.SH WIRE transfer details
+.SH EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
-To enable the "test" wire transfer method, you must set "ENABLE = YES" in "[exchange\-wire\-test]".
-Then, the following options must be in section "[exchange\-wire\-incoming\-test]" and "[exchange\-wire\-outgoing\-test]":
+The following options must be in section "[exchangedb\-postgres]" if the "postgres" plugin was selected for the database:
-.IP BANK_URI
- URL of the Taler bank.
+.IP CONFIG
+ How to access the database, i.e. "postgres:///taler" to use the "taler" database. Testcases use "talercheck".
-.IP BANK_ACCOUNT_NUMBER
- Number of the bank account of the exchange.
-To enable the "sepa" wire transfer method, you must set "ENABLE = YES" in "[exchange\-wire\-sepa]".
-Then, the following options must be in section "[exchange\-wire\-incoming\-sepa]" and "[exchange\-wire\-outgoing\-sepa]":
+.SH MERCHANT OPTIONS
-.IP SEPA_RESPONSE_FILE
- Filename with the JSON body for the /wire response, signed using the exchange\'s long-term offline master key. Use taler\-exchange\-sepa to create the SEPA_RESPONSE_FILE.
+The following options are from the "[merchant]" section and used by the merchant backend:
+.IP DB
+ Plugin to use for the database, i.e. "postgres"
+.IP PORT
+ Port on which the HTTP server listens, i.e. 8080.
+.IP WIRE_TRANSFER_DELAY
+ How quickly do we want the exchange to send us money? Note that wire transfer fees will be higher if we ask for money to be wired often. Given as a relative time, i.e. "5 s"
+.IP DEFAULT_MAX_WIRE_FEE
+ Maximum wire fee we are willing to accept from exchanges. Given as a Taler amount, i.e. "EUR:0.1"
+.IP DEFAULT_MAX_DEPOSIT_FEE
+ Maximum deposit fee we are willing to cover. Given as a Taler amount, i.e. "EUR:0.1"
-.SH Postgres database options
-The following options must be in section "[exchangedb\-postgres]":
+.SH MERCHANT POSTGRES BACKEND DATABASE OPTIONS
-.IP DB_CONN_STR
+The following options must be in section "[merchantdb\-postgres]" if the "postgres" plugin was selected for the database:
+
+.IP CONFIG
How to access the database, i.e. "postgres:///taler" to use the "taler" database. Testcases use "talercheck".
-.SH COIN OPTIONS
+.SH MERCHANT INSTANCES
+
+The merchant configuration must specify a set of instances, containing at least the "default" instance. The following options must be given in each "[instance-NAME]" section:
+
+.IP KEYFILE
+ Name of the file where the instance\'s private key is to be stored, i.e. "${TALER_CONFIG_HOME}/merchant/instance/name.priv"
+.IP NAME
+ Human-readable name of the instance, i.e. "Kudos Inc."
+
+Additionally, for instances that support tipping, the following options are required:
+
+.IP TIP_EXCHANGE
+ Base-URL of the exchange that holds the reserve for tipping, i.e. "https://exchange.demo.taler.net/"
+.IP TIP_EXCHANGE_PRIV_FILENAME
+ Filename with the private key granting access to the reserve, i.e. "${TALER_CONFIG_HOME}/merchant/reserve/tip.priv"
+
+
+.SH KNOWN EXCHANGES (for merchants and wallets)
+
+The merchant configuration can include a list of known exchanges if the merchant wants to specify that certain exchanges are explicitly trusted. For each trusted exchange, a section [exchange-NAME] must exist, where NAME is a merchant-given name for the exchange. The following options must be given in each "[exchange-NAME]" section:
+
+.IP BASE_URL
+ Base URL of the exchange, i.e. "https://exchange.demo.taler.net/"
+.IP MASTER_KEY
+ Crockford Base32 encoded master public key, public version of the exchange\'s long\-time offline signing key
+.IP CURRENCY
+ Name of the currency for which this exchange is trusted, i.e. "KUDOS"
+
+
+.SH KNOWN AUDITORS (for merchants and wallets)
+
+The merchant configuration can include a list of known exchanges if the merchant wants to specify that certain auditors are explicitly trusted. For each trusted exchange, a section [auditor-NAME] must exist, where NAME is a merchant-given name for the exchange. The following options must be given in each "[auditor-NAME]" section:
+
+.IP BASE_URL
+ Base URL of the auditor, i.e. "https://auditor.demo.taler.net/"
+.IP AUDITOR_KEY
+ Crockford Base32 encoded auditor public key.
+.IP CURRENCY
+ Name of the currency for which this auditor is trusted, i.e. "KUDOS"
+
+
+
+.SH ACCOUNT OPTIONS (for exchanges and merchants)
+
+An exchange (or merchant) can have multiple bank accounts. The following options are for sections named "[account-SOMETHING]". The SOMETHING is arbitrary and should be chosen to uniquely identify the bank account for the operator. Additional authentication options may need to be specified in the account section depending on the PLUGIN used.
+
+.IP URL
+ Specifies the payto://-URL of the account. The general format is payto://METHOD/DETAILS. This option is used for exchanges and merchants.
+.IP WIRE_RESPONSE
+ Specifies the name of the file in which the /wire response for this account should be located. Used by the Taler exchange service and the taler\-exchange\-wire tool and the taler\-merchant\-httpd (to generate the files).
+.IP PLUGIN
+ Name of the plugin can be used to access the account (i.e. "taler-bank" or "ebics"). Used by the merchant backend for back office operations (i.e. to identify incoming wire transfers) and by the exchange.
+.IP ENABLE_DEBIT
+ Must be set to YES for the accounts that the taler\-exchange\-aggregator should debit. Not used by merchants.
+.IP ENABLE_CREDIT
+ Must be set to YES for the accounts that the taler\-exchange\-wirewatch should check for credits. (It is yet uncertain if the merchant implementation may check this flag as well.)
+.IP HONOR_instance
+ Must be set to YES for the instances (where "instance" is the section name of the instance) of the merchant backend that should allow incoming wire transfers for this bank account.
+.IP ACTIVE_instance
+ Must be set to YES for the instances (where "instance" is the section name of the instance) of the merchant backend that should use this bank account in new offers/contracts. Setting ACTIVE_instance to YES requires also setting ENABLE_instance to YES.
+
+
+.SH TALER-BANK AUTHENTICATION OPTIONS (for accounts)
+
+The following authentication options are supported by the "taler-bank" wire plugin. They must be specified in the "[account-]" section that uses the "taler-bank" plugin.
+
+.IP TALER_BANK_AUTH_METHOD
+ Authentication method to use. "none" or "basic" are currently supported.
+.IP USERNAME
+ Username to use for authentication. Used with the "basic" authentication method.
+.IP PASSWORD
+ Password to use for authentication. Used with the "basic" authentication method.
+
+.SH EBICS AUTHENTICATION OPTIONS
+
+The following authentication options are supported by the "ebics" wire plugin. They must be specified in the "[account-]" section that uses the "ebics" plugin.
+
+.IP NONE
+ Currently the "ebics" implementation is incomplete and does not support authentication.
+
+
+.SH EXCHANGE WIRE FEE OPTIONS
+
+For each supported wire method (i.e. "x-taler-bank" or "sepa"), sections named "[fees-METHOD]" state the (aggregate) wire transfer fee and the reserve closing fees charged by the exchange. Note that fees are specified using the name of the wire method, not by the plugin name. You need to replace "YEAR" in the option name by the calendar year for which the fee should apply. Usually, fees should be given for serveral years in advance.
+
+.IP WIRE-FEE-YEAR
+ Aggregate wire transfer fee merchants are charged in YEAR. Specified as a Taler amount using the usual amount syntax (CURRENCY:VALUE.FRACTION).
+.IP CLOSING-FEE-YEAR
+ Reserve closing fee customers are charged in YEAR. Specified as a Taler amount using the usual amount syntax (CURRENCY:VALUE.FRACTION).
+
+
+.SH EXCHANGE COIN OPTIONS
The following options must be in sections starting with "[coin_]" and are used by taler\-exchange\-keyup to create denomination keys:
@@ -72,22 +200,27 @@ The following options must be in sections starting with "[coin_]" and are used b
.IP RSA_KEYSIZE
What is the RSA keysize modulos (in bits)?
-.SH KEY OPTIONS
-The following options are from the "[exchange_keys]" section and used by most taler\-exchange\-keyup to create keys:
+.SH AUDITOR OPTIONS
-.IP SIGNKEY_DURATION
- For how long is a signing key valid?
-.IP LEGAL_DURATION
- For how long are signatures with signing keys legally valid?
-.IP LOOKAHEAD_SIGN
- How long do we generate denomination and signing keys ahead of time?
-.IP LOOKAHEAD_PROVIDE
- How long into the future do we provide signing and denomination keys to clients?
+The following options must be in section "[auditor]" for the Taler auditor:
+
+.IP DB
+ Plugin to use for the database, i.e. "postgres"
+.IP AUDITOR_PRIV_FILE
+ Name of the file containing the auditor's private key
+
+
+.SH AUDITOR POSTGRES BACKEND DATABASE OPTIONS
+
+The following options must be in section "[auditordb\-postgres]" if the "postgres" plugin was selected for the database:
+
+.IP CONFIG
+ How to access the database, i.e. "postgres:///taler" to use the "taler" database. Testcases use "talercheck".
.SH BUGS
Report bugs by using Mantis <https://gnunet.org/bugs/> or by sending electronic mail to <taler@gnu.org>
.SH "SEE ALSO"
-\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-reservemod\fP(1), \fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-sepa(1)
+\fBtaler\-exchange\-httpd\fP(1), \fBtaler\-exchange\-keyup\fP(1), \fBtaler\-exchange\-dbinit\fP(1), \fBtaler\-exchange\-wire(1)
diff --git a/src/Makefile.am b/src/Makefile.am
index 2f158a1d..d2c92554 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 b8f6c624..f5d185cf 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 55a2a05f..d9c2d820 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 4fe2064f..9a6d3988 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 2f881ae2..13fbbc2f 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 5c1e7fbc..fd8ffbfd 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 abe820a6..9f2740b2 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 f6e4e7fe..9befeba9 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 d2035e88..17cd9fd0 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 00000000..04cf7b85
--- /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 1a70f571..002010b2 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 40adea54..e503bd8d 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 30090bf8..e94009fb 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 c01c27d8..2eb6d4f9 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 fbdfe825..3fd31eda 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 453782c7..88767385 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 5e0833b3..57c93508 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 76e3e4da..7e499a43 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 72429d4e..86a83fdb 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 f1056fdd..12789b2b 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 fe387779..7ca74a22 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 7d8761f9..8c8bd7ef 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 00000000..48093f2a
--- /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 00000000..85d80de5
--- /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 00000000..9445f048
--- /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 38b95282..7193bf11 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 3becf3d6..29290c99 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 c3e1ce85..a33f8d01 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 6f66e8ad..5854bf8b 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 1ff466f5..fd8404be 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 3a750e7f..65665c9c 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 a092ee2d..35cb20d2 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 3f14c511..638329d6 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 f65daec0..cf8304e2 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 a942b652..3aff0a3c 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 00000000..40dddbfa
--- /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 1b1b4221..fb5af93e 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 8d00415c..2c1ff0f4 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 3146f09b..00000000
--- 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 5e069af5..9842a37a 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 60244f15..390c0e5e 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 e54fe493..b0fe0a0f 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 39c496ec..5b9ff9be 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 49cbb2b9..fa76cfb0 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 277430b2..8bf47717 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 c7874ed1..99ee08a8 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 493febc2..429c86f3 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 bef6aec5..7daa18aa 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 d910da74..a0d0795f 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 69b800ff..bbbf3fb4 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 72dd2198..48f82bef 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 e0985366..cabfac7f 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 a5f35196..c2c8aef1 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 cc614fc8..7f8cc479 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 0335bcd4..f22e6381 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 7df8d9b2..743dbfed 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 f88f4206..48fd8eec 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 7cd2e276..9c9ef40e 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 69502d9d..8c1210da 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 66299d78..03322f8c 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 3de7474f..5ebd656c 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 00000000..275e9267
--- /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 e2591c88..5cde719c 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 4efec391..789aaea0 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 8a81befd..43891e55 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 e4b83249..8344974b 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 6c633055..140bceb2 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 926e2997..d0afc535 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 36f0cce4..a112af24 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 80974cca..cc583e8e 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 bfa05033..1cad5710 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 d45e7bb2..b22c55ce 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 1a20889d..dbde04df 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 30ea4ce6..22ca049e 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 e4284c27..b89dd087 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 33677559..0d6f9cd9 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 6d019ecc..0504ddfb 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 c281d21f..f1148beb 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 3914208f..dce92cea 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 68c36e88..0cf38d6d 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 c0e29609..2758d2d2 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 d26f731a..4b40e94b 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 00000000..f0bd1757
--- /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 4f9a6367..89b31ebb 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 00000000..494573ff
--- /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 00000000..9f6029d7
--- /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 416acac7..9aad9df0 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 11feaea7..2d223534 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 06e70c2a..6fadb88c 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 00000000..46989d50
--- /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 f5dba01a..0e149dde 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 90b4f074..d1d699b0 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 ccfde1b4..06aef8aa 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 00000000..d6d2e834
--- /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 5f651461..9fcf877f 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 07a3784c..00000000
--- 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 26b4f26f..00000000
--- 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 175345f0..00000000
--- 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 e5a0c332..00000000
--- 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 42fb51b7..00000000
--- 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 eb43d3dc..00000000
--- 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 7ee217ee..00000000
--- 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 58180b7b..aeb8689e 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 00000000..34d40e11
--- /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 */