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.
This commit is contained in:
parent
7a20062baf
commit
cb55c1a3af
7
.gitignore
vendored
7
.gitignore
vendored
@ -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
|
||||
|
@ -536,5 +536,6 @@ AC_CONFIG_FILES([Makefile
|
||||
src/util/Makefile
|
||||
src/util/taler-config
|
||||
src/wire/Makefile
|
||||
src/wire-plugins/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
@ -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
|
||||
|
||||
# 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"
|
||||
|
||||
# TBD: authentication data.
|
||||
|
||||
# Accounts need to be enabled for the aggregator to debit them.
|
||||
ENABLE_DEBIT = NO
|
||||
|
||||
# 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
|
||||
SEPA_RESPONSE_FILE = "sepa.json"
|
||||
# Must match URL.
|
||||
WIRE_RESPONSE = ${TALER_CONFIG_HOME}/account-2.json
|
||||
|
||||
[exchange-wire-outgoing-sepa]
|
||||
# TBD
|
||||
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
|
||||
|
||||
|
||||
[exchange-wire-test]
|
||||
# Change here to disable TEST wire transfers.
|
||||
ENABLE = 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
|
||||
|
||||
# Response for /wire
|
||||
TEST_RESPONSE_FILE = "test.json"
|
||||
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
|
||||
|
||||
# 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
|
||||
[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
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
@item
|
||||
@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
|
||||
|
||||
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
|
||||
|
||||
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):
|
||||
|
||||
@setsyntax ini
|
||||
@example
|
||||
|
||||
[account-1]
|
||||
URL = "payto://sepa/CH9300762011623852957"
|
||||
WIRE_RESPONSE = $@{TALER_CONFIG_HOME@}/account-1.json
|
||||
PLUGIN = ebics
|
||||
|
||||
# Use for exchange-aggregator (outgoing transfers)
|
||||
ENABLE_DEBIT = YES
|
||||
# Use for exchange-wirewatch (and listed in /wire)
|
||||
ENABLE_CREDIT = YES
|
||||
|
||||
# ... add authentication options here
|
||||
@end example
|
||||
|
||||
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
|
||||
@end example
|
||||
|
||||
The generated file will be echoed by the exchange when serving
|
||||
/wire@footnote{https://api.taler.net/api-exchange.html#wire-req}
|
||||
requests.
|
||||
|
||||
|
||||
@menu
|
||||
* Wiremethod-test::
|
||||
* Wiremethod-sepa::
|
||||
* Wire plugin ``taler_bank''::
|
||||
* Wire plugin ``ebics''::
|
||||
* Wire fee structure::
|
||||
@end menu
|
||||
|
||||
@node Wiremethod-test
|
||||
@subsection Wiremethod-test
|
||||
@node Wire plugin ``taler_bank''
|
||||
@subsection Wire plugin ``taler_bank''
|
||||
@cindex x-taler-bank
|
||||
@cindex taler_bank plugin
|
||||
|
||||
To enable the wire transfer method ``test'', you need to set
|
||||
``ENABLE=YES'' in section @cite{[exchange-wire-test]}.
|
||||
The @code{taler_bank} plugin implements the wire method ``x-taler-bank''.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
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": "test"@}' -t
|
||||
test -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.
|
||||
@node Wire plugin ``ebics''
|
||||
@subsection Wire plugin ``ebics''
|
||||
|
||||
The ``ebics'' wire plugin is not fully implemented and today
|
||||
does not support actual wire transfers.
|
||||
|
||||
@node Wiremethod-sepa
|
||||
@subsection Wiremethod-sepa
|
||||
|
||||
To enable the wire transfer method ``sepa'', you need to set
|
||||
``ENABLE=YES'' in section @cite{[exchange-wire-sepa]}.
|
||||
|
||||
|
||||
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 command line tool @cite{taler-exchange-wire} is used to create such a file.
|
||||
For example, the utility may be invoked as follows:
|
||||
|
||||
@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
|
||||
@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
|
||||
|
||||
@item
|
||||
@cite{exchange_account_numer}: which bank account number has the exchange
|
||||
|
||||
@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
|
||||
|
||||
|
203
doc/taler.conf.5
203
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 GLOBAL OPTIONS
|
||||
|
||||
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 CURRENCY
|
||||
Name of the currency, i.e. "EUR" for Euro.
|
||||
.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
|
||||
|
||||
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]":
|
||||
.SH EXCHANGE POSTGRES BACKEND DATABASE OPTIONS
|
||||
|
||||
.IP BANK_URI
|
||||
URL of the Taler bank.
|
||||
The following options must be in section "[exchangedb\-postgres]" if the "postgres" plugin was selected for the database:
|
||||
|
||||
.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]":
|
||||
|
||||
.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.
|
||||
|
||||
|
||||
.SH Postgres database options
|
||||
|
||||
The following options must be in section "[exchangedb\-postgres]":
|
||||
|
||||
.IP DB_CONN_STR
|
||||
.IP CONFIG
|
||||
How to access the database, i.e. "postgres:///taler" to use the "taler" database. Testcases use "talercheck".
|
||||
|
||||
.SH COIN OPTIONS
|
||||
|
||||
.SH MERCHANT OPTIONS
|
||||
|
||||
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 MERCHANT POSTGRES BACKEND DATABASE OPTIONS
|
||||
|
||||
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 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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
@ -1773,11 +1773,6 @@ struct WireCheckContext
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute date;
|
||||
|
||||
/**
|
||||
* Wire method used for the transfer.
|
||||
*/
|
||||
const char *method;
|
||||
|
||||
/**
|
||||
* Database transaction status.
|
||||
*/
|
||||
@ -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,25 +2395,22 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&wcc.h_wire))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -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,7 +3429,7 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (receiver_wire_account,
|
||||
&dr.h_wire))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
|
@ -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().
|
||||
*/
|
||||
@ -50,11 +89,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.
|
||||
*/
|
||||
@ -103,11 +137,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.
|
||||
*/
|
||||
@ -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,8 +653,12 @@ wire_out_cb (void *cls,
|
||||
amount));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (! json_equal ((json_t *) wire,
|
||||
roi->details.account_details))
|
||||
{
|
||||
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
|
||||
@ -613,8 +687,11 @@ wire_out_cb (void *cls,
|
||||
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))
|
||||
{
|
||||
@ -764,6 +841,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}",
|
||||
@ -1266,6 +1354,167 @@ history_credit_cb (void *cls,
|
||||
/* ***************************** Setup logic ************************ */
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -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,
|
||||
TALER_EXCHANGEDB_find_accounts (cfg,
|
||||
&process_account_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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,3 @@
|
||||
[auditordb-postgres]
|
||||
# Argument for Postgres for how to connect to the database.
|
||||
DB_CONN_STR = "postgres:///taler"
|
||||
CONFIG = "postgres:///taler"
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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"
|
||||
|
@ -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 \
|
||||
|
@ -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/
|
||||
|
@ -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;
|
||||
|
133
src/bank-lib/bank_api_parse.c
Normal file
133
src/bank-lib/bank_api_parse.c
Normal file
@ -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 */
|
@ -210,7 +210,8 @@ 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,
|
||||
|
@ -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",
|
||||
GNUNET_asprintf (&h[total].details.account_url,
|
||||
"payto://x-taler-bank/%s/%llu",
|
||||
"http://localhost:8080",
|
||||
"account_number",
|
||||
(json_int_t) pos->details.admin_add_incoming.debit_account_no);
|
||||
GNUNET_assert (NULL != h[total].details.account_details);
|
||||
(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",
|
||||
GNUNET_asprintf (&h[total].details.account_url,
|
||||
"payto://x-taler-bank/%s/%llu",
|
||||
"http://localhost:8080",
|
||||
"account_number",
|
||||
(json_int_t) pos->details.admin_add_incoming.credit_account_no);
|
||||
GNUNET_assert (NULL != h[total].details.account_details);
|
||||
(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);
|
||||
|
@ -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",
|
||||
GNUNET_asprintf (&h[total].details.account_url,
|
||||
"payto://x-taler-bank/%s/%llu",
|
||||
hs->bank_url,
|
||||
"account_number",
|
||||
(json_int_t) *debit_account_no);
|
||||
GNUNET_assert (NULL != h[total].details.account_details);
|
||||
(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",
|
||||
GNUNET_asprintf (&h[total].details.account_url,
|
||||
"payto://x-taler-bank/%s/%llu",
|
||||
hs->bank_url,
|
||||
"account_number",
|
||||
(json_int_t) *credit_account_no);
|
||||
GNUNET_assert (NULL != h[total].details.account_details);
|
||||
(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);
|
||||
|
@ -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],
|
||||
|
@ -895,7 +895,7 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (merchant_details,
|
||||
&dr.h_wire));
|
||||
|
||||
dr.timestamp = GNUNET_TIME_absolute_hton (timestamp);
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
@ -416,7 +416,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
|
||||
MAH_handle_is_ready (exchange));
|
||||
/* initialize h_wire */
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_hash (wire_details,
|
||||
TALER_JSON_wire_signature_hash (wire_details,
|
||||
&h_wire))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
|
@ -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",
|
||||
×tamp),
|
||||
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,7 +361,7 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (rhistory[off].details.close_details.receiver_account_details,
|
||||
&rcc.h_wire))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* Set to the "methods" JSON array returned by the
|
||||
* /wire request.
|
||||
*/
|
||||
json_t *methods;
|
||||
|
||||
/**
|
||||
* Current iteration offset in the @e methods array.
|
||||
*/
|
||||
unsigned int methods_off;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Verify that the signature on the "200 OK" response
|
||||
* for /wire/METHOD from the exchange is valid.
|
||||
*
|
||||
* @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
|
||||
* List of wire fees by method.
|
||||
*/
|
||||
static int
|
||||
verify_wire_method_signature_ok (const struct TALER_EXCHANGE_WireHandle *wh,
|
||||
const char *method,
|
||||
const json_t *json)
|
||||
struct FeeMap
|
||||
{
|
||||
const struct TALER_EXCHANGE_Keys *key_state;
|
||||
struct TALER_WIRE_Plugin *plugin;
|
||||
char *lib_name;
|
||||
char *emsg;
|
||||
enum TALER_ErrorCode ec;
|
||||
/**
|
||||
* Next entry in list.
|
||||
*/
|
||||
struct FeeMap *next;
|
||||
|
||||
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)
|
||||
/**
|
||||
* Wire method this fee structure is for.
|
||||
*/
|
||||
char *method;
|
||||
|
||||
/**
|
||||
* Array of wire fees, also linked list, but allocated
|
||||
* only once.
|
||||
*/
|
||||
struct TALER_EXCHANGE_WireAggregateFees *fee_list;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Frees @a fm.
|
||||
*
|
||||
* @param fm memory to release
|
||||
*/
|
||||
static void
|
||||
free_fees (struct FeeMap *fm)
|
||||
{
|
||||
GNUNET_free (lib_name);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Wire transfer method `%s' not supported\n",
|
||||
method);
|
||||
return GNUNET_NO;
|
||||
while (NULL != fm)
|
||||
{
|
||||
struct FeeMap *fe = fm->next;
|
||||
|
||||
GNUNET_free (fm->fee_list);
|
||||
GNUNET_free (fm->method);
|
||||
GNUNET_free (fm);
|
||||
fm = fe;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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];
|
||||
}
|
||||
}
|
||||
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;
|
||||
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()
|
||||
};
|
||||
|
||||
/* 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;
|
||||
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;
|
||||
}
|
||||
if (0 != response_code)
|
||||
{
|
||||
/* all supported methods were valid, use 'keep' for 'json' */
|
||||
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 (0 == (num_accounts = json_array_size (accounts)))
|
||||
{
|
||||
/* bogus reply */
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
response_code = 0;
|
||||
ec = TALER_EC_SERVER_JSON_INVALID;
|
||||
break;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (NULL != wh->cb)
|
||||
wh->cb (wh->cb_cls,
|
||||
response_code,
|
||||
TALER_JSON_get_error_code (json),
|
||||
(NULL != keep) ? keep : json);
|
||||
if (NULL != keep)
|
||||
json_decref (keep);
|
||||
(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 */
|
||||
|
@ -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,7 +1772,7 @@ wire_deposits_cb (void *cls,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
NULL);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_JSON_hash (wire,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&hw));
|
||||
json_decref (wire);
|
||||
if (0 != memcmp (&hw,
|
||||
@ -2331,12 +2343,14 @@ 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,
|
||||
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);
|
||||
@ -2581,7 +2595,7 @@ interpreter_run (void *cls)
|
||||
NULL);
|
||||
GNUNET_assert (NULL != wire);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_JSON_hash (wire,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&h_wire));
|
||||
json_decref (wire);
|
||||
contract_terms = json_loads (ref->details.deposit.contract_terms,
|
||||
@ -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);
|
||||
|
@ -9,7 +9,6 @@ TALER_TEST_HOME = test_exchange_api_home/
|
||||
CURRENCY = EUR
|
||||
|
||||
[exchange]
|
||||
|
||||
# HTTP port the exchange listens to
|
||||
PORT = 8081
|
||||
|
||||
@ -23,55 +22,58 @@ DB = postgres
|
||||
# exchange (or the twister) is actually listening.
|
||||
BASE_URL = "http://localhost:8081/"
|
||||
|
||||
[exchangedb-postgres]
|
||||
DB_CONN_STR = "postgres:///talercheck"
|
||||
|
||||
[auditordb-postgres]
|
||||
DB_CONN_STR = "postgres:///talercheck"
|
||||
|
||||
[exchange-wire-sepa]
|
||||
# Enable 'sepa' to test SEPA-specific routines.
|
||||
ENABLE = YES
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
CLOSING-FEE-2017 = 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
|
||||
|
||||
[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
|
||||
[exchangedb-postgres]
|
||||
CONFIG = "postgres:///talercheck"
|
||||
|
||||
[auditordb-postgres]
|
||||
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
|
||||
|
||||
# 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.
|
||||
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
|
||||
@ -81,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
|
||||
@ -92,17 +94,35 @@ 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
|
||||
[fees-x-taler-bank]
|
||||
# Fees for the forseeable future...
|
||||
# If you see this after 2017, 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
|
||||
|
||||
# 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
|
||||
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"url": "payto://sepa/CH9300762011623852957",
|
||||
"salt": "N83T9J9202WCC8TQFDMJDWEGZNBEKA33C1ZM241VNYH88RZNTHPW509Y1M2YF7Y098R8VRESWQ05H03BK1SPAZCWE54KARDCKT5N8AG",
|
||||
"master_sig": "D4V5GJ998YK7D6N0N56AD0J6MZNFEW6MRZT2CFPVQ5ME3NMQ59AA2007CXYESSFGRN70CNCFM06858QSSENCWTZM8VHEJ93YQ20ZJ1R"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"url": "payto://x-taler-bank/localhost:8082/2",
|
||||
"salt": "TMXB995ZZVKA02AG4074X3C6XX0BFTHY8XK76EF4BSG5XVDF069FEBN4TCKW9GS7NKZH409GKAVHMQPA3T361MC6VM7J268V3GBH42R",
|
||||
"master_sig": "CK7BGHKYVAT7DMVCN00DQ0761NCTJVESZT69049BCF3SKNJKVHXXEQ5X6FH2HFGHCJ18YA1MGHBD8RRG4W3G4KJWQJDY2CGPGTHDJ2G"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"url": "payto://x-taler-bank/http://localhost:8082/2",
|
||||
"salt": "WGRD0W7YKD8ZAN960B0JBRARRY0K5FQ4920Q3DJBTYH4GY7W0XNAX1F04R5B1E0RWH1NFG08TM8K1517WNCXTJM9KMH4913Q5XPK0N8",
|
||||
"master_sig": "J4N0KP64MGNEQX9HST9TDWK67152MSHHM9CTZH8GSMKD607BXSAF209AQYDKYT6QJP0NQXYXC1JMM9Z405DJHGV75JFMWP4G6WB6A00"
|
||||
}
|
@ -23,52 +23,53 @@ DB = postgres
|
||||
# exchange (or the twister) is actually listening.
|
||||
BASE_URL = "http://localhost:8081/"
|
||||
|
||||
[exchangedb-postgres]
|
||||
DB_CONN_STR = "postgres:///talercheck"
|
||||
|
||||
[auditordb-postgres]
|
||||
DB_CONN_STR = "postgres:///talercheck"
|
||||
|
||||
[exchange-wire-sepa]
|
||||
# Enable 'sepa' to test SEPA-specific routines.
|
||||
ENABLE = YES
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
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
|
||||
|
||||
CLOSING-FEE-2017 = 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
|
||||
|
||||
[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
|
||||
|
||||
[exchangedb-postgres]
|
||||
CONFIG = "postgres:///talercheck"
|
||||
|
||||
[auditordb-postgres]
|
||||
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
|
||||
|
||||
# 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.
|
||||
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
|
||||
@ -93,15 +94,30 @@ 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
|
||||
[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
|
||||
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
|
||||
|
||||
CLOSING-FEE-2017 = 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
|
||||
|
||||
[coin_eur_ct_1]
|
||||
value = EUR:0.01
|
||||
|
@ -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
|
||||
|
@ -42,6 +42,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,8 +196,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
|
||||
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_OK),
|
||||
@ -208,8 +215,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (43,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
|
||||
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
|
||||
@ -225,8 +231,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (43,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\"value\":1}]}",
|
||||
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
|
||||
@ -236,8 +241,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (43,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\"value\":2}]}",
|
||||
GNUNET_TIME_UNIT_ZERO, "EUR:5", MHD_HTTP_FORBIDDEN),
|
||||
@ -277,8 +281,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\
|
||||
\"value\":\"EUR:1\"}]}",
|
||||
@ -318,8 +321,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\
|
||||
\"value\":3}]}",
|
||||
@ -331,8 +333,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (43,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\",\
|
||||
\"value\":3}]}",
|
||||
@ -463,8 +464,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\","
|
||||
"\"value\":\"EUR:5\"}]}",
|
||||
@ -502,8 +502,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"more ice cream\","
|
||||
"\"value\":\"EUR:5\"}]}",
|
||||
@ -555,8 +554,7 @@ 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}",
|
||||
TALER_TESTING_make_wire_details (42,
|
||||
fakebank_url),
|
||||
"{\"items\":[{\"name\":\"ice cream\","
|
||||
"\"value\":\"EUR:5\"}]}",
|
||||
@ -648,8 +646,7 @@ 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}",
|
||||
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,8 +667,7 @@ 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}",
|
||||
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,8 +681,7 @@ 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}",
|
||||
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
|
||||
|
@ -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;
|
||||
@ -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.
|
||||
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
@ -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)
|
||||
@ -455,6 +459,7 @@ TALER_TESTING_cmd_payback (const char *label,
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make a /revoke command.
|
||||
*
|
||||
|
@ -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);
|
||||
|
||||
|
@ -248,9 +248,8 @@ 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;
|
||||
@ -296,12 +295,10 @@ 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);
|
||||
@ -310,9 +307,11 @@ track_transaction_run (void *cls,
|
||||
|
||||
/* Should not fail here, json has been parsed already */
|
||||
GNUNET_assert
|
||||
( (GNUNET_OK == TALER_JSON_hash (j_wire_details,
|
||||
( (GNUNET_OK ==
|
||||
TALER_JSON_wire_signature_hash (wire_details,
|
||||
&h_wire_details)) &&
|
||||
(GNUNET_OK == TALER_JSON_hash (j_contract_terms,
|
||||
(GNUNET_OK ==
|
||||
TALER_JSON_hash (j_contract_terms,
|
||||
&h_contract_terms)) );
|
||||
|
||||
if (GNUNET_OK != TALER_TESTING_get_trait_peer_key
|
||||
@ -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,
|
||||
|
@ -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
|
||||
@ -70,19 +71,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,22 +102,42 @@ 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))
|
||||
if (MHD_HTTP_OK == http_status)
|
||||
{
|
||||
for (unsigned int i=0;i<accounts_len;i++)
|
||||
{
|
||||
char *method;
|
||||
|
||||
method = TALER_WIRE_payto_get_method (accounts[i].url);
|
||||
if (0 == strcmp (ws->expected_method,
|
||||
method))
|
||||
{
|
||||
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 extraction in command %s failed\n",
|
||||
"Wire fee missmatch to command %s\n",
|
||||
cmd->label);
|
||||
json_dumpf (obj, stderr, 0);
|
||||
TALER_TESTING_interpreter_fail (ws->is);
|
||||
GNUNET_free (method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ws->method_found != GNUNET_OK)
|
||||
}
|
||||
}
|
||||
}
|
||||
GNUNET_free (method);
|
||||
}
|
||||
if (GNUNET_OK != ws->method_found)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"/wire does not offer method '%s'\n",
|
||||
@ -140,50 +145,10 @@ wire_cb (void *cls,
|
||||
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)
|
||||
{
|
||||
if (0 != TALER_amount_cmp (&fees->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);
|
||||
return;
|
||||
}
|
||||
fees = fees->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the command.
|
||||
|
@ -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;
|
||||
char *payto;
|
||||
json_t *ret;
|
||||
|
||||
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);
|
||||
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))
|
||||
{
|
||||
|
76
src/exchange-lib/testing_api_trait_json.c
Normal file
76
src/exchange-lib/testing_api_trait_json.c
Normal file
@ -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 */
|
@ -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"
|
||||
@ -80,49 +79,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.
|
||||
*
|
||||
|
@ -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 \
|
||||
|
@ -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
|
@ -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 (§ion,
|
||||
"exchange-wire-%s",
|
||||
"fees-%s",
|
||||
wiremethod);
|
||||
GNUNET_asprintf (&fn,
|
||||
"%s%s.fee",
|
||||
@ -1045,6 +1048,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.
|
||||
@ -1057,8 +1097,8 @@ create_wire_fees ()
|
||||
int ret;
|
||||
|
||||
ret = GNUNET_OK;
|
||||
TALER_WIRE_find_enabled (kcfg,
|
||||
&create_wire_fee_for_method,
|
||||
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;
|
||||
|
@ -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,19 +35,9 @@
|
||||
static char *masterkeyfile;
|
||||
|
||||
/**
|
||||
* Account holder information in JSON format.
|
||||
* Private key for signing.
|
||||
*/
|
||||
static json_t *account_holder;
|
||||
|
||||
/**
|
||||
* Which wire method is this for?
|
||||
*/
|
||||
static char *method;
|
||||
|
||||
/**
|
||||
* Where to write the result.
|
||||
*/
|
||||
static char *output_filename;
|
||||
static struct TALER_MasterPrivateKeyP master_priv;
|
||||
|
||||
/**
|
||||
* Return value from main().
|
||||
@ -53,6 +45,56 @@ static char *output_filename;
|
||||
static int global_ret;
|
||||
|
||||
|
||||
/**
|
||||
* 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 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);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function that will be run.
|
||||
*
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
1
src/exchange/.gitignore
vendored
1
src/exchange/.gitignore
vendored
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,35 +30,35 @@
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
struct TALER_WIRE_Plugin *wire_plugin;
|
||||
|
||||
/**
|
||||
* Name of the plugin.
|
||||
*/
|
||||
char *type;
|
||||
|
||||
/**
|
||||
* Wire transfer fee structure.
|
||||
*/
|
||||
struct TALER_EXCHANGEDB_AggregateFees *af;
|
||||
|
||||
/**
|
||||
* Name of the section that configures this account.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (NULL == type)
|
||||
for (struct WireAccount *wa = wa_head; NULL != wa; wa = wa->next)
|
||||
if (0 == strcmp (method,
|
||||
wa->wire_plugin->method))
|
||||
return wa;
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
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,
|
||||
{
|
||||
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,
|
||||
|
@ -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,7 +448,7 @@ TEH_DEPOSIT_handler_deposit (struct TEH_RequestHandler *rh,
|
||||
"timestamp");
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_hash (wire,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&my_h_wire))
|
||||
{
|
||||
TALER_LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n");
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
||||
|
||||
@ -43,11 +45,6 @@ struct Plugin
|
||||
*/
|
||||
struct Plugin *prev;
|
||||
|
||||
/**
|
||||
* Type of the wireformat.
|
||||
*/
|
||||
char *type;
|
||||
|
||||
/**
|
||||
* Pointer to the plugin.
|
||||
*/
|
||||
@ -55,6 +52,7 @@ struct Plugin
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Head of DLL of wire plugins.
|
||||
*/
|
||||
@ -65,51 +63,163 @@ static struct Plugin *wire_head;
|
||||
*/
|
||||
static struct Plugin *wire_tail;
|
||||
|
||||
/**
|
||||
* Array of wire methods supported by this exchange.
|
||||
*/
|
||||
static json_t *wire_accounts_array;
|
||||
|
||||
/**
|
||||
* Load plugin @a name.
|
||||
* Object mapping wire methods to the respective fee structure.
|
||||
*/
|
||||
static json_t *wire_fee_object;
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
if ( (NULL != ai->wire_response_filename) &&
|
||||
(GNUNET_YES == ai->credit_enabled) )
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (GNUNET_YES == ai->debit_enabled)
|
||||
{
|
||||
struct Plugin *p;
|
||||
json_t *fees;
|
||||
|
||||
p = GNUNET_new (struct Plugin);
|
||||
p->type = GNUNET_strdup (name);
|
||||
p->plugin = TALER_WIRE_plugin_load (cfg,
|
||||
name);
|
||||
ai->plugin_name);
|
||||
if (NULL == p->plugin)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to load plugin %s\n",
|
||||
name);
|
||||
GNUNET_free (p->type);
|
||||
ai->plugin_name);
|
||||
GNUNET_free (p);
|
||||
*ret = GNUNET_SYSERR;
|
||||
return;
|
||||
}
|
||||
fees = TEH_WIRE_get_fees (name);
|
||||
if (NULL == fees)
|
||||
if (GNUNET_OK !=
|
||||
load_fee (p->plugin->method))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Disabling method `%s' as wire transfer fees are not given correctly\n",
|
||||
name);
|
||||
GNUNET_free (p->type);
|
||||
"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;
|
||||
}
|
||||
json_decref (fees);
|
||||
GNUNET_CONTAINER_DLL_insert (wire_head,
|
||||
wire_tail,
|
||||
p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@ -124,8 +234,10 @@ TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
int ret;
|
||||
|
||||
ret = GNUNET_OK;
|
||||
TALER_WIRE_find_enabled (cfg,
|
||||
&load_plugin,
|
||||
wire_accounts_array = json_array ();
|
||||
wire_fee_object = json_object ();
|
||||
TALER_EXCHANGEDB_find_accounts (cfg,
|
||||
&load_account,
|
||||
&ret);
|
||||
if (NULL == wire_head)
|
||||
{
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 ()
|
||||
|
@ -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);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
@ -53,10 +53,59 @@ struct RejectContext
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
static struct TALER_WIRE_Plugin *wire_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?
|
||||
@ -90,11 +139,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?
|
||||
*/
|
||||
@ -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,7 +187,7 @@ shutdown_task (void *cls)
|
||||
}
|
||||
if (NULL != hh)
|
||||
{
|
||||
wire_plugin->get_history_cancel (wire_plugin->cls,
|
||||
wa_pos->wire_plugin->get_history_cancel (wa_pos->wire_plugin->cls,
|
||||
hh);
|
||||
hh = NULL;
|
||||
}
|
||||
@ -149,21 +195,64 @@ shutdown_task (void *cls)
|
||||
{
|
||||
char *wtid_s;
|
||||
|
||||
wtid_s = wire_plugin->reject_transfer_cancel (wire_plugin->cls,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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,
|
||||
{
|
||||
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);
|
||||
else
|
||||
task = GNUNET_SCHEDULER_add_now (&find_transfers,
|
||||
NULL);
|
||||
return GNUNET_OK; /* will be ignored anyway */
|
||||
}
|
||||
if (NULL != details->wtid_s)
|
||||
@ -344,7 +434,8 @@ 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,
|
||||
rt = wa_pos->wire_plugin->reject_transfer (wa_pos->wire_plugin->cls,
|
||||
wa_pos->section_name,
|
||||
row_off,
|
||||
row_off_size,
|
||||
&reject_cb,
|
||||
@ -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,11 +549,13 @@ 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,
|
||||
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,
|
||||
@ -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",
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,12 +434,20 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (deposit.receiver_wire_account,
|
||||
&deposit.h_wire));
|
||||
deposit.timestamp = GNUNET_TIME_absolute_get ();
|
||||
GNUNET_TIME_round_abs (&deposit.timestamp);
|
||||
|
@ -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/"
|
||||
URL = "payto://x-taler-bank/localhost:8082/3"
|
||||
|
||||
# From which account at the 'bank' should outgoing
|
||||
# wire transfers be made?
|
||||
EXCHANGE_ACCOUNT_NUMBER = 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.
|
||||
|
@ -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)/"}
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 = \
|
||||
|
@ -1,2 +1,2 @@
|
||||
[exchangedb-postgres]
|
||||
DB_CONN_STR = "postgres:///taler"
|
||||
CONFIG = "postgres:///taler"
|
||||
|
141
src/exchangedb/exchangedb_accounts.c
Normal file
141
src/exchangedb/exchangedb_accounts.c
Normal file
@ -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 */
|
@ -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
|
||||
|
@ -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,8 +247,7 @@ 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,
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (eddsa_prv,
|
||||
&merchant_pub.eddsa_pub);
|
||||
GNUNET_free (eddsa_prv);
|
||||
}
|
||||
@ -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 =
|
||||
|
@ -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,
|
||||
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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,7 +2236,7 @@ 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",
|
||||
GNUNET_PQ_result_spec_string ("sender_account_details",
|
||||
&bt->sender_account_details),
|
||||
GNUNET_PQ_result_spec_end
|
||||
};
|
||||
@ -2389,7 +2403,7 @@ 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",
|
||||
GNUNET_PQ_result_spec_string ("receiver_account",
|
||||
&closing->receiver_account_details),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("wtid",
|
||||
&closing->wtid),
|
||||
@ -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,13 +4578,13 @@ 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",
|
||||
GNUNET_PQ_result_spec_string ("account_details",
|
||||
&account_details),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
|
||||
&reserve_pub),
|
||||
@ -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,7 +5435,7 @@ 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",
|
||||
GNUNET_PQ_result_spec_string ("sender_account_details",
|
||||
&sender_account_details),
|
||||
GNUNET_PQ_result_spec_uint64 ("reserve_in_serial_id",
|
||||
&rowid),
|
||||
@ -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,7 +5956,7 @@ 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",
|
||||
GNUNET_PQ_result_spec_string ("receiver_account",
|
||||
&receiver_account),
|
||||
TALER_PQ_result_spec_amount ("amount",
|
||||
&amount_with_fee),
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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]
|
||||
|
@ -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,7 +843,7 @@ deposit_cb (void *cls,
|
||||
deposit_rowid = rowid;
|
||||
if (NULL != wire)
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_JSON_hash (wire,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&h_wire));
|
||||
if ( (0 != memcmp (merchant_pub,
|
||||
&deposit->merchant_pub,
|
||||
@ -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 !=
|
||||
{
|
||||
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));
|
||||
&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,7 +1376,7 @@ wire_missing_cb (void *cls,
|
||||
|
||||
if (NULL != wire)
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_JSON_hash (wire,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&h_wire));
|
||||
else
|
||||
memset (&h_wire,
|
||||
@ -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,16 +1846,17 @@ 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,
|
||||
TALER_JSON_wire_signature_hash (wire,
|
||||
&deposit.h_wire));
|
||||
deposit.receiver_wire_account = wire;
|
||||
deposit.amount_with_fee = value;
|
||||
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
@ -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 *************** */
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* Salt used to generate @e master_sig.
|
||||
*/
|
||||
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 *salt;
|
||||
|
||||
/**
|
||||
* @brief A Wire format inquiry handle
|
||||
* Signature of the exchange over the account (was checked by the API).
|
||||
*/
|
||||
struct TALER_EXCHANGE_WireHandle;
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -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 */
|
||||
|
@ -61,18 +61,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.
|
||||
*/
|
||||
@ -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;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
@ -630,7 +634,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,
|
||||
@ -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
|
||||
|
@ -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
|
||||
@ -25,6 +25,16 @@
|
||||
#include "taler_wire_plugin.h"
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
@ -160,6 +159,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
|
||||
@ -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
|
||||
|
@ -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 \
|
||||
|
193
src/json/json_wire.c
Normal file
193
src/json/json_wire.c
Normal file
@ -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 */
|
@ -43,6 +43,7 @@ libtalerutil_wallet_la_LDFLAGS = \
|
||||
libtalerutil_la_SOURCES = \
|
||||
amount.c \
|
||||
crypto.c \
|
||||
crypto_wire.c \
|
||||
util.c \
|
||||
os_installation.c
|
||||
|
||||
|
108
src/util/crypto_wire.c
Normal file
108
src/util/crypto_wire.c
Normal file
@ -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 */
|
101
src/wire-plugins/Makefile.am
Normal file
101
src/wire-plugins/Makefile.am
Normal file
@ -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
|
@ -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,
|
||||
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
|
||||
* The IBAN number.
|
||||
*/
|
||||
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()
|
||||
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;
|
||||
const char *q;
|
||||
char *result;
|
||||
|
||||
*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))
|
||||
#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)
|
||||
{
|
||||
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;
|
||||
result = GNUNET_strndup (iban,
|
||||
q - iban);
|
||||
}
|
||||
if (0 != strcasecmp (type,
|
||||
"sepa"))
|
||||
else
|
||||
{
|
||||
GNUNET_asprintf (emsg,
|
||||
"Transfer type `%s' invalid for SEPA wire plugin\n",
|
||||
type);
|
||||
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_TYPE;
|
||||
result = GNUNET_strdup (iban);
|
||||
}
|
||||
if (1 != validate_iban (iban))
|
||||
{
|
||||
GNUNET_asprintf (emsg,
|
||||
"IBAN `%s' invalid\n",
|
||||
iban);
|
||||
return TALER_EC_DEPOSIT_INVALID_WIRE_FORMAT_ACCOUNT_NUMBER;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
if (NULL != account)
|
||||
{
|
||||
account->iban = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
GNUNET_free (result);
|
||||
}
|
||||
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 for this plugin
|
||||
*
|
||||
* @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 the payto:// URL
|
||||
* @return #TALER_EC_NONE if correctly formatted
|
||||
*/
|
||||
static json_t *
|
||||
sepa_get_wire_details (void *cls,
|
||||
const struct GNUNET_CONFIGURATION_Handle *cfg,
|
||||
const char *account_name)
|
||||
static enum TALER_ErrorCode
|
||||
ebics_wire_validate (void *cls,
|
||||
const char *account_url)
|
||||
{
|
||||
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))
|
||||
{
|
||||
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
|
||||
account_name,
|
||||
"SEPA_RESPONSE_FILE");
|
||||
return NULL;
|
||||
}
|
||||
ret = json_load_file (sepa_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",
|
||||
sepa_wire_file,
|
||||
err.text,
|
||||
err.source,
|
||||
err.line);
|
||||
GNUNET_free (sepa_wire_file);
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
sepa_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 *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,8 +462,9 @@ 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,
|
||||
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,
|
||||
@ -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,7 +502,7 @@ sepa_prepare_wire_transfer_cancel (void *cls,
|
||||
* @return NULL on error
|
||||
*/
|
||||
static struct TALER_WIRE_ExecuteHandle *
|
||||
sepa_execute_wire_transfer (void *cls,
|
||||
ebics_execute_wire_transfer (void *cls,
|
||||
const char *buf,
|
||||
size_t buf_size,
|
||||
TALER_WIRE_ConfirmationCallback cc,
|
||||
@ -736,7 +526,7 @@ sepa_execute_wire_transfer (void *cls,
|
||||
* @param eh execution to cancel
|
||||
*/
|
||||
static void
|
||||
sepa_execute_wire_transfer_cancel (void *cls,
|
||||
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,7 +556,8 @@ 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,
|
||||
ebics_get_history (void *cls,
|
||||
const char *account_section,
|
||||
enum TALER_BANK_Direction direction,
|
||||
const void *start_off,
|
||||
size_t start_off_len,
|
||||
@ -784,7 +577,7 @@ sepa_get_history (void *cls,
|
||||
* @param whh operation to cancel
|
||||
*/
|
||||
static void
|
||||
sepa_get_history_cancel (void *cls,
|
||||
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,7 +645,8 @@ timeout_reject (void *cls)
|
||||
* @return handle to cancel the operation
|
||||
*/
|
||||
static struct TALER_WIRE_RejectHandle *
|
||||
sepa_reject_transfer (void *cls,
|
||||
ebics_reject_transfer (void *cls,
|
||||
const char *account_section,
|
||||
const void *start_off,
|
||||
size_t start_off_len,
|
||||
TALER_WIRE_RejectTransferCallback rej_cb,
|
||||
@ -881,7 +677,7 @@ sepa_reject_transfer (void *cls,
|
||||
* @return closure of the callback of the operation
|
||||
*/
|
||||
static void *
|
||||
sepa_reject_transfer_cancel (void *cls,
|
||||
ebics_reject_transfer_cancel (void *cls,
|
||||
struct TALER_WIRE_RejectHandle *rh)
|
||||
{
|
||||
void *ret = rh->rej_cb_cls;
|
||||
@ -893,21 +689,20 @@ 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",
|
||||
@ -920,36 +715,34 @@ libtaler_plugin_wire_sepa_init (void *cls)
|
||||
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 */
|
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@ -32,16 +32,16 @@
|
||||
struct TemplateClosure
|
||||
{
|
||||
|
||||
/**
|
||||
* URL of the bank for sending funds to the bank.
|
||||
*/
|
||||
char *bank_url;
|
||||
|
||||
/**
|
||||
* Which currency do we support?
|
||||
*/
|
||||
char *currency;
|
||||
|
||||
/**
|
||||
* Which configuration do we use to lookup accounts?
|
||||
*/
|
||||
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,
|
||||
@ -177,28 +155,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
|
||||
@ -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,
|
||||
@ -267,6 +226,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.
|
||||
*
|
||||
@ -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);
|
80
src/wire-plugins/test_ebics_wireformat.c
Normal file
80
src/wire-plugins/test_ebics_wireformat.c
Normal file
@ -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;
|
||||
}
|
@ -24,7 +24,6 @@
|
||||
#include "taler_wire_lib.h"
|
||||
#include "taler_wire_plugin.h"
|
||||
#include <gnunet/gnunet_json_lib.h>
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/**
|
||||
@ -37,11 +36,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.
|
||||
*/
|
||||
@ -65,35 +59,23 @@ 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.
|
||||
*/
|
||||
@ -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)
|
||||
{
|
@ -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"
|
@ -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 */
|
@ -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"
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user