Merge branch 'protocolv8'
This commit is contained in:
commit
6de49ea2c0
3
.gitignore
vendored
3
.gitignore
vendored
@ -32,6 +32,7 @@ GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
*.swp
|
||||
src/include/taler_error_codes.h
|
||||
src/lib/test_exchange_api
|
||||
doc/doxygen/doxygen_sqlite3.db
|
||||
src/auditor/taler-auditor-dbinit
|
||||
@ -81,6 +82,7 @@ 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/sq/test_sq
|
||||
src/util/test_amount
|
||||
src/util/test_crypto
|
||||
src/util/test_json
|
||||
@ -126,3 +128,4 @@ uncrustify.cfg
|
||||
vgcore.*
|
||||
tags
|
||||
/.vscode
|
||||
src/testing/test_bank_api_with_nexus
|
||||
|
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -5,3 +5,6 @@
|
||||
path = doc/prebuilt
|
||||
url = https://git.taler.net/docs.git
|
||||
branch = prebuilt
|
||||
[submodule "contrib/gana"]
|
||||
path = contrib/gana
|
||||
url = https://gnunet.org/git/gana.git
|
||||
|
2
README
2
README
@ -33,7 +33,7 @@ Dependencies:
|
||||
These are the direct dependencies for running a Taler exchange:
|
||||
|
||||
- GNUnet >= 0.10.2
|
||||
- GNU libmicrohttpd >= 0.9.55
|
||||
- GNU libmicrohttpd >= 0.9.71
|
||||
- Postgres >= 9.5
|
||||
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -eu
|
||||
|
||||
if ! git --version >/dev/null; then
|
||||
echo "git not installed"
|
||||
exit 1
|
||||
@ -7,6 +9,13 @@ fi
|
||||
|
||||
git submodule update --init
|
||||
|
||||
# Generate taler-error-codes.h in gana and copy it to
|
||||
# src/include/taler_error_codes.h
|
||||
cd contrib/gana/gnu-taler-error-codes
|
||||
make
|
||||
cd ../../..
|
||||
cp contrib/gana/gnu-taler-error-codes/taler-error-codes.h src/include/taler_error_codes.h
|
||||
|
||||
# This is more portable than `which' but comes with
|
||||
# the caveat of not(?) properly working on busybox's ash:
|
||||
existence()
|
||||
|
41
configure.ac
41
configure.ac
@ -261,6 +261,16 @@ AS_IF([test $libgnunetpq != 1],
|
||||
*** ]])])
|
||||
|
||||
|
||||
# Check for GNUnet's libgnunetsq
|
||||
libgnunetsq=0
|
||||
AC_MSG_CHECKING([for libgnunetsq])
|
||||
AC_CHECK_HEADERS([gnunet/gnunet_sq_lib.h],
|
||||
[AC_CHECK_LIB([gnunetsq], [GNUNET_SQ_result_spec_string], libgnunetsq=1)],
|
||||
[], [#ifdef HAVE_GNUNET_PLATFORM_H
|
||||
#include <gnunet/platform.h>
|
||||
#endif])
|
||||
|
||||
|
||||
# check for libmicrohttpd
|
||||
microhttpd=0
|
||||
AC_MSG_CHECKING([for microhttpd])
|
||||
@ -326,6 +336,35 @@ CFLAGS=$CFLAGS_SAVE
|
||||
LDFLAGS=$LDFLAGS_SAVE
|
||||
LIBS=$LIBS_SAVE
|
||||
|
||||
# test for sqlite
|
||||
sqlite=false
|
||||
AC_MSG_CHECKING(for SQLite)
|
||||
AC_ARG_WITH(sqlite,
|
||||
[ --with-sqlite=PFX base of SQLite installation],
|
||||
[AC_MSG_RESULT("$with_sqlite")
|
||||
AS_CASE([$with_sqlite],
|
||||
[no],[],
|
||||
[yes],[
|
||||
AC_CHECK_HEADERS(sqlite3.h,
|
||||
sqlite=true)],
|
||||
[
|
||||
LDFLAGS="-L$with_sqlite/lib $LDFLAGS"
|
||||
CPPFLAGS="-I$with_sqlite/include $CPPFLAGS"
|
||||
AC_CHECK_HEADERS(sqlite3.h,
|
||||
EXT_LIB_PATH="-L$with_sqlite/lib $EXT_LIB_PATH"
|
||||
SQLITE_LDFLAGS="-L$with_sqlite/lib"
|
||||
SQLITE_CPPFLAGS="-I$with_sqlite/include"
|
||||
sqlite=true)
|
||||
LDFLAGS=$SAVE_LDFLAGS
|
||||
CPPFLAGS=$SAVE_CPPFLAGS
|
||||
])
|
||||
],
|
||||
[AC_MSG_RESULT([--with-sqlite not specified])
|
||||
AC_CHECK_HEADERS(sqlite3.h, sqlite=true)])
|
||||
AM_CONDITIONAL(HAVE_SQLITE, [test x$sqlite = xtrue] && [test $libgnunetsq = 1])
|
||||
AC_SUBST(SQLITE_CPPFLAGS)
|
||||
AC_SUBST(SQLITE_LDFLAGS)
|
||||
|
||||
# check for libtalertwistertesting
|
||||
talertwister=0
|
||||
AC_MSG_CHECKING([for talertwister])
|
||||
@ -459,6 +498,7 @@ AM_CONDITIONAL([ENABLE_DOC], [test "x$enable_doc" = "xyes"])
|
||||
AM_CONDITIONAL([HAVE_EXPENSIVE_TESTS], [false])
|
||||
AM_CONDITIONAL([MHD_HAVE_EPOLL], [false])
|
||||
AM_CONDITIONAL([HAVE_POSTGRESQL], [false])
|
||||
AM_CONDITIONAL([HAVE_SQLITE], [false])
|
||||
AM_CONDITIONAL([HAVE_LIBCURL], [false])
|
||||
AM_CONDITIONAL([HAVE_LIBGNURL], [false])
|
||||
AM_CONDITIONAL([HAVE_DEVELOPER], [false])
|
||||
@ -488,6 +528,7 @@ AC_CONFIG_FILES([Makefile
|
||||
src/json/Makefile
|
||||
src/mhd/Makefile
|
||||
src/pq/Makefile
|
||||
src/sq/Makefile
|
||||
src/util/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
1
contrib/gana
Submodule
1
contrib/gana
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c0fedb8d45c41fb283fec714b48278e6661d51be
|
@ -87,6 +87,16 @@ transfers that cannot be reversed. We will only refuse to execute transfers if
|
||||
the transfers are prohibited by a competent legal authority and we are ordered
|
||||
to do so.
|
||||
|
||||
When using our Services, you agree to not take any action that intentionally
|
||||
imposes an unreasonable load on our infrastructure. If you find security
|
||||
problems in our Services, you agree to first report them to
|
||||
security@taler-systems.com and grant us the right to publish your report. We
|
||||
warrant that we will ourselves publicly disclose any issues reported within 3
|
||||
months, and that we will not prosecute anyone reporting security issues if
|
||||
they did not exploit the issue beyond a proof-of-concept, and followed the
|
||||
above responsible disclosure practice.
|
||||
|
||||
|
||||
Fees
|
||||
----
|
||||
|
||||
@ -104,17 +114,14 @@ We reserve the right to provide different types of rewards to users either in
|
||||
the form of discount for our Services or in any other form at our discretion
|
||||
and without prior notice to you.
|
||||
|
||||
Eligibility
|
||||
-----------
|
||||
Eligibility and Financial self-responsibility
|
||||
---------------------------------------------
|
||||
|
||||
To be eligible to use our Services, you must be able to form legally binding
|
||||
contracts or have the permission of your legal guardian. By using our
|
||||
Services, you represent and warrant that you meet all eligibility requirements
|
||||
that we outline in these Terms.
|
||||
|
||||
Financial self-responsibility
|
||||
-----------------------------
|
||||
|
||||
You will be responsible for maintaining the availability, integrity and
|
||||
confidentiality of the data stored in your wallet. When you setup a Taler
|
||||
Wallet, you are strongly advised to follow the precautionary measures offered
|
||||
@ -136,17 +143,6 @@ of Taler Systems SA. You are welcome to use the name in relation to processing
|
||||
payments using the Taler protocol, assuming your use is compatible with an
|
||||
official release from the GNU Project that is not older than two years.
|
||||
|
||||
Your use of our services
|
||||
------------------------
|
||||
|
||||
When using our Services, you agree to not take any action that intentionally
|
||||
imposes an unreasonable load on our infrastructure. If you find security
|
||||
problems in our Services, you agree to first report them to
|
||||
security@taler-systems.com and grant us the right to publish your report. We
|
||||
warrant that we will ourselves publicly disclose any issues reported within 3
|
||||
months, and that we will not prosecute anyone reporting security issues if
|
||||
they did not exploit the issue beyond a proof-of-concept, and followed the
|
||||
above responsible disclosure practice.
|
||||
|
||||
Limitation of liability & disclaimer of warranties
|
||||
--------------------------------------------------
|
||||
@ -175,9 +171,6 @@ Any other terms, conditions, warranties, or representations associated with
|
||||
such content, are solely between you and such organizations and/or
|
||||
individuals.
|
||||
|
||||
Limitation of liability
|
||||
-----------------------
|
||||
|
||||
To the fullest extent permitted by applicable law, in no event will we or any
|
||||
of our officers, directors, representatives, agents, servants, counsel,
|
||||
employees, consultants, lawyers, and other personnel authorized to act,
|
||||
@ -206,9 +199,6 @@ damages. Some jurisdictions do not allow the exclusion or limitation of
|
||||
liability for consequential or incidental damages, so the above limitation may
|
||||
not apply to you.
|
||||
|
||||
Warranty disclaimer
|
||||
-------------------
|
||||
|
||||
Our services are provided "as is" and without warranty of any kind. To the
|
||||
maximum extent permitted by law, we disclaim all representations and
|
||||
warranties, express or implied, relating to the services and underlying
|
||||
@ -225,8 +215,8 @@ implied warranties, so the foregoing disclaimers may not apply to you. This
|
||||
paragraph gives you specific legal rights and you may also have other legal
|
||||
rights that vary from state to state.
|
||||
|
||||
Indemnity
|
||||
---------
|
||||
Indemnity and Time limitation on claims and Termination
|
||||
-------------------------------------------------------
|
||||
|
||||
To the extent permitted by applicable law, you agree to defend, indemnify, and
|
||||
hold harmless the Taler Parties from and against any and all claims, damages,
|
||||
@ -236,32 +226,16 @@ the Services; (b) any feedback or submissions you provide to us concerning the
|
||||
Taler Wallet; (c) your violation of any term of this Agreement; or (d) your
|
||||
violation of any law, rule, or regulation, or the rights of any third party.
|
||||
|
||||
Time limitation on claims
|
||||
-------------------------
|
||||
|
||||
You agree that any claim you may have arising out of or related to your
|
||||
relationship with us must be filed within one year after such claim arises,
|
||||
otherwise, your claim in permanently barred.
|
||||
|
||||
Governing law
|
||||
-------------
|
||||
|
||||
No matter where you’re located, the laws of Switzerland will govern these
|
||||
Terms. If any provisions of these Terms are inconsistent with any applicable
|
||||
law, those provisions will be superseded or modified only to the extent such
|
||||
provisions are inconsistent. The parties agree to submit to the ordinary
|
||||
courts in Zurich, Switzerland for exclusive jurisdiction of any dispute
|
||||
arising out of or related to your use of the Services or your breach of these
|
||||
Terms.
|
||||
|
||||
Termination
|
||||
-----------
|
||||
|
||||
In the event of termination concerning your use of our Services, your
|
||||
obligations under this Agreement will still continue.
|
||||
|
||||
Discontinuance of services
|
||||
--------------------------
|
||||
|
||||
Discontinuance of services and Force majeure
|
||||
--------------------------------------------
|
||||
|
||||
We may, in our sole discretion and without cost to you, with or without prior
|
||||
notice, and at any time, modify or discontinue, temporarily or permanently,
|
||||
@ -273,24 +247,6 @@ or liable for any loss of funds in the event that we discontinue or depreciate
|
||||
the Services and your Taler Wallet fails to transfer out the coins within a
|
||||
three months notification period.
|
||||
|
||||
No waiver
|
||||
---------
|
||||
|
||||
Our failure to exercise or delay in exercising any right, power, or privilege
|
||||
under this Agreement shall not operate as a waiver; nor shall any single or
|
||||
partial exercise of any right, power, or privilege preclude any other or
|
||||
further exercise thereof.
|
||||
|
||||
Severability
|
||||
------------
|
||||
|
||||
If it turns out that any part of this Agreement is invalid, void, or for any
|
||||
reason unenforceable, that term will be deemed severable and limited or
|
||||
eliminated to the minimum extent necessary.
|
||||
|
||||
Force majeure
|
||||
-------------
|
||||
|
||||
We shall not be held liable for any delays, failure in performance, or
|
||||
interruptions of service which result directly or indirectly from any cause or
|
||||
condition beyond our reasonable control, including but not limited to: any
|
||||
@ -301,14 +257,29 @@ services, failure of equipment and/or software, other catastrophe, or any
|
||||
other occurrence which is beyond our reasonable control and shall not affect
|
||||
the validity and enforceability of any remaining provisions.
|
||||
|
||||
Assignment
|
||||
----------
|
||||
|
||||
Governing law, Waivers, Severability and Assignment
|
||||
------------------------------------------------
|
||||
|
||||
No matter where you’re located, the laws of Switzerland will govern these
|
||||
Terms. If any provisions of these Terms are inconsistent with any applicable
|
||||
law, those provisions will be superseded or modified only to the extent such
|
||||
provisions are inconsistent. The parties agree to submit to the ordinary
|
||||
courts in Zurich, Switzerland for exclusive jurisdiction of any dispute
|
||||
arising out of or related to your use of the Services or your breach of these
|
||||
Terms.
|
||||
|
||||
Our failure to exercise or delay in exercising any right, power, or privilege
|
||||
under this Agreement shall not operate as a waiver; nor shall any single or
|
||||
partial exercise of any right, power, or privilege preclude any other or
|
||||
further exercise thereof.
|
||||
|
||||
You agree that we may assign any of our rights and/or transfer, sub-contract,
|
||||
or delegate any of our obligations under these Terms.
|
||||
|
||||
Entire agreement
|
||||
----------------
|
||||
If it turns out that any part of this Agreement is invalid, void, or for any
|
||||
reason unenforceable, that term will be deemed severable and limited or
|
||||
eliminated to the minimum extent necessary.
|
||||
|
||||
This Agreement sets forth the entire understanding and agreement as to the
|
||||
subject matter hereof and supersedes any and all prior discussions,
|
||||
@ -317,6 +288,7 @@ prior versions of this Agreement) and every nature between us. Except as
|
||||
provided for above, any modification to this Agreement must be in writing and
|
||||
must be signed by both parties.
|
||||
|
||||
|
||||
Questions or comments
|
||||
---------------------
|
||||
|
||||
|
BIN
doc/audit/report-202005.pdf
Normal file
BIN
doc/audit/report-202005.pdf
Normal file
Binary file not shown.
238
doc/audit/response-202005.tex
Normal file
238
doc/audit/response-202005.tex
Normal file
@ -0,0 +1,238 @@
|
||||
\documentclass[11pt]{article}
|
||||
\oddsidemargin=0in \evensidemargin=0in
|
||||
\textwidth=6.2in \textheight=8.7in
|
||||
%\topmargin=-0.2in
|
||||
|
||||
\usepackage[ansinew]{inputenc}
|
||||
\usepackage{makeidx,amsmath,amssymb,exscale,multicol,epsfig,graphics}
|
||||
|
||||
\begin{document}
|
||||
\pagestyle{headings}
|
||||
\title{Preliminary response to the \\ GNU Taler security audit in Q2/Q3 2020}
|
||||
\author{Christian Grothoff \and Florian Dold}
|
||||
|
||||
\maketitle
|
||||
|
||||
\section{Abstract}
|
||||
|
||||
This is the preliminary response to the source code audit report CodeBlau
|
||||
created for GNU Taler in Q2/Q3 2020. A final response with more details is
|
||||
expected later this year.
|
||||
|
||||
\section{Management Summary}
|
||||
|
||||
We thank CodeBlau for their detailed report and thorough analysis. We are
|
||||
particularly impressed that they reported issues against components that were
|
||||
not even in-scope, and also that they found an {\em interesting} new corner
|
||||
case we had not previously considered. Finally, we also find several of their
|
||||
architectural recommendations to strengthen security to be worthwhile, and
|
||||
while some were already on our long-term roadmap, we will reprioritize our
|
||||
roadmap given their recommendations.
|
||||
|
||||
Given our extensive discussions with CodeBlau, we also have the impression
|
||||
that they really took the time to understand the system, and look forward
|
||||
to working with CodeBlau as a competent auditor for GNU Taler in the future.
|
||||
|
||||
\section{Issues in the exchange}
|
||||
|
||||
We agree with the issues CodeBlau discovered and both parties believe that
|
||||
they have all been addressed.
|
||||
|
||||
\section{Issues in the auditor}
|
||||
|
||||
We appreciate CodeBlau's extensive list of checks the Taler auditor performs,
|
||||
which was previously not documented adequately by us. We agree that the
|
||||
auditor still needs more comprehensive documentation.
|
||||
|
||||
As for issue \#6416, we agree with the analysis and the proposed fix, even if
|
||||
the implications are not fully clear. It has not yet been implemented as we
|
||||
want to carefully review all of the SQL statements implicated in the
|
||||
resolution and ensure we fully understand the implications.
|
||||
|
||||
\section{Issues in GNUnet}
|
||||
|
||||
We agree with the issues CodeBlau discovered and both parties believe that
|
||||
they have all been addressed.
|
||||
|
||||
\section{General remarks on the code}
|
||||
|
||||
We understand that writing the code in another programming language may make
|
||||
certain checks for the auditor less work to implement. However, our choice of C
|
||||
is based on the advantages that make it superior to contemporary languages for
|
||||
our use case: relatively low complexity of the language (compared to C++);
|
||||
availability of mature compilers, static and dynamic analysis tools;
|
||||
predictable performance; access to stable and battle-tested libraries; and
|
||||
future-proofness due to portability to older systems as well as new platforms.
|
||||
|
||||
We believe creating a parallel implementation in other languages would provide
|
||||
advantages, especially with respect to avoiding ``the implementation is the
|
||||
specification''-style issues. However, given limited resources will not make
|
||||
this a priority.
|
||||
|
||||
We disagree that all modern software development has embraced the idea that
|
||||
memory errors are to be handled in ways other than terminating or restarting
|
||||
the process. Many programming languages (Erlang, Java) hardly offer any other
|
||||
means of handling out-of-memory situations than to terminate the process. We
|
||||
also insist that Taler {\em does} handle out-of-memory as it does have code
|
||||
that terminates the process (we do {\em not} simply ignore the return value
|
||||
from {\tt malloc()} or other allocation functions!). We simply consider that
|
||||
terminating the process (which is run by a hypervisor that will restart the
|
||||
service) is the correct way to handle out-of-memory situations. We also have
|
||||
limits in place that should prevent attackers from causing large amounts of
|
||||
memory to be consumed, and also have code to automatically preemptively
|
||||
restart the process to guard against memory exhaustion from memory
|
||||
fragmentation. Finally, a common problem with abrupt termination may be
|
||||
corrupted files. However, the code mostly only reads from files and limits
|
||||
writing to the Postgres database. Hence, there is no possibility of corrupt
|
||||
files being left behind even in the case of abnormal termination.
|
||||
|
||||
|
||||
\section{More specs and documentation code}
|
||||
|
||||
We agree with the recommendation that the documentation should be improved,
|
||||
and will try to improve it along the lines recommended by CodeBlau.
|
||||
|
||||
\section{Protocol change: API for uniformly distributed seeds}
|
||||
|
||||
We agree with the suggestion, have made the necessary changes, and both
|
||||
parties believe that the suggestion has been implemented.
|
||||
|
||||
\section{Reduce code complexity}
|
||||
|
||||
\subsection{Reduce global variables}
|
||||
|
||||
While we do not disagree with the general goal to have few global variables,
|
||||
we also believe that there are cases where global variables make sense.
|
||||
|
||||
We have already tried to minimize the scope of variables. The remaining few
|
||||
global variables are largely ``read-only'' configuration data. The report does
|
||||
not point out specific instances that would be particularly beneficial to
|
||||
eliminate. As we continue to work on the code, we will of course evaluate
|
||||
whether the removal of a particular global variable would make the code
|
||||
cleaner.
|
||||
|
||||
Also, we want to point out that all global variables we introduce
|
||||
in the exchange are indicated with a prefix {\tt TEH\_} in the code, so they
|
||||
are easy to identify as such.
|
||||
|
||||
\subsection{Callbacks, type p(r)unning}
|
||||
|
||||
We understand that higher order functions in C can be confusing, but this
|
||||
is also a common pattern to enable code re-use and asynchronous execution
|
||||
which is essential for network applications. We do not believe that we
|
||||
use callbacks {\em excessively}. Rewriting the code in another language
|
||||
may indeed make this part easier to understand, alas would have other
|
||||
disadvantages as pointed out previously.
|
||||
|
||||
\subsection{Initializing structs with memset}
|
||||
|
||||
Using {\tt memset()} first prevents compiler (or valgrind) warnings about
|
||||
using uninitialized memory, possibly hiding bugs. We also do use struct
|
||||
initialization in many cases.
|
||||
|
||||
The GNUnet-wrappers are generally designed to be ``safer'' or ``stricter''
|
||||
variants of the corresponding libc functions, and not merely ``the same''.
|
||||
Hence we do not believe that renaming {\tt GNUNET\_malloc} is indicated.
|
||||
|
||||
The argument that {\tt memset()}ing first makes the code inherently more
|
||||
obvious also seems fallacious, as it would commonly result in dead stores,
|
||||
which can confuse developers and produce false-positive warnings from static
|
||||
analysis tools.
|
||||
|
||||
\subsection{NULL pointer handling}
|
||||
|
||||
The problem with the ``goto fail'' style error handling is that it rarely
|
||||
results in specific error handling where diagnostics are created that are
|
||||
specific to the error. Using this style of programming encourages developers
|
||||
to create simplistic error handling, which can result in inappropriate error
|
||||
handling logic and also makes it harder to attribute errors to the specific
|
||||
cause.
|
||||
|
||||
However, we have no prohibition on using this style of error handling either:
|
||||
if it is appropriate, develpers should make a case-by-case decision as to how
|
||||
to best handle a specific error.
|
||||
|
||||
We have made some first changes to how {\tt GNUNET\_free()} works in response
|
||||
to the report, and will discuss further changes with the GNUnet development
|
||||
team.
|
||||
|
||||
\subsection{Hidden security assumptions}
|
||||
|
||||
We disagree that the assumptions stated are ``hidden'', as (1) the Taler code
|
||||
has its own checks to warrant that the requirements of the {\tt
|
||||
GNUNET\_malloc()} API are satisfied (so enforcement is not limited to the
|
||||
abstraction layer), and (2) the maximum allocation size limit is quite clearly
|
||||
specified in the GNUnet documentation. Also, the GNUnet-functions are not
|
||||
merely an abstraction layer for portability, but they provided extended
|
||||
semantics that we rely upon. So it is not like it is possible to swap this
|
||||
layer and expect anything to continue to work.
|
||||
|
||||
When we use the libjansson library, it is understood that it does not use
|
||||
the GNUnet operations, and the code is careful about this distinction.
|
||||
|
||||
\subsection{Get rid of boolean function arguments}
|
||||
|
||||
We agree that this can make the code more readable, and have in some places
|
||||
already changed the code in this way.
|
||||
|
||||
\section{Structural Recommendation}
|
||||
|
||||
\subsection{Least privilege}
|
||||
|
||||
It is wrong to say that GNU Taler has ``no work done'' on privilege separation.
|
||||
For example, the {\tt taler-exchange-dbinit} tool is the only tool that requires
|
||||
CREATE, ALTER and DROP rights on database tables, thus enusring that the ``main''
|
||||
process does not need these rights.
|
||||
|
||||
We also already had the {\tt taler-exchange-keyup} tool responsible for
|
||||
initializing keys. In response to the audit, we already changed the GNUnet API
|
||||
to make sure that tools do not create keys as a side-effect of trying to read
|
||||
non-existent key files.
|
||||
|
||||
We agree with the recommendation on further privilege separation for access
|
||||
to cryptographic keys, and intend to implement this in the near future.
|
||||
|
||||
\subsection{File system access}
|
||||
|
||||
The auditor helpers actually only read from the file system, only the LaTeX
|
||||
invocation to compile the final report to PDF inherently needs write
|
||||
access. We do not predict that we will retool LaTeX. Also, the file system
|
||||
access is completely uncritical, as the auditor by design runs on a system
|
||||
that is separate from the production exchange system.
|
||||
|
||||
Because that system will not have {\em any} crypto keys (not even the one of
|
||||
the auditor!), CodeBlau is wrong to assume that reading from or writing to the
|
||||
file system represents a security threat.
|
||||
|
||||
We have started to better document the operational requirements on running the
|
||||
auditor.
|
||||
|
||||
\subsection{Avoid dlopen}
|
||||
|
||||
Taler actually uses {\tt ltdlopen()} from GNU libtool, which provides
|
||||
compiler flags to convert the dynamic linkage into static linkage. For
|
||||
development, dynamic linkage has many advantages.
|
||||
|
||||
We plan to test and document how to build GNU Taler with only static
|
||||
linkage, and will recommend this style of deployment for the Taler
|
||||
exchange for production.
|
||||
|
||||
\subsection{Reduce reliance on PostgreSQL}
|
||||
|
||||
CodeBlau's suggestion to use an append-only transaction logging service in
|
||||
addition to the PostgreSQL database is a reasonable suggestion for a
|
||||
production-grade deployment of GNU Taler, as it would allow partial disaster
|
||||
recovery even in the presence of an attacker that has gained write access to
|
||||
the exchange's database.
|
||||
|
||||
We are currently still investigating whether the transaction logging should be
|
||||
implemented directly by the exchange service, or via the database's extensible
|
||||
replication mechanism. Any implementation of such an append-only logging
|
||||
mechanism must be carefully designed to ensure it does not negatively impact
|
||||
the exchange's availability and does not interfere with serializability of
|
||||
database transactions. As such we believe that transaction logging can only be
|
||||
provided on a best-effort basis. Fortunately, even a best-effort append-only
|
||||
transaction log would serve to limit the financial damage incurred by the
|
||||
exchange in an active database compromise scenario.
|
||||
|
||||
\end{document}
|
@ -3,6 +3,9 @@ AM_CPPFLAGS = -I$(top_srcdir)/src/include
|
||||
if HAVE_POSTGRESQL
|
||||
PQ_DIR = pq
|
||||
endif
|
||||
if HAVE_SQLITE
|
||||
SQ_DIR = sq
|
||||
endif
|
||||
|
||||
pkgcfgdir = $(prefix)/share/taler/config.d/
|
||||
pkgcfg_DATA = \
|
||||
@ -17,6 +20,7 @@ SUBDIRS = \
|
||||
json \
|
||||
curl \
|
||||
$(PQ_DIR) \
|
||||
$(SQ_DIR) \
|
||||
mhd \
|
||||
bank-lib \
|
||||
exchangedb \
|
||||
|
@ -1 +0,0 @@
|
||||
1584124548
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
BX3MKH0E1YPF03P1T2G4NKMYNHBGE1TC2N5P6RWHT1JHNXC32EN0
|
File diff suppressed because it is too large
Load Diff
@ -8,6 +8,10 @@
|
||||
set -eu
|
||||
|
||||
|
||||
echo "Script disabled: taler-wallet-cli integration test known to fail right now!"
|
||||
exit 1
|
||||
|
||||
|
||||
trap "kill `jobs -p` &> /dev/null || true" ERR
|
||||
|
||||
# Exit, with status code "skip" (no 'real' failure)
|
||||
|
@ -1 +0,0 @@
|
||||
1585247241
|
Binary file not shown.
@ -1 +0,0 @@
|
||||
NG08W20XYEN3M663JQ0THGSRH2QT7Y3390933FVSZE033Q9A9XE0
|
File diff suppressed because it is too large
Load Diff
@ -155,7 +155,7 @@ verify_and_execute_deposit_confirmation (
|
||||
.purpose.size = htonl (sizeof (struct TALER_DepositConfirmationPS)),
|
||||
.h_contract_terms = dc->h_contract_terms,
|
||||
.h_wire = dc->h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (dc->timestamp),
|
||||
.exchange_timestamp = GNUNET_TIME_absolute_hton (dc->exchange_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (dc->refund_deadline),
|
||||
.coin_pub = dc->coin_pub,
|
||||
.merchant = dc->merchant
|
||||
@ -224,7 +224,8 @@ TAH_DEPOSIT_CONFIRMATION_handler (struct TAH_RequestHandler *rh,
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &dc.h_contract_terms),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire", &dc.h_wire),
|
||||
GNUNET_JSON_spec_absolute_time ("timestamp", &dc.timestamp),
|
||||
GNUNET_JSON_spec_absolute_time ("exchange_timestamp",
|
||||
&dc.exchange_timestamp),
|
||||
GNUNET_JSON_spec_absolute_time ("refund_deadline", &dc.refund_deadline),
|
||||
TALER_JSON_spec_amount ("amount_without_fee", &dc.amount_without_fee),
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_pub", &dc.coin_pub),
|
||||
|
@ -1535,7 +1535,8 @@ refresh_session_cb (void *cls,
|
||||
*
|
||||
* @param cls closure
|
||||
* @param rowid unique serial ID for the deposit in our DB
|
||||
* @param timestamp when did the deposit happen
|
||||
* @param exchange_timestamp when did the exchange get the deposit
|
||||
* @param wallet_timestamp when did the contract signing happen
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param denom_pub denomination public key of @a coin_pub
|
||||
* @param coin_pub public key of the coin
|
||||
@ -1553,7 +1554,8 @@ refresh_session_cb (void *cls,
|
||||
static int
|
||||
deposit_cb (void *cls,
|
||||
uint64_t rowid,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -1611,7 +1613,7 @@ deposit_cb (void *cls,
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
|
||||
.purpose.size = htonl (sizeof (dr)),
|
||||
.h_contract_terms = *h_contract_terms,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (timestamp),
|
||||
.wallet_timestamp = GNUNET_TIME_absolute_hton (wallet_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
|
||||
.deposit_fee = issue->fee_deposit,
|
||||
.merchant = *merchant_pub,
|
||||
@ -1802,7 +1804,6 @@ refund_cb (void *cls,
|
||||
.coin_pub = *coin_pub,
|
||||
.merchant = *merchant_pub,
|
||||
.rtransaction_id = GNUNET_htonll (rtransaction_id),
|
||||
.refund_fee = issue->fee_refund
|
||||
};
|
||||
|
||||
TALER_amount_hton (&rr.refund_amount,
|
||||
|
@ -114,11 +114,15 @@ test_dc (void *cls,
|
||||
.h_wire = dc->h_wire,
|
||||
.refund_deadline = dc->refund_deadline
|
||||
};
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
qs = TALER_ARL_edb->have_deposit (TALER_ARL_edb->cls,
|
||||
TALER_ARL_esession,
|
||||
&dep,
|
||||
GNUNET_NO /* do not check refund deadline */);
|
||||
GNUNET_NO /* do not check refund deadline */,
|
||||
&deposit_fee,
|
||||
&exchange_timestamp);
|
||||
if (qs > 0)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
@ -137,7 +141,8 @@ test_dc (void *cls,
|
||||
TALER_ARL_report (report_deposit_confirmation_inconsistencies,
|
||||
json_pack ("{s:o, s:o, s:I, s:o}",
|
||||
"timestamp",
|
||||
TALER_ARL_json_from_time_abs (dc->timestamp),
|
||||
TALER_ARL_json_from_time_abs (
|
||||
dc->exchange_timestamp),
|
||||
"amount",
|
||||
TALER_JSON_from_amount (&dc->amount_without_fee),
|
||||
"rowid",
|
||||
|
@ -550,7 +550,6 @@ handle_reserve_out (void *cls,
|
||||
}
|
||||
|
||||
/* check reserve_sig (first: setup remaining members of wsrd) */
|
||||
wsrd.withdraw_fee = issue->fee_withdraw;
|
||||
TALER_amount_hton (&wsrd.amount_with_fee,
|
||||
amount_with_fee);
|
||||
if (GNUNET_OK !=
|
||||
|
@ -1872,6 +1872,12 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
check_with_database "auditor-basedb"
|
||||
# run tests with pre-build database, if one is available
|
||||
if test -x auditor-basedb.mpub
|
||||
then
|
||||
check_with_database "auditor-basedb"
|
||||
else
|
||||
fail=77
|
||||
fi
|
||||
|
||||
exit $fail
|
||||
|
@ -543,6 +543,12 @@ else
|
||||
fi
|
||||
fi
|
||||
|
||||
check_with_database "revoke-basedb"
|
||||
# run tests with pre-build database, if one is available
|
||||
if test -x revoke-basedb.mpub
|
||||
then
|
||||
check_with_database "revoke-basedb"
|
||||
else
|
||||
fail=77
|
||||
fi
|
||||
|
||||
exit $fail
|
||||
|
@ -251,7 +251,7 @@ CREATE TABLE IF NOT EXISTS deposit_confirmations
|
||||
,serial_id BIGSERIAL UNIQUE
|
||||
,h_contract_terms BYTEA CHECK (LENGTH(h_contract_terms)=64)
|
||||
,h_wire BYTEA CHECK (LENGTH(h_wire)=64)
|
||||
,timestamp INT8 NOT NULL
|
||||
,exchange_timestamp INT8 NOT NULL
|
||||
,refund_deadline INT8 NOT NULL
|
||||
,amount_without_fee_val INT8 NOT NULL
|
||||
,amount_without_fee_frac INT4 NOT NULL
|
||||
|
@ -43,8 +43,8 @@ DROP TABLE IF EXISTS auditor_denominations CASCADE;
|
||||
DROP TABLE IF EXISTS deposit_confirmations CASCADE;
|
||||
DROP TABLE IF EXISTS auditor_exchanges CASCADE;
|
||||
|
||||
-- Drop versioning (0000.sql)
|
||||
DROP SCHEMA IF EXISTS _v CASCADE;
|
||||
-- Drop versioning (auditor-0001.sql)
|
||||
SELECT _v.unregister_patch('auditor-0001');
|
||||
|
||||
-- And we're out of here...
|
||||
COMMIT;
|
||||
|
@ -269,7 +269,7 @@ postgres_get_session (void *cls)
|
||||
"(master_pub"
|
||||
",h_contract_terms"
|
||||
",h_wire"
|
||||
",timestamp"
|
||||
",exchange_timestamp"
|
||||
",refund_deadline"
|
||||
",amount_without_fee_val"
|
||||
",amount_without_fee_frac"
|
||||
@ -286,7 +286,7 @@ postgres_get_session (void *cls)
|
||||
" serial_id"
|
||||
",h_contract_terms"
|
||||
",h_wire"
|
||||
",timestamp"
|
||||
",exchange_timestamp"
|
||||
",refund_deadline"
|
||||
",amount_without_fee_val"
|
||||
",amount_without_fee_frac"
|
||||
@ -1126,7 +1126,7 @@ postgres_insert_deposit_confirmation (
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->master_public_key),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_contract_terms),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->h_wire),
|
||||
TALER_PQ_query_param_absolute_time (&dc->timestamp),
|
||||
TALER_PQ_query_param_absolute_time (&dc->exchange_timestamp),
|
||||
TALER_PQ_query_param_absolute_time (&dc->refund_deadline),
|
||||
TALER_PQ_query_param_amount (&dc->amount_without_fee),
|
||||
GNUNET_PQ_query_param_auto_from_type (&dc->coin_pub),
|
||||
@ -1207,8 +1207,8 @@ deposit_confirmation_cb (void *cls,
|
||||
&dc.h_contract_terms),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
|
||||
&dc.h_wire),
|
||||
GNUNET_PQ_result_spec_absolute_time ("timestamp",
|
||||
&dc.timestamp),
|
||||
GNUNET_PQ_result_spec_absolute_time ("exchange_timestamp",
|
||||
&dc.exchange_timestamp),
|
||||
GNUNET_PQ_result_spec_absolute_time ("refund_deadline",
|
||||
&dc.refund_deadline),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_without_fee",
|
||||
|
@ -1016,9 +1016,9 @@ create_wire_fee_for_method (void *cls,
|
||||
af->wire_fee.currency)) )
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Invalid or missing amount in `%s' under `%s'\n",
|
||||
section,
|
||||
opt);
|
||||
"Invalid or missing amount for option `%s' in section `%s'\n",
|
||||
opt,
|
||||
section);
|
||||
*ret = GNUNET_SYSERR;
|
||||
GNUNET_free (opt);
|
||||
break;
|
||||
@ -1038,9 +1038,9 @@ create_wire_fee_for_method (void *cls,
|
||||
af->closing_fee.currency)) )
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Invalid or missing amount in `%s' under `%s'\n",
|
||||
section,
|
||||
opt);
|
||||
"Invalid or missing amount for option `%s' in section `%s'\n",
|
||||
opt,
|
||||
section);
|
||||
*ret = GNUNET_SYSERR;
|
||||
GNUNET_free (opt);
|
||||
break;
|
||||
|
@ -330,6 +330,8 @@ refund_by_coin_cb (void *cls,
|
||||
*
|
||||
* @param cls a `struct AggregationUnit`
|
||||
* @param row_id identifies database entry
|
||||
* @param exchange_timestamp when did the deposit happen
|
||||
* @param wallet_timestamp when did the contract happen
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -343,6 +345,8 @@ refund_by_coin_cb (void *cls,
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
deposit_cb (void *cls,
|
||||
uint64_t row_id,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -358,6 +362,8 @@ deposit_cb (void *cls,
|
||||
/* NOTE: potential optimization: use custom SQL API to not
|
||||
fetch this one: */
|
||||
(void) wire_deadline; /* already checked by SQL query */
|
||||
(void) exchange_timestamp;
|
||||
(void) wallet_timestamp;
|
||||
au->merchant_pub = *merchant_pub;
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Aggregator processing payment %s with amount %s\n",
|
||||
@ -501,6 +507,8 @@ deposit_cb (void *cls,
|
||||
*
|
||||
* @param cls a `struct AggregationUnit`
|
||||
* @param row_id identifies database entry
|
||||
* @param exchange_timestamp when did the exchange receive the deposit
|
||||
* @param wallet_timestamp when did the wallet sign the contract
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -514,6 +522,8 @@ deposit_cb (void *cls,
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
aggregate_cb (void *cls,
|
||||
uint64_t row_id,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -529,6 +539,8 @@ aggregate_cb (void *cls,
|
||||
/* NOTE: potential optimization: use custom SQL API to not
|
||||
fetch these: */
|
||||
(void) wire_deadline; /* checked by SQL */
|
||||
(void) exchange_timestamp;
|
||||
(void) wallet_timestamp;
|
||||
(void) wire; /* must match */
|
||||
GNUNET_break (0 == GNUNET_memcmp (&au->merchant_pub,
|
||||
merchant_pub));
|
||||
|
@ -420,6 +420,45 @@ proceed_with_handler (const struct TEH_RequestHandler *rh,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/seed" request.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param args array of additional options (must be empty for this function)
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
handler_seed (const struct TEH_RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
const char *const args[])
|
||||
{
|
||||
#define SEED_SIZE 32
|
||||
char *body;
|
||||
MHD_RESULT ret;
|
||||
struct MHD_Response *resp;
|
||||
|
||||
(void) rh;
|
||||
body = malloc (SEED_SIZE); /* must use malloc(), because MHD will use free() */
|
||||
if (NULL == body)
|
||||
return MHD_NO;
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
|
||||
body,
|
||||
SEED_SIZE);
|
||||
resp = MHD_create_response_from_buffer (SEED_SIZE,
|
||||
body,
|
||||
MHD_RESPMEM_MUST_FREE);
|
||||
TALER_MHD_add_global_headers (resp);
|
||||
ret = MHD_queue_response (connection,
|
||||
MHD_HTTP_OK,
|
||||
resp);
|
||||
GNUNET_break (MHD_YES == ret);
|
||||
MHD_destroy_response (resp);
|
||||
return ret;
|
||||
#undef SEED_SIZE
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle incoming HTTP request.
|
||||
*
|
||||
@ -472,6 +511,11 @@ handle_mhd_request (void *cls,
|
||||
.method = MHD_HTTP_METHOD_GET,
|
||||
.handler.get = &TEH_handler_agpl_redirect
|
||||
},
|
||||
{
|
||||
.url = "seed",
|
||||
.method = MHD_HTTP_METHOD_GET,
|
||||
.handler.get = &handler_seed
|
||||
},
|
||||
/* Terms of service */
|
||||
{
|
||||
.url = "terms",
|
||||
@ -654,9 +698,10 @@ handle_mhd_request (void *cls,
|
||||
{
|
||||
struct TEH_RequestHandler *rh = &handlers[i];
|
||||
|
||||
if (0 != strncmp (tok,
|
||||
rh->url,
|
||||
tok_size))
|
||||
if ( (0 != strncmp (tok,
|
||||
rh->url,
|
||||
tok_size)) ||
|
||||
(tok_size != strlen (rh->url) ) )
|
||||
continue;
|
||||
found = GNUNET_YES;
|
||||
/* The URL is a match! What we now do depends on the method. */
|
||||
@ -782,8 +827,8 @@ exchange_serve_process_config (void)
|
||||
&TEH_master_public_key.
|
||||
eddsa_pub))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Invalid master public key given in exchange configuration.");
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Invalid master public key given in exchange configuration.");
|
||||
GNUNET_free (master_public_key_str);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
@ -795,14 +840,18 @@ exchange_serve_process_config (void)
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_WIRE_init (TEH_cfg))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to setup wire subsystem\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
if (NULL ==
|
||||
(TEH_plugin = TALER_EXCHANGEDB_plugin_load (TEH_cfg)))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to initialize DB subsystem\n");
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to initialize DB subsystem\n");
|
||||
TEH_WIRE_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
@ -814,6 +863,8 @@ exchange_serve_process_config (void)
|
||||
&serve_unixpath,
|
||||
&unixpath_mode))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to setup HTTPd subsystem\n");
|
||||
TEH_WIRE_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
* @param coin_pub public key of the coin
|
||||
* @param h_wire hash of wire details
|
||||
* @param h_contract_terms hash of contract details
|
||||
* @param timestamp client's timestamp
|
||||
* @param exchange_timestamp exchange's timestamp
|
||||
* @param refund_deadline until when this deposit be refunded
|
||||
* @param merchant merchant public key
|
||||
* @param amount_without_fee fraction of coin value to deposit, without the fee
|
||||
@ -58,7 +58,7 @@ reply_deposit_success (struct MHD_Connection *connection,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute refund_deadline,
|
||||
const struct TALER_MerchantPublicKeyP *merchant,
|
||||
const struct TALER_Amount *amount_without_fee)
|
||||
@ -70,7 +70,7 @@ reply_deposit_success (struct MHD_Connection *connection,
|
||||
.purpose.size = htonl (sizeof (dc)),
|
||||
.h_contract_terms = *h_contract_terms,
|
||||
.h_wire = *h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (timestamp),
|
||||
.exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
|
||||
.coin_pub = *coin_pub,
|
||||
.merchant = *merchant
|
||||
@ -88,12 +88,16 @@ reply_deposit_success (struct MHD_Connection *connection,
|
||||
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
|
||||
"no keys");
|
||||
}
|
||||
return TALER_MHD_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:s, s:o, s:o}",
|
||||
"status", "DEPOSIT_OK",
|
||||
"sig", GNUNET_JSON_from_data_auto (&sig),
|
||||
"pub", GNUNET_JSON_from_data_auto (&pub));
|
||||
return TALER_MHD_reply_json_pack (
|
||||
connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:o, s:o, s:o}",
|
||||
"exchange_timestamp",
|
||||
GNUNET_JSON_from_time_abs (exchange_timestamp),
|
||||
"exchange_sig",
|
||||
GNUNET_JSON_from_data_auto (&sig),
|
||||
"exchange_pub",
|
||||
GNUNET_JSON_from_data_auto (&pub));
|
||||
}
|
||||
|
||||
|
||||
@ -107,6 +111,11 @@ struct DepositContext
|
||||
*/
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit;
|
||||
|
||||
/**
|
||||
* Our timestamp (when we received the request).
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
|
||||
/**
|
||||
* Value of the coin.
|
||||
*/
|
||||
@ -115,6 +124,74 @@ struct DepositContext
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Check if /deposit is already in the database. IF it returns a non-error
|
||||
* code, the transaction logic MUST NOT queue a MHD response. IF it returns
|
||||
* an hard error, the transaction logic MUST queue a MHD response and set @a
|
||||
* mhd_ret. We do return a "hard" error also if we found the deposit in the
|
||||
* database and generated a regular response.
|
||||
*
|
||||
* @param cls a `struct DepositContext`
|
||||
* @param connection MHD request context
|
||||
* @param session database session and transaction to use
|
||||
* @param[out] mhd_ret set to MHD status on error
|
||||
* @return transaction status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
deposit_precheck (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
MHD_RESULT *mhd_ret)
|
||||
{
|
||||
struct DepositContext *dc = cls;
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit = dc->deposit;
|
||||
struct TALER_Amount deposit_fee;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
qs = TEH_plugin->have_deposit (TEH_plugin->cls,
|
||||
session,
|
||||
deposit,
|
||||
GNUNET_YES /* check refund deadline */,
|
||||
&deposit_fee,
|
||||
&dc->exchange_timestamp);
|
||||
if (qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||
{
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_DEPOSIT_HISTORY_DB_ERROR,
|
||||
"Could not check for existing identical deposit");
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
|
||||
{
|
||||
struct TALER_Amount amount_without_fee;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"/deposit replay, accepting again!\n");
|
||||
GNUNET_assert (0 <=
|
||||
TALER_amount_subtract (&amount_without_fee,
|
||||
&deposit->amount_with_fee,
|
||||
&deposit_fee));
|
||||
*mhd_ret = reply_deposit_success (connection,
|
||||
&deposit->coin.coin_pub,
|
||||
&deposit->h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
dc->exchange_timestamp,
|
||||
deposit->refund_deadline,
|
||||
&deposit->merchant_pub,
|
||||
&amount_without_fee);
|
||||
/* Treat as 'hard' DB error as we want to rollback and
|
||||
never try again. */
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Execute database transaction for /deposit. Runs the transaction
|
||||
* logic; IF it returns a non-error code, the transaction logic MUST
|
||||
@ -140,44 +217,15 @@ deposit_transaction (void *cls,
|
||||
struct TALER_Amount spent;
|
||||
enum GNUNET_DB_QueryStatus qs;
|
||||
|
||||
qs = TEH_plugin->have_deposit (TEH_plugin->cls,
|
||||
session,
|
||||
deposit,
|
||||
GNUNET_YES /* check refund deadline */);
|
||||
/* Theoretically, someone other threat may have received
|
||||
and committed the deposit in the meantime. Check now
|
||||
that we are in the transaction scope. */
|
||||
qs = deposit_precheck (cls,
|
||||
connection,
|
||||
session,
|
||||
mhd_ret);
|
||||
if (qs < 0)
|
||||
{
|
||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||
{
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
TALER_EC_DEPOSIT_HISTORY_DB_ERROR,
|
||||
"Could not check for existing identical deposit");
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
|
||||
{
|
||||
struct TALER_Amount amount_without_fee;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"/deposit replay, accepting again!\n");
|
||||
GNUNET_assert (0 <=
|
||||
TALER_amount_subtract (&amount_without_fee,
|
||||
&deposit->amount_with_fee,
|
||||
&deposit->deposit_fee));
|
||||
*mhd_ret = reply_deposit_success (connection,
|
||||
&deposit->coin.coin_pub,
|
||||
&deposit->h_wire,
|
||||
&deposit->h_contract_terms,
|
||||
deposit->timestamp,
|
||||
deposit->refund_deadline,
|
||||
&deposit->merchant_pub,
|
||||
&amount_without_fee);
|
||||
/* Treat as 'hard' DB error as we want to rollback and
|
||||
never try again. */
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
}
|
||||
|
||||
/* Start with fee for THIS transaction */
|
||||
spent = deposit->amount_with_fee;
|
||||
@ -237,6 +285,7 @@ deposit_transaction (void *cls,
|
||||
}
|
||||
qs = TEH_plugin->insert_deposit (TEH_plugin->cls,
|
||||
session,
|
||||
dc->exchange_timestamp,
|
||||
deposit);
|
||||
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
|
||||
{
|
||||
@ -250,45 +299,6 @@ deposit_transaction (void *cls,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check that @a ts is reasonably close to our own RTC.
|
||||
*
|
||||
* @param ts timestamp to check
|
||||
* @return #GNUNET_OK if @a ts is reasonable
|
||||
*/
|
||||
static int
|
||||
check_timestamp_current (struct GNUNET_TIME_Absolute ts)
|
||||
{
|
||||
struct GNUNET_TIME_Relative r;
|
||||
struct GNUNET_TIME_Relative tolerance;
|
||||
|
||||
/* Let's be VERY generous (after all, this is basically about
|
||||
which year the deposit counts for in terms of tax purposes) */
|
||||
tolerance = GNUNET_TIME_UNIT_MONTHS;
|
||||
r = GNUNET_TIME_absolute_get_duration (ts);
|
||||
if (r.rel_value_us > tolerance.rel_value_us)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Deposit timestamp too old: %llu vs %llu > %llu\n",
|
||||
(unsigned long long) ts.abs_value_us,
|
||||
(unsigned long long) GNUNET_TIME_absolute_get ().abs_value_us,
|
||||
(unsigned long long) tolerance.rel_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
r = GNUNET_TIME_absolute_get_remaining (ts);
|
||||
if (r.rel_value_us > tolerance.rel_value_us)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
|
||||
"Deposit timestamp too new: %llu vs %llu < - %llu\n",
|
||||
(unsigned long long) ts.abs_value_us,
|
||||
(unsigned long long) GNUNET_TIME_absolute_get ().abs_value_us,
|
||||
(unsigned long long) tolerance.rel_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/coins/$COIN_PUB/deposit" request. Parses the JSON, and, if
|
||||
* successful, passes the JSON data to #deposit_transaction() to
|
||||
@ -312,15 +322,22 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
struct GNUNET_HashCode my_h_wire;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_json ("wire", &wire),
|
||||
TALER_JSON_spec_amount ("contribution", &deposit.amount_with_fee),
|
||||
TALER_JSON_spec_amount ("contribution",
|
||||
&deposit.amount_with_fee),
|
||||
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
|
||||
&deposit.coin.denom_pub_hash),
|
||||
TALER_JSON_spec_denomination_signature ("ub_sig", &deposit.coin.denom_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &deposit.merchant_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms", &deposit.h_contract_terms),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire", &deposit.h_wire),
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_sig", &deposit.csig),
|
||||
GNUNET_JSON_spec_absolute_time ("timestamp", &deposit.timestamp),
|
||||
TALER_JSON_spec_denomination_signature ("ub_sig",
|
||||
&deposit.coin.denom_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
|
||||
&deposit.merchant_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
|
||||
&deposit.h_contract_terms),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
||||
&deposit.h_wire),
|
||||
GNUNET_JSON_spec_fixed_auto ("coin_sig",
|
||||
&deposit.csig),
|
||||
GNUNET_JSON_spec_absolute_time ("timestamp",
|
||||
&deposit.timestamp),
|
||||
GNUNET_JSON_spec_absolute_time ("refund_deadline",
|
||||
&deposit.refund_deadline),
|
||||
GNUNET_JSON_spec_absolute_time ("wire_transfer_deadline",
|
||||
@ -359,17 +376,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
TALER_EC_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
|
||||
"refund_deadline");
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
check_timestamp_current (deposit.timestamp))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_DEPOSIT_INVALID_TIMESTAMP,
|
||||
"timestamp");
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_JSON_merchant_wire_signature_hash (wire,
|
||||
&my_h_wire))
|
||||
@ -393,6 +399,26 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
"h_wire");
|
||||
}
|
||||
|
||||
/* Check for idempotency: did we get this request before? */
|
||||
dc.deposit = &deposit;
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
TEH_DB_run_transaction (connection,
|
||||
"precheck deposit",
|
||||
&mhd_ret,
|
||||
&deposit_precheck,
|
||||
&dc))
|
||||
{
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return mhd_ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* new deposit */
|
||||
dc.exchange_timestamp = GNUNET_TIME_absolute_get ();
|
||||
(void) GNUNET_TIME_round_abs (&dc.exchange_timestamp);
|
||||
/* check denomination exists and is valid */
|
||||
{
|
||||
struct TEH_KS_StateHandle *key_state;
|
||||
@ -400,7 +426,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
enum TALER_ErrorCode ec;
|
||||
unsigned int hc;
|
||||
|
||||
key_state = TEH_KS_acquire (GNUNET_TIME_absolute_get ());
|
||||
key_state = TEH_KS_acquire (dc.exchange_timestamp);
|
||||
if (NULL == key_state)
|
||||
{
|
||||
TALER_LOG_ERROR ("Lacking keys to operate\n");
|
||||
@ -494,7 +520,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
.purpose.size = htonl (sizeof (dr)),
|
||||
.h_contract_terms = deposit.h_contract_terms,
|
||||
.h_wire = deposit.h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (deposit.timestamp),
|
||||
.wallet_timestamp = GNUNET_TIME_absolute_hton (deposit.timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (deposit.refund_deadline),
|
||||
.merchant = deposit.merchant_pub,
|
||||
.coin_pub = deposit.coin.coin_pub
|
||||
@ -520,7 +546,6 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
/* execute transaction */
|
||||
dc.deposit = &deposit;
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
|
||||
@ -549,7 +574,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
|
||||
&deposit.coin.coin_pub,
|
||||
&deposit.h_wire,
|
||||
&deposit.h_contract_terms,
|
||||
deposit.timestamp,
|
||||
dc.exchange_timestamp,
|
||||
deposit.refund_deadline,
|
||||
&deposit.merchant_pub,
|
||||
&amount_without_fee);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014--2019 Taler Systems SA
|
||||
Copyright (C) 2014--2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -44,7 +44,7 @@
|
||||
* #TALER_PROTOCOL_CURRENT and #TALER_PROTOCOL_AGE in
|
||||
* exchange_api_handle.c!
|
||||
*/
|
||||
#define EXCHANGE_PROTOCOL_VERSION "7:0:0"
|
||||
#define EXCHANGE_PROTOCOL_VERSION "8:0:0"
|
||||
|
||||
|
||||
/**
|
||||
@ -801,7 +801,7 @@ reload_keys_denom_iter (void *cls,
|
||||
handle_signal (SIGTERM);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
GNUNET_assert (NULL != dki->denom_priv.rsa_private_key);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Adding denomination key `%s' (%s) to active set\n",
|
||||
alias,
|
||||
@ -1660,6 +1660,9 @@ reload_public_denoms_cb (
|
||||
GNUNET_h2s (&issue->properties.denom_hash));
|
||||
return;
|
||||
}
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Loaded denomination key %s from DB, no private key (hopefully revoked!)\n",
|
||||
GNUNET_h2s (&issue->properties.denom_hash));
|
||||
/* we can assert here as we checked for duplicates just above */
|
||||
GNUNET_assert (GNUNET_OK == ret);
|
||||
}
|
||||
|
@ -73,12 +73,13 @@ reply_refund_success (struct MHD_Connection *connection,
|
||||
TALER_EC_EXCHANGE_BAD_CONFIGURATION,
|
||||
"no online signing key");
|
||||
}
|
||||
return TALER_MHD_reply_json_pack (connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:s, s:o, s:o}",
|
||||
"status", "REFUND_OK",
|
||||
"sig", GNUNET_JSON_from_data_auto (&sig),
|
||||
"pub", GNUNET_JSON_from_data_auto (&pub));
|
||||
return TALER_MHD_reply_json_pack (
|
||||
connection,
|
||||
MHD_HTTP_OK,
|
||||
"{s:o, s:o, s:o}",
|
||||
"refund_fee", TALER_JSON_from_amount (&refund->refund_fee),
|
||||
"exchange_sig", GNUNET_JSON_from_data_auto (&sig),
|
||||
"exchange_pub", GNUNET_JSON_from_data_auto (&pub));
|
||||
}
|
||||
|
||||
|
||||
@ -246,18 +247,15 @@ refund_transaction (void *cls,
|
||||
}
|
||||
|
||||
/* check currency is compatible */
|
||||
if ( (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&refund->details.refund_amount,
|
||||
&dep->amount_with_fee)) ||
|
||||
(GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&refund->details.refund_fee,
|
||||
&dep->deposit_fee)) )
|
||||
if (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&refund->details.refund_amount,
|
||||
&dep->amount_with_fee))
|
||||
{
|
||||
GNUNET_break_op (0); /* currency mismatch */
|
||||
TEH_plugin->free_coin_transaction_list (TEH_plugin->cls,
|
||||
tl);
|
||||
*mhd_ret = TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_PRECONDITION_FAILED,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_REFUND_CURRENCY_MISMATCH,
|
||||
"currencies involved do not match");
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
@ -339,15 +337,14 @@ refund_transaction (void *cls,
|
||||
* the fee structure, so this is not done here.
|
||||
*
|
||||
* @param connection the MHD connection to handle
|
||||
* @param refund information about the refund
|
||||
* @param[in,out] refund information about the refund
|
||||
* @return MHD result code
|
||||
*/
|
||||
static MHD_RESULT
|
||||
verify_and_execute_refund (struct MHD_Connection *connection,
|
||||
const struct TALER_EXCHANGEDB_Refund *refund)
|
||||
struct TALER_EXCHANGEDB_Refund *refund)
|
||||
{
|
||||
struct GNUNET_HashCode denom_hash;
|
||||
struct TALER_Amount expect_fee;
|
||||
|
||||
{
|
||||
struct TALER_RefundRequestPS rr = {
|
||||
@ -361,8 +358,6 @@ verify_and_execute_refund (struct MHD_Connection *connection,
|
||||
|
||||
TALER_amount_hton (&rr.refund_amount,
|
||||
&refund->details.refund_amount);
|
||||
TALER_amount_hton (&rr.refund_fee,
|
||||
&refund->details.refund_fee);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
|
||||
&rr,
|
||||
@ -429,43 +424,12 @@ verify_and_execute_refund (struct MHD_Connection *connection,
|
||||
ec,
|
||||
"denomination not found, but coin known");
|
||||
}
|
||||
TALER_amount_ntoh (&expect_fee,
|
||||
TALER_amount_ntoh (&refund->details.refund_fee,
|
||||
&dki->issue.properties.fee_refund);
|
||||
}
|
||||
TEH_KS_release (key_state);
|
||||
}
|
||||
|
||||
/* Check refund fee matches fee of denomination key! */
|
||||
if (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&expect_fee,
|
||||
&refund->details.refund_fee) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_REFUND_FEE_CURRENCY_MISMATCH,
|
||||
"refund_fee");
|
||||
}
|
||||
{
|
||||
int fee_cmp;
|
||||
|
||||
fee_cmp = TALER_amount_cmp (&refund->details.refund_fee,
|
||||
&expect_fee);
|
||||
if (-1 == fee_cmp)
|
||||
{
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_REFUND_FEE_TOO_LOW,
|
||||
"refund_fee");
|
||||
}
|
||||
if (1 == fee_cmp)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Refund fee proposed by merchant is higher than necessary.\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Finally run the actual transaction logic */
|
||||
{
|
||||
MHD_RESULT mhd_ret;
|
||||
@ -502,16 +466,20 @@ TEH_handler_refund (struct MHD_Connection *connection,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const json_t *root)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_Refund refund;
|
||||
struct TALER_EXCHANGEDB_Refund refund = {
|
||||
.details.refund_fee.currency = {0} /* set to invalid, just to be sure */
|
||||
};
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
TALER_JSON_spec_amount ("refund_amount", &refund.details.refund_amount),
|
||||
TALER_JSON_spec_amount ("refund_fee", &refund.details.refund_fee),
|
||||
TALER_JSON_spec_amount ("refund_amount",
|
||||
&refund.details.refund_amount),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
|
||||
&refund.details.h_contract_terms),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &refund.details.merchant_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_pub",
|
||||
&refund.details.merchant_pub),
|
||||
GNUNET_JSON_spec_uint64 ("rtransaction_id",
|
||||
&refund.details.rtransaction_id),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_sig", &refund.details.merchant_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_sig",
|
||||
&refund.details.merchant_sig),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -527,27 +495,6 @@ TEH_handler_refund (struct MHD_Connection *connection,
|
||||
if (GNUNET_NO == res)
|
||||
return MHD_YES; /* failure */
|
||||
}
|
||||
if (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&refund.details.refund_amount,
|
||||
&refund.details.refund_fee) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_REFUND_FEE_CURRENCY_MISMATCH,
|
||||
"refund_amount or refund_fee");
|
||||
}
|
||||
if (-1 == TALER_amount_cmp (&refund.details.refund_amount,
|
||||
&refund.details.refund_fee) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return TALER_MHD_reply_with_error (connection,
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
TALER_EC_REFUND_FEE_ABOVE_AMOUNT,
|
||||
"refund_amount");
|
||||
}
|
||||
{
|
||||
MHD_RESULT res;
|
||||
|
||||
|
@ -66,7 +66,7 @@ TEH_RESPONSE_compile_transaction_history (
|
||||
.purpose.size = htonl (sizeof (dr)),
|
||||
.h_contract_terms = deposit->h_contract_terms,
|
||||
.h_wire = deposit->h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp),
|
||||
.wallet_timestamp = GNUNET_TIME_absolute_hton (deposit->timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (
|
||||
deposit->refund_deadline),
|
||||
.merchant = deposit->merchant_pub,
|
||||
@ -185,8 +185,6 @@ TEH_RESPONSE_compile_transaction_history (
|
||||
|
||||
TALER_amount_hton (&rr.refund_amount,
|
||||
&refund->refund_amount);
|
||||
TALER_amount_hton (&rr.refund_fee,
|
||||
&refund->refund_fee);
|
||||
#if ENABLE_SANITY_CHECKS
|
||||
/* internal sanity check before we hand out a bogus sig... */
|
||||
if (GNUNET_OK !=
|
||||
|
@ -341,6 +341,8 @@ TEH_WIRE_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
&ret);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Error setting up bank accounts\n");
|
||||
TEH_WIRE_done ();
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
@ -349,6 +351,8 @@ TEH_WIRE_init (const struct GNUNET_CONFIGURATION_Handle *cfg)
|
||||
(0 == json_object_size (wire_fee_object)) )
|
||||
{
|
||||
TEH_WIRE_done ();
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"No bank accounts configured\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
wire_methods = json_pack ("{s:O, s:O, s:o}",
|
||||
|
@ -306,8 +306,6 @@ withdraw_transaction (void *cls,
|
||||
#endif
|
||||
wc->collectable.denom_pub_hash = wc->denom_pub_hash;
|
||||
wc->collectable.amount_with_fee = wc->amount_required;
|
||||
TALER_amount_ntoh (&wc->collectable.withdraw_fee,
|
||||
&wc->dki->issue.properties.fee_withdraw);
|
||||
wc->collectable.reserve_pub = wc->wsrd.reserve_pub;
|
||||
wc->collectable.h_coin_envelope = wc->wsrd.h_coin_envelope;
|
||||
wc->collectable.reserve_sig = wc->signature;
|
||||
@ -436,8 +434,6 @@ TEH_handler_withdraw (const struct TEH_RequestHandler *rh,
|
||||
}
|
||||
TALER_amount_hton (&wc.wsrd.amount_with_fee,
|
||||
&wc.amount_required);
|
||||
TALER_amount_hton (&wc.wsrd.withdraw_fee,
|
||||
&fee_withdraw);
|
||||
}
|
||||
|
||||
/* verify signature! */
|
||||
|
@ -43,8 +43,8 @@ DROP TABLE IF EXISTS reserves CASCADE;
|
||||
DROP TABLE IF EXISTS denomination_revocations CASCADE;
|
||||
DROP TABLE IF EXISTS denominations CASCADE;
|
||||
|
||||
-- Drop versioning (0000.sql)
|
||||
DROP SCHEMA IF EXISTS _v CASCADE;
|
||||
-- Unregister patch (0001.sql)
|
||||
SELECT _v.unregister_patch('exchange-0001');
|
||||
|
||||
-- And we're out of here...
|
||||
COMMIT;
|
||||
|
@ -254,7 +254,8 @@ CREATE TABLE IF NOT EXISTS deposits
|
||||
,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
|
||||
,amount_with_fee_val INT8 NOT NULL
|
||||
,amount_with_fee_frac INT4 NOT NULL
|
||||
,timestamp INT8 NOT NULL
|
||||
,wallet_timestamp INT8 NOT NULL
|
||||
,exchange_timestamp INT8 NOT NULL
|
||||
,refund_deadline INT8 NOT NULL
|
||||
,wire_deadline INT8 NOT NULL
|
||||
,merchant_pub BYTEA NOT NULL CHECK (LENGTH(merchant_pub)=32)
|
||||
|
@ -796,7 +796,7 @@ postgres_get_session (void *cls)
|
||||
"(coin_pub"
|
||||
",amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",timestamp"
|
||||
",wallet_timestamp"
|
||||
",refund_deadline"
|
||||
",wire_deadline"
|
||||
",merchant_pub"
|
||||
@ -804,22 +804,28 @@ postgres_get_session (void *cls)
|
||||
",h_wire"
|
||||
",coin_sig"
|
||||
",wire"
|
||||
",exchange_timestamp"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6, $7, $8, $9, $10,"
|
||||
" $11);",
|
||||
11),
|
||||
" $11, $12);",
|
||||
12),
|
||||
/* Fetch an existing deposit request, used to ensure idempotency
|
||||
during /deposit processing. Used in #postgres_have_deposit(). */
|
||||
GNUNET_PQ_make_prepare ("get_deposit",
|
||||
"SELECT"
|
||||
" amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",timestamp"
|
||||
",denominations.fee_deposit_val"
|
||||
",denominations.fee_deposit_frac"
|
||||
",wallet_timestamp"
|
||||
",exchange_timestamp"
|
||||
",refund_deadline"
|
||||
",wire_deadline"
|
||||
",h_contract_terms"
|
||||
",h_wire"
|
||||
" FROM deposits"
|
||||
" JOIN known_coins USING (coin_pub)"
|
||||
" JOIN denominations USING (denom_pub_hash)"
|
||||
" WHERE ((coin_pub=$1)"
|
||||
" AND (merchant_pub=$3)"
|
||||
" AND (h_contract_terms=$2))"
|
||||
@ -830,7 +836,8 @@ postgres_get_session (void *cls)
|
||||
"SELECT"
|
||||
" amount_with_fee_val"
|
||||
",amount_with_fee_frac"
|
||||
",timestamp"
|
||||
",wallet_timestamp"
|
||||
",exchange_timestamp"
|
||||
",merchant_pub"
|
||||
",denom.denom_pub"
|
||||
",coin_pub"
|
||||
@ -881,6 +888,8 @@ postgres_get_session (void *cls)
|
||||
",wire"
|
||||
",merchant_pub"
|
||||
",coin_pub"
|
||||
",exchange_timestamp"
|
||||
",wallet_timestamp"
|
||||
" FROM deposits"
|
||||
" JOIN known_coins USING (coin_pub)"
|
||||
" JOIN denominations denom USING (denom_pub_hash)"
|
||||
@ -900,6 +909,8 @@ postgres_get_session (void *cls)
|
||||
",denom.fee_deposit_val"
|
||||
",denom.fee_deposit_frac"
|
||||
",wire_deadline"
|
||||
",exchange_timestamp"
|
||||
",wallet_timestamp"
|
||||
",h_contract_terms"
|
||||
",coin_pub"
|
||||
" FROM deposits"
|
||||
@ -945,7 +956,7 @@ postgres_get_session (void *cls)
|
||||
",amount_with_fee_frac"
|
||||
",denom.fee_deposit_val"
|
||||
",denom.fee_deposit_frac"
|
||||
",timestamp"
|
||||
",wallet_timestamp"
|
||||
",refund_deadline"
|
||||
",wire_deadline"
|
||||
",merchant_pub"
|
||||
@ -1801,8 +1812,12 @@ postgres_iterate_denomination_info (void *cls,
|
||||
.cb_cls = cb_cls,
|
||||
.pg = pc
|
||||
};
|
||||
struct TALER_EXCHANGEDB_Session *session;
|
||||
|
||||
return GNUNET_PQ_eval_prepared_multi_select (postgres_get_session (pc)->conn,
|
||||
session = postgres_get_session (pc);
|
||||
if (NULL == session)
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
return GNUNET_PQ_eval_prepared_multi_select (session->conn,
|
||||
"denomination_iterate",
|
||||
params,
|
||||
&domination_cb_helper,
|
||||
@ -2571,6 +2586,8 @@ postgres_get_reserve_history (void *cls,
|
||||
* @param session database connection
|
||||
* @param deposit deposit to search for
|
||||
* @param check_extras whether to check extra fields match or not
|
||||
* @param[out] deposit_fee set to the deposit fee the exchange charged
|
||||
* @param[out] exchange_timestamp set to the time when the exchange received the deposit
|
||||
* @return 1 if we know this operation,
|
||||
* 0 if this exact deposit is unknown to us,
|
||||
* otherwise transaction error status
|
||||
@ -2579,7 +2596,9 @@ static enum GNUNET_DB_QueryStatus
|
||||
postgres_have_deposit (void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
int check_extras)
|
||||
int check_extras,
|
||||
struct TALER_Amount *deposit_fee,
|
||||
struct GNUNET_TIME_Absolute *exchange_timestamp)
|
||||
{
|
||||
struct PostgresClosure *pg = cls;
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
@ -2592,12 +2611,16 @@ postgres_have_deposit (void *cls,
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit2.amount_with_fee),
|
||||
TALER_PQ_result_spec_absolute_time ("timestamp",
|
||||
TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
|
||||
&deposit2.timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
|
||||
exchange_timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("refund_deadline",
|
||||
&deposit2.refund_deadline),
|
||||
TALER_PQ_result_spec_absolute_time ("wire_deadline",
|
||||
&deposit2.wire_deadline),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
deposit_fee),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_wire",
|
||||
&deposit2.h_wire),
|
||||
GNUNET_PQ_result_spec_end
|
||||
@ -2776,6 +2799,8 @@ postgres_get_ready_deposit (void *cls,
|
||||
struct TALER_Amount amount_with_fee;
|
||||
struct TALER_Amount deposit_fee;
|
||||
struct GNUNET_TIME_Absolute wire_deadline;
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp;
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
struct GNUNET_HashCode h_contract_terms;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
@ -2788,6 +2813,10 @@ postgres_get_ready_deposit (void *cls,
|
||||
&amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit_fee),
|
||||
TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
|
||||
&exchange_timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
|
||||
&wallet_timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("wire_deadline",
|
||||
&wire_deadline),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
@ -2817,6 +2846,8 @@ postgres_get_ready_deposit (void *cls,
|
||||
|
||||
qs = deposit_cb (deposit_cb_cls,
|
||||
serial_id,
|
||||
exchange_timestamp,
|
||||
wallet_timestamp,
|
||||
&merchant_pub,
|
||||
&coin_pub,
|
||||
&amount_with_fee,
|
||||
@ -2898,6 +2929,8 @@ match_deposit_cb (void *cls,
|
||||
{
|
||||
struct TALER_Amount amount_with_fee;
|
||||
struct TALER_Amount deposit_fee;
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp;
|
||||
struct GNUNET_TIME_Absolute wire_deadline;
|
||||
struct GNUNET_HashCode h_contract_terms;
|
||||
struct TALER_CoinSpendPublicKeyP coin_pub;
|
||||
@ -2912,6 +2945,10 @@ match_deposit_cb (void *cls,
|
||||
&deposit_fee),
|
||||
TALER_PQ_result_spec_absolute_time ("wire_deadline",
|
||||
&wire_deadline),
|
||||
TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
|
||||
&exchange_timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
|
||||
&wallet_timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("h_contract_terms",
|
||||
&h_contract_terms),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("coin_pub",
|
||||
@ -2930,6 +2967,8 @@ match_deposit_cb (void *cls,
|
||||
}
|
||||
qs = mdc->deposit_cb (mdc->deposit_cb_cls,
|
||||
serial_id,
|
||||
exchange_timestamp,
|
||||
wallet_timestamp,
|
||||
mdc->merchant_pub,
|
||||
&coin_pub,
|
||||
&amount_with_fee,
|
||||
@ -3033,6 +3072,8 @@ postgres_get_known_coin (void *cls,
|
||||
coin_info->coin_pub = *coin_pub;
|
||||
if (NULL == session)
|
||||
session = postgres_get_session (pc);
|
||||
if (NULL == session)
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
|
||||
"get_known_coin",
|
||||
params,
|
||||
@ -3072,6 +3113,8 @@ postgres_get_coin_denomination (
|
||||
TALER_B2S (coin_pub));
|
||||
if (NULL == session)
|
||||
session = postgres_get_session (pc);
|
||||
if (NULL == session)
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
return GNUNET_PQ_eval_prepared_singleton_select (session->conn,
|
||||
"get_coin_denomination",
|
||||
params,
|
||||
@ -3210,12 +3253,14 @@ postgres_ensure_coin_known (void *cls,
|
||||
*
|
||||
* @param cls the `struct PostgresClosure` with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param exchange_timestamp time the exchange received the deposit request
|
||||
* @param deposit deposit information to store
|
||||
* @return query result status
|
||||
*/
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
postgres_insert_deposit (void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit)
|
||||
{
|
||||
struct GNUNET_PQ_QueryParam params[] = {
|
||||
@ -3229,6 +3274,7 @@ postgres_insert_deposit (void *cls,
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->h_wire),
|
||||
GNUNET_PQ_query_param_auto_from_type (&deposit->csig),
|
||||
TALER_PQ_query_param_json (deposit->receiver_wire_account),
|
||||
TALER_PQ_query_param_absolute_time (&exchange_timestamp),
|
||||
GNUNET_PQ_query_param_end
|
||||
};
|
||||
|
||||
@ -3437,6 +3483,8 @@ postgres_get_melt (void *cls,
|
||||
melt->session.coin.denom_sig.rsa_signature = NULL;
|
||||
if (NULL == session)
|
||||
session = postgres_get_session (pg);
|
||||
if (NULL == session)
|
||||
return GNUNET_DB_STATUS_HARD_ERROR;
|
||||
qs = GNUNET_PQ_eval_prepared_singleton_select (session->conn,
|
||||
"get_melt",
|
||||
params,
|
||||
@ -4042,7 +4090,7 @@ add_coin_deposit (void *cls,
|
||||
&deposit->amount_with_fee),
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
|
||||
&deposit->deposit_fee),
|
||||
TALER_PQ_result_spec_absolute_time ("timestamp",
|
||||
TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
|
||||
&deposit->timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("refund_deadline",
|
||||
&deposit->refund_deadline),
|
||||
@ -5462,14 +5510,17 @@ deposit_serial_helper_cb (void *cls,
|
||||
for (unsigned int i = 0; i<num_results; i++)
|
||||
{
|
||||
struct TALER_EXCHANGEDB_Deposit deposit;
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
struct TALER_DenominationPublicKey denom_pub;
|
||||
uint8_t done = 0;
|
||||
uint64_t rowid;
|
||||
struct GNUNET_PQ_ResultSpec rs[] = {
|
||||
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
|
||||
&deposit.amount_with_fee),
|
||||
TALER_PQ_result_spec_absolute_time ("timestamp",
|
||||
TALER_PQ_result_spec_absolute_time ("wallet_timestamp",
|
||||
&deposit.timestamp),
|
||||
TALER_PQ_result_spec_absolute_time ("exchange_timestamp",
|
||||
&exchange_timestamp),
|
||||
GNUNET_PQ_result_spec_auto_from_type ("merchant_pub",
|
||||
&deposit.merchant_pub),
|
||||
GNUNET_PQ_result_spec_rsa_public_key ("denom_pub",
|
||||
@ -5505,6 +5556,7 @@ deposit_serial_helper_cb (void *cls,
|
||||
}
|
||||
ret = dsc->cb (dsc->cb_cls,
|
||||
rowid,
|
||||
exchange_timestamp,
|
||||
deposit.timestamp,
|
||||
&deposit.merchant_pub,
|
||||
&denom_pub,
|
||||
|
@ -833,6 +833,8 @@ static uint64_t deposit_rowid;
|
||||
* @param cls closure a `struct TALER_EXCHANGEDB_Deposit *`
|
||||
* @param rowid unique ID for the deposit in our DB, used for marking
|
||||
* it as 'tiny' or 'done'
|
||||
* @param exchange_timestamp when did the deposit happen
|
||||
* @param wallet_timestamp when did the wallet sign the contract
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -846,6 +848,8 @@ static uint64_t deposit_rowid;
|
||||
static enum GNUNET_DB_QueryStatus
|
||||
deposit_cb (void *cls,
|
||||
uint64_t rowid,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -890,7 +894,8 @@ deposit_cb (void *cls,
|
||||
*
|
||||
* @param cls closure
|
||||
* @param rowid unique serial ID for the deposit in our DB
|
||||
* @param timestamp when did the deposit happen
|
||||
* @param exchange_timestamp when did the deposit happen
|
||||
* @param wallet_timestamp when did the wallet sign the contract
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param denom_pub denomination of the @a coin_pub
|
||||
* @param coin_pub public key of the coin
|
||||
@ -908,7 +913,8 @@ deposit_cb (void *cls,
|
||||
static int
|
||||
audit_deposit_cb (void *cls,
|
||||
uint64_t rowid,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -1878,15 +1884,27 @@ run (void *cls)
|
||||
plugin->ensure_coin_known (plugin->cls,
|
||||
session,
|
||||
&deposit.coin));
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->insert_deposit (plugin->cls,
|
||||
{
|
||||
struct GNUNET_TIME_Absolute now;
|
||||
struct GNUNET_TIME_Absolute r;
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
now = GNUNET_TIME_absolute_get ();
|
||||
GNUNET_TIME_round_abs (&now);
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
plugin->insert_deposit (plugin->cls,
|
||||
session,
|
||||
now,
|
||||
&deposit));
|
||||
FAILIF (1 !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit));
|
||||
FAILIF (1 !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit,
|
||||
GNUNET_YES));
|
||||
&deposit,
|
||||
GNUNET_YES,
|
||||
&deposit_fee,
|
||||
&r));
|
||||
FAILIF (now.abs_value_us != r.abs_value_us);
|
||||
}
|
||||
{
|
||||
struct GNUNET_TIME_Absolute start_range;
|
||||
struct GNUNET_TIME_Absolute end_range;
|
||||
@ -1983,18 +2001,27 @@ run (void *cls)
|
||||
session,
|
||||
"test-2"));
|
||||
RND_BLK (&deposit2.merchant_pub); /* should fail if merchant is different */
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2,
|
||||
GNUNET_YES));
|
||||
deposit2.merchant_pub = deposit.merchant_pub;
|
||||
RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2,
|
||||
GNUNET_YES));
|
||||
{
|
||||
struct GNUNET_TIME_Absolute r;
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2,
|
||||
GNUNET_YES,
|
||||
&deposit_fee,
|
||||
&r));
|
||||
deposit2.merchant_pub = deposit.merchant_pub;
|
||||
RND_BLK (&deposit2.coin.coin_pub); /* should fail if coin is different */
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
plugin->have_deposit (plugin->cls,
|
||||
session,
|
||||
&deposit2,
|
||||
GNUNET_YES,
|
||||
&deposit_fee,
|
||||
&r));
|
||||
}
|
||||
FAILIF (GNUNET_OK !=
|
||||
test_melting (session));
|
||||
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
|
@ -300,9 +300,9 @@ struct TALER_AUDITORDB_DepositConfirmation
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
/**
|
||||
* Time when this confirmation was generated.
|
||||
* Time when this deposit confirmation was generated by the exchange.
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute timestamp;
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
|
||||
/**
|
||||
* How much time does the @e merchant have to issue a refund
|
||||
|
@ -384,16 +384,16 @@ struct TALER_BANK_DebitDetails
|
||||
const char *exchange_base_url;
|
||||
|
||||
/**
|
||||
* payto://-URL of the source account that
|
||||
* payto://-URI of the source account that
|
||||
* send the funds.
|
||||
*/
|
||||
const char *debit_account_url;
|
||||
const char *debit_account_url; // FIXME: rename: url->uri
|
||||
|
||||
/**
|
||||
* payto://-URL of the target account that
|
||||
* payto://-URI of the target account that
|
||||
* received the funds.
|
||||
*/
|
||||
const char *credit_account_url;
|
||||
const char *credit_account_url; // FIXME: rename: url->uri
|
||||
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -744,6 +744,32 @@ TALER_EXCHANGE_wire_cancel (struct TALER_EXCHANGE_WireHandle *wh);
|
||||
/* ********************* /coins/$COIN_PUB/deposit *********************** */
|
||||
|
||||
|
||||
/**
|
||||
* Sign a deposit permission. Function for wallets.
|
||||
*
|
||||
* @param amount the amount to be deposited
|
||||
* @param deposit_fee the deposit fee we expect to pay
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param coin_priv coin’s private key
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
* @param[out] coin_sig set to the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT
|
||||
*/
|
||||
void
|
||||
TALER_EXCHANGE_deposit_permission_sign (
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
struct GNUNET_TIME_Absolute refund_deadline,
|
||||
struct TALER_CoinSpendSignatureP *coin_sig);
|
||||
|
||||
|
||||
/**
|
||||
* @brief A Deposit Handle
|
||||
*/
|
||||
@ -756,6 +782,7 @@ struct TALER_EXCHANGE_DepositHandle;
|
||||
*
|
||||
* @param cls closure
|
||||
* @param hr HTTP response data
|
||||
* @param deposit_timestamp time when the exchange generated the deposit confirmation
|
||||
* @param exchange_sig signature provided by the exchange
|
||||
* @param exchange_pub exchange key used to sign @a obj, or NULL
|
||||
*/
|
||||
@ -763,6 +790,7 @@ typedef void
|
||||
(*TALER_EXCHANGE_DepositResultCallback) (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
struct GNUNET_TIME_Absolute deposit_timestamp,
|
||||
const struct TALER_ExchangeSignatureP *exchange_sig,
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub);
|
||||
|
||||
@ -851,6 +879,7 @@ struct TALER_EXCHANGE_RefundHandle;
|
||||
*
|
||||
* @param cls closure
|
||||
* @param hr HTTP response data
|
||||
* @param refund_fee the refund fee the exchange charged us
|
||||
* @param sign_key exchange key used to sign @a obj, or NULL
|
||||
* @param signature the actual signature, or NULL on error
|
||||
*/
|
||||
@ -858,6 +887,7 @@ typedef void
|
||||
(*TALER_EXCHANGE_RefundCallback) (
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct TALER_ExchangePublicKeyP *sign_key,
|
||||
const struct TALER_ExchangeSignatureP *signature);
|
||||
|
||||
@ -878,7 +908,6 @@ typedef void
|
||||
* @param amount the amount to be refunded; must be larger than the refund fee
|
||||
* (as that fee is still being subtracted), and smaller than the amount
|
||||
* (with deposit fee) of the original deposit contribution of this coin
|
||||
* @param refund_fee fee applicable to this coin for the refund
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded
|
||||
* @param coin_pub coin’s public key of the coin from the original deposit operation
|
||||
* @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation);
|
||||
@ -894,7 +923,6 @@ typedef void
|
||||
struct TALER_EXCHANGE_RefundHandle *
|
||||
TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t rtransaction_id,
|
||||
@ -922,7 +950,6 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
* @param amount the amount to be refunded; must be larger than the refund fee
|
||||
* (as that fee is still being subtracted), and smaller than the amount
|
||||
* (with deposit fee) of the original deposit contribution of this coin
|
||||
* @param refund_fee fee applicable to this coin for the refund
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded
|
||||
* @param coin_pub coin’s public key of the coin from the original deposit operation
|
||||
* @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation);
|
||||
@ -939,7 +966,6 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
struct TALER_EXCHANGE_RefundHandle *
|
||||
TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t rtransaction_id,
|
||||
@ -1584,32 +1610,68 @@ TALER_EXCHANGE_link_cancel (struct TALER_EXCHANGE_LinkHandle *lh);
|
||||
struct TALER_EXCHANGE_TransfersGetHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Information the exchange returns per wire transfer.
|
||||
*/
|
||||
struct TALER_EXCHANGE_TransferData
|
||||
{
|
||||
|
||||
/**
|
||||
* exchange key used to sign
|
||||
*/
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
|
||||
/**
|
||||
* exchange signature over the transfer data
|
||||
*/
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
|
||||
/**
|
||||
* hash of the wire transfer address the transfer went to
|
||||
*/
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
/**
|
||||
* time when the exchange claims to have performed the wire transfer
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute execution_time;
|
||||
|
||||
/**
|
||||
* Actual amount of the wire transfer, excluding the wire fee.
|
||||
*/
|
||||
struct TALER_Amount total_amount;
|
||||
|
||||
/**
|
||||
* wire fee that was charged by the exchange
|
||||
*/
|
||||
struct TALER_Amount wire_fee;
|
||||
|
||||
/**
|
||||
* length of the @e details array
|
||||
*/
|
||||
unsigned int details_length;
|
||||
|
||||
/**
|
||||
* array with details about the combined transactions
|
||||
*/
|
||||
const struct TALER_TrackTransferDetails *details;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data, including all
|
||||
* of the coin transactions that were combined into the wire transfer.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param hr HTTP response data
|
||||
* @param sign_key exchange key used to sign @a json, or NULL
|
||||
* @param h_wire hash of the wire transfer address the transfer went to, or NULL on error
|
||||
* @param execution_time time when the exchange claims to have performed the wire transfer
|
||||
* @param total_amount total amount of the wire transfer, or NULL if the exchange could
|
||||
* not provide any @a wtid (set only if @a http_status is #MHD_HTTP_OK)
|
||||
* @param wire_fee wire fee that was charged by the exchange
|
||||
* @param details_length length of the @a details array
|
||||
* @param details array with details about the combined transactions
|
||||
* @param ta transfer data, (set only if @a http_status is #MHD_HTTP_OK, otherwise NULL)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_EXCHANGE_TransfersGetCallback)(
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_ExchangePublicKeyP *sign_key,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *total_amount,
|
||||
const struct TALER_Amount *wire_fee,
|
||||
unsigned int details_length,
|
||||
const struct TALER_TrackTransferDetails *details);
|
||||
const struct TALER_EXCHANGE_TransferData *ta);
|
||||
|
||||
|
||||
/**
|
||||
@ -1650,25 +1712,57 @@ TALER_EXCHANGE_transfers_get_cancel (
|
||||
struct TALER_EXCHANGE_DepositGetHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Data returned for a successful GET /deposits/ request. Note that
|
||||
* most fields are only set if the status is #MHD_HTTP_OK. Only
|
||||
* the @e execution_time is available if the status is #MHD_HTTP_ACCEPTED.
|
||||
*/
|
||||
struct TALER_EXCHANGE_DepositData
|
||||
{
|
||||
|
||||
/**
|
||||
* exchange key used to sign, all zeros if exchange did not
|
||||
* yet execute the transaction
|
||||
*/
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
|
||||
/**
|
||||
* signature from the exchange over the deposit data, all zeros if exchange did not
|
||||
* yet execute the transaction
|
||||
*/
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
|
||||
/**
|
||||
* wire transfer identifier used by the exchange, all zeros if exchange did not
|
||||
* yet execute the transaction
|
||||
*/
|
||||
struct TALER_WireTransferIdentifierRawP wtid;
|
||||
|
||||
/**
|
||||
* actual or planned execution time for the wire transfer
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute execution_time;
|
||||
|
||||
/**
|
||||
* contribution to the total amount by this coin, all zeros if exchange did not
|
||||
* yet execute the transaction
|
||||
*/
|
||||
struct TALER_Amount coin_contribution;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function called with detailed wire transfer data.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param hr HTTP response data
|
||||
* @param sign_key exchange key used to sign @a json, or NULL
|
||||
* @param wtid wire transfer identifier used by the exchange, NULL if exchange did not
|
||||
* yet execute the transaction
|
||||
* @param execution_time actual or planned execution time for the wire transfer
|
||||
* @param coin_contribution contribution to the total amount by this coin (can be NULL)
|
||||
* @param dd details about the deposit (NULL on errors)
|
||||
*/
|
||||
typedef void
|
||||
(*TALER_EXCHANGE_DepositGetCallback)(
|
||||
void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_ExchangePublicKeyP *sign_key,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *coin_contribution);
|
||||
const struct TALER_EXCHANGE_DepositData *dd);
|
||||
|
||||
|
||||
/**
|
||||
|
@ -975,6 +975,8 @@ struct TALER_EXCHANGEDB_Session;
|
||||
* @param cls closure
|
||||
* @param rowid unique ID for the deposit in our DB, used for marking
|
||||
* it as 'tiny' or 'done'
|
||||
* @param exchange_timestamp when did the exchange receive the deposit
|
||||
* @param wallet_timestamp when did the wallet sign the contract
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param coin_pub public key of the coin
|
||||
* @param amount_with_fee amount that was deposited including fee
|
||||
@ -990,6 +992,8 @@ typedef enum GNUNET_DB_QueryStatus
|
||||
(*TALER_EXCHANGEDB_DepositIterator)(
|
||||
void *cls,
|
||||
uint64_t rowid,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
const struct TALER_Amount *amount_with_fee,
|
||||
@ -1022,7 +1026,8 @@ typedef void
|
||||
*
|
||||
* @param cls closure
|
||||
* @param rowid unique serial ID for the deposit in our DB
|
||||
* @param timestamp when did the deposit happen
|
||||
* @param exchange_timestamp when did the deposit happen
|
||||
* @param wallet_timestamp when did the contract happen
|
||||
* @param merchant_pub public key of the merchant
|
||||
* @param denom_pub denomination public key of @a coin_pub
|
||||
* @param coin_pub public key of the coin
|
||||
@ -1042,7 +1047,8 @@ typedef int
|
||||
(*TALER_EXCHANGEDB_DepositCallback)(
|
||||
void *cls,
|
||||
uint64_t rowid,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
const struct TALER_DenominationPublicKey *denom_pub,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -1841,6 +1847,8 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
* @param session database connection
|
||||
* @param deposit deposit to search for
|
||||
* @param check_extras whether to check extra fields or not
|
||||
* @param[out] deposit_fee set to the deposit fee the exchange charged
|
||||
* @param[out] exchange_timestamp set to the time when the exchange received the deposit
|
||||
* @return 1 if we know this operation,
|
||||
* 0 if this exact deposit is unknown to us,
|
||||
* otherwise transaction error status
|
||||
@ -1849,7 +1857,9 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
(*have_deposit)(void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit,
|
||||
int check_extras);
|
||||
int check_extras,
|
||||
struct TALER_Amount *deposit_fee,
|
||||
struct GNUNET_TIME_Absolute *exchange_timestamp);
|
||||
|
||||
|
||||
/**
|
||||
@ -1857,12 +1867,14 @@ struct TALER_EXCHANGEDB_Plugin
|
||||
*
|
||||
* @param cls the @e cls of this struct with the plugin-specific state
|
||||
* @param session connection to the database
|
||||
* @param exchange_timestamp time the exchange received the deposit request
|
||||
* @param deposit deposit information to store
|
||||
* @return query result status
|
||||
*/
|
||||
enum GNUNET_DB_QueryStatus
|
||||
(*insert_deposit)(void *cls,
|
||||
struct TALER_EXCHANGEDB_Session *session,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
const struct TALER_EXCHANGEDB_Deposit *deposit);
|
||||
|
||||
|
||||
|
@ -264,7 +264,8 @@ TALER_MHD_parse_post_cleanup_callback (void *con_cls);
|
||||
|
||||
/**
|
||||
* Parse JSON object into components based on the given field
|
||||
* specification.
|
||||
* specification. If parsing fails, we return an HTTP
|
||||
* status code of 400 (#MHD_HTTP_BAD_REQUEST).
|
||||
*
|
||||
* @param connection the connection to send an error response to
|
||||
* @param root the JSON node to start the navigation at.
|
||||
@ -282,6 +283,30 @@ TALER_MHD_parse_json_data (struct MHD_Connection *connection,
|
||||
struct GNUNET_JSON_Specification *spec);
|
||||
|
||||
|
||||
/**
|
||||
* Parse JSON object that we (the server!) generated into components based on
|
||||
* the given field specification. The difference to
|
||||
* #TALER_MHD_parse_json_data() is that this function will fail
|
||||
* with an HTTP failure of 500 (internal server error) in case
|
||||
* parsing fails, instead of blaming it on the client with a
|
||||
* 400 (#MHD_HTTP_BAD_REQUEST).
|
||||
*
|
||||
* @param connection the connection to send an error response to
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param spec field specification for the parser
|
||||
* @return
|
||||
* #GNUNET_YES if navigation was successful (caller is responsible
|
||||
* for freeing allocated variable-size data using
|
||||
* GNUNET_JSON_parse_free() when done)
|
||||
* #GNUNET_NO if json is malformed, error response was generated
|
||||
* #GNUNET_SYSERR on internal error
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_MHD_parse_internal_json_data (struct MHD_Connection *connection,
|
||||
const json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec);
|
||||
|
||||
|
||||
/**
|
||||
* Parse JSON array into components based on the given field
|
||||
* specification. Generates error response on parse errors.
|
||||
|
@ -316,19 +316,6 @@ struct TALER_WithdrawRequestPS
|
||||
*/
|
||||
struct TALER_AmountNBO amount_with_fee;
|
||||
|
||||
/**
|
||||
* Withdrawal fee charged by the exchange. This must match the Exchange's
|
||||
* denomination key's withdrawal fee. If the client puts in an
|
||||
* invalid withdrawal fee (too high or too low) that does not match
|
||||
* the Exchange's denomination key, the withdraw operation is invalid
|
||||
* and will be rejected by the exchange. The @e amount_with_fee minus
|
||||
* the @e withdraw_fee is must match the value of the generated
|
||||
* coin. We include this in what is being signed so that we can
|
||||
* verify a exchange's accounting without needing to access the
|
||||
* respective denomination key information each time.
|
||||
*/
|
||||
struct TALER_AmountNBO withdraw_fee;
|
||||
|
||||
/**
|
||||
* Hash of the denomination public key for the coin that is withdrawn.
|
||||
*/
|
||||
@ -376,7 +363,7 @@ struct TALER_DepositRequestPS
|
||||
* deposit request in a timely fashion (so back-dating is not
|
||||
* prevented).
|
||||
*/
|
||||
struct GNUNET_TIME_AbsoluteNBO timestamp;
|
||||
struct GNUNET_TIME_AbsoluteNBO wallet_timestamp;
|
||||
|
||||
/**
|
||||
* How much time does the merchant have to issue a refund request?
|
||||
@ -442,9 +429,10 @@ struct TALER_DepositConfirmationPS
|
||||
struct GNUNET_HashCode h_wire GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Time when this confirmation was generated.
|
||||
* Time when this confirmation was generated / when the exchange received
|
||||
* the deposit request.
|
||||
*/
|
||||
struct GNUNET_TIME_AbsoluteNBO timestamp;
|
||||
struct GNUNET_TIME_AbsoluteNBO exchange_timestamp;
|
||||
|
||||
/**
|
||||
* How much time does the @e merchant have to issue a refund
|
||||
@ -517,17 +505,6 @@ struct TALER_RefundRequestPS
|
||||
*/
|
||||
struct TALER_AmountNBO refund_amount;
|
||||
|
||||
/**
|
||||
* Refund fee charged by the exchange. This must match the
|
||||
* Exchange's denomination key's refund fee. If the client puts in
|
||||
* an invalid refund fee (too high or too low) that does not match
|
||||
* the Exchange's denomination key, the refund operation is invalid
|
||||
* and will be rejected by the exchange. The @e amount_with_fee
|
||||
* minus the @e refund_fee is the amount that will be credited to
|
||||
* the original coin.
|
||||
*/
|
||||
struct TALER_AmountNBO refund_fee;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -1153,10 +1130,8 @@ struct TALER_ProposalDataPS
|
||||
struct PaymentResponsePS
|
||||
{
|
||||
/**
|
||||
* Set to TALER_SIGNATURE_MERCHANT_PAYMENT_OK so far. Note that
|
||||
* unsuccessful payments are usually proven by some exchange's signature,
|
||||
* thus it is unlikely that a merchant needs to set a purpose other than
|
||||
* the above mentioned
|
||||
* Set to #TALER_SIGNATURE_MERCHANT_PAYMENT_OK. Note that
|
||||
* unsuccessful payments are usually proven by some exchange's signature.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
|
152
src/include/taler_sq_lib.h
Normal file
152
src/include/taler_sq_lib.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file include/taler_sq_lib.h
|
||||
* @brief helper functions for DB interactions with SQLite
|
||||
* @author Jonathan Buchanan
|
||||
*/
|
||||
#ifndef TALER_SQ_LIB_H_
|
||||
#define TALER_SQ_LIB_H_
|
||||
|
||||
#include <sqlite3.h>
|
||||
#include <jansson.h>
|
||||
#include <gnunet/gnunet_sq_lib.h>
|
||||
#include "taler_util.h"
|
||||
|
||||
/**
|
||||
* Generate query parameter for a currency, consisting of the
|
||||
* components "value", "fraction" in this order. The
|
||||
* types must be a 64-bit integer and a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_amount_nbo (const struct TALER_AmountNBO *x);
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for a currency, consisting of the
|
||||
* components "value", "fraction" in this order. The
|
||||
* types must be a 64-bit integer and a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_amount (const struct TALER_Amount *x);
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for a JSON object (stored as a string
|
||||
* in the DB). Note that @a x must really be a JSON object or array,
|
||||
* passing just a value (string, integer) is not supported and will
|
||||
* result in an abort.
|
||||
*
|
||||
* @param x pointer to the json object to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_json (const json_t *x);
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for an absolute time value.
|
||||
* In contrast to
|
||||
* #GNUNET_SQ_query_param_absolute_time(), this function
|
||||
* will abort (!) if the time given is not rounded!
|
||||
* The database must store a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x);
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for an absolute time value.
|
||||
* In contrast to
|
||||
* #GNUNET_SQ_query_param_absolute_time(), this function
|
||||
* will abort (!) if the time given is not rounded!
|
||||
* The database must store a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_absolute_time_nbo (const struct
|
||||
GNUNET_TIME_AbsoluteNBO *x);
|
||||
|
||||
|
||||
/**
|
||||
* Currency amount expected.
|
||||
*
|
||||
* @param currency currency to use for @a amount
|
||||
* @param[out] amount where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_amount_nbo (const char *currency,
|
||||
struct TALER_AmountNBO *amount);
|
||||
|
||||
|
||||
/**
|
||||
* Currency amount expected.
|
||||
*
|
||||
* @param currency currency to use for @a amount
|
||||
* @param[out] amount where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_amount (const char *currency,
|
||||
struct TALER_Amount *amount);
|
||||
|
||||
|
||||
/**
|
||||
* json_t expected.
|
||||
*
|
||||
* @param[out] jp where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_json (json_t **jp);
|
||||
|
||||
|
||||
/**
|
||||
* Rounded absolute time expected.
|
||||
* In contrast to #GNUNET_SQ_query_param_absolute_time_nbo(),
|
||||
* this function ensures that the result is rounded and can
|
||||
* be converted to JSON.
|
||||
*
|
||||
* @param[out] at where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at);
|
||||
|
||||
|
||||
/**
|
||||
* Rounded absolute time expected.
|
||||
* In contrast to #GNUNET_SQ_result_spec_absolute_time_nbo(),
|
||||
* this function ensures that the result is rounded and can
|
||||
* be converted to JSON.
|
||||
*
|
||||
* @param[out] at where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_absolute_time_nbo (struct GNUNET_TIME_AbsoluteNBO *at);
|
||||
|
||||
|
||||
#endif /* TALER_SQ_LIB_H_ */
|
||||
|
||||
/* end of include/taler_sq_lib.h */
|
@ -388,10 +388,9 @@ struct TALER_TESTING_Interpreter
|
||||
void *final_cleanup_cb_cls;
|
||||
|
||||
/**
|
||||
* Instruction pointer. Tells #interpreter_run() which
|
||||
* instruction to run next. Need (signed) int because
|
||||
* it gets -1 when rewinding the interpreter to the first
|
||||
* CMD.
|
||||
* Instruction pointer. Tells #interpreter_run() which instruction to run
|
||||
* next. Need (signed) int because it gets -1 when rewinding the
|
||||
* interpreter to the first CMD.
|
||||
*/
|
||||
int ip;
|
||||
|
||||
@ -599,7 +598,22 @@ TALER_TESTING_interpreter_fail (struct TALER_TESTING_Interpreter *is);
|
||||
* @return a end-command.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_end ();
|
||||
TALER_TESTING_cmd_end (void);
|
||||
|
||||
|
||||
/**
|
||||
* Make the instruction pointer point to @a target_label
|
||||
* only if @a counter is greater than zero.
|
||||
*
|
||||
* @param label command label
|
||||
* @param target_label label of the new instruction pointer's destination after the jump;
|
||||
* must be before the current instruction
|
||||
* @param counter counts how many times the rewinding is to happen.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_rewind_ip (const char *label,
|
||||
const char *target_label,
|
||||
unsigned int counter);
|
||||
|
||||
|
||||
/**
|
||||
@ -816,7 +830,6 @@ TALER_TESTING_setup_with_auditor_and_exchange (TALER_TESTING_Main main_cb,
|
||||
* @param config_filename configuration filename.
|
||||
* @param bank_url base URL of the bank, used by `wget' to check
|
||||
* that the bank was started right.
|
||||
*
|
||||
* @return the process, or NULL if the process could not
|
||||
* be started.
|
||||
*/
|
||||
@ -839,6 +852,7 @@ TALER_TESTING_run_bank (const char *config_filename,
|
||||
struct TALER_TESTING_LibeufinServices
|
||||
TALER_TESTING_run_libeufin (const struct TALER_TESTING_BankConfiguration *bc);
|
||||
|
||||
|
||||
/**
|
||||
* Runs the Fakebank by guessing / extracting the portnumber
|
||||
* from the base URL.
|
||||
@ -1089,7 +1103,7 @@ TALER_TESTING_cmd_admin_add_incoming (
|
||||
* @param payto_debit_account which account sends money.
|
||||
* @param auth authentication data
|
||||
* @param ref reference to a command that can offer a reserve
|
||||
* private key.
|
||||
* private key or public key.
|
||||
* @return the command.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
@ -1345,6 +1359,16 @@ TALER_TESTING_cmd_status (const char *label,
|
||||
const char *expected_balance,
|
||||
unsigned int expected_response_code);
|
||||
|
||||
/**
|
||||
* Index of the deposit value trait of a deposit command.
|
||||
*/
|
||||
#define TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_VALUE 0
|
||||
|
||||
/**
|
||||
* Index of the deposit fee trait of a deposit command.
|
||||
*/
|
||||
#define TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_FEE 1
|
||||
|
||||
/**
|
||||
* Create a "deposit" command.
|
||||
*
|
||||
@ -1670,7 +1694,6 @@ TALER_TESTING_cmd_check_bank_empty (const char *label);
|
||||
* @param label command label.
|
||||
* @param expected_response_code expected HTTP status code.
|
||||
* @param refund_amount the amount to ask a refund for.
|
||||
* @param refund_fee expected refund fee.
|
||||
* @param coin_reference reference to a command that can
|
||||
* provide a coin to be refunded.
|
||||
* @param refund_transaction_id transaction id to use
|
||||
@ -1682,7 +1705,6 @@ struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_refund_with_id (const char *label,
|
||||
unsigned int expected_response_code,
|
||||
const char *refund_amount,
|
||||
const char *refund_fee,
|
||||
const char *deposit_reference,
|
||||
uint64_t refund_transaction_id);
|
||||
|
||||
@ -1693,7 +1715,6 @@ TALER_TESTING_cmd_refund_with_id (const char *label,
|
||||
* @param label command label.
|
||||
* @param expected_response_code expected HTTP status code.
|
||||
* @param refund_amount the amount to ask a refund for.
|
||||
* @param refund_fee expected refund fee.
|
||||
* @param coin_reference reference to a command that can
|
||||
* provide a coin to be refunded.
|
||||
*
|
||||
@ -1703,7 +1724,6 @@ struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_refund (const char *label,
|
||||
unsigned int expected_response_code,
|
||||
const char *refund_amount,
|
||||
const char *refund_fee,
|
||||
const char *deposit_reference);
|
||||
|
||||
|
||||
@ -1890,6 +1910,18 @@ TALER_TESTING_cmd_batch_next (struct TALER_TESTING_Interpreter *is);
|
||||
struct TALER_TESTING_Command *
|
||||
TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd);
|
||||
|
||||
|
||||
/**
|
||||
* Set what command the batch should be at.
|
||||
*
|
||||
* @param cmd current batch command
|
||||
* @param new_ip where to move the IP
|
||||
*/
|
||||
void
|
||||
TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int new_ip);
|
||||
|
||||
|
||||
/**
|
||||
* Make a serialize-keys CMD.
|
||||
*
|
||||
@ -1921,6 +1953,7 @@ TALER_TESTING_cmd_connect_with_state (const char *label,
|
||||
* @param dbc collects plugin and session handles
|
||||
* @param merchant_name Human-readable name of the merchant.
|
||||
* @param merchant_account merchant's account name (NOT a payto:// URI)
|
||||
* @param exchange_timestamp when did the exchange receive the deposit
|
||||
* @param wire_deadline point in time where the aggregator should have
|
||||
* wired money to the merchant.
|
||||
* @param amount_with_fee amount to deposit (inclusive of deposit fee)
|
||||
@ -1928,14 +1961,15 @@ TALER_TESTING_cmd_connect_with_state (const char *label,
|
||||
* @return the command.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_insert_deposit (const char *label,
|
||||
const struct
|
||||
TALER_TESTING_DatabaseConnection *dbc,
|
||||
const char *merchant_name,
|
||||
const char *merchant_account,
|
||||
struct GNUNET_TIME_Relative wire_deadline,
|
||||
const char *amount_with_fee,
|
||||
const char *deposit_fee);
|
||||
TALER_TESTING_cmd_insert_deposit (
|
||||
const char *label,
|
||||
const struct TALER_TESTING_DatabaseConnection *dbc,
|
||||
const char *merchant_name,
|
||||
const char *merchant_account,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Relative wire_deadline,
|
||||
const char *amount_with_fee,
|
||||
const char *deposit_fee);
|
||||
|
||||
|
||||
/**
|
||||
@ -2339,6 +2373,31 @@ TALER_TESTING_make_trait_denom_sig (
|
||||
const struct TALER_DenominationSignature *sig);
|
||||
|
||||
|
||||
/**
|
||||
* Offer number trait, 32-bit version.
|
||||
*
|
||||
* @param index the number's index number.
|
||||
* @param n number to offer.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_uint32 (unsigned int index,
|
||||
const uint32_t *n);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a "number" value from @a cmd, 32-bit version.
|
||||
*
|
||||
* @param cmd command to extract the number from.
|
||||
* @param index the number's index number.
|
||||
* @param[out] n set to the number coming from @a cmd.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_uint32 (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const uint32_t **n);
|
||||
|
||||
|
||||
/**
|
||||
* Offer number trait, 64-bit version.
|
||||
*
|
||||
@ -2364,6 +2423,31 @@ TALER_TESTING_get_trait_uint64 (const struct TALER_TESTING_Command *cmd,
|
||||
const uint64_t **n);
|
||||
|
||||
|
||||
/**
|
||||
* Offer number trait, 64-bit signed version.
|
||||
*
|
||||
* @param index the number's index number.
|
||||
* @param n number to offer.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_int64 (unsigned int index,
|
||||
const int64_t *n);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a "number" value from @a cmd, 64-bit signed version.
|
||||
*
|
||||
* @param cmd command to extract the number from.
|
||||
* @param index the number's index number.
|
||||
* @param[out] n set to the number coming from @a cmd.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_int64 (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const int64_t **n);
|
||||
|
||||
|
||||
/**
|
||||
* Offer a number.
|
||||
*
|
||||
@ -2513,6 +2597,33 @@ TALER_TESTING_make_trait_exchange_keys (unsigned int index,
|
||||
const json_t *keys);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain json from @a cmd.
|
||||
*
|
||||
* @param cmd command to extract the json from.
|
||||
* @param index index number associate with the json on offer.
|
||||
* @param[out] json where to write the json.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_json (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const json_t **json);
|
||||
|
||||
|
||||
/**
|
||||
* Offer json in a trait.
|
||||
*
|
||||
* @param index index number associate with the json
|
||||
* on offer.
|
||||
* @param json json to offer.
|
||||
* @return the trait.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_json (unsigned int index,
|
||||
const json_t *json);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a private key from a "merchant". Used e.g. to obtain
|
||||
* a merchant's priv to sign a /track request.
|
||||
@ -2854,4 +2965,33 @@ TALER_TESTING_make_trait_absolute_time (
|
||||
unsigned int index,
|
||||
const struct GNUNET_TIME_Absolute *time);
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a relative time from @a cmd.
|
||||
*
|
||||
* @param cmd command to extract trait from
|
||||
* @param index which time to pick if
|
||||
* @a cmd has multiple on offer.
|
||||
* @param[out] time set to the wanted WTID.
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_relative_time (
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const struct GNUNET_TIME_Relative **time);
|
||||
|
||||
|
||||
/**
|
||||
* Offer a relative time.
|
||||
*
|
||||
* @param index associate the object with this index
|
||||
* @param time which object should be returned
|
||||
* @return the trait.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_relative_time (
|
||||
unsigned int index,
|
||||
const struct GNUNET_TIME_Relative *time);
|
||||
|
||||
#endif
|
||||
|
@ -298,4 +298,52 @@ char *
|
||||
TALER_xtalerbank_account_from_payto (const char *payto);
|
||||
|
||||
|
||||
/**
|
||||
* Possible values for a binary filter.
|
||||
*/
|
||||
enum TALER_EXCHANGE_YesNoAll
|
||||
{
|
||||
/**
|
||||
* If condition is yes.
|
||||
*/
|
||||
TALER_EXCHANGE_YNA_YES = 1,
|
||||
|
||||
/**
|
||||
* If condition is no.
|
||||
*/
|
||||
TALER_EXCHANGE_YNA_NO = 2,
|
||||
|
||||
/**
|
||||
* Condition disabled.
|
||||
*/
|
||||
TALER_EXCHANGE_YNA_ALL = 3
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Convert query argument to @a yna value.
|
||||
*
|
||||
* @param connection connection to take query argument from
|
||||
* @param arg argument to try for
|
||||
* @param default_val value to assign if the argument is not present
|
||||
* @param[out] value to set
|
||||
* @return true on success, false if the parameter was malformed
|
||||
*/
|
||||
bool
|
||||
TALER_arg_to_yna (struct MHD_Connection *connection,
|
||||
const char *arg,
|
||||
enum TALER_EXCHANGE_YesNoAll default_val,
|
||||
enum TALER_EXCHANGE_YesNoAll *yna);
|
||||
|
||||
|
||||
/**
|
||||
* Convert YNA value to a string.
|
||||
*
|
||||
* @param yna value to convert
|
||||
* @return string representation ("yes"/"no"/"all").
|
||||
*/
|
||||
const char *
|
||||
TALER_yna_to_string (enum TALER_EXCHANGE_YesNoAll yna);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -148,7 +148,7 @@ handle_deposit_confirmation_finished (void *cls,
|
||||
*
|
||||
* @param h_wire hash of merchant wire details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
|
||||
* @param timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param exchange_timestamp timestamp when the deposit was received by the wallet
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
* @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant
|
||||
* @param coin_pub coin’s public key
|
||||
@ -165,7 +165,7 @@ handle_deposit_confirmation_finished (void *cls,
|
||||
static int
|
||||
verify_signatures (const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute refund_deadline,
|
||||
const struct TALER_Amount *amount_without_fee,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -184,7 +184,7 @@ verify_signatures (const struct GNUNET_HashCode *h_wire,
|
||||
.purpose.size = htonl (sizeof (dc)),
|
||||
.h_contract_terms = *h_contract_terms,
|
||||
.h_wire = *h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (timestamp),
|
||||
.exchange_timestamp = GNUNET_TIME_absolute_hton (exchange_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
|
||||
.coin_pub = *coin_pub,
|
||||
.merchant = *merchant_pub
|
||||
@ -256,7 +256,7 @@ verify_signatures (const struct GNUNET_HashCode *h_wire,
|
||||
* @param auditor the auditor handle; the auditor must be ready to operate
|
||||
* @param h_wire hash of merchant wire details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the auditor)
|
||||
* @param timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param exchange_timestamp timestamp when deposit was received by the exchange
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the auditor (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
* @param amount_without_fee the amount confirmed to be wired by the exchange to the merchant
|
||||
* @param coin_pub coin’s public key
|
||||
@ -278,7 +278,7 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
struct TALER_AUDITOR_Handle *auditor,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
struct GNUNET_TIME_Absolute timestamp,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Absolute refund_deadline,
|
||||
const struct TALER_Amount *amount_without_fee,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
@ -298,7 +298,7 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
json_t *deposit_confirmation_obj;
|
||||
CURL *eh;
|
||||
|
||||
(void) GNUNET_TIME_round_abs (×tamp);
|
||||
(void) GNUNET_TIME_round_abs (&exchange_timestamp);
|
||||
(void) GNUNET_TIME_round_abs (&refund_deadline);
|
||||
(void) GNUNET_TIME_round_abs (&ep_start);
|
||||
(void) GNUNET_TIME_round_abs (&ep_expire);
|
||||
@ -308,7 +308,7 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
if (GNUNET_OK !=
|
||||
verify_signatures (h_wire,
|
||||
h_contract_terms,
|
||||
timestamp,
|
||||
exchange_timestamp,
|
||||
refund_deadline,
|
||||
amount_without_fee,
|
||||
coin_pub,
|
||||
@ -336,7 +336,8 @@ TALER_AUDITOR_deposit_confirmation (
|
||||
"h_wire", GNUNET_JSON_from_data_auto (h_wire),
|
||||
"h_contract_terms", GNUNET_JSON_from_data_auto (
|
||||
h_contract_terms),
|
||||
"timestamp", GNUNET_JSON_from_time_abs (timestamp),
|
||||
"exchange_timestamp", GNUNET_JSON_from_time_abs (
|
||||
exchange_timestamp),
|
||||
"refund_deadline", GNUNET_JSON_from_time_abs (refund_deadline),
|
||||
"amount_without_fee", TALER_JSON_from_amount (
|
||||
amount_without_fee),
|
||||
|
@ -146,11 +146,12 @@ TALER_EXCHANGE_parse_reserve_history (
|
||||
{
|
||||
struct TALER_ReserveSignatureP sig;
|
||||
struct TALER_WithdrawRequestPS withdraw_purpose;
|
||||
struct TALER_Amount withdraw_fee;
|
||||
struct GNUNET_JSON_Specification withdraw_spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
|
||||
&sig),
|
||||
TALER_JSON_spec_amount_nbo ("withdraw_fee",
|
||||
&withdraw_purpose.withdraw_fee),
|
||||
TALER_JSON_spec_amount ("withdraw_fee",
|
||||
&withdraw_fee),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
|
||||
&withdraw_purpose.h_denomination_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_coin_envelope",
|
||||
@ -189,26 +190,23 @@ TALER_EXCHANGE_parse_reserve_history (
|
||||
{
|
||||
const struct TALER_EXCHANGE_Keys *key_state;
|
||||
const struct TALER_EXCHANGE_DenomPublicKey *dki;
|
||||
struct TALER_Amount fee;
|
||||
|
||||
key_state = TALER_EXCHANGE_get_keys (exchange);
|
||||
dki = TALER_EXCHANGE_get_denomination_key_by_hash (key_state,
|
||||
&withdraw_purpose.
|
||||
h_denomination_pub);
|
||||
TALER_amount_ntoh (&fee,
|
||||
&withdraw_purpose.withdraw_fee);
|
||||
if ( (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&fee,
|
||||
TALER_amount_cmp_currency (&withdraw_fee,
|
||||
&dki->fee_withdraw)) ||
|
||||
(0 !=
|
||||
TALER_amount_cmp (&fee,
|
||||
TALER_amount_cmp (&withdraw_fee,
|
||||
&dki->fee_withdraw)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (withdraw_spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rh->details.withdraw.fee = fee;
|
||||
rh->details.withdraw.fee = withdraw_fee;
|
||||
}
|
||||
rh->details.withdraw.out_authorization_sig
|
||||
= json_object_get (transaction,
|
||||
@ -526,7 +524,7 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire",
|
||||
&dr.h_wire),
|
||||
GNUNET_JSON_spec_absolute_time_nbo ("timestamp",
|
||||
&dr.timestamp),
|
||||
&dr.wallet_timestamp),
|
||||
GNUNET_JSON_spec_absolute_time_nbo ("refund_deadline",
|
||||
&dr.refund_deadline),
|
||||
TALER_JSON_spec_amount_nbo ("deposit_fee",
|
||||
@ -634,9 +632,16 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
else if (0 == strcasecmp (type,
|
||||
"REFUND"))
|
||||
{
|
||||
struct TALER_RefundRequestPS rr;
|
||||
struct TALER_MerchantSignatureP sig;
|
||||
struct TALER_Amount refund_fee;
|
||||
struct TALER_RefundRequestPS rr = {
|
||||
.purpose.size = htonl (sizeof (rr)),
|
||||
.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
|
||||
.coin_pub = *coin_pub
|
||||
};
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
TALER_JSON_spec_amount ("refund_fee",
|
||||
&refund_fee),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_sig",
|
||||
&sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_contract_terms",
|
||||
@ -645,8 +650,6 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
&rr.merchant),
|
||||
GNUNET_JSON_spec_uint64 ("rtransaction_id",
|
||||
&rr.rtransaction_id),
|
||||
TALER_JSON_spec_amount_nbo ("refund_fee",
|
||||
&rr.refund_fee),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -658,9 +661,6 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rr.purpose.size = htonl (sizeof (rr));
|
||||
rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
|
||||
rr.coin_pub = *coin_pub;
|
||||
TALER_amount_hton (&rr.refund_amount,
|
||||
&amount);
|
||||
if (GNUNET_OK !=
|
||||
@ -683,13 +683,11 @@ TALER_EXCHANGE_verify_coin_history (
|
||||
/* check that refund fee matches our expectations from /keys! */
|
||||
if (NULL != dk)
|
||||
{
|
||||
TALER_amount_ntoh (&fee,
|
||||
&rr.refund_fee);
|
||||
if ( (GNUNET_YES !=
|
||||
TALER_amount_cmp_currency (&fee,
|
||||
TALER_amount_cmp_currency (&refund_fee,
|
||||
&dk->fee_refund)) ||
|
||||
(0 !=
|
||||
TALER_amount_cmp (&fee,
|
||||
TALER_amount_cmp (&refund_fee,
|
||||
&dk->fee_refund)) )
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
|
@ -160,7 +160,7 @@ auditor_cb (void *cls,
|
||||
ah,
|
||||
&dh->depconf.h_wire,
|
||||
&dh->depconf.h_contract_terms,
|
||||
GNUNET_TIME_absolute_ntoh (dh->depconf.timestamp),
|
||||
GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
|
||||
GNUNET_TIME_absolute_ntoh (dh->depconf.refund_deadline),
|
||||
&amount_without_fee,
|
||||
&dh->depconf.coin_pub,
|
||||
@ -196,8 +196,10 @@ verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
|
||||
{
|
||||
const struct TALER_EXCHANGE_Keys *key_state;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("sig", exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("pub", exchange_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
|
||||
GNUNET_JSON_spec_absolute_time_nbo ("exchange_timestamp",
|
||||
&dh->depconf.exchange_timestamp),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -386,6 +388,7 @@ handle_deposit_finished (void *cls,
|
||||
}
|
||||
dh->cb (dh->cb_cls,
|
||||
&hr,
|
||||
GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
|
||||
es,
|
||||
ep);
|
||||
TALER_EXCHANGE_deposit_cancel (dh);
|
||||
@ -429,7 +432,7 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
|
||||
.purpose.size = htonl (sizeof (dr)),
|
||||
.h_contract_terms = *h_contract_terms,
|
||||
.h_wire = *h_wire,
|
||||
.timestamp = GNUNET_TIME_absolute_hton (timestamp),
|
||||
.wallet_timestamp = GNUNET_TIME_absolute_hton (timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
|
||||
.merchant = *merchant_pub,
|
||||
.coin_pub = *coin_pub
|
||||
@ -487,6 +490,59 @@ verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sign a deposit permission. Function for wallets.
|
||||
*
|
||||
* @param amount the amount to be deposited
|
||||
* @param deposit_fee the deposit fee we expect to pay
|
||||
* @param h_wire hash of the merchant’s account details
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer (further details are never disclosed to the exchange)
|
||||
* @param coin_priv coin’s private key
|
||||
* @param wallet_timestamp timestamp when the contract was finalized, must not be too far in the future
|
||||
* @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests)
|
||||
* @param refund_deadline date until which the merchant can issue a refund to the customer via the exchange (can be zero if refunds are not allowed); must not be after the @a wire_deadline
|
||||
* @param[out] coin_sig set to the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT
|
||||
*/
|
||||
void
|
||||
TALER_EXCHANGE_deposit_permission_sign (
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *deposit_fee,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp,
|
||||
const struct TALER_MerchantPublicKeyP *merchant_pub,
|
||||
struct GNUNET_TIME_Absolute refund_deadline,
|
||||
struct TALER_CoinSpendSignatureP *coin_sig)
|
||||
{
|
||||
struct TALER_DepositRequestPS dr = {
|
||||
.purpose.size = htonl
|
||||
(sizeof (dr)),
|
||||
.purpose.purpose = htonl
|
||||
(TALER_SIGNATURE_WALLET_COIN_DEPOSIT),
|
||||
.h_contract_terms = *h_contract_terms,
|
||||
.h_wire = *h_wire,
|
||||
.wallet_timestamp = GNUNET_TIME_absolute_hton (wallet_timestamp),
|
||||
.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline),
|
||||
.merchant = *merchant_pub
|
||||
};
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&wallet_timestamp));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&refund_deadline));
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&dr.coin_pub.eddsa_pub);
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
deposit_fee);
|
||||
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
|
||||
&dr,
|
||||
&coin_sig->eddsa_signature);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Submit a deposit permission to the exchange and get the exchange's response.
|
||||
* Note that while we return the response verbatim to the caller for
|
||||
@ -658,7 +714,7 @@ TALER_EXCHANGE_deposit (struct TALER_EXCHANGE_Handle *exchange,
|
||||
TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT);
|
||||
dh->depconf.h_contract_terms = *h_contract_terms;
|
||||
dh->depconf.h_wire = h_wire;
|
||||
dh->depconf.timestamp = GNUNET_TIME_absolute_hton (timestamp);
|
||||
/* dh->depconf.exchange_timestamp; -- initialized later from exchange reply! */
|
||||
dh->depconf.refund_deadline = GNUNET_TIME_absolute_hton (refund_deadline);
|
||||
TALER_amount_hton (&dh->depconf.amount_without_fee,
|
||||
&amount_without_fee);
|
||||
|
@ -33,7 +33,7 @@
|
||||
|
||||
|
||||
/**
|
||||
* @brief A Deposit Wtid Handle
|
||||
* @brief A Deposit Get Handle
|
||||
*/
|
||||
struct TALER_EXCHANGE_DepositGetHandle
|
||||
{
|
||||
@ -84,31 +84,19 @@ struct TALER_EXCHANGE_DepositGetHandle
|
||||
*
|
||||
* @param dwh deposit wtid handle
|
||||
* @param json json reply with the signature
|
||||
* @param[out] exchange_pub set to the exchange's public key
|
||||
* @param exchange_pub the exchange's public key
|
||||
* @param exchange_sig the exchange's signature
|
||||
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
|
||||
*/
|
||||
static int
|
||||
verify_deposit_wtid_signature_ok (
|
||||
const struct TALER_EXCHANGE_DepositGetHandle *dwh,
|
||||
const json_t *json,
|
||||
struct TALER_ExchangePublicKeyP *exchange_pub)
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
||||
const struct TALER_ExchangeSignatureP *exchange_sig)
|
||||
{
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
const struct TALER_EXCHANGE_Keys *key_state;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (json,
|
||||
spec,
|
||||
NULL, NULL))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
key_state = TALER_EXCHANGE_get_keys (dwh->exchange);
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGE_test_signing_key (key_state,
|
||||
@ -120,7 +108,7 @@ verify_deposit_wtid_signature_ok (
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE,
|
||||
&dwh->depconf,
|
||||
&exchange_sig.eddsa_signature,
|
||||
&exchange_sig->eddsa_signature,
|
||||
&exchange_pub->eddsa_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
@ -144,12 +132,6 @@ handle_deposit_wtid_finished (void *cls,
|
||||
const void *response)
|
||||
{
|
||||
struct TALER_EXCHANGE_DepositGetHandle *dwh = cls;
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid = NULL;
|
||||
struct GNUNET_TIME_Absolute execution_time = GNUNET_TIME_UNIT_FOREVER_ABS;
|
||||
const struct TALER_Amount *coin_contribution = NULL;
|
||||
struct TALER_Amount coin_contribution_s;
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
struct TALER_ExchangePublicKeyP *ep = NULL;
|
||||
const json_t *j = response;
|
||||
struct TALER_EXCHANGE_HttpResponse hr = {
|
||||
.reply = j,
|
||||
@ -164,10 +146,13 @@ handle_deposit_wtid_finished (void *cls,
|
||||
break;
|
||||
case MHD_HTTP_OK:
|
||||
{
|
||||
struct TALER_EXCHANGE_DepositData dd;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
|
||||
GNUNET_JSON_spec_absolute_time ("execution_time", &execution_time),
|
||||
TALER_JSON_spec_amount ("coin_contribution", &coin_contribution_s),
|
||||
GNUNET_JSON_spec_absolute_time ("execution_time", &dd.execution_time),
|
||||
TALER_JSON_spec_amount ("coin_contribution", &dd.coin_contribution),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &dd.exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &dd.exchange_pub),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -181,15 +166,15 @@ handle_deposit_wtid_finished (void *cls,
|
||||
hr.ec = TALER_EC_DEPOSITS_INVALID_BODY_BY_EXCHANGE;
|
||||
break;
|
||||
}
|
||||
wtid = &dwh->depconf.wtid;
|
||||
dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (execution_time);
|
||||
dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (
|
||||
dd.execution_time);
|
||||
TALER_amount_hton (&dwh->depconf.coin_contribution,
|
||||
&coin_contribution_s);
|
||||
coin_contribution = &coin_contribution_s;
|
||||
&dd.coin_contribution);
|
||||
if (GNUNET_OK !=
|
||||
verify_deposit_wtid_signature_ok (dwh,
|
||||
j,
|
||||
&exchange_pub))
|
||||
&dd.exchange_pub,
|
||||
&dd.exchange_sig))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
hr.http_status = 0;
|
||||
@ -197,13 +182,19 @@ handle_deposit_wtid_finished (void *cls,
|
||||
}
|
||||
else
|
||||
{
|
||||
ep = &exchange_pub;
|
||||
dd.wtid = dwh->depconf.wtid;
|
||||
dwh->cb (dwh->cb_cls,
|
||||
&hr,
|
||||
&dd);
|
||||
TALER_EXCHANGE_deposits_get_cancel (dwh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_ACCEPTED:
|
||||
{
|
||||
/* Transaction known, but not executed yet */
|
||||
struct GNUNET_TIME_Absolute execution_time;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_absolute_time ("execution_time", &execution_time),
|
||||
GNUNET_JSON_spec_end ()
|
||||
@ -219,6 +210,18 @@ handle_deposit_wtid_finished (void *cls,
|
||||
hr.ec = TALER_EC_DEPOSITS_INVALID_BODY_BY_EXCHANGE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct TALER_EXCHANGE_DepositData dd = {
|
||||
.execution_time = execution_time
|
||||
};
|
||||
|
||||
dwh->cb (dwh->cb_cls,
|
||||
&hr,
|
||||
&dd);
|
||||
TALER_EXCHANGE_deposits_get_cancel (dwh);
|
||||
return;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
@ -259,10 +262,7 @@ handle_deposit_wtid_finished (void *cls,
|
||||
}
|
||||
dwh->cb (dwh->cb_cls,
|
||||
&hr,
|
||||
ep,
|
||||
wtid,
|
||||
execution_time,
|
||||
coin_contribution);
|
||||
NULL);
|
||||
TALER_EXCHANGE_deposits_get_cancel (dwh);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@
|
||||
* Which version of the Taler protocol is implemented
|
||||
* by this library? Used to determine compatibility.
|
||||
*/
|
||||
#define EXCHANGE_PROTOCOL_CURRENT 7
|
||||
#define EXCHANGE_PROTOCOL_CURRENT 8
|
||||
|
||||
/**
|
||||
* How many versions are we backwards compatible with?
|
||||
|
@ -445,11 +445,11 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
|
||||
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
|
||||
char *end;
|
||||
|
||||
end = GNUNET_STRINGS_data_to_string (&melt.coin_pub,
|
||||
sizeof (struct
|
||||
TALER_CoinSpendPublicKeyP),
|
||||
pub_str,
|
||||
sizeof (pub_str));
|
||||
end = GNUNET_STRINGS_data_to_string (
|
||||
&melt.coin_pub,
|
||||
sizeof (struct TALER_CoinSpendPublicKeyP),
|
||||
pub_str,
|
||||
sizeof (pub_str));
|
||||
*end = '\0';
|
||||
GNUNET_snprintf (arg_str,
|
||||
sizeof (arg_str),
|
||||
|
@ -81,23 +81,23 @@ struct TALER_EXCHANGE_RefundHandle
|
||||
* Verify that the signature on the "200 OK" response
|
||||
* from the exchange is valid.
|
||||
*
|
||||
* @param rh refund handle
|
||||
* @param[in,out] rh refund handle (refund fee added)
|
||||
* @param json json reply with the signature
|
||||
* @param[out] exchange_pub set to the exchange's public key
|
||||
* @param[out] exchange_sig set to the exchange's signature
|
||||
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
|
||||
*/
|
||||
static int
|
||||
verify_refund_signature_ok (const struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
verify_refund_signature_ok (struct TALER_EXCHANGE_RefundHandle *rh,
|
||||
const json_t *json,
|
||||
struct TALER_ExchangePublicKeyP *exchange_pub,
|
||||
struct TALER_ExchangeSignatureP *exchange_sig)
|
||||
|
||||
{
|
||||
const struct TALER_EXCHANGE_Keys *key_state;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
GNUNET_JSON_spec_fixed_auto ("sig", exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("pub", exchange_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
|
||||
TALER_JSON_spec_amount_nbo ("refund_fee", &rh->depconf.refund_fee),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
@ -148,12 +148,15 @@ handle_refund_finished (void *cls,
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
struct TALER_ExchangePublicKeyP *ep = NULL;
|
||||
struct TALER_ExchangeSignatureP *es = NULL;
|
||||
struct TALER_Amount ra;
|
||||
const struct TALER_Amount *rf = NULL;
|
||||
const json_t *j = response;
|
||||
struct TALER_EXCHANGE_HttpResponse hr = {
|
||||
.reply = j,
|
||||
.http_status = (unsigned int) response_code
|
||||
};
|
||||
|
||||
|
||||
rh->job = NULL;
|
||||
switch (response_code)
|
||||
{
|
||||
@ -175,6 +178,9 @@ handle_refund_finished (void *cls,
|
||||
{
|
||||
ep = &exchange_pub;
|
||||
es = &exchange_sig;
|
||||
TALER_amount_ntoh (&ra,
|
||||
&rh->depconf.refund_fee);
|
||||
rf = &ra;
|
||||
}
|
||||
break;
|
||||
case MHD_HTTP_BAD_REQUEST:
|
||||
@ -233,6 +239,7 @@ handle_refund_finished (void *cls,
|
||||
}
|
||||
rh->cb (rh->cb_cls,
|
||||
&hr,
|
||||
rf,
|
||||
ep,
|
||||
es);
|
||||
TALER_EXCHANGE_refund_cancel (rh);
|
||||
@ -256,7 +263,6 @@ handle_refund_finished (void *cls,
|
||||
* @param amount the amount to be refunded; must be larger than the refund fee
|
||||
* (as that fee is still being subtracted), and smaller than the amount
|
||||
* (with deposit fee) of the original deposit contribution of this coin
|
||||
* @param refund_fee fee applicable to this coin for the refund
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded
|
||||
* @param coin_pub coin’s public key of the coin from the original deposit operation
|
||||
* @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation);
|
||||
@ -272,7 +278,6 @@ handle_refund_finished (void *cls,
|
||||
struct TALER_EXCHANGE_RefundHandle *
|
||||
TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t rtransaction_id,
|
||||
@ -294,14 +299,11 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
rr.rtransaction_id = GNUNET_htonll (rtransaction_id);
|
||||
TALER_amount_hton (&rr.refund_amount,
|
||||
amount);
|
||||
TALER_amount_hton (&rr.refund_fee,
|
||||
refund_fee);
|
||||
GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
|
||||
&rr,
|
||||
&merchant_sig.eddsa_sig);
|
||||
return TALER_EXCHANGE_refund2 (exchange,
|
||||
amount,
|
||||
refund_fee,
|
||||
h_contract_terms,
|
||||
coin_pub,
|
||||
rtransaction_id,
|
||||
@ -329,7 +331,6 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
* @param amount the amount to be refunded; must be larger than the refund fee
|
||||
* (as that fee is still being subtracted), and smaller than the amount
|
||||
* (with deposit fee) of the original deposit contribution of this coin
|
||||
* @param refund_fee fee applicable to this coin for the refund
|
||||
* @param h_contract_terms hash of the contact of the merchant with the customer that is being refunded
|
||||
* @param coin_pub coin’s public key of the coin from the original deposit operation
|
||||
* @param rtransaction_id transaction id for the transaction between merchant and customer (of refunding operation);
|
||||
@ -346,7 +347,6 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange,
|
||||
struct TALER_EXCHANGE_RefundHandle *
|
||||
TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange,
|
||||
const struct TALER_Amount *amount,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct GNUNET_HashCode *h_contract_terms,
|
||||
const struct TALER_CoinSpendPublicKeyP *coin_pub,
|
||||
uint64_t rtransaction_id,
|
||||
@ -376,12 +376,11 @@ TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange,
|
||||
"/coins/%s/refund",
|
||||
pub_str);
|
||||
}
|
||||
refund_obj = json_pack ("{s:o, s:o," /* amount/fee */
|
||||
refund_obj = json_pack ("{s:o," /* amount */
|
||||
" s:o," /* h_contract_terms */
|
||||
" s:I," /* rtransaction id */
|
||||
" s:o, s:o}", /* merchant_pub, merchant_sig */
|
||||
"refund_amount", TALER_JSON_from_amount (amount),
|
||||
"refund_fee", TALER_JSON_from_amount (refund_fee),
|
||||
"h_contract_terms", GNUNET_JSON_from_data_auto (
|
||||
h_contract_terms),
|
||||
"rtransaction_id", (json_int_t) rtransaction_id,
|
||||
@ -410,8 +409,6 @@ TALER_EXCHANGE_refund2 (struct TALER_EXCHANGE_Handle *exchange,
|
||||
rh->depconf.rtransaction_id = GNUNET_htonll (rtransaction_id);
|
||||
TALER_amount_hton (&rh->depconf.refund_amount,
|
||||
amount);
|
||||
TALER_amount_hton (&rh->depconf.refund_fee,
|
||||
refund_fee);
|
||||
|
||||
eh = TALER_EXCHANGE_curl_easy_get_ (rh->url);
|
||||
if ( (NULL == eh) ||
|
||||
|
@ -85,24 +85,18 @@ check_transfers_get_response_ok (
|
||||
const json_t *json)
|
||||
{
|
||||
json_t *details_j;
|
||||
struct GNUNET_HashCode h_wire;
|
||||
struct GNUNET_TIME_Absolute exec_time;
|
||||
struct TALER_Amount total_amount;
|
||||
struct TALER_EXCHANGE_TransferData td;
|
||||
struct TALER_Amount total_expected;
|
||||
struct TALER_Amount wire_fee;
|
||||
struct TALER_MerchantPublicKeyP merchant_pub;
|
||||
unsigned int num_details;
|
||||
struct TALER_ExchangePublicKeyP exchange_pub;
|
||||
struct TALER_ExchangeSignatureP exchange_sig;
|
||||
struct GNUNET_JSON_Specification spec[] = {
|
||||
TALER_JSON_spec_amount ("total", &total_amount),
|
||||
TALER_JSON_spec_amount ("wire_fee", &wire_fee),
|
||||
TALER_JSON_spec_amount ("total", &td.total_amount),
|
||||
TALER_JSON_spec_amount ("wire_fee", &td.wire_fee),
|
||||
GNUNET_JSON_spec_fixed_auto ("merchant_pub", &merchant_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire", &h_wire),
|
||||
GNUNET_JSON_spec_absolute_time ("execution_time", &exec_time),
|
||||
GNUNET_JSON_spec_fixed_auto ("h_wire", &td.h_wire),
|
||||
GNUNET_JSON_spec_absolute_time ("execution_time", &td.execution_time),
|
||||
GNUNET_JSON_spec_json ("deposits", &details_j),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &exchange_pub),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &td.exchange_sig),
|
||||
GNUNET_JSON_spec_fixed_auto ("exchange_pub", &td.exchange_pub),
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
struct TALER_EXCHANGE_HttpResponse hr = {
|
||||
@ -119,22 +113,32 @@ check_transfers_get_response_ok (
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_amount_get_zero (total_amount.currency,
|
||||
TALER_amount_get_zero (td.total_amount.currency,
|
||||
&total_expected))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
num_details = json_array_size (details_j);
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGE_test_signing_key (
|
||||
TALER_EXCHANGE_get_keys (wdh->exchange),
|
||||
&td.exchange_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
td.details_length = json_array_size (details_j);
|
||||
{
|
||||
struct TALER_TrackTransferDetails details[num_details];
|
||||
unsigned int i;
|
||||
struct GNUNET_HashContext *hash_context;
|
||||
struct TALER_WireDepositDetailP dd;
|
||||
struct TALER_WireDepositDataPS wdp;
|
||||
struct TALER_TrackTransferDetails *details;
|
||||
|
||||
details = GNUNET_new_array (td.details_length,
|
||||
struct TALER_TrackTransferDetails);
|
||||
td.details = details;
|
||||
hash_context = GNUNET_CRYPTO_hash_context_start ();
|
||||
for (i = 0; i<num_details; i++)
|
||||
for (unsigned int i = 0; i<td.details_length; i++)
|
||||
{
|
||||
struct TALER_TrackTransferDetails *detail = &details[i];
|
||||
struct json_t *detail_j = json_array_get (details_j, i);
|
||||
@ -147,25 +151,17 @@ check_transfers_get_response_ok (
|
||||
GNUNET_JSON_spec_end ()
|
||||
};
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (detail_j,
|
||||
spec_detail,
|
||||
NULL, NULL))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
/* build up big hash for signature checking later */
|
||||
dd.h_contract_terms = detail->h_contract_terms;
|
||||
dd.execution_time = GNUNET_TIME_absolute_hton (exec_time);
|
||||
dd.coin_pub = detail->coin_pub;
|
||||
TALER_amount_hton (&dd.deposit_value,
|
||||
&detail->coin_value);
|
||||
TALER_amount_hton (&dd.deposit_fee,
|
||||
&detail->coin_fee);
|
||||
if ( (0 >
|
||||
if ( (GNUNET_OK !=
|
||||
GNUNET_JSON_parse (detail_j,
|
||||
spec_detail,
|
||||
NULL, NULL)) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_amount_cmp_currency (&total_expected,
|
||||
&detail->coin_value)) ||
|
||||
(GNUNET_OK !=
|
||||
TALER_amount_cmp_currency (&total_expected,
|
||||
&detail->coin_fee)) ||
|
||||
(0 >
|
||||
TALER_amount_add (&total_expected,
|
||||
&total_expected,
|
||||
&detail->coin_value)) ||
|
||||
@ -177,71 +173,78 @@ check_transfers_get_response_ok (
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_CRYPTO_hash_context_abort (hash_context);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
GNUNET_free (details);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_CRYPTO_hash_context_read (
|
||||
hash_context,
|
||||
&dd,
|
||||
sizeof (struct TALER_WireDepositDetailP));
|
||||
/* build up big hash for signature checking later */
|
||||
{
|
||||
struct TALER_WireDepositDetailP dd;
|
||||
|
||||
dd.h_contract_terms = detail->h_contract_terms;
|
||||
dd.execution_time = GNUNET_TIME_absolute_hton (td.execution_time);
|
||||
dd.coin_pub = detail->coin_pub;
|
||||
TALER_amount_hton (&dd.deposit_value,
|
||||
&detail->coin_value);
|
||||
TALER_amount_hton (&dd.deposit_fee,
|
||||
&detail->coin_fee);
|
||||
GNUNET_CRYPTO_hash_context_read (hash_context,
|
||||
&dd,
|
||||
sizeof (dd));
|
||||
}
|
||||
}
|
||||
/* Check signature */
|
||||
wdp.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT);
|
||||
wdp.purpose.size = htonl (sizeof (struct TALER_WireDepositDataPS));
|
||||
TALER_amount_hton (&wdp.total,
|
||||
&total_amount);
|
||||
TALER_amount_hton (&wdp.wire_fee,
|
||||
&wire_fee);
|
||||
wdp.merchant_pub = merchant_pub;
|
||||
wdp.h_wire = h_wire;
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&wdp.h_details);
|
||||
if (GNUNET_OK !=
|
||||
TALER_EXCHANGE_test_signing_key (TALER_EXCHANGE_get_keys (
|
||||
wdh->exchange),
|
||||
&exchange_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (
|
||||
TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT,
|
||||
&wdp,
|
||||
&exchange_sig.eddsa_signature,
|
||||
&exchange_pub.eddsa_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
return GNUNET_SYSERR;
|
||||
struct TALER_WireDepositDataPS wdp = {
|
||||
.purpose.purpose = htonl (
|
||||
TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT),
|
||||
.purpose.size = htonl (sizeof (wdp)),
|
||||
.merchant_pub = merchant_pub,
|
||||
.h_wire = td.h_wire
|
||||
};
|
||||
|
||||
TALER_amount_hton (&wdp.total,
|
||||
&td.total_amount);
|
||||
TALER_amount_hton (&wdp.wire_fee,
|
||||
&td.wire_fee);
|
||||
GNUNET_CRYPTO_hash_context_finish (hash_context,
|
||||
&wdp.h_details);
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (
|
||||
TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT,
|
||||
&wdp,
|
||||
&td.exchange_sig.eddsa_signature,
|
||||
&td.exchange_pub.eddsa_pub))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
GNUNET_free (details);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 >
|
||||
TALER_amount_subtract (&total_expected,
|
||||
&total_expected,
|
||||
&wire_fee))
|
||||
&td.wire_fee))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
GNUNET_free (details);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (0 !=
|
||||
TALER_amount_cmp (&total_expected,
|
||||
&total_amount))
|
||||
&td.total_amount))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
GNUNET_free (details);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
wdh->cb (wdh->cb_cls,
|
||||
&hr,
|
||||
&exchange_pub,
|
||||
&h_wire,
|
||||
exec_time,
|
||||
&total_amount,
|
||||
&wire_fee,
|
||||
num_details,
|
||||
details);
|
||||
&td);
|
||||
GNUNET_free (details);
|
||||
}
|
||||
GNUNET_JSON_parse_free (spec);
|
||||
TALER_EXCHANGE_transfers_get_cancel (wdh);
|
||||
@ -322,12 +325,7 @@ handle_transfers_get_finished (void *cls,
|
||||
}
|
||||
wdh->cb (wdh->cb_cls,
|
||||
&hr,
|
||||
NULL,
|
||||
NULL,
|
||||
GNUNET_TIME_UNIT_ZERO_ABS,
|
||||
NULL,
|
||||
NULL,
|
||||
0, NULL);
|
||||
NULL);
|
||||
TALER_EXCHANGE_transfers_get_cancel (wdh);
|
||||
}
|
||||
|
||||
|
@ -429,8 +429,6 @@ TALER_EXCHANGE_withdraw2 (
|
||||
|
||||
TALER_amount_hton (&req.amount_with_fee,
|
||||
&wh->requested_amount);
|
||||
TALER_amount_hton (&req.withdraw_fee,
|
||||
&dk->fee_withdraw);
|
||||
GNUNET_CRYPTO_hash (pd->coin_ev,
|
||||
pd->coin_ev_size,
|
||||
&req.h_coin_envelope);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014--2019 Taler Systems SA
|
||||
Copyright (C) 2014--2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU Affero General Public License as published by the Free Software
|
||||
@ -56,7 +56,7 @@
|
||||
* (we could not even queue an error message,
|
||||
* close HTTP session with MHD_NO)
|
||||
*/
|
||||
int
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_MHD_parse_post_json (struct MHD_Connection *connection,
|
||||
void **con_cls,
|
||||
const char *upload_data,
|
||||
@ -186,12 +186,12 @@ TALER_MHD_parse_request_arg_data (struct MHD_Connection *connection,
|
||||
* #GNUNET_NO if json is malformed, error response was generated
|
||||
* #GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_MHD_parse_json_data (struct MHD_Connection *connection,
|
||||
const json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec)
|
||||
{
|
||||
int ret;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *error_json_name;
|
||||
unsigned int error_line;
|
||||
|
||||
@ -220,6 +220,58 @@ TALER_MHD_parse_json_data (struct MHD_Connection *connection,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse JSON object that we (the server!) generated into components based on
|
||||
* the given field specification. The difference to
|
||||
* #TALER_MHD_parse_json_data() is that this function will fail
|
||||
* with an HTTP failure of 500 (internal server error) in case
|
||||
* parsing fails, instead of blaming it on the client with a
|
||||
* 400 (#MHD_HTTP_BAD_REQUEST).
|
||||
*
|
||||
* @param connection the connection to send an error response to
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param spec field specification for the parser
|
||||
* @return
|
||||
* #GNUNET_YES if navigation was successful (caller is responsible
|
||||
* for freeing allocated variable-size data using
|
||||
* GNUNET_JSON_parse_free() when done)
|
||||
* #GNUNET_NO if json is malformed, error response was generated
|
||||
* #GNUNET_SYSERR on internal error
|
||||
*/
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_MHD_parse_internal_json_data (struct MHD_Connection *connection,
|
||||
const json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec)
|
||||
{
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *error_json_name;
|
||||
unsigned int error_line;
|
||||
|
||||
ret = GNUNET_JSON_parse (root,
|
||||
spec,
|
||||
&error_json_name,
|
||||
&error_line);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
{
|
||||
if (NULL == error_json_name)
|
||||
error_json_name = "<no field>";
|
||||
ret = (MHD_YES ==
|
||||
TALER_MHD_reply_json_pack (connection,
|
||||
MHD_HTTP_INTERNAL_SERVER_ERROR,
|
||||
"{s:s, s:I, s:s, s:I}",
|
||||
"hint", "JSON parse error",
|
||||
"code",
|
||||
(json_int_t)
|
||||
TALER_EC_INTERNAL_INVARIANT_FAILURE,
|
||||
"field", error_json_name,
|
||||
"line", (json_int_t) error_line))
|
||||
? GNUNET_NO : GNUNET_SYSERR;
|
||||
return ret;
|
||||
}
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse JSON array into components based on the given field
|
||||
* specification. Generates error response on parse errors.
|
||||
@ -235,13 +287,13 @@ TALER_MHD_parse_json_data (struct MHD_Connection *connection,
|
||||
* #GNUNET_NO if json is malformed, error response was generated
|
||||
* #GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
enum GNUNET_GenericReturnValue
|
||||
TALER_MHD_parse_json_array (struct MHD_Connection *connection,
|
||||
const json_t *root,
|
||||
struct GNUNET_JSON_Specification *spec,
|
||||
...)
|
||||
{
|
||||
int ret;
|
||||
enum GNUNET_GenericReturnValue ret;
|
||||
const char *error_json_name;
|
||||
unsigned int error_line;
|
||||
va_list ap;
|
||||
|
40
src/sq/Makefile.am
Normal file
40
src/sq/Makefile.am
Normal file
@ -0,0 +1,40 @@
|
||||
# This Makefile.am is in the public domain
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS) $(SQLITE_CPPFLAGS)
|
||||
|
||||
if USE_COVERAGE
|
||||
AM_CFLAGS = --coverage -O0
|
||||
XLIB = -lgcov
|
||||
endif
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalersq.la
|
||||
|
||||
libtalersq_la_SOURCES = \
|
||||
sq_query_helper.c \
|
||||
sq_result_helper.c
|
||||
|
||||
libtalersq_la_LIBADD = \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil -ljansson \
|
||||
-lsqlite3 $(XLIB)
|
||||
|
||||
libtalersq_la_LDFLAGS = \
|
||||
$(SQLITE_LDFLAGS) \
|
||||
-version-info 0:0:0 \
|
||||
-export-dynamic -no-undefined
|
||||
|
||||
TESTS = \
|
||||
test_sq
|
||||
|
||||
check_PROGRAMS= \
|
||||
test_sq
|
||||
|
||||
test_sq_SOURCES = \
|
||||
test_sq.c
|
||||
test_sq_LDADD = \
|
||||
libtalersq.la \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetsq \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
-lsqlite3 $(XLIB)
|
288
src/sq/sq_query_helper.c
Normal file
288
src/sq/sq_query_helper.c
Normal file
@ -0,0 +1,288 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file sq/sq_query_helper.c
|
||||
* @brief helper functions for Taler-specific SQLite3 interactions
|
||||
* @author Jonathan Buchanan
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <sqlite3.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <gnunet/gnunet_sq_lib.h>
|
||||
#include "taler_sq_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* Function called to convert input argument into SQL parameters.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param data pointer to input argument, here a `struct TALER_Amount`
|
||||
* @param data_len number of bytes in @a data (if applicable)
|
||||
* @param stmt sqlite statement to parameters for
|
||||
* @param off offset of the argument to bind in @a stmt, numbered from 1,
|
||||
* so immediately suitable for passing to `sqlite3_bind`-functions.
|
||||
* @return #GNUNET_SYSERR on error, #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
qconv_amount (void *cls,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
sqlite3_stmt *stmt,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct TALER_Amount *amount = data;
|
||||
|
||||
(void) cls;
|
||||
GNUNET_assert (sizeof (struct TALER_Amount) == data_len);
|
||||
if (SQLITE_OK != sqlite3_bind_int64 (stmt,
|
||||
(int) off,
|
||||
(sqlite3_int64) amount->value))
|
||||
return GNUNET_SYSERR;
|
||||
if (SQLITE_OK != sqlite3_bind_int64 (stmt,
|
||||
(int) off + 1,
|
||||
(sqlite3_int64) amount->fraction))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for a currency, consisting of the
|
||||
* components "value", "fraction" in this order. The
|
||||
* types must be a 64-bit integer and a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_amount (const struct TALER_Amount *x)
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam res =
|
||||
{ &qconv_amount, NULL, x, sizeof (*x), 2 };
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to convert input argument into SQL parameters.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param data pointer to input argument, here a `struct TALER_AmountNBO`
|
||||
* @param data_len number of bytes in @a data (if applicable)
|
||||
* @param stmt sqlite statement to parameters for
|
||||
* @param off offset of the argument to bind in @a stmt, numbered from 1,
|
||||
* so immediately suitable for passing to `sqlite3_bind`-functions.
|
||||
* @return #GNUNET_SYSERR on error, #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
qconv_amount_nbo (void *cls,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
sqlite3_stmt *stmt,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct TALER_AmountNBO *amount = data;
|
||||
struct TALER_Amount amount_hbo;
|
||||
|
||||
(void) cls;
|
||||
TALER_amount_ntoh (&amount_hbo,
|
||||
amount);
|
||||
return qconv_amount (cls,
|
||||
&amount_hbo,
|
||||
sizeof (struct TALER_Amount),
|
||||
stmt,
|
||||
off);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for a currency, consisting of the
|
||||
* components "value", "fraction" in this order. The
|
||||
* types must be a 64-bit integer and a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_amount_nbo (const struct TALER_AmountNBO *x)
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam res =
|
||||
{ &qconv_amount_nbo, NULL, x, sizeof (*x), 2 };
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to convert input argument into SQL parameters.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param data pointer to input argument, here a `struct TALER_Amount`
|
||||
* @param data_len number of bytes in @a data (if applicable)
|
||||
* @param stmt sqlite statement to parameters for
|
||||
* @param off offset of the argument to bind in @a stmt, numbered from 1,
|
||||
* so immediately suitable for passing to `sqlite3_bind`-functions.
|
||||
* @return #GNUNET_SYSERR on error, #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
qconv_json (void *cls,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
sqlite3_stmt *stmt,
|
||||
unsigned int off)
|
||||
{
|
||||
const json_t *json = data;
|
||||
char *str;
|
||||
|
||||
(void) cls;
|
||||
(void) data_len;
|
||||
str = json_dumps (json, JSON_COMPACT);
|
||||
if (NULL == str)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (SQLITE_OK != sqlite3_bind_text (stmt,
|
||||
(int) off,
|
||||
str,
|
||||
strlen (str) + 1,
|
||||
SQLITE_TRANSIENT))
|
||||
return GNUNET_SYSERR;
|
||||
GNUNET_free (str);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for a JSON object (stored as a string
|
||||
* in the DB). Note that @a x must really be a JSON object or array,
|
||||
* passing just a value (string, integer) is not supported and will
|
||||
* result in an abort.
|
||||
*
|
||||
* @param x pointer to the json object to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_json (const json_t *x)
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam res =
|
||||
{ &qconv_json, NULL, x, sizeof (*x), 1 };
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to convert input argument into SQL parameters.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param data pointer to input argument, here a `struct TALER_Amount`
|
||||
* @param data_len number of bytes in @a data (if applicable)
|
||||
* @param stmt sqlite statement to parameters for
|
||||
* @param off offset of the argument to bind in @a stmt, numbered from 1,
|
||||
* so immediately suitable for passing to `sqlite3_bind`-functions.
|
||||
* @return #GNUNET_SYSERR on error, #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
qconv_round_time (void *cls,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
sqlite3_stmt *stmt,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct GNUNET_TIME_Absolute *at = data;
|
||||
struct GNUNET_TIME_Absolute tmp;
|
||||
|
||||
(void) cls;
|
||||
GNUNET_assert (sizeof (struct GNUNET_TIME_AbsoluteNBO) == data_len);
|
||||
GNUNET_break (NULL == cls);
|
||||
tmp = *at;
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&tmp));
|
||||
if (SQLITE_OK != sqlite3_bind_int64 (stmt,
|
||||
(int) off,
|
||||
(sqlite3_int64) at->abs_value_us))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for an absolute time value.
|
||||
* In contrast to
|
||||
* #GNUNET_SQ_query_param_absolute_time(), this function
|
||||
* will abort (!) if the time given is not rounded!
|
||||
* The database must store a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_absolute_time (const struct GNUNET_TIME_Absolute *x)
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam res =
|
||||
{ &qconv_round_time, NULL, x, sizeof (*x), 1 };
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to convert input argument into SQL parameters.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param data pointer to input argument, here a `struct TALER_Amount`
|
||||
* @param data_len number of bytes in @a data (if applicable)
|
||||
* @param stmt sqlite statement to parameters for
|
||||
* @param off offset of the argument to bind in @a stmt, numbered from 1,
|
||||
* so immediately suitable for passing to `sqlite3_bind`-functions.
|
||||
* @return #GNUNET_SYSERR on error, #GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
qconv_round_time_abs (void *cls,
|
||||
const void *data,
|
||||
size_t data_len,
|
||||
sqlite3_stmt *stmt,
|
||||
unsigned int off)
|
||||
{
|
||||
const struct GNUNET_TIME_AbsoluteNBO *at = data;
|
||||
struct GNUNET_TIME_Absolute tmp;
|
||||
|
||||
(void) cls;
|
||||
GNUNET_assert (sizeof (struct GNUNET_TIME_AbsoluteNBO) == data_len);
|
||||
GNUNET_break (NULL == cls);
|
||||
tmp = GNUNET_TIME_absolute_ntoh (*at);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&tmp));
|
||||
if (SQLITE_OK != sqlite3_bind_int64 (stmt,
|
||||
(int) off,
|
||||
(sqlite3_int64) tmp.abs_value_us))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate query parameter for an absolute time value.
|
||||
* In contrast to
|
||||
* #GNUNET_SQ_query_param_absolute_time(), this function
|
||||
* will abort (!) if the time given is not rounded!
|
||||
* The database must store a 64-bit integer.
|
||||
*
|
||||
* @param x pointer to the query parameter to pass
|
||||
*/
|
||||
struct GNUNET_SQ_QueryParam
|
||||
TALER_SQ_query_param_absolute_time_nbo (const struct
|
||||
GNUNET_TIME_AbsoluteNBO *x)
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam res =
|
||||
{ &qconv_round_time_abs, NULL, x, sizeof (*x), 1 };
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* end of sq/sq_query_helper.c */
|
381
src/sq/sq_result_helper.c
Normal file
381
src/sq/sq_result_helper.c
Normal file
@ -0,0 +1,381 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file sq/sq_result_helper.c
|
||||
* @brief functions to initialize parameter arrays
|
||||
* @author Jonathan Buchanan
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <sqlite3.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <gnunet/gnunet_sq_lib.h>
|
||||
#include "taler_sq_lib.h"
|
||||
#include "taler_amount_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* Extract amount data from a SQLite database
|
||||
*
|
||||
* @param cls closure, a `const char *` giving the currency
|
||||
* @param result where to extract data from
|
||||
* @param column column to extract data from
|
||||
* @param[in,out] dst_size where to store size of result, may be NULL
|
||||
* @param[out] dst where to store the result
|
||||
* @return
|
||||
* #GNUNET_YES if all results could be extracted
|
||||
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
|
||||
*/
|
||||
static int
|
||||
extract_amount (void *cls,
|
||||
sqlite3_stmt *result,
|
||||
unsigned int column,
|
||||
size_t *dst_size,
|
||||
void *dst)
|
||||
{
|
||||
struct TALER_Amount *amount = dst;
|
||||
const char *currency = cls;
|
||||
if ((sizeof (struct TALER_Amount) != *dst_size) ||
|
||||
(SQLITE_INTEGER != sqlite3_column_type (result,
|
||||
(int) column)) ||
|
||||
(SQLITE_INTEGER != sqlite3_column_type (result,
|
||||
(int) column + 1)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_strlcpy (amount->currency,
|
||||
currency,
|
||||
TALER_CURRENCY_LEN);
|
||||
amount->value = (uint64_t) sqlite3_column_int64 (result,
|
||||
(int) column);
|
||||
uint64_t frac = (uint64_t) sqlite3_column_int64 (result,
|
||||
(int) column + 1);
|
||||
amount->fraction = (uint32_t) frac;
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Currency amount expected.
|
||||
*
|
||||
* @param currency the currency to use for @a amount
|
||||
* @param[out] amount where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_amount (const char *currency,
|
||||
struct TALER_Amount *amount)
|
||||
{
|
||||
struct GNUNET_SQ_ResultSpec res = {
|
||||
.conv = &extract_amount,
|
||||
.cls = (void *) currency,
|
||||
.dst = (void *) amount,
|
||||
.dst_size = sizeof (struct TALER_Amount),
|
||||
.num_params = 2
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract amount data from a SQLite database
|
||||
*
|
||||
* @param cls closure, a `const char *` giving the currency
|
||||
* @param result where to extract data from
|
||||
* @param column column to extract data from
|
||||
* @param[in,out] dst_size where to store size of result, may be NULL
|
||||
* @param[out] dst where to store the result
|
||||
* @return
|
||||
* #GNUNET_YES if all results could be extracted
|
||||
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
|
||||
*/
|
||||
static int
|
||||
extract_amount_nbo (void *cls,
|
||||
sqlite3_stmt *result,
|
||||
unsigned int column,
|
||||
size_t *dst_size,
|
||||
void *dst)
|
||||
{
|
||||
struct TALER_AmountNBO *amount = dst;
|
||||
struct TALER_Amount amount_hbo;
|
||||
size_t amount_hbo_size = sizeof (struct TALER_Amount);
|
||||
if (GNUNET_YES != extract_amount (cls,
|
||||
result,
|
||||
column,
|
||||
&amount_hbo_size,
|
||||
&amount_hbo))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
TALER_amount_hton (amount,
|
||||
&amount_hbo);
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Currency amount expected.
|
||||
*
|
||||
* @param currency the currency to use for @a amount
|
||||
* @param[out] amount where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_amount_nbo (const char *currency,
|
||||
struct TALER_AmountNBO *amount)
|
||||
{
|
||||
struct GNUNET_SQ_ResultSpec res = {
|
||||
.conv = &extract_amount_nbo,
|
||||
.cls = (void *) currency,
|
||||
.dst = (void *) amount,
|
||||
.dst_size = sizeof (struct TALER_AmountNBO),
|
||||
.num_params = 2
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract amount data from a SQLite database
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result where to extract data from
|
||||
* @param column column to extract data from
|
||||
* @param[in,out] dst_size where to store size of result, may be NULL
|
||||
* @param[out] dst where to store the result
|
||||
* @return
|
||||
* #GNUNET_YES if all results could be extracted
|
||||
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
|
||||
*/
|
||||
static int
|
||||
extract_json (void *cls,
|
||||
sqlite3_stmt *result,
|
||||
unsigned int column,
|
||||
size_t *dst_size,
|
||||
void *dst)
|
||||
{
|
||||
json_t **j_dst = dst;
|
||||
const char *res;
|
||||
json_error_t json_error;
|
||||
size_t slen;
|
||||
|
||||
(void) cls;
|
||||
(void) dst_size;
|
||||
if (SQLITE_TEXT != sqlite3_column_type (result,
|
||||
column))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
res = (const char *) sqlite3_column_text (result,
|
||||
column);
|
||||
slen = strlen (res);
|
||||
*j_dst = json_loadb (res,
|
||||
slen,
|
||||
JSON_REJECT_DUPLICATES,
|
||||
&json_error);
|
||||
if (NULL == *j_dst)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse JSON result for column %d: %s (%s)\n",
|
||||
column,
|
||||
json_error.text,
|
||||
json_error.source);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function called to clean up memory allocated
|
||||
* by a #GNUNET_SQ_ResultConverter.
|
||||
*
|
||||
* @param cls closure
|
||||
*/
|
||||
static void
|
||||
clean_json (void *cls)
|
||||
{
|
||||
json_t **dst = cls;
|
||||
|
||||
(void) cls;
|
||||
if (NULL != *dst)
|
||||
{
|
||||
json_decref (*dst);
|
||||
*dst = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* json_t expected.
|
||||
*
|
||||
* @param[out] jp where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_json (json_t **jp)
|
||||
{
|
||||
struct GNUNET_SQ_ResultSpec res = {
|
||||
.conv = &extract_json,
|
||||
.cleaner = &clean_json,
|
||||
.dst = (void *) jp,
|
||||
.cls = (void *) jp,
|
||||
.num_params = 1
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract amount data from a SQLite database
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result where to extract data from
|
||||
* @param column column to extract data from
|
||||
* @param[in,out] dst_size where to store size of result, may be NULL
|
||||
* @param[out] dst where to store the result
|
||||
* @return
|
||||
* #GNUNET_YES if all results could be extracted
|
||||
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
|
||||
*/
|
||||
static int
|
||||
extract_round_time (void *cls,
|
||||
sqlite3_stmt *result,
|
||||
unsigned int column,
|
||||
size_t *dst_size,
|
||||
void *dst)
|
||||
{
|
||||
struct GNUNET_TIME_Absolute *udst = dst;
|
||||
struct GNUNET_TIME_Absolute tmp;
|
||||
|
||||
(void) cls;
|
||||
if (SQLITE_INTEGER != sqlite3_column_type (result,
|
||||
(int) column))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_assert (NULL != dst);
|
||||
if (sizeof (struct GNUNET_TIME_Absolute) != *dst_size)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
tmp.abs_value_us = sqlite3_column_int64 (result,
|
||||
(int) column);
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&tmp));
|
||||
*udst = tmp;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rounded absolute time expected.
|
||||
* In contrast to #GNUNET_SQ_query_param_absolute_time_nbo(),
|
||||
* this function ensures that the result is rounded and can
|
||||
* be converted to JSON.
|
||||
*
|
||||
* @param[out] at where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_absolute_time (struct GNUNET_TIME_Absolute *at)
|
||||
{
|
||||
struct GNUNET_SQ_ResultSpec res = {
|
||||
.conv = &extract_round_time,
|
||||
.dst = (void *) at,
|
||||
.dst_size = sizeof (struct GNUNET_TIME_Absolute),
|
||||
.num_params = 1
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract amount data from a SQLite database
|
||||
*
|
||||
* @param cls closure
|
||||
* @param result where to extract data from
|
||||
* @param column column to extract data from
|
||||
* @param[in,out] dst_size where to store size of result, may be NULL
|
||||
* @param[out] dst where to store the result
|
||||
* @return
|
||||
* #GNUNET_YES if all results could be extracted
|
||||
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
|
||||
*/
|
||||
static int
|
||||
extract_round_time_nbo (void *cls,
|
||||
sqlite3_stmt *result,
|
||||
unsigned int column,
|
||||
size_t *dst_size,
|
||||
void *dst)
|
||||
{
|
||||
struct GNUNET_TIME_AbsoluteNBO *udst = dst;
|
||||
struct GNUNET_TIME_Absolute tmp;
|
||||
|
||||
(void) cls;
|
||||
if (SQLITE_INTEGER != sqlite3_column_type (result,
|
||||
(int) column))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
GNUNET_assert (NULL != dst);
|
||||
if (sizeof (struct GNUNET_TIME_AbsoluteNBO) != *dst_size)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
tmp.abs_value_us = sqlite3_column_int64 (result,
|
||||
(int) column);
|
||||
GNUNET_break (GNUNET_OK ==
|
||||
GNUNET_TIME_round_abs (&tmp));
|
||||
*udst = GNUNET_TIME_absolute_hton (tmp);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Rounded absolute time expected.
|
||||
* In contrast to #GNUNET_SQ_result_spec_absolute_time_nbo(),
|
||||
* this function ensures that the result is rounded and can
|
||||
* be converted to JSON.
|
||||
*
|
||||
* @param[out] at where to store the result
|
||||
* @return array entry for the result specification to use
|
||||
*/
|
||||
struct GNUNET_SQ_ResultSpec
|
||||
TALER_SQ_result_spec_absolute_time_nbo (struct GNUNET_TIME_AbsoluteNBO *at)
|
||||
{
|
||||
struct GNUNET_SQ_ResultSpec res = {
|
||||
.conv = &extract_round_time_nbo,
|
||||
.dst = (void *) at,
|
||||
.dst_size = sizeof (struct GNUNET_TIME_AbsoluteNBO),
|
||||
.num_params = 1
|
||||
};
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/* end of sq/sq_result_helper.c */
|
227
src/sq/test_sq.c
Normal file
227
src/sq/test_sq.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file sq/test_sq.c
|
||||
* @brief Tests for SQLite3 convenience API
|
||||
* @author Jonathan Buchanan
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_sq_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* Run actual test queries.
|
||||
*
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int
|
||||
run_queries (sqlite3 *db)
|
||||
{
|
||||
struct TALER_Amount hamount;
|
||||
struct TALER_AmountNBO namount;
|
||||
json_t *json;
|
||||
struct GNUNET_TIME_Absolute htime = GNUNET_TIME_absolute_get ();
|
||||
struct GNUNET_TIME_AbsoluteNBO ntime;
|
||||
sqlite3_stmt *test_insert;
|
||||
sqlite3_stmt *test_select;
|
||||
struct GNUNET_SQ_PrepareStatement ps[] = {
|
||||
GNUNET_SQ_make_prepare ("INSERT INTO test_sq ("
|
||||
" hamount_val"
|
||||
",hamount_frac"
|
||||
",namount_val"
|
||||
",namount_frac"
|
||||
",json"
|
||||
",htime"
|
||||
",ntime"
|
||||
") VALUES "
|
||||
"($1, $2, $3, $4, $5, $6, $7)",
|
||||
&test_insert),
|
||||
GNUNET_SQ_make_prepare ("SELECT"
|
||||
" hamount_val"
|
||||
",hamount_frac"
|
||||
",namount_val"
|
||||
",namount_frac"
|
||||
",json"
|
||||
",htime"
|
||||
",ntime"
|
||||
" FROM test_sq",
|
||||
&test_select),
|
||||
GNUNET_SQ_PREPARE_END
|
||||
};
|
||||
int ret = 0;
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_string_to_amount ("EUR:1.23",
|
||||
&hamount));
|
||||
TALER_amount_hton (&namount,
|
||||
&hamount);
|
||||
json = json_object ();
|
||||
json_object_set_new (json, "foo", json_integer (42));
|
||||
GNUNET_assert (NULL != json);
|
||||
GNUNET_TIME_round_abs (&htime);
|
||||
ntime = GNUNET_TIME_absolute_hton (htime);
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_SQ_prepare (db,
|
||||
ps));
|
||||
|
||||
{
|
||||
struct GNUNET_SQ_QueryParam params_insert[] = {
|
||||
TALER_SQ_query_param_amount (&hamount),
|
||||
TALER_SQ_query_param_amount_nbo (&namount),
|
||||
TALER_SQ_query_param_json (json),
|
||||
TALER_SQ_query_param_absolute_time (&htime),
|
||||
TALER_SQ_query_param_absolute_time_nbo (&ntime),
|
||||
GNUNET_SQ_query_param_end
|
||||
};
|
||||
GNUNET_SQ_reset (db,
|
||||
test_insert);
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_SQ_bind (test_insert,
|
||||
params_insert));
|
||||
GNUNET_assert (SQLITE_DONE == sqlite3_step (test_insert));
|
||||
sqlite3_finalize (test_insert);
|
||||
}
|
||||
|
||||
{
|
||||
struct TALER_Amount result_amount;
|
||||
struct TALER_AmountNBO nresult_amount;
|
||||
struct TALER_Amount nresult_amount_converted;
|
||||
json_t *result_json;
|
||||
struct GNUNET_TIME_Absolute hresult_time;
|
||||
struct GNUNET_TIME_AbsoluteNBO nresult_time;
|
||||
struct GNUNET_SQ_QueryParam params_select[] = {
|
||||
GNUNET_SQ_query_param_end
|
||||
};
|
||||
struct GNUNET_SQ_ResultSpec results_select[] = {
|
||||
TALER_SQ_result_spec_amount ("EUR",
|
||||
&result_amount),
|
||||
TALER_SQ_result_spec_amount_nbo ("EUR",
|
||||
&nresult_amount),
|
||||
TALER_SQ_result_spec_json (&result_json),
|
||||
TALER_SQ_result_spec_absolute_time (&hresult_time),
|
||||
TALER_SQ_result_spec_absolute_time_nbo (&nresult_time),
|
||||
GNUNET_SQ_result_spec_end
|
||||
};
|
||||
|
||||
GNUNET_SQ_reset (db,
|
||||
test_select);
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_SQ_bind (test_select,
|
||||
params_select));
|
||||
GNUNET_assert (SQLITE_ROW == sqlite3_step (test_select));
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_SQ_extract_result (test_select,
|
||||
results_select));
|
||||
TALER_amount_ntoh (&nresult_amount_converted,
|
||||
&nresult_amount);
|
||||
if ((GNUNET_OK != TALER_amount_cmp_currency (&hamount,
|
||||
&result_amount)) ||
|
||||
(0 != TALER_amount_cmp (&hamount,
|
||||
&result_amount)) ||
|
||||
(GNUNET_OK != TALER_amount_cmp_currency (&hamount,
|
||||
&nresult_amount_converted)) ||
|
||||
(0 != TALER_amount_cmp (&hamount,
|
||||
&nresult_amount_converted)) ||
|
||||
(1 != json_equal (json,
|
||||
result_json)) ||
|
||||
(htime.abs_value_us != hresult_time.abs_value_us) ||
|
||||
(ntime.abs_value_us__ != nresult_time.abs_value_us__))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Result from database doesn't match input\n");
|
||||
ret = 1;
|
||||
}
|
||||
GNUNET_SQ_cleanup_result (results_select);
|
||||
sqlite3_finalize (test_select);
|
||||
}
|
||||
json_decref (json);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
const char *const argv[])
|
||||
{
|
||||
struct GNUNET_SQ_ExecuteStatement es[] = {
|
||||
GNUNET_SQ_make_execute ("CREATE TEMPORARY TABLE IF NOT EXISTS test_sq ("
|
||||
" hamount_val INT8 NOT NULL"
|
||||
",hamount_frac INT8 NOT NULL"
|
||||
",namount_val INT8 NOT NULL"
|
||||
",namount_frac INT8 NOT NULL"
|
||||
",json VARCHAR NOT NULL"
|
||||
",htime INT8 NOT NULL"
|
||||
",ntime INT8 NOT NULL"
|
||||
")"),
|
||||
GNUNET_SQ_EXECUTE_STATEMENT_END
|
||||
};
|
||||
sqlite3 *db;
|
||||
int ret;
|
||||
|
||||
GNUNET_log_setup ("test-pq",
|
||||
"WARNING",
|
||||
NULL);
|
||||
|
||||
if (SQLITE_OK != sqlite3_open ("talercheck.db",
|
||||
&db))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to open SQLite3 database\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != GNUNET_SQ_exec_statements (db,
|
||||
es))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to create new table\n");
|
||||
if ((SQLITE_OK != sqlite3_close (db)) ||
|
||||
(0 != unlink ("talercheck.db")))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to close db or unlink\n");
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = run_queries (db);
|
||||
|
||||
if (SQLITE_OK !=
|
||||
sqlite3_exec (db,
|
||||
"DROP TABLE test_sq",
|
||||
NULL, NULL, NULL))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to drop table\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (SQLITE_OK != sqlite3_close (db))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to close database\n");
|
||||
ret = 1;
|
||||
}
|
||||
if (0 != unlink ("talercheck.db"))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to unlink test database file\n");
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of sq/test_sq.c */
|
@ -61,6 +61,7 @@ libtalertesting_la_SOURCES = \
|
||||
testing_api_cmd_refund.c \
|
||||
testing_api_cmd_refresh.c \
|
||||
testing_api_cmd_revoke.c \
|
||||
testing_api_cmd_rewind.c \
|
||||
testing_api_cmd_serialize_keys.c \
|
||||
testing_api_cmd_signal.c \
|
||||
testing_api_cmd_sleep.c \
|
||||
|
@ -353,7 +353,6 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-ok",
|
||||
MHD_HTTP_OK,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1"),
|
||||
/**
|
||||
* Spend 4.99 EUR of the refunded 4.99 EUR coin (1ct gone
|
||||
|
@ -346,6 +346,8 @@ run (void *cls,
|
||||
NULL,
|
||||
0,
|
||||
MHD_HTTP_NOT_FOUND),
|
||||
TALER_TESTING_cmd_sleep ("sleep-before-aggregator",
|
||||
1),
|
||||
/* Run transfers. Note that _actual_ aggregation will NOT
|
||||
* happen here, as each deposit operation is run with a
|
||||
* fresh merchant public key, so the aggregator will treat
|
||||
@ -528,18 +530,15 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-ok",
|
||||
MHD_HTTP_OK,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1"),
|
||||
TALER_TESTING_cmd_refund ("refund-ok-double",
|
||||
MHD_HTTP_OK,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1"),
|
||||
/* Previous /refund(s) had id == 0. */
|
||||
TALER_TESTING_cmd_refund_with_id ("refund-conflicting",
|
||||
MHD_HTTP_CONFLICT,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1",
|
||||
1),
|
||||
/**
|
||||
@ -573,7 +572,6 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-fail",
|
||||
MHD_HTTP_GONE,
|
||||
"EUR:4.99",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-2"),
|
||||
TALER_TESTING_cmd_check_bank_empty ("check-empty-after-refund"),
|
||||
/**
|
||||
@ -607,7 +605,6 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-ok-fast",
|
||||
MHD_HTTP_OK,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1b"),
|
||||
/**
|
||||
* Run transfers. This will do the transfer as refund deadline
|
||||
|
@ -173,12 +173,6 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-currency-mismatch",
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
"USD:5",
|
||||
"USD:0.01",
|
||||
"deposit-refund-1"),
|
||||
TALER_TESTING_cmd_refund ("refund-fee-above-amount",
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
"EUR:5",
|
||||
"EUR:10",
|
||||
"deposit-refund-1"),
|
||||
TALER_TESTING_cmd_flip_upload ("flip-upload",
|
||||
CONFIG_FILE,
|
||||
@ -186,7 +180,6 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-bad-sig",
|
||||
MHD_HTTP_FORBIDDEN,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1"),
|
||||
|
||||
/* This next deposit CMD is only used to provide a
|
||||
@ -207,17 +200,10 @@ run (void *cls,
|
||||
TALER_TESTING_cmd_refund ("refund-deposit-not-found",
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"EUR:5",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-to-fail"),
|
||||
TALER_TESTING_cmd_refund ("refund-insufficient-funds",
|
||||
MHD_HTTP_PRECONDITION_FAILED,
|
||||
"EUR:50",
|
||||
"EUR:0.01",
|
||||
"deposit-refund-1"),
|
||||
TALER_TESTING_cmd_refund ("refund-fee-too-low",
|
||||
MHD_HTTP_BAD_REQUEST,
|
||||
"EUR:5",
|
||||
"EUR:0.000001",
|
||||
"deposit-refund-1"),
|
||||
TALER_TESTING_cmd_end ()
|
||||
};
|
||||
|
@ -108,6 +108,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -126,6 +127,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -134,6 +136,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -153,6 +156,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
"4",
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -160,6 +164,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
"5",
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -167,6 +172,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"alice",
|
||||
"4",
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:1",
|
||||
"EUR:0.1"),
|
||||
@ -195,6 +201,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -204,6 +211,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -229,6 +237,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
10),
|
||||
@ -239,6 +248,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -263,6 +273,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.102",
|
||||
"EUR:0.1"),
|
||||
@ -274,6 +285,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.102",
|
||||
"EUR:0.1"),
|
||||
@ -281,6 +293,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.102",
|
||||
"EUR:0.1"),
|
||||
@ -292,6 +305,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.102",
|
||||
"EUR:0.1"),
|
||||
@ -303,6 +317,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.112",
|
||||
"EUR:0.1"),
|
||||
@ -319,6 +334,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.109",
|
||||
"EUR:0.1"),
|
||||
@ -330,6 +346,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.119",
|
||||
"EUR:0.1"),
|
||||
@ -346,6 +363,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.122",
|
||||
"EUR:0.1"),
|
||||
@ -362,6 +380,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -375,6 +394,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -390,6 +410,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.122",
|
||||
"EUR:0.1"),
|
||||
@ -406,6 +427,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -419,6 +441,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS,
|
||||
5),
|
||||
@ -434,6 +457,7 @@ run (void *cls,
|
||||
&dbc,
|
||||
"bob",
|
||||
USER42_ACCOUNT,
|
||||
GNUNET_TIME_absolute_get (),
|
||||
GNUNET_TIME_UNIT_ZERO,
|
||||
"EUR:0.112",
|
||||
"EUR:0.1"),
|
||||
|
@ -203,6 +203,7 @@ deposit_confirmation_run (void *cls,
|
||||
const struct TALER_TESTING_Command *deposit_cmd;
|
||||
struct GNUNET_HashCode h_wire;
|
||||
struct GNUNET_HashCode h_contract_terms;
|
||||
const struct GNUNET_TIME_Absolute *exchange_timestamp = NULL;
|
||||
struct GNUNET_TIME_Absolute timestamp;
|
||||
struct GNUNET_TIME_Absolute refund_deadline;
|
||||
struct TALER_Amount amount_without_fee;
|
||||
@ -238,6 +239,11 @@ deposit_confirmation_run (void *cls,
|
||||
TALER_TESTING_get_trait_exchange_sig (deposit_cmd,
|
||||
dcs->coin_index,
|
||||
&exchange_sig));
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_TESTING_get_trait_absolute_time (deposit_cmd,
|
||||
dcs->coin_index,
|
||||
&exchange_timestamp));
|
||||
GNUNET_assert (NULL != exchange_timestamp);
|
||||
keys = TALER_EXCHANGE_get_keys (dcs->is->exchange);
|
||||
GNUNET_assert (NULL != keys);
|
||||
spk = TALER_EXCHANGE_get_signing_key_info (keys,
|
||||
@ -309,7 +315,7 @@ deposit_confirmation_run (void *cls,
|
||||
dcs->dc = TALER_AUDITOR_deposit_confirmation (dcs->auditor,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
timestamp,
|
||||
*exchange_timestamp,
|
||||
refund_deadline,
|
||||
&amount_without_fee,
|
||||
&coin_pub,
|
||||
|
@ -81,6 +81,11 @@ struct AdminAddIncomingState
|
||||
*/
|
||||
struct TALER_ReservePrivateKeyP reserve_priv;
|
||||
|
||||
/**
|
||||
* Whether we know the private key or not.
|
||||
*/
|
||||
bool reserve_priv_known;
|
||||
|
||||
/**
|
||||
* Reserve public key matching @e reserve_priv.
|
||||
*/
|
||||
@ -271,6 +276,7 @@ admin_add_incoming_run (void *cls,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct AdminAddIncomingState *fts = cls;
|
||||
bool have_public = false;
|
||||
|
||||
(void) cmd;
|
||||
/* Use reserve public key as subject */
|
||||
@ -278,6 +284,7 @@ admin_add_incoming_run (void *cls,
|
||||
{
|
||||
const struct TALER_TESTING_Command *ref;
|
||||
const struct TALER_ReservePrivateKeyP *reserve_priv;
|
||||
const struct TALER_ReservePublicKeyP *reserve_pub;
|
||||
|
||||
ref = TALER_TESTING_interpreter_lookup_command
|
||||
(is, fts->reserve_reference);
|
||||
@ -292,11 +299,23 @@ admin_add_incoming_run (void *cls,
|
||||
0,
|
||||
&reserve_priv))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
if (GNUNET_OK != TALER_TESTING_get_trait_reserve_pub (ref,
|
||||
0,
|
||||
&reserve_pub))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
have_public = true;
|
||||
fts->reserve_pub.eddsa_pub = reserve_pub->eddsa_pub;
|
||||
fts->reserve_priv_known = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv;
|
||||
fts->reserve_priv_known = true;
|
||||
}
|
||||
fts->reserve_priv.eddsa_priv = reserve_priv->eddsa_priv;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -349,6 +368,7 @@ admin_add_incoming_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
fts->reserve_priv_known = true;
|
||||
GNUNET_free (keys);
|
||||
GNUNET_free (section);
|
||||
GNUNET_CONFIGURATION_destroy (cfg);
|
||||
@ -358,10 +378,12 @@ admin_add_incoming_run (void *cls,
|
||||
/* No referenced reserve, no instance to take priv
|
||||
* from, no explicit subject given: create new key! */
|
||||
GNUNET_CRYPTO_eddsa_key_create (&fts->reserve_priv.eddsa_priv);
|
||||
fts->reserve_priv_known = true;
|
||||
}
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv,
|
||||
&fts->reserve_pub.eddsa_pub);
|
||||
if (! have_public)
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&fts->reserve_priv.eddsa_priv,
|
||||
&fts->reserve_pub.eddsa_pub);
|
||||
fts->reserve_history.type = TALER_EXCHANGE_RTT_CREDIT;
|
||||
fts->reserve_history.amount = fts->amount;
|
||||
fts->reserve_history.details.in_details.sender_url
|
||||
@ -432,30 +454,58 @@ admin_add_incoming_traits (void *cls,
|
||||
unsigned int index)
|
||||
{
|
||||
struct AdminAddIncomingState *fts = cls;
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
|
||||
fts->payto_debit_account),
|
||||
/* Used as a marker, content does not matter */
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
|
||||
"payto://void/the-exchange"),
|
||||
TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
|
||||
fts->exchange_credit_url),
|
||||
TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
|
||||
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
|
||||
TALER_TESTING_make_trait_reserve_priv (0,
|
||||
&fts->reserve_priv),
|
||||
TALER_TESTING_make_trait_reserve_pub (0,
|
||||
&fts->reserve_pub),
|
||||
TALER_TESTING_make_trait_reserve_history (0,
|
||||
&fts->reserve_history),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
if (fts->reserve_priv_known)
|
||||
{
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
|
||||
fts->payto_debit_account),
|
||||
/* Used as a marker, content does not matter */
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
|
||||
"payto://void/the-exchange"),
|
||||
TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
|
||||
fts->exchange_credit_url),
|
||||
TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
|
||||
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
|
||||
TALER_TESTING_make_trait_reserve_priv (0,
|
||||
&fts->reserve_priv),
|
||||
TALER_TESTING_make_trait_reserve_pub (0,
|
||||
&fts->reserve_pub),
|
||||
TALER_TESTING_make_trait_reserve_history (0,
|
||||
&fts->reserve_history),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
return TALER_TESTING_get_trait (traits,
|
||||
ret,
|
||||
trait,
|
||||
index);
|
||||
return TALER_TESTING_get_trait (traits,
|
||||
ret,
|
||||
trait,
|
||||
index);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct TALER_TESTING_Trait traits[] = {
|
||||
TALER_TESTING_make_trait_bank_row (&fts->serial_id),
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_DEBIT,
|
||||
fts->payto_debit_account),
|
||||
/* Used as a marker, content does not matter */
|
||||
TALER_TESTING_make_trait_payto (TALER_TESTING_PT_CREDIT,
|
||||
"payto://void/the-exchange"),
|
||||
TALER_TESTING_make_trait_url (TALER_TESTING_UT_EXCHANGE_BANK_ACCOUNT_URL,
|
||||
fts->exchange_credit_url),
|
||||
TALER_TESTING_make_trait_amount_obj (0, &fts->amount),
|
||||
TALER_TESTING_make_trait_absolute_time (0, &fts->timestamp),
|
||||
TALER_TESTING_make_trait_reserve_pub (0,
|
||||
&fts->reserve_pub),
|
||||
TALER_TESTING_make_trait_reserve_history (0,
|
||||
&fts->reserve_history),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
return TALER_TESTING_get_trait (traits,
|
||||
ret,
|
||||
trait,
|
||||
index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -548,7 +598,7 @@ TALER_TESTING_cmd_admin_add_incoming (const char *label,
|
||||
* @param payto_debit_account which account sends money
|
||||
* @param auth authentication data
|
||||
* @param ref reference to a command that can offer a reserve
|
||||
* private key.
|
||||
* private key or public key.
|
||||
* @return the command.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
|
@ -228,5 +228,27 @@ TALER_TESTING_cmd_batch_get_current (const struct TALER_TESTING_Command *cmd)
|
||||
{
|
||||
struct BatchState *bs = cmd->cls;
|
||||
|
||||
GNUNET_assert (cmd->run == &batch_run);
|
||||
return &bs->batch[bs->batch_ip];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set what command the batch should be at.
|
||||
*
|
||||
* @param cmd current batch command
|
||||
* @param new_ip where to move the IP
|
||||
*/
|
||||
void
|
||||
TALER_TESTING_cmd_batch_set_current (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int new_ip)
|
||||
{
|
||||
struct BatchState *bs = cmd->cls;
|
||||
|
||||
/* sanity checks */
|
||||
GNUNET_assert (cmd->run == &batch_run);
|
||||
for (unsigned int i = 0; i < new_ip; i++)
|
||||
GNUNET_assert (NULL != bs->batch[i].label);
|
||||
/* actual logic */
|
||||
bs->batch_ip = new_ip;
|
||||
}
|
||||
|
@ -52,6 +52,11 @@ struct DepositState
|
||||
*/
|
||||
struct TALER_Amount amount;
|
||||
|
||||
/**
|
||||
* Deposit fee.
|
||||
*/
|
||||
struct TALER_Amount deposit_fee;
|
||||
|
||||
/**
|
||||
* Reference to any command that is able to provide a coin.
|
||||
*/
|
||||
@ -91,9 +96,9 @@ struct DepositState
|
||||
struct TALER_EXCHANGE_DepositHandle *dh;
|
||||
|
||||
/**
|
||||
* Timestamp of the /deposit operation.
|
||||
* Timestamp of the /deposit operation in the wallet (contract signing time).
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute timestamp;
|
||||
struct GNUNET_TIME_Absolute wallet_timestamp;
|
||||
|
||||
/**
|
||||
* Interpreter state.
|
||||
@ -126,6 +131,11 @@ struct DepositState
|
||||
*/
|
||||
int deposit_succeeded;
|
||||
|
||||
/**
|
||||
* When did the exchange receive the deposit?
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
|
||||
/**
|
||||
* Signing key used by the exchange to sign the
|
||||
* deposit confirmation.
|
||||
@ -198,6 +208,7 @@ do_retry (void *cls)
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param hr HTTP response details
|
||||
* @param exchange_timestamp when did the exchange receive the deposit permission
|
||||
* @param exchange_sig signature provided by the exchange
|
||||
* (NULL on errors)
|
||||
* @param exchange_pub public key of the exchange,
|
||||
@ -206,6 +217,7 @@ do_retry (void *cls)
|
||||
static void
|
||||
deposit_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
const struct TALER_ExchangeSignatureP *exchange_sig,
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub)
|
||||
{
|
||||
@ -254,6 +266,7 @@ deposit_cb (void *cls,
|
||||
if (MHD_HTTP_OK == hr->http_status)
|
||||
{
|
||||
ds->deposit_succeeded = GNUNET_YES;
|
||||
ds->exchange_timestamp = exchange_timestamp;
|
||||
ds->exchange_pub = *exchange_pub;
|
||||
ds->exchange_sig = *exchange_sig;
|
||||
}
|
||||
@ -305,7 +318,7 @@ deposit_run (void *cls,
|
||||
ds->coin_index = ods->coin_index;
|
||||
ds->wire_details = json_incref (ods->wire_details);
|
||||
ds->contract_terms = json_incref (ods->contract_terms);
|
||||
ds->timestamp = ods->timestamp;
|
||||
ds->wallet_timestamp = ods->wallet_timestamp;
|
||||
ds->refund_deadline = ods->refund_deadline;
|
||||
ds->amount = ods->amount;
|
||||
ds->merchant_priv = ods->merchant_priv;
|
||||
@ -366,6 +379,7 @@ deposit_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
ds->deposit_fee = denom_pub->fee_deposit;
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
|
||||
&coin_pub.eddsa_pub);
|
||||
|
||||
@ -379,39 +393,27 @@ deposit_run (void *cls,
|
||||
}
|
||||
else
|
||||
{
|
||||
ds->refund_deadline = ds->timestamp;
|
||||
wire_deadline = GNUNET_TIME_relative_to_absolute
|
||||
(GNUNET_TIME_UNIT_ZERO);
|
||||
ds->refund_deadline = ds->wallet_timestamp;
|
||||
wire_deadline = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_ZERO);
|
||||
}
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&ds->merchant_priv.eddsa_priv,
|
||||
&merchant_pub.eddsa_pub);
|
||||
|
||||
(void) GNUNET_TIME_round_abs (&wire_deadline);
|
||||
|
||||
{
|
||||
struct TALER_DepositRequestPS dr;
|
||||
struct GNUNET_HashCode h_wire;
|
||||
|
||||
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_merchant_wire_signature_hash (ds->wire_details,
|
||||
&dr.h_wire));
|
||||
dr.timestamp = GNUNET_TIME_absolute_hton (ds->timestamp);
|
||||
dr.refund_deadline = GNUNET_TIME_absolute_hton
|
||||
(ds->refund_deadline);
|
||||
TALER_amount_hton (&dr.amount_with_fee,
|
||||
&ds->amount);
|
||||
TALER_amount_hton (&dr.deposit_fee,
|
||||
&denom_pub->fee_deposit);
|
||||
dr.merchant = merchant_pub;
|
||||
dr.coin_pub = coin_pub;
|
||||
GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv,
|
||||
&dr,
|
||||
&coin_sig.eddsa_signature);
|
||||
&h_wire));
|
||||
TALER_EXCHANGE_deposit_permission_sign (&ds->amount,
|
||||
&denom_pub->fee_deposit,
|
||||
&h_wire,
|
||||
&h_contract_terms,
|
||||
coin_priv,
|
||||
ds->wallet_timestamp,
|
||||
&merchant_pub,
|
||||
ds->refund_deadline,
|
||||
&coin_sig);
|
||||
}
|
||||
ds->dh = TALER_EXCHANGE_deposit (is->exchange,
|
||||
&ds->amount,
|
||||
@ -421,7 +423,7 @@ deposit_run (void *cls,
|
||||
&coin_pub,
|
||||
denom_pub_sig,
|
||||
&denom_pub->key,
|
||||
ds->timestamp,
|
||||
ds->wallet_timestamp,
|
||||
&merchant_pub,
|
||||
ds->refund_deadline,
|
||||
&coin_sig,
|
||||
@ -532,8 +534,14 @@ deposit_traits (void *cls,
|
||||
ds->contract_terms),
|
||||
TALER_TESTING_make_trait_merchant_priv (0,
|
||||
&ds->merchant_priv),
|
||||
TALER_TESTING_make_trait_amount_obj (0,
|
||||
&ds->amount),
|
||||
TALER_TESTING_make_trait_amount_obj (
|
||||
TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_VALUE,
|
||||
&ds->amount),
|
||||
TALER_TESTING_make_trait_amount_obj (
|
||||
TALER_TESTING_CMD_DEPOSIT_TRAIT_IDX_DEPOSIT_FEE,
|
||||
&ds->deposit_fee),
|
||||
TALER_TESTING_make_trait_absolute_time (0,
|
||||
&ds->exchange_timestamp),
|
||||
TALER_TESTING_trait_end ()
|
||||
};
|
||||
|
||||
@ -599,12 +607,12 @@ TALER_TESTING_cmd_deposit (const char *label,
|
||||
label);
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
ds->timestamp = GNUNET_TIME_absolute_get ();
|
||||
(void) GNUNET_TIME_round_abs (&ds->timestamp);
|
||||
ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
|
||||
(void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
|
||||
|
||||
json_object_set_new (ds->contract_terms,
|
||||
"timestamp",
|
||||
GNUNET_JSON_from_time_abs (ds->timestamp));
|
||||
GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
|
||||
if (0 != refund_deadline.rel_value_us)
|
||||
{
|
||||
ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
|
||||
@ -687,12 +695,12 @@ TALER_TESTING_cmd_deposit_with_ref (const char *label,
|
||||
label);
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
ds->timestamp = GNUNET_TIME_absolute_get ();
|
||||
(void) GNUNET_TIME_round_abs (&ds->timestamp);
|
||||
ds->wallet_timestamp = GNUNET_TIME_absolute_get ();
|
||||
(void) GNUNET_TIME_round_abs (&ds->wallet_timestamp);
|
||||
|
||||
json_object_set_new (ds->contract_terms,
|
||||
"timestamp",
|
||||
GNUNET_JSON_from_time_abs (ds->timestamp));
|
||||
GNUNET_JSON_from_time_abs (ds->wallet_timestamp));
|
||||
if (0 != refund_deadline.rel_value_us)
|
||||
{
|
||||
ds->refund_deadline = GNUNET_TIME_relative_to_absolute (refund_deadline);
|
||||
|
@ -81,29 +81,17 @@ struct TrackTransactionState
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param hr HTTP response details
|
||||
* @param exchange_pub public key of the exchange
|
||||
* @param wtid wire transfer identifier, NULL if exchange did not
|
||||
* execute the transaction yet.
|
||||
* @param execution_time actual or planned execution time for the
|
||||
* wire transfer.
|
||||
* @param coin_contribution contribution to the total amount of
|
||||
* the deposited coin (can be NULL).
|
||||
* @param dd data about the wire transfer associated with the deposit
|
||||
*/
|
||||
static void
|
||||
deposit_wtid_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
||||
const struct TALER_WireTransferIdentifierRawP *wtid,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *coin_contribution)
|
||||
const struct TALER_EXCHANGE_DepositData *dd)
|
||||
{
|
||||
struct TrackTransactionState *tts = cls;
|
||||
struct TALER_TESTING_Interpreter *is = tts->is;
|
||||
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
|
||||
|
||||
(void) coin_contribution;
|
||||
(void) exchange_pub;
|
||||
(void) execution_time;
|
||||
tts->tth = NULL;
|
||||
if (tts->expected_response_code != hr->http_status)
|
||||
{
|
||||
@ -123,7 +111,7 @@ deposit_wtid_cb (void *cls,
|
||||
switch (hr->http_status)
|
||||
{
|
||||
case MHD_HTTP_OK:
|
||||
tts->wtid = *wtid;
|
||||
tts->wtid = dd->wtid;
|
||||
if (NULL != tts->bank_transfer_reference)
|
||||
{
|
||||
const struct TALER_TESTING_Command *bank_transfer_cmd;
|
||||
@ -151,7 +139,7 @@ deposit_wtid_cb (void *cls,
|
||||
}
|
||||
|
||||
/* Compare that expected and gotten subjects match. */
|
||||
if (0 != GNUNET_memcmp (wtid,
|
||||
if (0 != GNUNET_memcmp (&dd->wtid,
|
||||
wtid_want))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
@ -159,6 +147,8 @@ deposit_wtid_cb (void *cls,
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
case MHD_HTTP_ACCEPTED:
|
||||
/* allowed, nothing to check here */
|
||||
|
@ -57,6 +57,11 @@ struct InsertDepositState
|
||||
*/
|
||||
struct GNUNET_TIME_Relative wire_deadline;
|
||||
|
||||
/**
|
||||
* When did the exchange receive the deposit?
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp;
|
||||
|
||||
/**
|
||||
* Amount to deposit, inclusive of deposit fee.
|
||||
*/
|
||||
@ -210,6 +215,7 @@ insert_deposit_run (void *cls,
|
||||
(GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
|
||||
ids->dbc->plugin->insert_deposit (ids->dbc->plugin->cls,
|
||||
ids->dbc->session,
|
||||
ids->exchange_timestamp,
|
||||
&deposit)) ||
|
||||
(GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
|
||||
ids->dbc->plugin->commit (ids->dbc->plugin->cls,
|
||||
@ -275,6 +281,7 @@ insert_deposit_traits (void *cls,
|
||||
* @param dbc collects database plugin and session handles.
|
||||
* @param merchant_name Human-readable name of the merchant.
|
||||
* @param merchant_account merchant's account name (NOT a payto:// URI)
|
||||
* @param exchange_timestamp when did the exchange receive the deposit
|
||||
* @param wire_deadline point in time where the aggregator should have
|
||||
* wired money to the merchant.
|
||||
* @param amount_with_fee amount to deposit (inclusive of deposit fee)
|
||||
@ -282,21 +289,24 @@ insert_deposit_traits (void *cls,
|
||||
* @return the command.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_insert_deposit (const char *label,
|
||||
const struct
|
||||
TALER_TESTING_DatabaseConnection *dbc,
|
||||
const char *merchant_name,
|
||||
const char *merchant_account,
|
||||
struct GNUNET_TIME_Relative wire_deadline,
|
||||
const char *amount_with_fee,
|
||||
const char *deposit_fee)
|
||||
TALER_TESTING_cmd_insert_deposit (
|
||||
const char *label,
|
||||
const struct TALER_TESTING_DatabaseConnection *dbc,
|
||||
const char *merchant_name,
|
||||
const char *merchant_account,
|
||||
struct GNUNET_TIME_Absolute exchange_timestamp,
|
||||
struct GNUNET_TIME_Relative wire_deadline,
|
||||
const char *amount_with_fee,
|
||||
const char *deposit_fee)
|
||||
{
|
||||
struct InsertDepositState *ids;
|
||||
|
||||
GNUNET_TIME_round_abs (&exchange_timestamp);
|
||||
ids = GNUNET_new (struct InsertDepositState);
|
||||
ids->dbc = dbc;
|
||||
ids->merchant_name = merchant_name;
|
||||
ids->merchant_account = merchant_account;
|
||||
ids->exchange_timestamp = exchange_timestamp;
|
||||
ids->wire_deadline = wire_deadline;
|
||||
ids->amount_with_fee = amount_with_fee;
|
||||
ids->deposit_fee = deposit_fee;
|
||||
|
@ -43,11 +43,6 @@ struct RefundState
|
||||
*/
|
||||
const char *refund_amount;
|
||||
|
||||
/**
|
||||
* Expected refund fee.
|
||||
*/
|
||||
const char *refund_fee;
|
||||
|
||||
/**
|
||||
* Reference to any command that can provide a coin to refund.
|
||||
*/
|
||||
@ -81,6 +76,7 @@ struct RefundState
|
||||
*
|
||||
* @param cls closure
|
||||
* @param hr HTTP response details
|
||||
* @param refund_fee the refund fee the exchange charged
|
||||
* @param exchange_pub public key the exchange
|
||||
* used for signing @a obj.
|
||||
* @param exchange_sig actual signature confirming the refund
|
||||
@ -88,6 +84,7 @@ struct RefundState
|
||||
static void
|
||||
refund_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_Amount *refund_fee,
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
||||
const struct TALER_ExchangeSignatureP *exchange_sig)
|
||||
{
|
||||
@ -95,6 +92,7 @@ refund_cb (void *cls,
|
||||
struct RefundState *rs = cls;
|
||||
struct TALER_TESTING_Command *refund_cmd;
|
||||
|
||||
(void) refund_fee;
|
||||
refund_cmd = &rs->is->commands[rs->is->ip];
|
||||
rs->rh = NULL;
|
||||
if (rs->expected_response_code != hr->http_status)
|
||||
@ -133,7 +131,6 @@ refund_run (void *cls,
|
||||
struct TALER_CoinSpendPublicKeyP coin;
|
||||
const json_t *contract_terms;
|
||||
struct GNUNET_HashCode h_contract_terms;
|
||||
struct TALER_Amount refund_fee;
|
||||
struct TALER_Amount refund_amount;
|
||||
const struct TALER_MerchantPrivateKeyP *merchant_priv;
|
||||
const struct TALER_TESTING_Command *coin_cmd;
|
||||
@ -153,19 +150,6 @@ refund_run (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_string_to_amount (rs->refund_fee,
|
||||
&refund_fee))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Failed to parse amount `%s' at %u/%s\n",
|
||||
rs->refund_fee,
|
||||
is->ip,
|
||||
cmd->label);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
|
||||
coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
|
||||
rs->coin_reference);
|
||||
if (NULL == coin_cmd)
|
||||
@ -211,7 +195,6 @@ refund_run (void *cls,
|
||||
}
|
||||
rs->rh = TALER_EXCHANGE_refund (rs->exchange,
|
||||
&refund_amount,
|
||||
&refund_fee,
|
||||
&h_contract_terms,
|
||||
&coin,
|
||||
rs->refund_transaction_id,
|
||||
@ -254,7 +237,6 @@ refund_cleanup (void *cls,
|
||||
* @param label command label.
|
||||
* @param expected_response_code expected HTTP status code.
|
||||
* @param refund_amount the amount to ask a refund for.
|
||||
* @param refund_fee expected refund fee.
|
||||
* @param coin_reference reference to a command that can
|
||||
* provide a coin to be refunded.
|
||||
*
|
||||
@ -264,7 +246,6 @@ struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_refund (const char *label,
|
||||
unsigned int expected_response_code,
|
||||
const char *refund_amount,
|
||||
const char *refund_fee,
|
||||
const char *coin_reference)
|
||||
{
|
||||
struct RefundState *rs;
|
||||
@ -273,7 +254,6 @@ TALER_TESTING_cmd_refund (const char *label,
|
||||
|
||||
rs->expected_response_code = expected_response_code;
|
||||
rs->refund_amount = refund_amount;
|
||||
rs->refund_fee = refund_fee;
|
||||
rs->coin_reference = coin_reference;
|
||||
{
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
@ -295,7 +275,6 @@ TALER_TESTING_cmd_refund (const char *label,
|
||||
* @param label command label.
|
||||
* @param expected_response_code expected HTTP status code.
|
||||
* @param refund_amount the amount to ask a refund for.
|
||||
* @param refund_fee expected refund fee.
|
||||
* @param coin_reference reference to a command that can
|
||||
* provide a coin to be refunded.
|
||||
* @param refund_transaction_id transaction id to use
|
||||
@ -308,7 +287,6 @@ TALER_TESTING_cmd_refund_with_id
|
||||
(const char *label,
|
||||
unsigned int expected_response_code,
|
||||
const char *refund_amount,
|
||||
const char *refund_fee,
|
||||
const char *coin_reference,
|
||||
uint64_t refund_transaction_id)
|
||||
{
|
||||
@ -317,7 +295,6 @@ TALER_TESTING_cmd_refund_with_id
|
||||
rs = GNUNET_new (struct RefundState);
|
||||
rs->expected_response_code = expected_response_code;
|
||||
rs->refund_amount = refund_amount;
|
||||
rs->refund_fee = refund_fee;
|
||||
rs->coin_reference = coin_reference;
|
||||
rs->refund_transaction_id = refund_transaction_id;
|
||||
{
|
||||
|
222
src/testing/testing_api_cmd_rewind.c
Normal file
222
src/testing/testing_api_cmd_rewind.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2014-2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as
|
||||
published by the Free Software 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 testing/testing_api_cmd_rewind.c
|
||||
* @brief command to rewind the instruction pointer.
|
||||
* @author Marcello Stanisci
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <taler/taler_exchange_service.h>
|
||||
#include <taler/taler_testing_lib.h>
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* State for a "rewind" CMD.
|
||||
*/
|
||||
struct RewindIpState
|
||||
{
|
||||
/**
|
||||
* Instruction pointer to set into the interpreter.
|
||||
*/
|
||||
const char *target_label;
|
||||
|
||||
/**
|
||||
* How many times this set should take place. However, this value lives at
|
||||
* the calling process, and this CMD is only in charge of checking and
|
||||
* decremeting it.
|
||||
*/
|
||||
unsigned int counter;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Only defined to respect the API.
|
||||
*/
|
||||
static void
|
||||
rewind_ip_cleanup (void *cls,
|
||||
const struct TALER_TESTING_Command *cmd)
|
||||
{
|
||||
(void) cls;
|
||||
(void) cmd;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Seek for the @a target command in @a batch (and rewind to it
|
||||
* if successful).
|
||||
*
|
||||
* @param is the interpreter state (for failures)
|
||||
* @param cmd batch to search for @a target
|
||||
* @param target command to search for
|
||||
* @return #GNUNET_OK on success, #GNUNET_NO if target was not found,
|
||||
* #GNUNET_SYSERR if target is in the future and we failed
|
||||
*/
|
||||
static int
|
||||
seek_batch (struct TALER_TESTING_Interpreter *is,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
const struct TALER_TESTING_Command *target)
|
||||
{
|
||||
unsigned int new_ip;
|
||||
#define BATCH_INDEX 1
|
||||
struct TALER_TESTING_Command *batch;
|
||||
struct TALER_TESTING_Command *current;
|
||||
struct TALER_TESTING_Command *icmd;
|
||||
const struct TALER_TESTING_Command *match;
|
||||
|
||||
current = TALER_TESTING_cmd_batch_get_current (cmd);
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
TALER_TESTING_get_trait_cmd (cmd,
|
||||
BATCH_INDEX,
|
||||
&batch));
|
||||
match = NULL;
|
||||
for (new_ip = 0;
|
||||
NULL != (icmd = &batch[new_ip]);
|
||||
new_ip++)
|
||||
{
|
||||
if (current == target)
|
||||
current = NULL;
|
||||
if (icmd == target)
|
||||
{
|
||||
match = icmd;
|
||||
break;
|
||||
}
|
||||
if (TALER_TESTING_cmd_is_batch (icmd))
|
||||
{
|
||||
int ret = seek_batch (is,
|
||||
icmd,
|
||||
target);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
return GNUNET_SYSERR; /* failure! */
|
||||
if (GNUNET_OK == ret)
|
||||
{
|
||||
match = icmd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL == current)
|
||||
{
|
||||
/* refuse to jump forward */
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (NULL == match)
|
||||
return GNUNET_NO; /* not found */
|
||||
TALER_TESTING_cmd_batch_set_current (cmd,
|
||||
new_ip);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the "rewind" CMD.
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param cmd command being executed now.
|
||||
* @param is the interpreter state.
|
||||
*/
|
||||
static void
|
||||
rewind_ip_run (void *cls,
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
struct TALER_TESTING_Interpreter *is)
|
||||
{
|
||||
struct RewindIpState *ris = cls;
|
||||
const struct TALER_TESTING_Command *target;
|
||||
unsigned int new_ip;
|
||||
|
||||
(void) cmd;
|
||||
if (0 == ris->counter)
|
||||
{
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
return;
|
||||
}
|
||||
target
|
||||
= TALER_TESTING_interpreter_lookup_command (is,
|
||||
ris->target_label);
|
||||
if (NULL == target)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
ris->counter--;
|
||||
for (new_ip = 0;
|
||||
NULL != is->commands[new_ip].label;
|
||||
new_ip++)
|
||||
{
|
||||
const struct TALER_TESTING_Command *cmd = &is->commands[new_ip];
|
||||
|
||||
if (cmd == target)
|
||||
break;
|
||||
if (TALER_TESTING_cmd_is_batch (cmd))
|
||||
{
|
||||
int ret = seek_batch (is,
|
||||
cmd,
|
||||
target);
|
||||
if (GNUNET_SYSERR == ret)
|
||||
return; /* failure! */
|
||||
if (GNUNET_OK == ret)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (new_ip > is->ip)
|
||||
{
|
||||
/* refuse to jump forward */
|
||||
GNUNET_break (0);
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
is->ip = new_ip - 1; /* -1 because the next function will advance by one */
|
||||
TALER_TESTING_interpreter_next (is);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make the instruction pointer point to @a new_ip
|
||||
* only if @a counter is greater than zero.
|
||||
*
|
||||
* @param label command label
|
||||
* @param target_label label of the new instruction pointer's destination after the jump;
|
||||
* must be before the current instruction
|
||||
* @param counter counts how many times the rewinding is to happen.
|
||||
*/
|
||||
struct TALER_TESTING_Command
|
||||
TALER_TESTING_cmd_rewind_ip (const char *label,
|
||||
const char *target_label,
|
||||
unsigned int counter)
|
||||
{
|
||||
struct RewindIpState *ris;
|
||||
|
||||
ris = GNUNET_new (struct RewindIpState);
|
||||
ris->target_label = target_label;
|
||||
ris->counter = counter;
|
||||
{
|
||||
struct TALER_TESTING_Command cmd = {
|
||||
.cls = ris,
|
||||
.label = label,
|
||||
.run = &rewind_ip_run,
|
||||
.cleanup = &rewind_ip_cleanup
|
||||
};
|
||||
|
||||
return cmd;
|
||||
}
|
||||
}
|
@ -40,7 +40,6 @@ stat_cleanup (void *cls,
|
||||
(void) cls;
|
||||
(void) cmd;
|
||||
/* nothing to clean. */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
@ -121,37 +121,18 @@ track_transfer_cleanup (void *cls,
|
||||
*
|
||||
* @param cls closure.
|
||||
* @param hr HTTP response details
|
||||
* @param exchange_pub public key the exchange used for signing
|
||||
* the response.
|
||||
* @param h_wire hash of the wire transfer address the transfer
|
||||
* went to, or NULL on error.
|
||||
* @param execution_time time when the exchange claims to have
|
||||
* performed the wire transfer.
|
||||
* @param total_amount total amount of the wire transfer, or NULL
|
||||
* if the exchange could not provide any @a wtid (set only
|
||||
* if @a http_status is "200 OK").
|
||||
* @param wire_fee wire fee that was charged by the exchange.
|
||||
* @param details_length length of the @a details array.
|
||||
* @param details array with details about the combined
|
||||
* transactions.
|
||||
* @param ta transfer data returned by the exchange
|
||||
*/
|
||||
static void
|
||||
track_transfer_cb (void *cls,
|
||||
const struct TALER_EXCHANGE_HttpResponse *hr,
|
||||
const struct TALER_ExchangePublicKeyP *exchange_pub,
|
||||
const struct GNUNET_HashCode *h_wire,
|
||||
struct GNUNET_TIME_Absolute execution_time,
|
||||
const struct TALER_Amount *total_amount,
|
||||
const struct TALER_Amount *wire_fee,
|
||||
unsigned int details_length,
|
||||
const struct TALER_TrackTransferDetails *details)
|
||||
const struct TALER_EXCHANGE_TransferData *ta)
|
||||
{
|
||||
struct TrackTransferState *tts = cls;
|
||||
struct TALER_TESTING_Interpreter *is = tts->is;
|
||||
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
|
||||
struct TALER_Amount expected_amount;
|
||||
|
||||
(void) exchange_pub;
|
||||
tts->tth = NULL;
|
||||
if (tts->expected_response_code != hr->http_status)
|
||||
{
|
||||
@ -193,14 +174,14 @@ track_transfer_cb (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (total_amount,
|
||||
if (0 != TALER_amount_cmp (&ta->total_amount,
|
||||
&expected_amount))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Total amount mismatch to command %s - "
|
||||
"%s vs %s\n",
|
||||
cmd->label,
|
||||
TALER_amount_to_string (total_amount),
|
||||
TALER_amount_to_string (&ta->total_amount),
|
||||
TALER_amount_to_string (&expected_amount));
|
||||
json_dumpf (hr->reply,
|
||||
stderr,
|
||||
@ -219,7 +200,7 @@ track_transfer_cb (void *cls,
|
||||
return;
|
||||
}
|
||||
|
||||
if (0 != TALER_amount_cmp (wire_fee,
|
||||
if (0 != TALER_amount_cmp (&ta->wire_fee,
|
||||
&expected_amount))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
@ -266,7 +247,7 @@ track_transfer_cb (void *cls,
|
||||
TALER_JSON_merchant_wire_signature_hash (wire_details,
|
||||
&h_wire_details));
|
||||
if (0 != GNUNET_memcmp (&h_wire_details,
|
||||
h_wire))
|
||||
&ta->h_wire))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"Wire hash missmath to command %s\n",
|
||||
@ -301,7 +282,7 @@ track_transfer_cb (void *cls,
|
||||
TALER_TESTING_interpreter_fail (is);
|
||||
return;
|
||||
}
|
||||
if (0 != TALER_amount_cmp (total_amount,
|
||||
if (0 != TALER_amount_cmp (&ta->total_amount,
|
||||
total_amount_from_reference))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
|
@ -69,6 +69,7 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
|
||||
#define BATCH_INDEX 1
|
||||
struct TALER_TESTING_Command *batch;
|
||||
struct TALER_TESTING_Command *current;
|
||||
struct TALER_TESTING_Command *icmd;
|
||||
const struct TALER_TESTING_Command *match;
|
||||
|
||||
current = TALER_TESTING_cmd_batch_get_current (cmd);
|
||||
@ -79,15 +80,15 @@ TALER_TESTING_interpreter_lookup_command (struct TALER_TESTING_Interpreter *is,
|
||||
/* We must do the loop forward, but we can find the last match */
|
||||
match = NULL;
|
||||
for (unsigned int j = 0;
|
||||
NULL != (cmd = &batch[j])->label;
|
||||
NULL != (icmd = &batch[j])->label;
|
||||
j++)
|
||||
{
|
||||
if (current == cmd)
|
||||
if (current == icmd)
|
||||
break; /* do not go past current command */
|
||||
if ( (NULL != cmd->label) &&
|
||||
(0 == strcmp (cmd->label,
|
||||
if ( (NULL != icmd->label) &&
|
||||
(0 == strcmp (icmd->label,
|
||||
label)) )
|
||||
match = cmd;
|
||||
match = icmd;
|
||||
}
|
||||
if (NULL != match)
|
||||
return match;
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#define TALER_TESTING_TRAIT_WIRE_DETAILS "wire-details"
|
||||
#define TALER_TESTING_TRAIT_EXCHANGE_KEYS "exchange-keys"
|
||||
#define TALER_TESTING_TRAIT_JSON "json"
|
||||
|
||||
/**
|
||||
* Obtain serialized exchange keys from @a cmd.
|
||||
@ -120,4 +121,45 @@ TALER_TESTING_make_trait_wire_details
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain json from @a cmd.
|
||||
*
|
||||
* @param cmd command to extract the json from.
|
||||
* @param index index number associate with the json on offer.
|
||||
* @param[out] json where to write the json.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_json (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const json_t **json)
|
||||
{
|
||||
return cmd->traits (cmd->cls,
|
||||
(const void **) json,
|
||||
TALER_TESTING_TRAIT_JSON,
|
||||
index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer json in a trait.
|
||||
*
|
||||
* @param index index number associate with the json
|
||||
* on offer.
|
||||
* @param json json to offer.
|
||||
* @return the trait.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_json (unsigned int index,
|
||||
const json_t *json)
|
||||
{
|
||||
struct TALER_TESTING_Trait ret = {
|
||||
.index = index,
|
||||
.trait_name = TALER_TESTING_TRAIT_JSON,
|
||||
.ptr = (const json_t *) json
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of testing_api_trait_json.c */
|
||||
|
@ -28,7 +28,9 @@
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
#define TALER_TESTING_TRAIT_UINT "uint"
|
||||
#define TALER_TESTING_TRAIT_UINT32 "uint-32"
|
||||
#define TALER_TESTING_TRAIT_UINT64 "uint-64"
|
||||
#define TALER_TESTING_TRAIT_INT64 "int-64"
|
||||
#define TALER_TESTING_TRAIT_BANK_ROW "bank-transaction-row"
|
||||
|
||||
|
||||
@ -72,6 +74,45 @@ TALER_TESTING_make_trait_uint (unsigned int index,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a "number" value from @a cmd, 32-bit version.
|
||||
*
|
||||
* @param cmd command to extract the number from.
|
||||
* @param index the number's index number.
|
||||
* @param[out] n set to the number coming from @a cmd.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_uint32 (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const uint32_t **n)
|
||||
{
|
||||
return cmd->traits (cmd->cls,
|
||||
(const void **) n,
|
||||
TALER_TESTING_TRAIT_UINT32,
|
||||
index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer number trait, 32-bit version.
|
||||
*
|
||||
* @param index the number's index number.
|
||||
* @param n number to offer.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_uint32 (unsigned int index,
|
||||
const uint32_t *n)
|
||||
{
|
||||
struct TALER_TESTING_Trait ret = {
|
||||
.index = index,
|
||||
.trait_name = TALER_TESTING_TRAIT_UINT32,
|
||||
.ptr = (const void *) n
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a "number" value from @a cmd, 64-bit version.
|
||||
*
|
||||
@ -111,6 +152,45 @@ TALER_TESTING_make_trait_uint64 (unsigned int index,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a "number" value from @a cmd, 64-bit signed version.
|
||||
*
|
||||
* @param cmd command to extract the number from.
|
||||
* @param index the number's index number.
|
||||
* @param[out] n set to the number coming from @a cmd.
|
||||
* @return #GNUNET_OK on success.
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_int64 (const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const int64_t **n)
|
||||
{
|
||||
return cmd->traits (cmd->cls,
|
||||
(const void **) n,
|
||||
TALER_TESTING_TRAIT_INT64,
|
||||
index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer number trait, 64-bit signed version.
|
||||
*
|
||||
* @param index the number's index number.
|
||||
* @param n number to offer.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_int64 (unsigned int index,
|
||||
const int64_t *n)
|
||||
{
|
||||
struct TALER_TESTING_Trait ret = {
|
||||
.index = index,
|
||||
.trait_name = TALER_TESTING_TRAIT_INT64,
|
||||
.ptr = (const void *) n
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a bank transaction row value from @a cmd.
|
||||
*
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "taler_testing_lib.h"
|
||||
|
||||
#define TALER_TESTING_TRAIT_TIME_ABS "time-abs"
|
||||
#define TALER_TESTING_TRAIT_TIME_REL "time-rel"
|
||||
|
||||
/**
|
||||
* Obtain a absolute time from @a cmd.
|
||||
@ -73,4 +74,47 @@ TALER_TESTING_make_trait_absolute_time
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain a relative time from @a cmd.
|
||||
*
|
||||
* @param cmd command to extract trait from
|
||||
* @param index which time to pick if
|
||||
* @a cmd has multiple on offer.
|
||||
* @param[out] time set to the wanted WTID.
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_TESTING_get_trait_relative_time (
|
||||
const struct TALER_TESTING_Command *cmd,
|
||||
unsigned int index,
|
||||
const struct GNUNET_TIME_Relative **time)
|
||||
{
|
||||
return cmd->traits (cmd->cls,
|
||||
(const void **) time,
|
||||
TALER_TESTING_TRAIT_TIME_REL,
|
||||
index);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Offer a relative time.
|
||||
*
|
||||
* @param index associate the object with this index
|
||||
* @param time which object should be returned
|
||||
* @return the trait.
|
||||
*/
|
||||
struct TALER_TESTING_Trait
|
||||
TALER_TESTING_make_trait_relative_time (
|
||||
unsigned int index,
|
||||
const struct GNUNET_TIME_Relative *time)
|
||||
{
|
||||
struct TALER_TESTING_Trait ret = {
|
||||
.index = index,
|
||||
.trait_name = TALER_TESTING_TRAIT_TIME_REL,
|
||||
.ptr = (const void *) time
|
||||
};
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* end of testing_api_trait_time.c */
|
||||
|
@ -42,6 +42,7 @@ libtalerutil_la_SOURCES = \
|
||||
payto.c \
|
||||
url.c \
|
||||
util.c \
|
||||
yna.c \
|
||||
os_installation.c
|
||||
|
||||
libtalerutil_la_LIBADD = \
|
||||
|
88
src/util/yna.c
Normal file
88
src/util/yna.c
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
Copyright (C) 2020 Taler Systems SA
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file yna.c
|
||||
* @brief Utility functions for yes/no/all filters
|
||||
* @author Jonathan Buchanan
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
|
||||
|
||||
/**
|
||||
* Convert query argument to @a yna value.
|
||||
*
|
||||
* @param connection connection to take query argument from
|
||||
* @param arg argument to try for
|
||||
* @param default_val value to assign if the argument is not present
|
||||
* @param[out] value to set
|
||||
* @return true on success, false if the parameter was malformed
|
||||
*/
|
||||
bool
|
||||
TALER_arg_to_yna (struct MHD_Connection *connection,
|
||||
const char *arg,
|
||||
enum TALER_EXCHANGE_YesNoAll default_val,
|
||||
enum TALER_EXCHANGE_YesNoAll *yna)
|
||||
{
|
||||
const char *str;
|
||||
|
||||
str = MHD_lookup_connection_value (connection,
|
||||
MHD_GET_ARGUMENT_KIND,
|
||||
arg);
|
||||
if (NULL == str)
|
||||
{
|
||||
*yna = default_val;
|
||||
return true;
|
||||
}
|
||||
if (0 == strcasecmp (str, "yes"))
|
||||
{
|
||||
*yna = TALER_EXCHANGE_YNA_YES;
|
||||
return true;
|
||||
}
|
||||
if (0 == strcasecmp (str, "no"))
|
||||
{
|
||||
*yna = TALER_EXCHANGE_YNA_NO;
|
||||
return true;
|
||||
}
|
||||
if (0 == strcasecmp (str, "all"))
|
||||
{
|
||||
*yna = TALER_EXCHANGE_YNA_ALL;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert YNA value to a string.
|
||||
*
|
||||
* @param yna value to convert
|
||||
* @return string representation ("yes"/"no"/"all").
|
||||
*/
|
||||
const char *
|
||||
TALER_yna_to_string (enum TALER_EXCHANGE_YesNoAll yna)
|
||||
{
|
||||
switch (yna)
|
||||
{
|
||||
case TALER_EXCHANGE_YNA_YES:
|
||||
return "yes";
|
||||
case TALER_EXCHANGE_YNA_NO:
|
||||
return "no";
|
||||
case TALER_EXCHANGE_YNA_ALL:
|
||||
return "all";
|
||||
}
|
||||
GNUNET_assert (0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user