summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
m---------contrib/gana0
-rw-r--r--contrib/pp/en/0.epubbin13772 -> 14983 bytes
-rw-r--r--contrib/pp/en/0.html65
-rw-r--r--contrib/pp/en/0.pdfbin81244 -> 77445 bytes
-rw-r--r--contrib/pp/en/0.txt43
-rw-r--r--contrib/pp/en/0.xml57
-rw-r--r--contrib/pp/locale/de/LC_MESSAGES/pp.po248
-rw-r--r--contrib/pp/pp.rst42
-rw-r--r--contrib/tos/en/0.epubbin16629 -> 17320 bytes
-rw-r--r--contrib/tos/en/0.html163
-rw-r--r--contrib/tos/en/0.pdfbin99859 -> 82060 bytes
-rw-r--r--contrib/tos/en/0.txt112
-rw-r--r--contrib/tos/en/0.xml97
-rw-r--r--contrib/tos/locale/de/LC_MESSAGES/tos.po442
-rw-r--r--contrib/tos/tos.rst2
-rw-r--r--debian/.gitignore3
-rw-r--r--debian/changelog12
-rw-r--r--doc/cbdc-es/cbdc-es.tex1283
-rw-r--r--doc/cbdc-es/cbdc.bib566
-rw-r--r--doc/cbdc-es/deposito.pdfbin0 -> 96830 bytes
-rw-r--r--doc/cbdc-es/eshyphexh.tex1367
-rw-r--r--doc/cbdc-es/graphic-es.odpbin0 -> 145669 bytes
-rw-r--r--doc/cbdc-es/retirada.pdfbin0 -> 62191 bytes
-rw-r--r--doc/cbdc-es/taler_figure_1_dora_SPANISH.jpgbin0 -> 44235 bytes
-rw-r--r--doc/cbdc-es/taler_figure_2_dora_SPANISH.jpgbin0 -> 50323 bytes
-rw-r--r--src/auditor/taler-helper-auditor-reserves.c5
-rwxr-xr-xsrc/auditor/test-auditor.sh4
-rwxr-xr-xsrc/auditor/test-revocation.sh25
-rw-r--r--src/bank-lib/bank_api_credit.c11
-rw-r--r--src/bank-lib/bank_api_debit.c9
-rw-r--r--src/bank-lib/fakebank.c114
-rwxr-xr-xsrc/bank-lib/test_bank.sh6
-rw-r--r--src/curl/curl.c2
-rw-r--r--src/exchange-tools/taler-exchange-dbinit.c2
-rw-r--r--src/exchange/Makefile.am4
-rw-r--r--src/exchange/exchange.conf25
-rw-r--r--src/exchange/taler-exchange-aggregator.c2
-rw-r--r--src/exchange/taler-exchange-closer.c2
-rw-r--r--src/exchange/taler-exchange-httpd.c291
-rw-r--r--src/exchange/taler-exchange-httpd.h99
-rw-r--r--src/exchange/taler-exchange-httpd_deposit.c33
-rw-r--r--src/exchange/taler-exchange-httpd_deposits_get.c90
-rw-r--r--src/exchange/taler-exchange-httpd_keys.c29
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-check.c207
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-check.h42
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.c519
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-proof.h49
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-wallet.c155
-rw-r--r--src/exchange/taler-exchange-httpd_kyc-wallet.h45
-rw-r--r--src/exchange/taler-exchange-httpd_withdraw.c114
-rw-r--r--src/exchangedb/Makefile.am4
-rw-r--r--src/exchangedb/drop0001.sql22
-rw-r--r--src/exchangedb/drop0002.sql31
-rw-r--r--src/exchangedb/drop0003.sql26
-rw-r--r--src/exchangedb/plugin_exchangedb_postgres.c535
-rw-r--r--src/exchangedb/test_exchangedb.c121
-rw-r--r--src/include/taler_crypto_lib.h20
-rw-r--r--src/include/taler_curl_lib.h2
-rw-r--r--src/include/taler_exchange_service.h411
-rw-r--r--src/include/taler_exchangedb_plugin.h243
-rw-r--r--src/include/taler_fakebank_lib.h6
-rw-r--r--src/include/taler_json_lib.h4
-rw-r--r--src/include/taler_signatures.h48
-rw-r--r--src/include/taler_util.h8
-rw-r--r--src/json/json_wire.c62
-rw-r--r--src/lib/Makefile.am2
-rw-r--r--src/lib/exchange_api_common.c4
-rw-r--r--src/lib/exchange_api_deposit.c182
-rw-r--r--src/lib/exchange_api_deposits_get.c114
-rw-r--r--src/lib/exchange_api_handle.c28
-rw-r--r--src/lib/exchange_api_handle.h4
-rw-r--r--src/lib/exchange_api_kyc_check.c297
-rw-r--r--src/lib/exchange_api_kyc_wallet.c232
-rw-r--r--src/lib/exchange_api_link.c4
-rw-r--r--src/lib/exchange_api_withdraw.c76
-rw-r--r--src/lib/exchange_api_withdraw2.c26
-rw-r--r--src/mhd/mhd_responses.c5
-rw-r--r--src/mhd/mhd_run.c10
-rw-r--r--src/testing/testing_api_cmd_deposit.c40
-rw-r--r--src/testing/testing_api_cmd_deposits_get.c24
-rw-r--r--src/testing/testing_api_cmd_insert_deposit.c8
-rw-r--r--src/testing/testing_api_cmd_withdraw.c58
-rw-r--r--src/testing/testing_api_helpers_bank.c10
-rw-r--r--src/util/config.c14
-rw-r--r--src/util/crypto_helper_denom.c12
-rw-r--r--src/util/crypto_wire.c28
-rw-r--r--src/util/test_crypto.c16
88 files changed, 7554 insertions, 1571 deletions
diff --git a/configure.ac b/configure.ac
index d68aea9c..6995b9b3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
#
#
AC_PREREQ([2.69])
-AC_INIT([taler-exchange], [0.8.4], [taler-bug@gnunet.org])
+AC_INIT([taler-exchange], [0.8.5], [taler-bug@gnunet.org])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_SRCDIR([src/util/util.c])
AC_CONFIG_HEADERS([taler_config.h])
diff --git a/contrib/gana b/contrib/gana
-Subproject 0272caa8ff8ee7553d035d29fb19d01866df43e
+Subproject 8c7d9be40ba627348da3e01b91b4f1d3cc78631
diff --git a/contrib/pp/en/0.epub b/contrib/pp/en/0.epub
index 49669a4a..7e9e5343 100644
--- a/contrib/pp/en/0.epub
+++ b/contrib/pp/en/0.epub
Binary files differ
diff --git a/contrib/pp/en/0.html b/contrib/pp/en/0.html
index 1e73557f..ce704535 100644
--- a/contrib/pp/en/0.html
+++ b/contrib/pp/en/0.html
@@ -1,17 +1,16 @@
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<html lang="en">
<head>
- <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Privacy Policy &#8212; Taler Privacy Policy</title>
- <link rel="stylesheet" href="_static/epub.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
- <script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <script type="text/javascript" src="_static/language_data.js"></script>
+ <link rel="stylesheet" href="_static/epub.css" type="text/css" />
+ <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
+ <script src="_static/jquery.js"></script>
+ <script src="_static/underscore.js"></script>
+ <script src="_static/doctools.js"></script>
</head><body>
<div class="document">
@@ -60,9 +59,9 @@ and retain information with a strict business need. That being said, when
using our Services, we inherently have to collect the following information:</p>
<blockquote>
<div><ul class="simple">
-<li>Bank account details necessary when receiving funds from you to top-up your wallet or to transfer funds to you when you are being paid via Taler. At the current experimental stage, only the pseudonym and password you entered in the bank demonstrator is stored.</li>
-<li>The amounts being withdrawn or deposited, with associated unique transaction identifiers and cryptographic signatures authorizing the transaction. Note that for purchases, we cannot identify the buyer from the collected data, so when you spend money, we only receive non-personal information.</li>
-<li>When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us.</li>
+<li><p>Bank account details necessary when receiving funds from you to top-up your wallet or to transfer funds to you when you are being paid via Taler. At the current experimental stage, only the pseudonym and password you entered in the bank demonstrator is stored.</p></li>
+<li><p>The amounts being withdrawn or deposited, with associated unique transaction identifiers and cryptographic signatures authorizing the transaction. Note that for purchases, we cannot identify the buyer from the collected data, so when you spend money, we only receive non-personal information.</p></li>
+<li><p>When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us.</p></li>
</ul>
</div></blockquote>
</div>
@@ -71,9 +70,9 @@ using our Services, we inherently have to collect the following information:</p>
<p>We may process your information for the following reasons:</p>
<blockquote>
<div><ul class="simple">
-<li>to transfer money as specified by our users (Taler transactions);</li>
-<li>to assist government entities in linking income to the underlying contract</li>
-<li>to support you using the Taler Wallet or to improve our Services</li>
+<li><p>to transfer money as specified by our users (Taler transactions);</p></li>
+<li><p>to assist government entities in linking income to the underlying contract as required by law and local regulations</p></li>
+<li><p>to support you using the Taler Wallet or to improve our Services</p></li>
</ul>
</div></blockquote>
</div>
@@ -96,8 +95,7 @@ errors with the Taler Wallet that you reported.</p>
<p>We may provide your Personal Information to our employees, contractors,
agents, service providers, and designees (“Agents”) to enable them to perform
certain services for us exclusively, including: improvement and maintenance of
-our software and Services. By accepting this Privacy Policy, as outlined
-above, you consent to any such transfer.</p>
+our software and Services.</p>
</div>
<div class="section" id="protection-of-us-and-others">
<h2>Protection of us and others<a class="headerlink" href="#protection-of-us-and-others" title="Permalink to this headline">¶</a></h2>
@@ -118,6 +116,38 @@ and keep your data accurate. Any data that is no longer needed for purposes
specified in the “How We Use the Information We Gather” section will be
deleted after ninety (90) days.</p>
</div>
+<div class="section" id="what-are-your-data-protection-rights">
+<h2>What are your data protection rights?<a class="headerlink" href="#what-are-your-data-protection-rights" title="Permalink to this headline">¶</a></h2>
+<p>Anastasis would like to make sure you are fully aware of all of your
+data protection rights. Every user is entitled to the following:</p>
+<dl class="simple">
+<dt><strong>The right to access</strong>: You have the right to request Anastasis for</dt><dd><p>copies of your personal data. We may charge you a small fee for this
+service.</p>
+</dd>
+</dl>
+<p><strong>The right to rectification</strong>: You have the right to request that
+Anastasis correct any information you believe is inaccurate. You also
+have the right to request Anastasis to complete information you
+believe is incomplete. The right to erasure - You have the right to
+request that Anastasis erase your personal data, under certain
+conditions.</p>
+<dl class="simple">
+<dt><strong>The right to restrict processing</strong>: You have the right to request</dt><dd><p>that Anastasis restrict the processing of your personal data, under
+certain conditions.</p>
+</dd>
+<dt><strong>The right to object to processing</strong>: You have the right to object to</dt><dd><p>Anastasis’s processing of your personal data, under certain
+conditions.</p>
+</dd>
+<dt><strong>The right to data portability</strong>: You have the right to request that</dt><dd><p>Anastasis transfer the data that we have collected to another
+organization, or directly to you, under certain conditions.</p>
+</dd>
+</dl>
+<p>If you make a request, we have one month to respond to you. If you
+would like to exercise any of these rights, please contact us at our
+email: <a class="reference external" href="mailto:privacy&#37;&#52;&#48;taler-systems&#46;com">privacy<span>&#64;</span>taler-systems<span>&#46;</span>com</a></p>
+<p>You can always contact your local data protection authority to enforce
+your rights.</p>
+</div>
<div class="section" id="data-retention">
<h2>Data retention<a class="headerlink" href="#data-retention" title="Permalink to this headline">¶</a></h2>
<p>If you uninstall the Taler Wallet mobile applications from your device, or
@@ -171,6 +201,7 @@ privacy practices that are not addressed in this Privacy Statement.</p>
</div>
+ <div class="clearer"></div>
</div>
</div>
</div>
diff --git a/contrib/pp/en/0.pdf b/contrib/pp/en/0.pdf
index f594aa3b..842a8306 100644
--- a/contrib/pp/en/0.pdf
+++ b/contrib/pp/en/0.pdf
Binary files differ
diff --git a/contrib/pp/en/0.txt b/contrib/pp/en/0.txt
index a5194d32..d6e42faf 100644
--- a/contrib/pp/en/0.txt
+++ b/contrib/pp/en/0.txt
@@ -79,7 +79,7 @@ We may process your information for the following reasons:
* to transfer money as specified by our users (Taler transactions);
* to assist government entities in linking income to the underlying
- contract
+ contract as required by law and local regulations
* to support you using the Taler Wallet or to improve our Services
@@ -109,9 +109,7 @@ Agents or third party partners
We may provide your Personal Information to our employees,
contractors, agents, service providers, and designees (“Agents”) to
enable them to perform certain services for us exclusively, including:
-improvement and maintenance of our software and Services. By accepting
-this Privacy Policy, as outlined above, you consent to any such
-transfer.
+improvement and maintenance of our software and Services.
Protection of us and others
@@ -138,6 +136,43 @@ purposes specified in the “How We Use the Information We Gather”
section will be deleted after ninety (90) days.
+What are your data protection rights?
+=====================================
+
+Anastasis would like to make sure you are fully aware of all of your
+data protection rights. Every user is entitled to the following:
+
+**The right to access**: You have the right to request Anastasis for
+ copies of your personal data. We may charge you a small fee for
+ this service.
+
+**The right to rectification**: You have the right to request that
+Anastasis correct any information you believe is inaccurate. You also
+have the right to request Anastasis to complete information you
+believe is incomplete. The right to erasure - You have the right to
+request that Anastasis erase your personal data, under certain
+conditions.
+
+**The right to restrict processing**: You have the right to request
+ that Anastasis restrict the processing of your personal data, under
+ certain conditions.
+
+**The right to object to processing**: You have the right to object to
+ Anastasis's processing of your personal data, under certain
+ conditions.
+
+**The right to data portability**: You have the right to request that
+ Anastasis transfer the data that we have collected to another
+ organization, or directly to you, under certain conditions.
+
+If you make a request, we have one month to respond to you. If you
+would like to exercise any of these rights, please contact us at our
+email: privacy@taler-systems.com
+
+You can always contact your local data protection authority to enforce
+your rights.
+
+
Data retention
==============
diff --git a/contrib/pp/en/0.xml b/contrib/pp/en/0.xml
index 3050c92b..d4400542 100644
--- a/contrib/pp/en/0.xml
+++ b/contrib/pp/en/0.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
-<!-- Generated by Docutils 0.14 -->
-<document source="/home/grothoff/research/taler/exchange/contrib/pp/pp.rst">
+<!-- Generated by Docutils 0.16 -->
+<document source="/research/taler/exchange/contrib/pp/pp.rst">
<section ids="privacy-policy" names="privacy\ policy">
<title>Privacy Policy</title>
<paragraph>Last Updated: 11.12.2019</paragraph>
@@ -64,7 +64,7 @@
<paragraph>to transfer money as specified by our users (Taler transactions);</paragraph>
</list_item>
<list_item>
- <paragraph>to assist government entities in linking income to the underlying contract</paragraph>
+ <paragraph>to assist government entities in linking income to the underlying contract as required by law and local regulations</paragraph>
</list_item>
<list_item>
<paragraph>to support you using the Taler Wallet or to improve our Services</paragraph>
@@ -91,8 +91,7 @@
<paragraph>We may provide your Personal Information to our employees, contractors,
agents, service providers, and designees (“Agents”) to enable them to perform
certain services for us exclusively, including: improvement and maintenance of
- our software and Services. By accepting this Privacy Policy, as outlined
- above, you consent to any such transfer.</paragraph>
+ our software and Services.</paragraph>
</section>
<section ids="protection-of-us-and-others" names="protection\ of\ us\ and\ others">
<title>Protection of us and others</title>
@@ -113,6 +112,54 @@
specified in the “How We Use the Information We Gather” section will be
deleted after ninety (90) days.</paragraph>
</section>
+ <section ids="what-are-your-data-protection-rights" names="what\ are\ your\ data\ protection\ rights?">
+ <title>What are your data protection rights?</title>
+ <paragraph>Anastasis would like to make sure you are fully aware of all of your
+ data protection rights. Every user is entitled to the following:</paragraph>
+ <definition_list>
+ <definition_list_item>
+ <term><strong>The right to access</strong>: You have the right to request Anastasis for</term>
+ <definition>
+ <paragraph>copies of your personal data. We may charge you a small fee for this
+ service.</paragraph>
+ </definition>
+ </definition_list_item>
+ </definition_list>
+ <paragraph><strong>The right to rectification</strong>: You have the right to request that
+ Anastasis correct any information you believe is inaccurate. You also
+ have the right to request Anastasis to complete information you
+ believe is incomplete. The right to erasure - You have the right to
+ request that Anastasis erase your personal data, under certain
+ conditions.</paragraph>
+ <definition_list>
+ <definition_list_item>
+ <term><strong>The right to restrict processing</strong>: You have the right to request</term>
+ <definition>
+ <paragraph>that Anastasis restrict the processing of your personal data, under
+ certain conditions.</paragraph>
+ </definition>
+ </definition_list_item>
+ <definition_list_item>
+ <term><strong>The right to object to processing</strong>: You have the right to object to</term>
+ <definition>
+ <paragraph>Anastasis’s processing of your personal data, under certain
+ conditions.</paragraph>
+ </definition>
+ </definition_list_item>
+ <definition_list_item>
+ <term><strong>The right to data portability</strong>: You have the right to request that</term>
+ <definition>
+ <paragraph>Anastasis transfer the data that we have collected to another
+ organization, or directly to you, under certain conditions.</paragraph>
+ </definition>
+ </definition_list_item>
+ </definition_list>
+ <paragraph>If you make a request, we have one month to respond to you. If you
+ would like to exercise any of these rights, please contact us at our
+ email: <reference refuri="mailto:privacy@taler-systems.com">privacy@taler-systems.com</reference></paragraph>
+ <paragraph>You can always contact your local data protection authority to enforce
+ your rights.</paragraph>
+ </section>
<section ids="data-retention" names="data\ retention">
<title>Data retention</title>
<paragraph>If you uninstall the Taler Wallet mobile applications from your device, or
diff --git a/contrib/pp/locale/de/LC_MESSAGES/pp.po b/contrib/pp/locale/de/LC_MESSAGES/pp.po
index b9544472..b97b7037 100644
--- a/contrib/pp/locale/de/LC_MESSAGES/pp.po
+++ b/contrib/pp/locale/de/LC_MESSAGES/pp.po
@@ -1,21 +1,20 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+)
# This file is distributed under the same license as the pp package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: pp 0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-02-07 00:51+0100\n"
+"POT-Creation-Date: 2021-09-30 21:41+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 2.6.0\n"
#: ../../pp.rst:2
msgid "Privacy Policy"
@@ -26,14 +25,7 @@ msgid "Last Updated: 11.12.2019"
msgstr ""
#: ../../pp.rst:6
-msgid ""
-"This Privacy Policy describes the policies and procedures of Taler "
-"Systems SA (“we,” “our,” or “us”) pertaining to the collection, use, and "
-"disclosure of your information on our sites and related mobile "
-"applications and products we offer (the “Services” or “Taler Wallet”). "
-"This Privacy Statement applies to your personal data when you use our "
-"Services, and does not apply to online websites or services that we do "
-"not own or control."
+msgid "This Privacy Policy describes the policies and procedures of Taler Systems SA (“we,” “our,” or “us”) pertaining to the collection, use, and disclosure of your information on our sites and related mobile applications and products we offer (the “Services” or “Taler Wallet”). This Privacy Statement applies to your personal data when you use our Services, and does not apply to online websites or services that we do not own or control."
msgstr ""
#: ../../pp.rst:15
@@ -41,17 +33,7 @@ msgid "Overview"
msgstr ""
#: ../../pp.rst:17
-msgid ""
-"Your privacy is important to us. We follow a few fundamental principles: "
-"We don’t ask you for personally identifiable information (defined below)."
-" That being said, your contact information, such as your phone number, "
-"social media handle, or email address (depending on how you contact us), "
-"may be collected when you communicate with us, for example to report a "
-"bug or other error related to the Taler Wallet. We don’t share your "
-"information with third parties except when strictly required to deliver "
-"you our Services and products, or to comply with the law. If you have any"
-" questions or concerns about this policy, please reach out to us at "
-"privacy@taler-systems.net."
+msgid "Your privacy is important to us. We follow a few fundamental principles: We don’t ask you for personally identifiable information (defined below). That being said, your contact information, such as your phone number, social media handle, or email address (depending on how you contact us), may be collected when you communicate with us, for example to report a bug or other error related to the Taler Wallet. We don’t share your information with third parties except when strictly required to deliver you our Services and products, or to comply with the law. If you have any questions or concerns about this policy, please reach out to us at privacy@taler-systems.net."
msgstr ""
#: ../../pp.rst:29
@@ -59,9 +41,7 @@ msgid "How you accept this policy"
msgstr ""
#: ../../pp.rst:31
-msgid ""
-"By using our Services or visiting our sites, you agree to the use, "
-"disclosure, and procedures outlined in this Privacy Policy."
+msgid "By using our Services or visiting our sites, you agree to the use, disclosure, and procedures outlined in this Privacy Policy."
msgstr ""
#: ../../pp.rst:36
@@ -69,49 +49,23 @@ msgid "What personal information do we collect from our users?"
msgstr ""
#: ../../pp.rst:38
-msgid ""
-"The information we collect from you falls into two categories: (i) "
-"personally identifiable information (i.e., data that could potentially "
-"identify you as an individual) (“Personal Information”), and (ii) non-"
-"personally identifiable information (i.e., information that cannot be "
-"used to identify who you are) (“Non-Personal Information”). This Privacy "
-"Policy covers both categories and will tell you how we might collect and "
-"use each type."
+msgid "The information we collect from you falls into two categories: (i) personally identifiable information (i.e., data that could potentially identify you as an individual) (“Personal Information”), and (ii) non-personally identifiable information (i.e., information that cannot be used to identify who you are) (“Non-Personal Information”). This Privacy Policy covers both categories and will tell you how we might collect and use each type."
msgstr ""
#: ../../pp.rst:45
-msgid ""
-"We do our best to not collect any Personal Information from Taler Wallet "
-"users. We believe that the Taler Wallet never transmits personal "
-"information to our services without at least clear implied consent, and "
-"we only process and retain information with a strict business need. That "
-"being said, when using our Services, we inherently have to collect the "
-"following information:"
+msgid "We do our best to not collect any Personal Information from Taler Wallet users. We believe that the Taler Wallet never transmits personal information to our services without at least clear implied consent, and we only process and retain information with a strict business need. That being said, when using our Services, we inherently have to collect the following information:"
msgstr ""
#: ../../pp.rst:51
-msgid ""
-"Bank account details necessary when receiving funds from you to top-up "
-"your wallet or to transfer funds to you when you are being paid via "
-"Taler. At the current experimental stage, only the pseudonym and password"
-" you entered in the bank demonstrator is stored."
+msgid "Bank account details necessary when receiving funds from you to top-up your wallet or to transfer funds to you when you are being paid via Taler. At the current experimental stage, only the pseudonym and password you entered in the bank demonstrator is stored."
msgstr ""
#: ../../pp.rst:53
-msgid ""
-"The amounts being withdrawn or deposited, with associated unique "
-"transaction identifiers and cryptographic signatures authorizing the "
-"transaction. Note that for purchases, we cannot identify the buyer from "
-"the collected data, so when you spend money, we only receive non-personal"
-" information."
+msgid "The amounts being withdrawn or deposited, with associated unique transaction identifiers and cryptographic signatures authorizing the transaction. Note that for purchases, we cannot identify the buyer from the collected data, so when you spend money, we only receive non-personal information."
msgstr ""
#: ../../pp.rst:55
-msgid ""
-"When you contact us. We may collect certain information if you choose to "
-"contact us, for example to report a bug or other error with the Taler "
-"Wallet. This may include contact information such as your name, email "
-"address or phone number depending on the method you choose to contact us."
+msgid "When you contact us. We may collect certain information if you choose to contact us, for example to report a bug or other error with the Taler Wallet. This may include contact information such as your name, email address or phone number depending on the method you choose to contact us."
msgstr ""
#: ../../pp.rst:59
@@ -127,7 +81,7 @@ msgid "to transfer money as specified by our users (Taler transactions);"
msgstr ""
#: ../../pp.rst:64
-msgid "to assist government entities in linking income to the underlying contract"
+msgid "to assist government entities in linking income to the underlying contract as required by law and local regulations"
msgstr ""
#: ../../pp.rst:65
@@ -139,26 +93,15 @@ msgid "How we share and use the information we gather"
msgstr ""
#: ../../pp.rst:71
-msgid ""
-"We may share your Personal Data or other information about you only if "
-"you are a merchant receiving income, with your bank, to the degree "
-"necessary to execute the payment."
+msgid "We may share your Personal Data or other information about you only if you are a merchant receiving income, with your bank, to the degree necessary to execute the payment."
msgstr ""
#: ../../pp.rst:75
-msgid ""
-"We retain Personal Data to transfer funds to the accounts designated by "
-"our users. We may retain Personal Data only for as long as mandated by "
-"law and required for the wire transfers."
+msgid "We retain Personal Data to transfer funds to the accounts designated by our users. We may retain Personal Data only for as long as mandated by law and required for the wire transfers."
msgstr ""
#: ../../pp.rst:79
-msgid ""
-"We primarily use the limited information we receive directly from you to "
-"enhance the Taler Wallet. Some ways we may use your Personal Information "
-"are to: Contact you when necessary to respond to your comments, answer "
-"your questions, or obtain additional information on issues related to "
-"bugs or errors with the Taler Wallet that you reported."
+msgid "We primarily use the limited information we receive directly from you to enhance the Taler Wallet. Some ways we may use your Personal Information are to: Contact you when necessary to respond to your comments, answer your questions, or obtain additional information on issues related to bugs or errors with the Taler Wallet that you reported."
msgstr ""
#: ../../pp.rst:87
@@ -166,118 +109,113 @@ msgid "Agents or third party partners"
msgstr ""
#: ../../pp.rst:89
-msgid ""
-"We may provide your Personal Information to our employees, contractors, "
-"agents, service providers, and designees (“Agents”) to enable them to "
-"perform certain services for us exclusively, including: improvement and "
-"maintenance of our software and Services. By accepting this Privacy "
-"Policy, as outlined above, you consent to any such transfer."
+msgid "We may provide your Personal Information to our employees, contractors, agents, service providers, and designees (“Agents”) to enable them to perform certain services for us exclusively, including: improvement and maintenance of our software and Services."
msgstr ""
-#: ../../pp.rst:97
+#: ../../pp.rst:96
msgid "Protection of us and others"
msgstr ""
-#: ../../pp.rst:99
-msgid ""
-"We reserve the right to access, read, preserve, and disclose any "
-"information that we reasonably believe is necessary to comply with the "
-"law or a court order."
+#: ../../pp.rst:98
+msgid "We reserve the right to access, read, preserve, and disclose any information that we reasonably believe is necessary to comply with the law or a court order."
msgstr ""
-#: ../../pp.rst:105
+#: ../../pp.rst:104
msgid "What personal information can I access or change?"
msgstr ""
-#: ../../pp.rst:107
-msgid ""
-"You can request access to the information we have collected from you. You"
-" can do this by contacting us at privacy@taler-systems.net. We will make "
-"sure to provide you with a copy of the data we process about you. To "
-"comply with your request, we may ask you to verify your identity. We will"
-" fulfill your request by sending your copy electronically. For any "
-"subsequent access request, we may charge you with an administrative fee. "
-"If you believe that the information we have collected is incorrect, you "
-"are welcome to contact us so we can update it and keep your data "
-"accurate. Any data that is no longer needed for purposes specified in the"
-" “How We Use the Information We Gather” section will be deleted after "
-"ninety (90) days."
-msgstr ""
-
-#: ../../pp.rst:120
+#: ../../pp.rst:106
+msgid "You can request access to the information we have collected from you. You can do this by contacting us at privacy@taler-systems.net. We will make sure to provide you with a copy of the data we process about you. To comply with your request, we may ask you to verify your identity. We will fulfill your request by sending your copy electronically. For any subsequent access request, we may charge you with an administrative fee. If you believe that the information we have collected is incorrect, you are welcome to contact us so we can update it and keep your data accurate. Any data that is no longer needed for purposes specified in the “How We Use the Information We Gather” section will be deleted after ninety (90) days."
+msgstr ""
+
+#: ../../pp.rst:119
+msgid "What are your data protection rights?"
+msgstr ""
+
+#: ../../pp.rst:121
+msgid "Anastasis would like to make sure you are fully aware of all of your data protection rights. Every user is entitled to the following:"
+msgstr ""
+
+#: ../../pp.rst:126
+msgid "**The right to access**: You have the right to request Anastasis for"
+msgstr ""
+
+#: ../../pp.rst:125
+msgid "copies of your personal data. We may charge you a small fee for this service."
+msgstr ""
+
+#: ../../pp.rst:128
+msgid "**The right to rectification**: You have the right to request that Anastasis correct any information you believe is inaccurate. You also have the right to request Anastasis to complete information you believe is incomplete. The right to erasure - You have the right to request that Anastasis erase your personal data, under certain conditions."
+msgstr ""
+
+#: ../../pp.rst:137
+msgid "**The right to restrict processing**: You have the right to request"
+msgstr ""
+
+#: ../../pp.rst:136
+msgid "that Anastasis restrict the processing of your personal data, under certain conditions."
+msgstr ""
+
+#: ../../pp.rst:141
+msgid "**The right to object to processing**: You have the right to object to"
+msgstr ""
+
+#: ../../pp.rst:140
+msgid "Anastasis's processing of your personal data, under certain conditions."
+msgstr ""
+
+#: ../../pp.rst:145
+msgid "**The right to data portability**: You have the right to request that"
+msgstr ""
+
+#: ../../pp.rst:144
+msgid "Anastasis transfer the data that we have collected to another organization, or directly to you, under certain conditions."
+msgstr ""
+
+#: ../../pp.rst:147
+msgid "If you make a request, we have one month to respond to you. If you would like to exercise any of these rights, please contact us at our email: privacy@taler-systems.com"
+msgstr ""
+
+#: ../../pp.rst:151
+msgid "You can always contact your local data protection authority to enforce your rights."
+msgstr ""
+
+#: ../../pp.rst:156
msgid "Data retention"
msgstr ""
-#: ../../pp.rst:122
-msgid ""
-"If you uninstall the Taler Wallet mobile applications from your device, "
-"or request that your information be deleted, we still may retain some "
-"information that you have provided to us to maintain the Taler Wallet or "
-"to comply with relevant laws."
+#: ../../pp.rst:158
+msgid "If you uninstall the Taler Wallet mobile applications from your device, or request that your information be deleted, we still may retain some information that you have provided to us to maintain the Taler Wallet or to comply with relevant laws."
msgstr ""
-#: ../../pp.rst:129
+#: ../../pp.rst:165
msgid "Data security"
msgstr ""
-#: ../../pp.rst:131
-msgid ""
-"We are committed to making sure your information is protected. We employ "
-"several physical and electronic safeguards to keep your information safe,"
-" including encrypted user passwords, two factor verification and "
-"authentication on passwords where possible, and securing connections with"
-" industry standard transport layer security. You are also welcome to "
-"contact us using GnuPG encrypted e-mail. Even with all these precautions,"
-" we cannot fully guarantee against the access, disclosure, alteration, or"
-" deletion of data through events, including but not limited to hardware "
-"or software failure or unauthorized use. Any information that you provide"
-" to us is done so entirely at your own risk."
+#: ../../pp.rst:167
+msgid "We are committed to making sure your information is protected. We employ several physical and electronic safeguards to keep your information safe, including encrypted user passwords, two factor verification and authentication on passwords where possible, and securing connections with industry standard transport layer security. You are also welcome to contact us using GnuPG encrypted e-mail. Even with all these precautions, we cannot fully guarantee against the access, disclosure, alteration, or deletion of data through events, including but not limited to hardware or software failure or unauthorized use. Any information that you provide to us is done so entirely at your own risk."
msgstr ""
-#: ../../pp.rst:144
+#: ../../pp.rst:180
msgid "Changes and updates to privacy policy"
msgstr ""
-#: ../../pp.rst:146
-msgid ""
-"We reserve the right to update and revise this privacy policy at any "
-"time. We occasionally review this Privacy Policy to make sure it complies"
-" with applicable laws and conforms to changes in our business. We may "
-"need to update this Privacy Policy, and we reserve the right to do so at "
-"any time. If we do revise this Privacy Policy, we will update the "
-"“Effective Date” at the bottom of this page so that you can tell if it "
-"has changed since your last visit. As we generally do not collect contact"
-" information and also do not track your visits, we will not be able to "
-"notify you directly. However, the Taler Wallet may inform you about a "
-"change in the privacy policy once it detects that the policy has changed."
-" Please review this Privacy Policy regularly to ensure that you are aware"
-" of its terms. Any use of our Services after an amendment to our Privacy "
-"Policy constitutes your acceptance to the revised or amended agreement."
-msgstr ""
-
-#: ../../pp.rst:162
+#: ../../pp.rst:182
+msgid "We reserve the right to update and revise this privacy policy at any time. We occasionally review this Privacy Policy to make sure it complies with applicable laws and conforms to changes in our business. We may need to update this Privacy Policy, and we reserve the right to do so at any time. If we do revise this Privacy Policy, we will update the “Effective Date” at the bottom of this page so that you can tell if it has changed since your last visit. As we generally do not collect contact information and also do not track your visits, we will not be able to notify you directly. However, the Taler Wallet may inform you about a change in the privacy policy once it detects that the policy has changed. Please review this Privacy Policy regularly to ensure that you are aware of its terms. Any use of our Services after an amendment to our Privacy Policy constitutes your acceptance to the revised or amended agreement."
+msgstr ""
+
+#: ../../pp.rst:198
msgid "International users and visitors"
msgstr ""
-#: ../../pp.rst:164
-msgid ""
-"Our Services are hosted in Switzerland. If you are a user accessing the "
-"Services from the European Union, Asia, US, or any other region with laws"
-" or regulations governing personal data collection, use, and disclosure "
-"that differ from Swiss laws, please be advised that through your "
-"continued use of the Services, which is governed by Swiss law, you are "
-"transferring your Personal Information to Switzerland and you consent to "
-"that transfer."
+#: ../../pp.rst:200
+msgid "Our Services are hosted in Switzerland. If you are a user accessing the Services from the European Union, Asia, US, or any other region with laws or regulations governing personal data collection, use, and disclosure that differ from Swiss laws, please be advised that through your continued use of the Services, which is governed by Swiss law, you are transferring your Personal Information to Switzerland and you consent to that transfer."
msgstr ""
-#: ../../pp.rst:173
+#: ../../pp.rst:209
msgid "Questions"
msgstr ""
-#: ../../pp.rst:175
-msgid ""
-"Please contact us at privacy@taler-systems.net if you have questions "
-"about our privacy practices that are not addressed in this Privacy "
-"Statement."
+#: ../../pp.rst:211
+msgid "Please contact us at privacy@taler-systems.net if you have questions about our privacy practices that are not addressed in this Privacy Statement."
msgstr ""
-
diff --git a/contrib/pp/pp.rst b/contrib/pp/pp.rst
index d37c10c2..e6d003d8 100644
--- a/contrib/pp/pp.rst
+++ b/contrib/pp/pp.rst
@@ -61,7 +61,7 @@ How we collect and process information
We may process your information for the following reasons:
* to transfer money as specified by our users (Taler transactions);
- * to assist government entities in linking income to the underlying contract
+ * to assist government entities in linking income to the underlying contract as required by law and local regulations
* to support you using the Taler Wallet or to improve our Services
@@ -89,8 +89,7 @@ Agents or third party partners
We may provide your Personal Information to our employees, contractors,
agents, service providers, and designees (“Agents”) to enable them to perform
certain services for us exclusively, including: improvement and maintenance of
-our software and Services. By accepting this Privacy Policy, as outlined
-above, you consent to any such transfer.
+our software and Services.
Protection of us and others
@@ -116,6 +115,43 @@ specified in the “How We Use the Information We Gather” section will be
deleted after ninety (90) days.
+What are your data protection rights?
+-------------------------------------
+
+Anastasis would like to make sure you are fully aware of all of your
+data protection rights. Every user is entitled to the following:
+
+**The right to access**: You have the right to request Anastasis for
+ copies of your personal data. We may charge you a small fee for this
+ service.
+
+**The right to rectification**: You have the right to request that
+Anastasis correct any information you believe is inaccurate. You also
+have the right to request Anastasis to complete information you
+believe is incomplete. The right to erasure - You have the right to
+request that Anastasis erase your personal data, under certain
+conditions.
+
+**The right to restrict processing**: You have the right to request
+ that Anastasis restrict the processing of your personal data, under
+ certain conditions.
+
+**The right to object to processing**: You have the right to object to
+ Anastasis's processing of your personal data, under certain
+ conditions.
+
+**The right to data portability**: You have the right to request that
+ Anastasis transfer the data that we have collected to another
+ organization, or directly to you, under certain conditions.
+
+If you make a request, we have one month to respond to you. If you
+would like to exercise any of these rights, please contact us at our
+email: privacy@taler-systems.com
+
+You can always contact your local data protection authority to enforce
+your rights.
+
+
Data retention
--------------
diff --git a/contrib/tos/en/0.epub b/contrib/tos/en/0.epub
index 5acb8dfc..2e6c6609 100644
--- a/contrib/tos/en/0.epub
+++ b/contrib/tos/en/0.epub
Binary files differ
diff --git a/contrib/tos/en/0.html b/contrib/tos/en/0.html
index 07a3ab40..6e7f66f5 100644
--- a/contrib/tos/en/0.html
+++ b/contrib/tos/en/0.html
@@ -1,17 +1,16 @@
-<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
+<html lang="en">
<head>
- <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Terms Of Service &#8212; Taler Terms of Service</title>
- <link rel="stylesheet" href="_static/epub.css" type="text/css" />
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
- <script type="text/javascript" id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
- <script type="text/javascript" src="_static/jquery.js"></script>
- <script type="text/javascript" src="_static/underscore.js"></script>
- <script type="text/javascript" src="_static/doctools.js"></script>
- <script type="text/javascript" src="_static/language_data.js"></script>
+ <link rel="stylesheet" href="_static/epub.css" type="text/css" />
+ <script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
+ <script src="_static/jquery.js"></script>
+ <script src="_static/underscore.js"></script>
+ <script src="_static/doctools.js"></script>
</head><body>
<div class="document">
@@ -39,25 +38,25 @@ carefully.</p>
<h3>Highlights:<a class="headerlink" href="#highlights" title="Permalink to this headline">¶</a></h3>
<blockquote>
<div><ul class="simple">
-<li>You are responsible for keeping the data in your Taler Wallet at all times
+<li><p>You are responsible for keeping the data in your Taler Wallet at all times
under your control. Any losses arising from you not being in control of
-your private information are your problem.</li>
-<li>We will try to transfer funds we hold in escrow for our users to any legal
+your private information are your problem.</p></li>
+<li><p>We will try to transfer funds we hold in escrow for our users to any legal
recipient to the best of our ability within the limitations of the law and
our implementation. However, the Services offered today are highly
-experimental and the set of recipients of funds is severely restricted.</li>
-<li>For our Services, we may charge transaction fees. The specific fee structure
+experimental and the set of recipients of funds is severely restricted.</p></li>
+<li><p>For our Services, we may charge transaction fees. The specific fee structure
is provided based on the Taler protocol and should be shown to you when you
withdraw electronic coins using a Taler Wallet. You agree and understand
-that the Taler protocol allows for the fee structure to change.</li>
-<li>You agree to not intentionally overwhelm our systems with requests and
-follow responsible disclosure if you find security issues in our services.</li>
-<li>We cannot be held accountable for our Services not being available due to
+that the Taler protocol allows for the fee structure to change.</p></li>
+<li><p>You agree to not intentionally overwhelm our systems with requests and
+follow responsible disclosure if you find security issues in our services.</p></li>
+<li><p>We cannot be held accountable for our Services not being available due to
circumstances beyond our control. If we modify or terminate our services,
we will try to give you the opportunity to recover your funds. However,
given the experimental state of the Services today, this may not be
possible. You are strongly advised to limit your use of the Service
-to small-scale experiments expecting total loss of all funds.</li>
+to small-scale experiments expecting total loss of all funds.</p></li>
</ul>
</div></blockquote>
<p>These terms outline approved uses of our Services. The Services and these
@@ -103,6 +102,14 @@ situations where we are unable to make transfers at all or lead to incorrect
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.</p>
+<p>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
+<a class="reference external" href="mailto:security&#37;&#52;&#48;taler-systems&#46;com">security<span>&#64;</span>taler-systems<span>&#46;</span>com</a> 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.</p>
</div>
<div class="section" id="fees">
<h2>Fees<a class="headerlink" href="#fees" title="Permalink to this headline">¶</a></h2>
@@ -120,15 +127,12 @@ 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.</p>
</div>
-<div class="section" id="eligibility">
-<h2>Eligibility<a class="headerlink" href="#eligibility" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="eligibility-and-financial-self-responsibility">
+<h2>Eligibility and Financial self-responsibility<a class="headerlink" href="#eligibility-and-financial-self-responsibility" title="Permalink to this headline">¶</a></h2>
<p>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.</p>
-</div>
-<div class="section" id="financial-self-responsibility">
-<h2>Financial self-responsibility<a class="headerlink" href="#financial-self-responsibility" title="Permalink to this headline">¶</a></h2>
<p>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
@@ -149,17 +153,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.</p>
</div>
-<div class="section" id="your-use-of-our-services">
-<h2>Your use of our services<a class="headerlink" href="#your-use-of-our-services" title="Permalink to this headline">¶</a></h2>
-<p>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
-<a class="reference external" href="mailto:security&#37;&#52;&#48;taler-systems&#46;com">security<span>&#64;</span>taler-systems<span>&#46;</span>com</a> 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.</p>
-</div>
<div class="section" id="limitation-of-liability-disclaimer-of-warranties">
<h2>Limitation of liability &amp; disclaimer of warranties<a class="headerlink" href="#limitation-of-liability-disclaimer-of-warranties" title="Permalink to this headline">¶</a></h2>
<p>You understand and agree that we have no control over, and no duty to take any
@@ -172,22 +165,19 @@ Taler Wallet, including, but not limited to your Taler Wallet coins or backup
encryption keys. You release us from all liability related to any losses,
damages, or claims arising from:</p>
<ol class="loweralpha simple">
-<li>user error such as forgotten passwords, incorrectly constructed
-transactions;</li>
-<li>server failure or data loss;</li>
-<li>unauthorized access to the Taler Wallet application;</li>
-<li>bugs or other errors in the Taler Wallet software; and</li>
-<li>any unauthorized third party activities, including, but not limited to,
+<li><p>user error such as forgotten passwords, incorrectly constructed
+transactions;</p></li>
+<li><p>server failure or data loss;</p></li>
+<li><p>unauthorized access to the Taler Wallet application;</p></li>
+<li><p>bugs or other errors in the Taler Wallet software; and</p></li>
+<li><p>any unauthorized third party activities, including, but not limited to,
the use of viruses, phishing, brute forcing, or other means of attack
against the Taler Wallet. We make no representations concerning any
-Third Party Content contained in or accessed through our Services.</li>
+Third Party Content contained in or accessed through our Services.</p></li>
</ol>
<p>Any other terms, conditions, warranties, or representations associated with
such content, are solely between you and such organizations and/or
individuals.</p>
-</div>
-<div class="section" id="limitation-of-liability">
-<h2>Limitation of liability<a class="headerlink" href="#limitation-of-liability" title="Permalink to this headline">¶</a></h2>
<p>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,
@@ -195,23 +185,23 @@ acting, or purporting to act on our behalf (collectively the “Taler Parties”
be liable to you under contract, tort, strict liability, negligence, or any
other legal or equitable theory, for:</p>
<ol class="loweralpha simple">
-<li>any lost profits, data loss, cost of procurement of substitute goods or
+<li><p>any lost profits, data loss, cost of procurement of substitute goods or
services, or direct, indirect, incidental, special, punitive, compensatory,
-or consequential damages of any kind whatsoever resulting from:</li>
+or consequential damages of any kind whatsoever resulting from:</p></li>
</ol>
<blockquote>
<div><ol class="lowerroman simple">
-<li>your use of, or conduct in connection with, our services;</li>
-<li>any unauthorized use of your wallet and/or private key due to your
-failure to maintain the confidentiality of your wallet;</li>
-<li>any interruption or cessation of transmission to or from the services; or</li>
-<li>any bugs, viruses, trojan horses, or the like that are found in the Taler
+<li><p>your use of, or conduct in connection with, our services;</p></li>
+<li><p>any unauthorized use of your wallet and/or private key due to your
+failure to maintain the confidentiality of your wallet;</p></li>
+<li><p>any interruption or cessation of transmission to or from the services; or</p></li>
+<li><p>any bugs, viruses, trojan horses, or the like that are found in the Taler
Wallet software or that may be transmitted to or through our services by
-any third party (regardless of the source of origination), or</li>
+any third party (regardless of the source of origination), or</p></li>
</ol>
</div></blockquote>
<ol class="loweralpha simple" start="2">
-<li>any direct damages.</li>
+<li><p>any direct damages.</p></li>
</ol>
<p>These limitations apply regardless of legal theory, whether based on tort,
strict liability, breach of contract, breach of warranty, or any other legal
@@ -219,9 +209,6 @@ theory, and whether or not we were advised of the possibility of such
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.</p>
-</div>
-<div class="section" id="warranty-disclaimer">
-<h2>Warranty disclaimer<a class="headerlink" href="#warranty-disclaimer" title="Permalink to this headline">¶</a></h2>
<p>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
@@ -238,8 +225,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.</p>
</div>
-<div class="section" id="indemnity">
-<h2>Indemnity<a class="headerlink" href="#indemnity" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="indemnity-and-time-limitation-on-claims-and-termination">
+<h2>Indemnity and Time limitation on claims and Termination<a class="headerlink" href="#indemnity-and-time-limitation-on-claims-and-termination" title="Permalink to this headline">¶</a></h2>
<p>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,
obligations, losses, liabilities, costs or debt, and expenses (including, but
@@ -247,30 +234,14 @@ not limited to, attorney’s fees) arising from: (a) your use of and access to
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.</p>
-</div>
-<div class="section" id="time-limitation-on-claims">
-<h2>Time limitation on claims<a class="headerlink" href="#time-limitation-on-claims" title="Permalink to this headline">¶</a></h2>
<p>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.</p>
-</div>
-<div class="section" id="governing-law">
-<h2>Governing law<a class="headerlink" href="#governing-law" title="Permalink to this headline">¶</a></h2>
-<p>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.</p>
-</div>
-<div class="section" id="termination">
-<h2>Termination<a class="headerlink" href="#termination" title="Permalink to this headline">¶</a></h2>
<p>In the event of termination concerning your use of our Services, your
obligations under this Agreement will still continue.</p>
</div>
-<div class="section" id="discontinuance-of-services">
-<h2>Discontinuance of services<a class="headerlink" href="#discontinuance-of-services" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="discontinuance-of-services-and-force-majeure">
+<h2>Discontinuance of services and Force majeure<a class="headerlink" href="#discontinuance-of-services-and-force-majeure" title="Permalink to this headline">¶</a></h2>
<p>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,
any portion of our Services. We will use the Taler protocol’s provisions to
@@ -280,22 +251,6 @@ three months to observe these notifications. We shall not be held responsible
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.</p>
-</div>
-<div class="section" id="no-waiver">
-<h2>No waiver<a class="headerlink" href="#no-waiver" title="Permalink to this headline">¶</a></h2>
-<p>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.</p>
-</div>
-<div class="section" id="severability">
-<h2>Severability<a class="headerlink" href="#severability" title="Permalink to this headline">¶</a></h2>
-<p>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.</p>
-</div>
-<div class="section" id="force-majeure">
-<h2>Force majeure<a class="headerlink" href="#force-majeure" title="Permalink to this headline">¶</a></h2>
<p>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
@@ -306,13 +261,24 @@ 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.</p>
</div>
-<div class="section" id="assignment">
-<h2>Assignment<a class="headerlink" href="#assignment" title="Permalink to this headline">¶</a></h2>
+<div class="section" id="governing-law-waivers-severability-and-assignment">
+<h2>Governing law, Waivers, Severability and Assignment<a class="headerlink" href="#governing-law-waivers-severability-and-assignment" title="Permalink to this headline">¶</a></h2>
+<p>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.</p>
+<p>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.</p>
<p>You agree that we may assign any of our rights and/or transfer, sub-contract,
or delegate any of our obligations under these Terms.</p>
-</div>
-<div class="section" id="entire-agreement">
-<h2>Entire agreement<a class="headerlink" href="#entire-agreement" title="Permalink to this headline">¶</a></h2>
+<p>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.</p>
<p>This Agreement sets forth the entire understanding and agreement as to the
subject matter hereof and supersedes any and all prior discussions,
agreements, and understandings of any kind (including, without limitation, any
@@ -328,6 +294,7 @@ message on our contact page at <a class="reference external" href="mailto:legal&
</div>
+ <div class="clearer"></div>
</div>
</div>
</div>
diff --git a/contrib/tos/en/0.pdf b/contrib/tos/en/0.pdf
index ce3f013c..89d39493 100644
--- a/contrib/tos/en/0.pdf
+++ b/contrib/tos/en/0.pdf
Binary files differ
diff --git a/contrib/tos/en/0.txt b/contrib/tos/en/0.txt
index ce0893fa..c124d70e 100644
--- a/contrib/tos/en/0.txt
+++ b/contrib/tos/en/0.txt
@@ -103,6 +103,16 @@ lead to incorrect 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
====
@@ -123,18 +133,14 @@ 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
@@ -160,20 +166,6 @@ 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
==================================================
@@ -207,10 +199,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
@@ -246,10 +234,6 @@ possibility of such 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
@@ -268,8 +252,8 @@ 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
@@ -281,36 +265,16 @@ feedback or submissions you provide to us concerning the Taler Wallet;
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,
@@ -323,27 +287,6 @@ 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
@@ -356,15 +299,28 @@ 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
diff --git a/contrib/tos/en/0.xml b/contrib/tos/en/0.xml
index 75974dc4..ee93a4cc 100644
--- a/contrib/tos/en/0.xml
+++ b/contrib/tos/en/0.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
-<!-- Generated by Docutils 0.14 -->
-<document source="/home/grothoff/research/taler/exchange/contrib/tos/tos.rst">
+<!-- Generated by Docutils 0.16 -->
+<document source="/research/taler/exchange/contrib/tos/tos.rst">
<section ids="terms-of-service" names="terms\ of\ service">
<title>Terms Of Service</title>
<paragraph>Last Updated: 12.4.2019</paragraph>
@@ -96,6 +96,14 @@
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.</paragraph>
+ <paragraph>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
+ <reference refuri="mailto:security@taler-systems.com">security@taler-systems.com</reference> 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.</paragraph>
</section>
<section ids="fees" names="fees">
<title>Fees</title>
@@ -113,15 +121,12 @@
the form of discount for our Services or in any other form at our discretion
and without prior notice to you.</paragraph>
</section>
- <section ids="eligibility" names="eligibility">
- <title>Eligibility</title>
+ <section ids="eligibility-and-financial-self-responsibility" names="eligibility\ and\ financial\ self-responsibility">
+ <title>Eligibility and Financial self-responsibility</title>
<paragraph>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.</paragraph>
- </section>
- <section ids="financial-self-responsibility" names="financial\ self-responsibility">
- <title>Financial self-responsibility</title>
<paragraph>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
@@ -142,17 +147,6 @@
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.</paragraph>
</section>
- <section ids="your-use-of-our-services" names="your\ use\ of\ our\ services">
- <title>Your use of our services</title>
- <paragraph>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
- <reference refuri="mailto:security@taler-systems.com">security@taler-systems.com</reference> 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.</paragraph>
- </section>
<section ids="limitation-of-liability-disclaimer-of-warranties" names="limitation\ of\ liability\ &amp;\ disclaimer\ of\ warranties">
<title>Limitation of liability &amp; disclaimer of warranties</title>
<paragraph>You understand and agree that we have no control over, and no duty to take any
@@ -188,9 +182,6 @@
<paragraph>Any other terms, conditions, warranties, or representations associated with
such content, are solely between you and such organizations and/or
individuals.</paragraph>
- </section>
- <section ids="limitation-of-liability" names="limitation\ of\ liability">
- <title>Limitation of liability</title>
<paragraph>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,
@@ -234,9 +225,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.</paragraph>
- </section>
- <section ids="warranty-disclaimer" names="warranty\ disclaimer">
- <title>Warranty disclaimer</title>
<paragraph>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
@@ -253,8 +241,8 @@
paragraph gives you specific legal rights and you may also have other legal
rights that vary from state to state.</paragraph>
</section>
- <section ids="indemnity" names="indemnity">
- <title>Indemnity</title>
+ <section ids="indemnity-and-time-limitation-on-claims-and-termination" names="indemnity\ and\ time\ limitation\ on\ claims\ and\ termination">
+ <title>Indemnity and Time limitation on claims and Termination</title>
<paragraph>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,
obligations, losses, liabilities, costs or debt, and expenses (including, but
@@ -262,30 +250,14 @@
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.</paragraph>
- </section>
- <section ids="time-limitation-on-claims" names="time\ limitation\ on\ claims">
- <title>Time limitation on claims</title>
<paragraph>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.</paragraph>
- </section>
- <section ids="governing-law" names="governing\ law">
- <title>Governing law</title>
- <paragraph>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.</paragraph>
- </section>
- <section ids="termination" names="termination">
- <title>Termination</title>
<paragraph>In the event of termination concerning your use of our Services, your
obligations under this Agreement will still continue.</paragraph>
</section>
- <section ids="discontinuance-of-services" names="discontinuance\ of\ services">
- <title>Discontinuance of services</title>
+ <section ids="discontinuance-of-services-and-force-majeure" names="discontinuance\ of\ services\ and\ force\ majeure">
+ <title>Discontinuance of services and Force majeure</title>
<paragraph>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,
any portion of our Services. We will use the Taler protocol’s provisions to
@@ -295,22 +267,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.</paragraph>
- </section>
- <section ids="no-waiver" names="no\ waiver">
- <title>No waiver</title>
- <paragraph>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.</paragraph>
- </section>
- <section ids="severability" names="severability">
- <title>Severability</title>
- <paragraph>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.</paragraph>
- </section>
- <section ids="force-majeure" names="force\ majeure">
- <title>Force majeure</title>
<paragraph>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
@@ -321,13 +277,24 @@
other occurrence which is beyond our reasonable control and shall not affect
the validity and enforceability of any remaining provisions.</paragraph>
</section>
- <section ids="assignment" names="assignment">
- <title>Assignment</title>
+ <section ids="governing-law-waivers-severability-and-assignment" names="governing\ law,\ waivers,\ severability\ and\ assignment">
+ <title>Governing law, Waivers, Severability and Assignment</title>
+ <paragraph>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.</paragraph>
+ <paragraph>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.</paragraph>
<paragraph>You agree that we may assign any of our rights and/or transfer, sub-contract,
or delegate any of our obligations under these Terms.</paragraph>
- </section>
- <section ids="entire-agreement" names="entire\ agreement">
- <title>Entire agreement</title>
+ <paragraph>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.</paragraph>
<paragraph>This Agreement sets forth the entire understanding and agreement as to the
subject matter hereof and supersedes any and all prior discussions,
agreements, and understandings of any kind (including, without limitation, any
diff --git a/contrib/tos/locale/de/LC_MESSAGES/tos.po b/contrib/tos/locale/de/LC_MESSAGES/tos.po
index 21aa9c88..e821c9c1 100644
--- a/contrib/tos/locale/de/LC_MESSAGES/tos.po
+++ b/contrib/tos/locale/de/LC_MESSAGES/tos.po
@@ -1,21 +1,20 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) 2014-2020 Taler Systems SA (GPLv3+ or GFDL 1.3+)
# This file is distributed under the same license as the tos package.
-# FIRST AUTHOR <EMAIL@ADDRESS>, 2020.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: tos 0\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2020-02-07 01:00+0100\n"
+"POT-Creation-Date: 2021-09-30 21:42+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=utf-8\n"
+"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: Babel 2.6.0\n"
#: ../../tos.rst:2
msgid "Terms Of Service"
@@ -26,11 +25,7 @@ msgid "Last Updated: 12.4.2019"
msgstr ""
#: ../../tos.rst:6
-msgid ""
-"Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment "
-"service through our Internet presence (collectively the “Services”). "
-"Before using our Services, please read the Terms of Service (the “Terms” "
-"or the “Agreement”) carefully."
+msgid "Welcome! Taler Systems SA (“we,” “our,” or “us”) provides a payment service through our Internet presence (collectively the “Services”). Before using our Services, please read the Terms of Service (the “Terms” or the “Agreement”) carefully."
msgstr ""
#: ../../tos.rst:12
@@ -38,14 +33,7 @@ msgid "Overview"
msgstr ""
#: ../../tos.rst:14
-msgid ""
-"This section provides a brief summary of the highlights of this "
-"Agreement. Please note that when you accept this Agreement, you are "
-"accepting all of the terms and conditions and not just this section. We "
-"and possibly other third parties provide Internet services which interact"
-" with the Taler Wallet’s self-hosted personal payment application. When "
-"using the Taler Wallet to interact with our Services, you are agreeing to"
-" our Terms, so please read carefully."
+msgid "This section provides a brief summary of the highlights of this Agreement. Please note that when you accept this Agreement, you are accepting all of the terms and conditions and not just this section. We and possibly other third parties provide Internet services which interact with the Taler Wallet’s self-hosted personal payment application. When using the Taler Wallet to interact with our Services, you are agreeing to our Terms, so please read carefully."
msgstr ""
#: ../../tos.rst:23
@@ -53,54 +41,27 @@ msgid "Highlights:"
msgstr ""
#: ../../tos.rst:25
-msgid ""
-"You are responsible for keeping the data in your Taler Wallet at all "
-"times under your control. Any losses arising from you not being in "
-"control of your private information are your problem."
+msgid "You are responsible for keeping the data in your Taler Wallet at all times under your control. Any losses arising from you not being in control of your private information are your problem."
msgstr ""
#: ../../tos.rst:28
-msgid ""
-"We will try to transfer funds we hold in escrow for our users to any "
-"legal recipient to the best of our ability within the limitations of the "
-"law and our implementation. However, the Services offered today are "
-"highly experimental and the set of recipients of funds is severely "
-"restricted."
+msgid "We will try to transfer funds we hold in escrow for our users to any legal recipient to the best of our ability within the limitations of the law and our implementation. However, the Services offered today are highly experimental and the set of recipients of funds is severely restricted."
msgstr ""
#: ../../tos.rst:32
-msgid ""
-"For our Services, we may charge transaction fees. The specific fee "
-"structure is provided based on the Taler protocol and should be shown to "
-"you when you withdraw electronic coins using a Taler Wallet. You agree "
-"and understand that the Taler protocol allows for the fee structure to "
-"change."
+msgid "For our Services, we may charge transaction fees. The specific fee structure is provided based on the Taler protocol and should be shown to you when you withdraw electronic coins using a Taler Wallet. You agree and understand that the Taler protocol allows for the fee structure to change."
msgstr ""
#: ../../tos.rst:36
-msgid ""
-"You agree to not intentionally overwhelm our systems with requests and "
-"follow responsible disclosure if you find security issues in our "
-"services."
+msgid "You agree to not intentionally overwhelm our systems with requests and follow responsible disclosure if you find security issues in our services."
msgstr ""
#: ../../tos.rst:38
-msgid ""
-"We cannot be held accountable for our Services not being available due to"
-" circumstances beyond our control. If we modify or terminate our "
-"services, we will try to give you the opportunity to recover your funds. "
-"However, given the experimental state of the Services today, this may not"
-" be possible. You are strongly advised to limit your use of the Service "
-"to small-scale experiments expecting total loss of all funds."
+msgid "We cannot be held accountable for our Services not being available due to circumstances beyond our control. If we modify or terminate our services, we will try to give you the opportunity to recover your funds. However, given the experimental state of the Services today, this may not be possible. You are strongly advised to limit your use of the Service to small-scale experiments expecting total loss of all funds."
msgstr ""
#: ../../tos.rst:45
-msgid ""
-"These terms outline approved uses of our Services. The Services and these"
-" Terms are still at an experimental stage. If you have any questions or "
-"comments related to this Agreement, please send us a message to legal"
-"@taler-systems.com. If you do not agree to this Agreement, you must not "
-"use our Services."
+msgid "These terms outline approved uses of our Services. The Services and these Terms are still at an experimental stage. If you have any questions or comments related to this Agreement, please send us a message to legal@taler-systems.com. If you do not agree to this Agreement, you must not use our Services."
msgstr ""
#: ../../tos.rst:52
@@ -108,19 +69,7 @@ msgid "How you accept this policy"
msgstr ""
#: ../../tos.rst:54
-msgid ""
-"By sending funds to us (to top-up your Taler Wallet), you acknowledge "
-"that you have read, understood, and agreed to these Terms. We reserve the"
-" right to change these Terms at any time. If you disagree with the "
-"change, we may in the future offer you with an easy option to recover "
-"your unspent funds. However, in the current experimental period you "
-"acknowledge that this feature is not yet available, resulting in your "
-"funds being lost unless you accept the new Terms. If you continue to use "
-"our Services other than to recover your unspent funds, your continued use"
-" of our Services following any such change will signify your acceptance "
-"to be bound by the then current Terms. Please check the effective date "
-"above to determine if there have been any changes since you have last "
-"reviewed these Terms."
+msgid "By sending funds to us (to top-up your Taler Wallet), you acknowledge that you have read, understood, and agreed to these Terms. We reserve the right to change these Terms at any time. If you disagree with the change, we may in the future offer you with an easy option to recover your unspent funds. However, in the current experimental period you acknowledge that this feature is not yet available, resulting in your funds being lost unless you accept the new Terms. If you continue to use our Services other than to recover your unspent funds, your continued use of our Services following any such change will signify your acceptance to be bound by the then current Terms. Please check the effective date above to determine if there have been any changes since you have last reviewed these Terms."
msgstr ""
#: ../../tos.rst:67
@@ -128,390 +77,165 @@ msgid "Services"
msgstr ""
#: ../../tos.rst:69
-msgid ""
-"We will try to transfer funds that we hold in escrow for our users to any"
-" legal recipient to the best of our ability and within the limitations of"
-" the law and our implementation. However, the Services offered today are "
-"highly experimental and the set of recipients of funds is severely "
-"restricted. The Taler Wallet can be loaded by exchanging fiat currencies"
-" against electronic coins. We are providing this exchange service. Once "
-"your Taler Wallet is loaded with electronic coins they can be spent for "
-"purchases if the seller is accepting Taler as a means of payment. We are "
-"not guaranteeing that any seller is accepting Taler at all or a "
-"particular seller. The seller or recipient of deposits of electronic "
-"coins must specify the target account, as per the design of the Taler "
-"protocol. They are responsible for following the protocol and specifying "
-"the correct bank account, and are solely liable for any losses that may "
-"arise from specifying the wrong account. We will allow the government to "
-"link wire transfers to the underlying contract hash. It is the "
-"responsibility of recipients to preserve the full contracts and to pay "
-"whatever taxes and charges may be applicable. Technical issues may lead "
-"to situations where we are unable to make transfers at all or lead to "
-"incorrect 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."
-msgstr ""
-
-#: ../../tos.rst:91
-msgid "Fees"
+msgid "We will try to transfer funds that we hold in escrow for our users to any legal recipient to the best of our ability and within the limitations of the law and our implementation. However, the Services offered today are highly experimental and the set of recipients of funds is severely restricted. The Taler Wallet can be loaded by exchanging fiat currencies against electronic coins. We are providing this exchange service. Once your Taler Wallet is loaded with electronic coins they can be spent for purchases if the seller is accepting Taler as a means of payment. We are not guaranteeing that any seller is accepting Taler at all or a particular seller. The seller or recipient of deposits of electronic coins must specify the target account, as per the design of the Taler protocol. They are responsible for following the protocol and specifying the correct bank account, and are solely liable for any losses that may arise from specifying the wrong account. We will allow the government to link wire transfers to the underlying contract hash. It is the responsibility of recipients to preserve the full contracts and to pay whatever taxes and charges may be applicable. Technical issues may lead to situations where we are unable to make transfers at all or lead to incorrect 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."
msgstr ""
-#: ../../tos.rst:93
-msgid ""
-"You agree to pay the fees for exchanges and withdrawals completed via the"
-" Taler Wallet (\"Fees\") as defined by us, which we may change from time "
-"to time. With the exception of wire transfer fees, Taler transaction fees"
-" are set for any electronic coin at the time of withdrawal and fixed "
-"throughout the validity period of the respective electronic coin. Your "
-"wallet should obtain and display applicable fees when withdrawing funds. "
-"Fees for coins obtained as change may differ from the fees applicable to "
-"the original coin. Wire transfer fees that are independent from "
-"electronic coins may change annually. You authorize us to charge or "
-"deduct applicable fees owed in connection with deposits, exchanges and "
-"withdrawals following the rules of the Taler protocol. 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."
-msgstr ""
-
-#: ../../tos.rst:108
-msgid "Eligibility"
-msgstr ""
-
-#: ../../tos.rst:110
-msgid ""
-"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."
+#: ../../tos.rst:90
+msgid "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."
+msgstr ""
+
+#: ../../tos.rst:101
+msgid "Fees"
msgstr ""
-#: ../../tos.rst:116
-msgid "Financial self-responsibility"
+#: ../../tos.rst:103
+msgid "You agree to pay the fees for exchanges and withdrawals completed via the Taler Wallet (\"Fees\") as defined by us, which we may change from time to time. With the exception of wire transfer fees, Taler transaction fees are set for any electronic coin at the time of withdrawal and fixed throughout the validity period of the respective electronic coin. Your wallet should obtain and display applicable fees when withdrawing funds. Fees for coins obtained as change may differ from the fees applicable to the original coin. Wire transfer fees that are independent from electronic coins may change annually. You authorize us to charge or deduct applicable fees owed in connection with deposits, exchanges and withdrawals following the rules of the Taler protocol. 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."
msgstr ""
#: ../../tos.rst:118
-msgid ""
-"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 by the software to minimize the chances to losse access to or "
-"control over your Wallet data. We will not be liable for any loss or "
-"damage arising from your failure to comply with this paragraph."
+msgid "Eligibility and Financial self-responsibility"
msgstr ""
-#: ../../tos.rst:126
-msgid "Copyrights and trademarks"
+#: ../../tos.rst:120
+msgid "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."
msgstr ""
-#: ../../tos.rst:128
-msgid ""
-"The Taler Wallet is released under the terms of the GNU General Public "
-"License (GNU GPL). You have the right to access, use, and share the Taler"
-" Wallet, in modified or unmodified form. However, the GPL is a strong "
-"copyleft license, which means that any derivative works must be "
-"distributed under the same license terms as the original software. If you"
-" have any questions, you should review the GNU GPL’s full terms and "
-"conditions at https://www.gnu.org/licenses/gpl-3.0.en.html. “Taler” "
-"itself is a trademark 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."
+#: ../../tos.rst:125
+msgid "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 by the software to minimize the chances to losse access to or control over your Wallet data. We will not be liable for any loss or damage arising from your failure to comply with this paragraph."
msgstr ""
-#: ../../tos.rst:140
-msgid "Your use of our services"
+#: ../../tos.rst:133
+msgid "Copyrights and trademarks"
msgstr ""
-#: ../../tos.rst:142
-msgid ""
-"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."
+#: ../../tos.rst:135
+msgid "The Taler Wallet is released under the terms of the GNU General Public License (GNU GPL). You have the right to access, use, and share the Taler Wallet, in modified or unmodified form. However, the GPL is a strong copyleft license, which means that any derivative works must be distributed under the same license terms as the original software. If you have any questions, you should review the GNU GPL’s full terms and conditions at https://www.gnu.org/licenses/gpl-3.0.en.html. “Taler” itself is a trademark 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."
msgstr ""
-#: ../../tos.rst:152
+#: ../../tos.rst:148
msgid "Limitation of liability & disclaimer of warranties"
msgstr ""
-#: ../../tos.rst:154
-msgid ""
-"You understand and agree that we have no control over, and no duty to "
-"take any action regarding: Failures, disruptions, errors, or delays in "
-"processing that you may experience while using our Services; The risk of "
-"failure of hardware, software, and Internet connections; The risk of "
-"malicious software being introduced or found in the software underlying "
-"the Taler Wallet; The risk that third parties may obtain unauthorized "
-"access to information stored within your Taler Wallet, including, but not"
-" limited to your Taler Wallet coins or backup encryption keys. You "
-"release us from all liability related to any losses, damages, or claims "
-"arising from:"
+#: ../../tos.rst:150
+msgid "You understand and agree that we have no control over, and no duty to take any action regarding: Failures, disruptions, errors, or delays in processing that you may experience while using our Services; The risk of failure of hardware, software, and Internet connections; The risk of malicious software being introduced or found in the software underlying the Taler Wallet; The risk that third parties may obtain unauthorized access to information stored within your Taler Wallet, including, but not limited to your Taler Wallet coins or backup encryption keys. You release us from all liability related to any losses, damages, or claims arising from:"
msgstr ""
-#: ../../tos.rst:164
-msgid ""
-"user error such as forgotten passwords, incorrectly constructed "
-"transactions;"
+#: ../../tos.rst:160
+msgid "user error such as forgotten passwords, incorrectly constructed transactions;"
msgstr ""
-#: ../../tos.rst:166
+#: ../../tos.rst:162
msgid "server failure or data loss;"
msgstr ""
-#: ../../tos.rst:167
+#: ../../tos.rst:163
msgid "unauthorized access to the Taler Wallet application;"
msgstr ""
-#: ../../tos.rst:168
+#: ../../tos.rst:164
msgid "bugs or other errors in the Taler Wallet software; and"
msgstr ""
-#: ../../tos.rst:169
-msgid ""
-"any unauthorized third party activities, including, but not limited to, "
-"the use of viruses, phishing, brute forcing, or other means of attack "
-"against the Taler Wallet. We make no representations concerning any Third"
-" Party Content contained in or accessed through our Services."
+#: ../../tos.rst:165
+msgid "any unauthorized third party activities, including, but not limited to, the use of viruses, phishing, brute forcing, or other means of attack against the Taler Wallet. We make no representations concerning any Third Party Content contained in or accessed through our Services."
msgstr ""
-#: ../../tos.rst:174
-msgid ""
-"Any other terms, conditions, warranties, or representations associated "
-"with such content, are solely between you and such organizations and/or "
-"individuals."
+#: ../../tos.rst:170
+msgid "Any other terms, conditions, warranties, or representations associated with such content, are solely between you and such organizations and/or individuals."
msgstr ""
-#: ../../tos.rst:179
-msgid "Limitation of liability"
+#: ../../tos.rst:174
+msgid "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, acting, or purporting to act on our behalf (collectively the “Taler Parties”) be liable to you under contract, tort, strict liability, negligence, or any other legal or equitable theory, for:"
msgstr ""
#: ../../tos.rst:181
-msgid ""
-"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, acting, or purporting to act on our behalf (collectively the "
-"“Taler Parties”) be liable to you under contract, tort, strict liability,"
-" negligence, or any other legal or equitable theory, for:"
+msgid "any lost profits, data loss, cost of procurement of substitute goods or services, or direct, indirect, incidental, special, punitive, compensatory, or consequential damages of any kind whatsoever resulting from:"
msgstr ""
-#: ../../tos.rst:188
-msgid ""
-"any lost profits, data loss, cost of procurement of substitute goods or "
-"services, or direct, indirect, incidental, special, punitive, "
-"compensatory, or consequential damages of any kind whatsoever resulting "
-"from:"
-msgstr ""
-
-#: ../../tos.rst:192
+#: ../../tos.rst:185
msgid "your use of, or conduct in connection with, our services;"
msgstr ""
-#: ../../tos.rst:193
-msgid ""
-"any unauthorized use of your wallet and/or private key due to your "
-"failure to maintain the confidentiality of your wallet;"
+#: ../../tos.rst:186
+msgid "any unauthorized use of your wallet and/or private key due to your failure to maintain the confidentiality of your wallet;"
msgstr ""
-#: ../../tos.rst:195
+#: ../../tos.rst:188
msgid "any interruption or cessation of transmission to or from the services; or"
msgstr ""
-#: ../../tos.rst:196
-msgid ""
-"any bugs, viruses, trojan horses, or the like that are found in the Taler"
-" Wallet software or that may be transmitted to or through our services by"
-" any third party (regardless of the source of origination), or"
+#: ../../tos.rst:189
+msgid "any bugs, viruses, trojan horses, or the like that are found in the Taler Wallet software or that may be transmitted to or through our services by any third party (regardless of the source of origination), or"
msgstr ""
-#: ../../tos.rst:200
+#: ../../tos.rst:193
msgid "any direct damages."
msgstr ""
-#: ../../tos.rst:202
-msgid ""
-"These limitations apply regardless of legal theory, whether based on "
-"tort, strict liability, breach of contract, breach of warranty, or any "
-"other legal theory, and whether or not we were advised of the possibility"
-" of such 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."
-msgstr ""
-
-#: ../../tos.rst:210
-msgid "Warranty disclaimer"
+#: ../../tos.rst:195
+msgid "These limitations apply regardless of legal theory, whether based on tort, strict liability, breach of contract, breach of warranty, or any other legal theory, and whether or not we were advised of the possibility of such 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."
msgstr ""
-#: ../../tos.rst:212
-msgid ""
-"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 "
-"software or any content on the services, whether provided or owned by us "
-"or by any third party, including without limitation, warranties of "
-"merchantability, fitness for a particular purpose, title, non-"
-"infringement, freedom from computer virus, and any implied warranties "
-"arising from course of dealing, course of performance, or usage in trade,"
-" all of which are expressly disclaimed. In addition, we do not represent "
-"or warrant that the content accessible via the services is accurate, "
-"complete, available, current, free of viruses or other harmful "
-"components, or that the results of using the services will meet your "
-"requirements. Some states do not allow the disclaimer of 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."
+#: ../../tos.rst:202
+msgid "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 software or any content on the services, whether provided or owned by us or by any third party, including without limitation, warranties of merchantability, fitness for a particular purpose, title, non-infringement, freedom from computer virus, and any implied warranties arising from course of dealing, course of performance, or usage in trade, all of which are expressly disclaimed. In addition, we do not represent or warrant that the content accessible via the services is accurate, complete, available, current, free of viruses or other harmful components, or that the results of using the services will meet your requirements. Some states do not allow the disclaimer of 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."
msgstr ""
-#: ../../tos.rst:229
-msgid "Indemnity"
+#: ../../tos.rst:219
+msgid "Indemnity and Time limitation on claims and Termination"
msgstr ""
-#: ../../tos.rst:231
-msgid ""
-"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, obligations, losses, liabilities, costs or debt, and"
-" expenses (including, but not limited to, attorney’s fees) arising from: "
-"(a) your use of and access to 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."
+#: ../../tos.rst:221
+msgid "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, obligations, losses, liabilities, costs or debt, and expenses (including, but not limited to, attorney’s fees) arising from: (a) your use of and access to 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."
msgstr ""
-#: ../../tos.rst:240
-msgid "Time limitation on claims"
+#: ../../tos.rst:229
+msgid "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."
msgstr ""
-#: ../../tos.rst:242
-msgid ""
-"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."
+#: ../../tos.rst:233
+msgid "In the event of termination concerning your use of our Services, your obligations under this Agreement will still continue."
msgstr ""
-#: ../../tos.rst:247
-msgid "Governing law"
+#: ../../tos.rst:238
+msgid "Discontinuance of services and Force majeure"
msgstr ""
-#: ../../tos.rst:249
-msgid ""
-"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."
+#: ../../tos.rst:240
+msgid "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, any portion of our Services. We will use the Taler protocol’s provisions to notify Wallets if our Services are to be discontinued. It is your responsibility to ensure that the Taler Wallet is online at least once every three months to observe these notifications. We shall not be held responsible 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."
msgstr ""
-#: ../../tos.rst:258
-msgid "Termination"
+#: ../../tos.rst:250
+msgid "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 delay or failure due to any act of God, act of civil or military authorities, act of terrorism, civil disturbance, war, strike or other labor dispute, fire, interruption in telecommunications or Internet services or network provider 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."
msgstr ""
-#: ../../tos.rst:260
-msgid ""
-"In the event of termination concerning your use of our Services, your "
-"obligations under this Agreement will still continue."
+#: ../../tos.rst:262
+msgid "Governing law, Waivers, Severability and Assignment"
msgstr ""
#: ../../tos.rst:264
-msgid "Discontinuance of services"
+msgid "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."
msgstr ""
-#: ../../tos.rst:266
-msgid ""
-"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, any portion of our Services. We will use the Taler "
-"protocol’s provisions to notify Wallets if our Services are to be "
-"discontinued. It is your responsibility to ensure that the Taler Wallet "
-"is online at least once every three months to observe these "
-"notifications. We shall not be held responsible 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."
+#: ../../tos.rst:272
+msgid "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."
msgstr ""
#: ../../tos.rst:277
-msgid "No waiver"
+msgid "You agree that we may assign any of our rights and/or transfer, sub-contract, or delegate any of our obligations under these Terms."
msgstr ""
-#: ../../tos.rst:279
-msgid ""
-"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."
+#: ../../tos.rst:280
+msgid "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."
msgstr ""
-#: ../../tos.rst:285
-msgid "Severability"
+#: ../../tos.rst:284
+msgid "This Agreement sets forth the entire understanding and agreement as to the subject matter hereof and supersedes any and all prior discussions, agreements, and understandings of any kind (including, without limitation, any 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."
msgstr ""
-#: ../../tos.rst:287
-msgid ""
-"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."
-msgstr ""
-
-#: ../../tos.rst:292
-msgid "Force majeure"
-msgstr ""
-
-#: ../../tos.rst:294
-msgid ""
-"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 delay or failure due to any act of God, act of civil or "
-"military authorities, act of terrorism, civil disturbance, war, strike or"
-" other labor dispute, fire, interruption in telecommunications or "
-"Internet services or network provider 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."
-msgstr ""
-
-#: ../../tos.rst:305
-msgid "Assignment"
-msgstr ""
-
-#: ../../tos.rst:307
-msgid ""
-"You agree that we may assign any of our rights and/or transfer, sub-"
-"contract, or delegate any of our obligations under these Terms."
-msgstr ""
-
-#: ../../tos.rst:311
-msgid "Entire agreement"
-msgstr ""
-
-#: ../../tos.rst:313
-msgid ""
-"This Agreement sets forth the entire understanding and agreement as to "
-"the subject matter hereof and supersedes any and all prior discussions, "
-"agreements, and understandings of any kind (including, without "
-"limitation, any 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."
-msgstr ""
-
-#: ../../tos.rst:321
+#: ../../tos.rst:293
msgid "Questions or comments"
msgstr ""
-#: ../../tos.rst:323
-msgid ""
-"We welcome comments, questions, concerns, or suggestions. Please send us "
-"a message on our contact page at legal@taler-systems.com."
+#: ../../tos.rst:295
+msgid "We welcome comments, questions, concerns, or suggestions. Please send us a message on our contact page at legal@taler-systems.com."
msgstr ""
-
-#~ msgid "Indemntiy"
-#~ msgstr ""
-
diff --git a/contrib/tos/tos.rst b/contrib/tos/tos.rst
index 9e500cae..2509b87b 100644
--- a/contrib/tos/tos.rst
+++ b/contrib/tos/tos.rst
@@ -259,7 +259,7 @@ the validity and enforceability of any remaining provisions.
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
diff --git a/debian/.gitignore b/debian/.gitignore
index 46b94f7a..f3ddfd1d 100644
--- a/debian/.gitignore
+++ b/debian/.gitignore
@@ -18,3 +18,6 @@ taler-auditor.postrm.debhelper
taler-auditor.substvars
taler-auditor/
taler-exchange.postrm.debhelper
+*.debhelper
+*.substvars
+taler-exchange-offline
diff --git a/debian/changelog b/debian/changelog
index c6d809bd..8dcaf12d 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
+taler-exchange (0.8.5-3) unstable; urgency=low
+
+ * Updating to latest Git with minor bugfixes and improvements.
+
+ -- Christian Grothoff <grothoff@taler.net> Tue, 12 Oct 2021 13:12:58 +0200
+
+taler-exchange (0.8.5-2) unstable; urgency=low
+
+ * Updating to latest Git with minor bugfixes and improvements.
+
+ -- Christian Grothoff <grothoff@taler.net> Mon, 27 Sep 2021 13:12:58 +0200
+
taler-exchange (0.8.5-1) unstable; urgency=low
* Updating to latest Git with minor bugfixes and improvements.
diff --git a/doc/cbdc-es/cbdc-es.tex b/doc/cbdc-es/cbdc-es.tex
new file mode 100644
index 00000000..8c87c3e0
--- /dev/null
+++ b/doc/cbdc-es/cbdc-es.tex
@@ -0,0 +1,1283 @@
+\documentclass[a4paper,10pt]{article} %tamaño de papel y letra ``base''
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[top=2cm,
+bottom=2cm,
+includefoot,
+left=3cm,
+right=2cm,
+footskip=1cm]{geometry}
+\usepackage{url}
+\IfFileExists{lmodern.sty}{\usepackage{lmodern}}{}
+\usepackage{graphicx}
+\usepackage{mathpazo}
+\usepackage{amsmath}
+\usepackage{mathptmx}
+\usepackage{color}
+\usepackage[utf8]{inputenc}
+\usepackage[T1]{fontenc}
+\usepackage[hidelinks]{hyperref}
+ %\usepackage{natbib,har2nat}
+\usepackage{natbib}
+\usepackage[spanish]{babel}
+\input{eshyphexh.tex}
+ %\renewcommand{\abstractname}{Resumen}
+ %\renewcommand{\refname}{Referencias}
+ % de estas cosas se ocupa \usepackage[spanish]{babel}
+
+
+\title{Cómo Emitir una Moneda Digital del Banco Central}
+\author{David Chaum\footnote{david@chaum.com} \\
+ xx Network \and
+ Christian Grothoff\footnote{christian.grothoff@bfh.ch} \\
+ BFH\footnote{Universidad de Ciencias Aplicadas de Berna}
+ \quad y Proyecto GNU \and
+ Thomas Moser\footnote{thomas.moser@snb.ch}\\
+ Banco Nacional de Suiza}
+\date{Esta versión: octubre 2021 \\
+ Primera versión: mayo 2020}
+
+
+
+\begin{document}
+
+\maketitle
+
+\begin{abstract}
+Con la aparición de Bitcoin y monedas estables propuestas recientemente
+por grandes empresas tecnológicas como Diem (antes Libra), los bancos
+centrales se enfrentan a la creciente competencia de particulares que
+ofrecen su propia alternativa digital al dinero en efectivo. No
+abordamos la cuestión normativa de si un un banco central debería o no
+emitir una moneda digital del banco central (Central Bank Digital
+Currency -- CBDC). Contribuimos en cambio al actual debate de
+investigación mostrando de qué manera un banco central podría hacerlo si
+así lo deseara. Proponemos un sistema basado en tokens sin tecnología de
+libro mayor distribuido, y mostramos que el efectivo electrónico ya
+implementado solo mediante software se puede mejorar para preservar la
+privacidad en las transacciones, cumplir con los requisitos
+reglamentarios de modo convincente y ofrecer un nivel de protección de
+resistencia cuántica contra los riesgos sistémicos que amenazan la
+privacidad. Ni la política monetaria ni la estabilidad financiera se
+verían materialmente afectadas porque una CBDC con este diseño
+replicaría el efectivo físico en lugar de los depósitos bancarios. \\
+JEL: E42, E51, E52, E58, G2
+\\
+Keywords: Monedas digitales, banco central, CBDC, firmas ciegas, monedas
+estables
+\end{abstract}
+
+\vspace{40pt}
+
+\section*{Agradecimientos}
+Agradecemos a Michael Barczay, Roman Baumann, Morten Bech, Nicolas Cuche,
+Florian Dold, Andreas Fuster, Stefan Kügel, Benjamin Müller, Dirk Niepelt,
+Oliver Sigrist, Richard Stallman, Andreas Wehrli, y tres colaboradores
+anónimos por sus comentarios y sugerencias. Las ideas, opiniones,
+investigaciones y conclusiones o recomendaciones expresadas en este
+documento pertenecen estrictamente a los autores. No reflejan
+necesariamente los puntos de vista del Banco Nacional de Suiza (BNS). El
+BNS no asume ninguna responsabilidad por errores u omisiones ni por la
+exactitud de la información contenida en este documento.
+
+Traducción: Javier Sepulveda \& Dora Scilipoti
+
+
+\newpage
+
+%\tableofcontents
+
+\section{Introducción}\label{1.-introducciuxf3n}
+
+Desde la aparición de los ordenadores personales en los años ochenta, y
+especialmente desde que en 1991 la National Science Foundation quitara
+las restricciones al uso de Internet para propósitos comerciales, se ha
+buscado crear dinero digital para realizar pagos en línea. La primera
+propuesta la realizó~\citet{Chaum1983}. A pesar de que tales métodos fueron
+implementados, no prosperaron. Fueron en cambio los sistemas con tarjeta
+de crédito los que se convirtieron en el método dominante para pagos en
+línea. La propuesta de~\citet{Nakamoto} para un sistema P2P de dinero
+digital y el posterior lanzamiento exitoso de Bitcoin desataron una
+nueva era de investigación sobre el tema y desarrollo de dinero digital.
+CoinMarketCap enumera más de 5.000 criptomonedas. Recientemente los
+bancos centrales han empezado a considerar, o al menos estudiar, la
+emisión de monedas digitales~\cite[véase][]{AuerBoehme,AuerCornelli,Boar,Kiff,Mancini-Griffoli}.
+
+Actualmente los bancos centrales emiten dos tipos de dinero: (i)
+reservas en forma de cuentas de liquidación en los bancos centrales para
+determinados participantes del mercado financiero y (ii) moneda en forma
+de billetes disponibles para el público. En consecuencia, la
+bibliografía sobre la moneda digital del banco central (CBDC) distingue
+entre (a) venta de CBDC al por mayor, con acceso limitado, y (b) venta
+de CBDC al por menor, accesible al público \cite[véase, p. ej.][]{Bech}.
+Una CBDC al por mayor sería menos disruptiva para el sistema
+actual debido a que los bancos y los participantes seleccionados del
+mercado financiero ya tienen acceso a dinero digital del banco en forma
+de cuentas del banco central, que utilizan para liquidar pagos
+interbancarios. La cuestión aquí es si la tokenización del dinero de un
+banco central y la tecnología de libro mayor distribuido (Distributed
+Ledger Technology - DLT) ofrecen beneficios netos en comparación con los
+sistemas de liquidación bruta en tiempo real (Real-Time Gross
+Settlement - RTGS). Hasta el momento, la conclusión es que no es así, al
+menos cuando se trata de pagos interbancarios nacionales~\cite[véase][]{Chapman}.
+
+Una CBDC al por menor, que sería una nueva forma de dinero del banco
+central a disposición del público, podría ser más disruptiva para el
+sistema actual, dependiendo de su diseño. Cuanto más compita una CBDC de
+este tipo con los depósitos bancarios comerciales, mayor será la amenaza
+para la financiación bancaria, con un posible impacto adverso en el
+crédito bancario y la actividad económica~\cite[véase][]{Agur}. Sin
+embargo, una CBDC al por menor podría también tener
+beneficios~\cite[véase][]{Bordo,Berentsen,Bindseil,Niepelt,Riksbank,BoE}.
+Poner a disposición de
+todos dinero electrónico del banco central sin riesgo de contrapartida
+podría mejorar la estabilidad y la resistencia del sistema de pago al
+por menor. También podría proporcionar una infraestructura de pago
+neutral para promover la competencia, la eficiencia y la innovación. En
+general, es probable que los costos y beneficios de una CBDC al por
+menor difieran de un país a otro. Para conocer la opinión del Banco
+Nacional de Suiza, que no tiene planes de emitir una CBDC al por
+menor~\cite[véase][]{Jordan}.
+
+El presente documento se centra en una CBDC al por menor, pero no abordamos la
+cuestión de si un banco central \emph{debería o no} emitir una moneda
+CBDC. Nos centramos en cambio en el diseño potencial de una
+CBCD. Recientemente ha habido un creciente interés en el diseño de monedas
+CBCD (\cite[véase p. ej.][]{Allen,BoE}). El diseño que proponemos difiere
+significativamente de otras propuestas. Nuestro sistema se basa en la
+tecnología eCash descrita por Chaum~\cite{Chaum1983,Chaum1990},
+mejorándola. En particular, proponemos un sistema para CBCD basado en tokens y
+solo mediante software, sin blockchain para la DLT. La DLT es un diseño
+interesante en ausencia de un actor principal o si las entidades que
+interactúan no concuerdan en nombrar un actor central de confianza. Sin
+embargo, este no es el caso de una CBCD al por menor emitida por un
+\emph{banco central}. Distribuir el libro mayor del banco central con una
+blockchain solo aumenta los costes de transacción, no proporciona beneficios
+tangibles en una implementación por parte de un banco central. Utilizar la DLT
+para emitir dinero digital puede ser útil si no hay un banco central para
+empezar (p. ej. el proyecto Sovereign de las Islas Marshall) o si la
+intención explícita es prescindir de un banco central
+(p. ej. Bitcoin).\footnote{Puede haber buenos casos de uso para la DLT en el
+caso de infraestructura de mercado financiero, tal como los intercambios
+digitales, donde surge la cuestión de como obtener dinero del banco central en
+la DLT a efectos de liquidación. Sin embargo en esas situaciones, los
+beneficios potenciales de la DLT, por ejemplo menos costes o reconciliación
+automática, no surgen de una emisión descentralizada del dinero del banco
+central.}
+
+La CBCD basada en tokens que se propone aquí permite también la
+preservación de una cualidad clave del dinero físico: la privacidad en
+la transacción. Usualmente se argumenta que las protecciones
+criptográficas para la privacidad exigen tantos recursos computacionales
+que su utilización en dispositivos móviles no es factible~\cite[véase][]{Allen}.
+Si bien esto puede ser cierto en el contexto de la DLT,
+donde la rastreabilidad pública de las transacciones es necesaria para
+prevenir el doble gasto~\cite{Narayanan}, no es cierto para el
+protocolo de firma ciega de tipo Chaum con un banco central que se
+propone en el presente documento. Nuestra CBDC, basada en firmas ciegas
+y arquitectura de dos niveles, garantiza una perfecta privacidad de
+resistencia cuántica en las transacciones, al mismo tiempo que
+proporciona protecciones sociales tales como impedir el lavado de dinero
+(Anti-Money Laundering - AML) y financiar la lucha contra el terrorismo
+(Counter Terrorism Financing -- CFT), protecciones que de hecho tienen
+mayor fuerza que con los billetes.
+
+La privacidad en las transacciones es importante por tres razones.
+Primero, porque protege a los usuarios frente al escrutinio y el abuso
+de vigilancia gubernamental. Los programas de vigilancia masiva son
+problemáticos incluso si las personas creen que no tienen nada que
+esconder, simplemente por la posibilidad de error y abuso,
+particularmente si los programas carecen de transparencia e
+imputabilidad~\cite[véase][]{Solove}. Segundo, porque la privacidad en las
+transacciones protege a los usuarios frente a la explotación de datos por parte
+de los proveedores de servicios de pago.
+Tercero, porque protege a los usuarios frente a la contraparte en la
+transacción, descartando la posibilidad de un posterior comportamiento
+oportunista, o frente a riesgos de seguridad debido a fallos o
+negligencia en la protección de los datos del cliente~\cite[véase][]{Kahn2005}.
+
+Este documento está estructurado como sigue: en la sección 2 explicamos
+la diferencia entre el dinero del banco central y otro dinero. En la
+sección 3 analizamos los diseños de CBDC comunes y simplistas, antes
+de proponer nuestro diseño en la sección 4. Luego comentamos
+consideraciones políticas y normativas (5) y trabajos relacionados (6);
+en fin, concluimos (7).
+
+
+\section{¿Qué es el dinero del banco central?}
+ \label{2.-quuxe9-es-el-dinero-del-banco-central}
+
+El dinero es un activo que puede ser usado para comprar bienes y
+servicios. Para ser considerado dinero, este activo debe ser aceptado
+por otras entidades distintas del emisor. Este es el motivo por el que
+los vales, por ejemplo, no se consideran dinero. El dinero genuino tiene
+que ser aceptado \emph{comúnmente} como medio de intercambio. Si bien el
+dinero tiene otras funciones, por ejemplo como unidad de cuenta y
+depósito de valor, la característica que lo distingue es su función como
+medio de intercambio. Normalmente, la unidad de cuenta (p. ej. cómo se
+cotizan los precios y cómo se registran las deudas) coincide con el
+medio de intercambio por razones de conveniencia. La separación puede
+ocurrir, sin embargo, si el valor del medio de intercambio carece de
+estabilidad en relación a los bienes y servicios
+comercializados.\footnote{Esto puede ocurrir espontáneamente en un entorno
+de alta-inflación, p. ej. cuando los precios se fijan en USD pero los pagos
+se realizan en divisa local. Lo mismo es cierto para los pagos en Bitcoin,
+donde los precios usualmente se fijan en USA u otras divisas locales debido a
+la alta volatilidad de Bitcoin. Una separación también puede ocurrir por el
+diseño, p. ej. en la Unidad de Fomento (UF) de Chile o la Special Drawing Right
+(SDR) del fondo monetario internacional (IMF). Sin embargo, también entonces el
+propósito es tener una unidad de cuenta más estable.} El dinero debe también ser
+un depósito de valor para poder actuar como medio de intercambio, porque
+debe preservar su poder de compra desde el momento en que se recibe
+hasta el momento en que se gasta. Sin embargo, varios otros activos
+sirven como depósito de valor, como por ejemplo acciones, bonos, metales
+preciosos e inmuebles. Por tanto, la característica como depósito de
+valor no es distintiva del dinero.
+
+En la economía moderna, el público usa dos tipos diferentes de dinero:
+(a) dinero estatal y (b) dinero privado. El dinero estatal lo emite
+típicamente un banco central, que actúa como agente del Estado. El
+dinero del banco central está disponible para determinadas instituciones
+financieras en forma de depósitos en el banco central (reservas) y para
+el público en forma de moneda (billetes y monedas), también llamado
+``efectivo''. En una economía moderna con dinero fiduciario, tal dinero
+no tiene valor intrínseco. Legalmente es una obligación del banco
+central, aunque no es canjeable.
+
+En la mayoría de los países, el dinero del banco central se define como
+moneda de curso legal, lo cual significa que debe ser aceptado como pago
+de una deuda monetaria, incluyendo impuestos y multas legales. Si bien
+esto garantiza que el dinero del banco central tenga algún valor, el
+estatus de moneda de curso legal es insuficiente para que el dinero del
+banco central mantenga un valor estable. Más bien, es la política
+monetaria de los bancos centrales la que mantiene el valor del dinero.
+Mantener la estabilidad de los precios, es decir, un valor estable del
+dinero en relación con el valor de los bienes y servicios
+comercializados, es una de las principales responsabilidades de los
+bancos centrales.
+
+En una economía moderna, la mayoría de los pagos se hacen con dinero
+privado emitido por bancos comerciales. Tal dinero se compone de
+depósitos a la vista que la gente tiene en los bancos comerciales. A
+estos depósitos bancarios se puede acceder con cheques, tarjetas de
+débito, tarjetas de crédito, u otros medios para transferir dinero. Son
+una obligación del respectivo banco comercial. Una característica
+fundamental de los depósitos bancarios es que los bancos comerciales
+garantizan la convertibilidad, bajo demanda, en dinero del banco central
+a un precio fijo, es decir, a la par. Los depositantes pueden retirar
+sus fondos en efectivo o transferirlos a una tasa fija de 1:1. Los
+bancos comerciales mantienen estable el valor de su dinero vinculándolo
+al dinero del banco central.
+
+No obstante, en un sistema de reserva fraccionado, un banco comercial
+-- incluso siendo solvente -- puede no contar con la liquidez necesaria
+para cumplir su promesa de convertir los depósitos bancarios en dinero
+del banco central (p. ej. en caso de una caída bancaria) de manera tal
+que los clientes no puedan retirar su dinero. Un banco también puede
+llegar a ser insolvente e ir a la bancarrota, y como resultado los
+clientes pueden perder su dinero. Así, los bancos comerciales están
+regulados para mitigar estos riesgos.
+
+Una diferencia significativa entre el dinero de un banco central y el
+dinero emitido privadamente por un banco comercial es, por lo tanto, que
+este último conlleva un riesgo para la contraparte. Un banco central
+puede siempre cumplir con sus obligaciones usando su propio dinero no
+reembolsable. El dinero del banco central es el único activo monetario
+de una economía nacional sin riesgo crediticio o de liquidez. Por lo
+tanto, es el activo que típicamente se prefiere para los pagos en las
+infraestructuras del mercado financiero (véase p. ej. CPMI-IOSCO
+\emph{Principles for Financial Market Infrastructures}, 2012). Otra
+diferencia es que el dinero del banco central afianza el sistema
+monetario nacional al proporcionar una referencia de valor con la que el
+dinero de los bancos comerciales mantiene una convertibilidad a la par.
+
+Aparte de los bancos comerciales, otra entidades privadas ocasionalmente
+intentan emitir dinero, las criptomonedas son solo el intento más
+reciente. Pero a diferencia de los depósitos bancarios, tal dinero no es
+comúnmente aceptado como medio de intercambio. Esto también sucede con
+Bitcoin, la criptomoneda más aceptada. Un impedimento a su utilidad como
+medio de intercambio es la alta volatilidad de su valor. Una respuesta
+reciente a este problema fue la aparición de las llamadas monedas
+estables. Las monedas estables generalmente intentan estabilizar su
+valor en una de las dos maneras siguientes: o bien imitando a los bancos
+centrales (monedas estables algorítmicas) o bien imitando a los bancos
+comerciales o a los medios de inversión (monedas estables con respaldo
+de activos).\footnote{Para más detalles sobre la taxonomía y descripción
+de las monedas estables véase~\citet{Bullmann}.}
+
+Las ``monedas estables algorítmicas'' dependen de algoritmos para
+regular su suministro. En otras palabras, intentan alcanzar la
+estabilidad de su precio con sus propias ``políticas monetarias
+algorítmicas''. Hay ejemplos de tales monedas estables (p. ej. Nubits),
+pero hasta ahora ninguna ha estabilizado su valor por largo tiempo.
+
+Las monedas estables ``respaldadas con activos'' difieren en función del
+tipo de activos que usan y de los derechos legales que adquieren los
+titulares de monedas estables. Los tipos de activos que típicamente se
+usan son: dinero (reservas del banco central, billetes o depósitos en
+bancos comerciales), productos básicos (p. ej. oro), valores y a veces
+otras criptomonedas. Cuán bien tal esquema estabilice el valor de las
+monedas en relación al activo o los activos subyacentes depende de
+manera crucial de los derechos legales que adquieran los titulares de
+las monedas estables. Si una moneda estable es canjeable a un precio
+fijo (p. ej. 1 moneda = 1 USD, o 1 moneda = 1 onza de oro), tal
+estabilidad teóricamente se conseguirá.\footnote{Si también estabilice o
+no el valor de las monedas estables en relación con los bienes y
+servicios negociados depende de la estabilidad del valor del respectivo
+activo en relación con el valor de los bienes y servicios.} Lo que el esquema
+esencialmente hace es replicar a los bancos comerciales garantizando la
+convertibilidad al activo subyacente a la vista. Sin embargo, a
+diferencia de los depósitos bancarios, que típicamente están solo
+parcialmente respaldados por las reservas monetarias del banco central,
+las monedas estables generalmente están respaldadas completamente por
+las reservas del activo subyacente para evitar el riesgo de liquidez,
+principalmente porque carecen de beneficios públicos tales como el
+soporte de seguros de depósito y prestamistas de última instancia, que
+se aplican en cambio a los bancos regulados.
+
+Las monedas estables respaldadas con dinero se llaman también monedas
+estables fiduciarias. Sin embargo, mantener el 100\% de garantía en
+dinero (billetes o depósitos bancarios) no es muy rentable. En
+consecuencia, los proveedores de monedas estables tienen un incentivo
+para economizar su tenencia de activos y trasladarse hacia un sistema de
+reserva fraccionado, tal como lo hicieron los bancos comerciales.\footnote
+{La incertidumbre sobre si un moneda estable está
+totalmente garantizada puede ser una de las razones por las que una
+moneda estable puede negociarse por debajo de la par en el mercado
+secundario~\cite[véase][]{Lyons}. Este fue
+también históricamente el caso con los billetes cuando eran emitidos
+por los bancos comerciales. Tales billetes solían negociarse con
+diversos descuentos en el mercado secundario antes de que la emisión
+de billetes fuera nacionalizada y transferida al monopolio de los
+bancos centrales.} Esto implica que reducen su tenencia de activos de
+bajo rendimiento al mínimo que se considere necesario para satisfacer el
+requisito de convertibilidad. Añadiendo en cambio activos líquidos de
+alto rendimiento tales como bonos del Estado. Esto mejora la
+rentabilidad pero también incrementa el nivel de riesgo.
+
+Sin embargo, incluso si una moneda estable está garantizada al 100\% por
+un depósito en un banco comercial, sigue expuesta a los riesgos de
+crédito y liquidez del banco subyacente. Este riesgo se puede eliminar
+si los depósitos se mantienen en el banco central para que la moneda
+estable esté respaldada por las reservas del banco central. Tales
+monedas estables han sido llamadas ``CBDC sintéticas''~\cite{Adrian}.
+Es importante señalar, sin embargo, que tales
+monedas estables no son dinero del banco central y por lo tanto no son
+CBDC, ya que no constituyen obligaciones del banco central y, por lo
+tanto, siguen expuestas al riesgo de contraparte, es decir, el riesgo de
+que el emisor de la moneda estable se declare en quiebra.
+
+Si una moneda estable no es canjeable a un precio fijo, su estabilidad
+no está garantizada por el activo subyacente. Si la moneda estable a
+pesar de esto representa una participación en la propiedad del activo
+subyacente, el esquema se asemeja a un fondo de inversión fijo o a un
+fondo cotizado en bolsa (Exchange-Traded Fund - ETF), y se aplican los
+correspondientes riesgos. El valor de la moneda dependerá del valor neto
+de los activos del fondo, pero su valor real puede desviarse. Si hay
+participantes autorizados que puedan crear y canjear monedas estables y
+así actuar como arbitristas, como en el caso de los ETF y como estaba
+previsto para Diem~\cite{Libra}, es probable que la
+desviación sea mínima.
+
+En general, las monedas estables tiene una mayor probabilidad de llegar
+a convertirse en dinero que las criptomonedas, especialmente si se
+regulan adecuadamente. Sin embargo, la disponibilidad de CBDC limitaría
+significativamente su utilidad.
+
+\section{Diseños simplistas de CBDC} \label{3.-diseuxf1os-simplistas-de-cbdc}
+
+Como se ha señalado, una CBDC sería una obligación del banco central.
+Dos posibles diseños que se analizan en la literatura son: (a) una CBDC
+basada en cuentas y (b) una CBDC basada en tokens (o basada en valor).
+Estos diseños corresponden a los dos tipos existentes de dinero de un
+banco central y sus correspondientes sistemas de pago (Kahn \& Roberds
+2008): las reservas de un banco central (en un sistema basado en
+cuentas) y billetes (en un sistema basado en tokens). Un pago se produce
+si un activo monetario se transfiere de un pagador a un beneficiario. En
+un sistema basado en cuentas, una transferencia se produce cobrándole a
+la cuenta del pagador y transfiriendo el crédito a la cuenta del
+beneficiario. En un sistema basado en tokens, la transferencia se
+produce transfiriendo el valor en sí o el token, es decir, un objeto que
+representa el activo monetario. El mejor ejemplo de un token es el
+efectivo -- monedas o billetes. Pagar con efectivo significa entregar
+una moneda o un billete. No es necesario registrar la transferencia, la
+posesión del token es suficiente. Por lo tanto, las partes no están
+obligadas a revelar sus identidades en ningún momento durante la
+transacción, ambas pueden permanecer anónimas. De todas maneras, el
+beneficiario tiene que poder verificar la autenticidad del token. Esta
+es la razón por la que los bancos centrales invierten mucho en elementos
+de seguridad para los billetes.
+
+Ha habido sugerencias de que la distinción entre los sistemas basados en
+cuentas y los sistemas basados en tokens no es aplicable a las monedas
+digitales~\cite{Garratt}. Nosotros tenemos una opinión diferente
+porque creemos que hay una diferencia significativa. La distinción
+fundamental es la información contenida en el activo. En un sistema
+basado en cuentas, los activos (las cuentas) se asocian con los
+historiales de las transacciones, que incluyen todas las operaciones de
+crédito y débito de las cuentas. En un sistema basado en tokens, los
+activos (tokens) incluyen información acerca de su valor y de la entidad
+que emitió el token. Por tanto, la única posibilidad de lograr la
+propiedad de privacidad de la transacción como la que se obtiene con el
+dinero efectivo reside en los sistemas basados en tokens.\footnote
+{Si bien el término ``Bitcoin'' sugiere el uso de tokens, Bitcoin es un
+sistema basado en cuentas. La única diferencia entre un sistema
+tradicional basado en cuentas y una blockchain es que las cuentas no
+se guardan en una base de datos central, sino en una base de datos
+descentralizada del tipo ``solo por anexión''.}
+
+\subsection{CBDC basada en cuentas}\label{cbdc-basada-en-cuentas}
+
+La forma más simple de lanzar una CBDC sería permitir que el público
+tenga cuentas de depósito en el banco central. Esto implica que el banco
+central seria responsable de llevar a cabo verificaciones para conocer a
+sus clientes (Know-Your-Customer - KYC) y asegurar el cumplimiento del
+AML y CFT. Esto incluiría no solo realizar el proceso inicial del KYC,
+sino también autentificar a los clientes para las transacciones
+bancarias, gestionar el fraude y lidiar con los falsos positivos y las
+autenticaciones de los falsos negativos. Dada la limitada presencia
+física de bancos centrales en la sociedad, y el hecho de que la
+autenticación del ciudadano es algo que probablemente en la actualidad
+los bancos no estén preparados para hacer a gran escala, cualquier CBDC
+basada en cuentas requeriría que el banco central delegara estas
+verificaciones. Todo el servicio y mantenimiento de tales cuentas podría
+asignarse a proveedores externos~\cite{Bindseil}, o la legislación
+podría obligar a los bancos comerciales a abrir cuentas bancarias en el
+banco central para sus clientes~\cite{Berentsen}.
+
+Tal CBDC basada en cuentas daría potencialmente a un banco central mucha
+información. Una posible preocupación podría ser que esto permitiera a
+los gobiernos realizar fácilmente vigilancia masiva e imponer sanciones
+a los titulares de cuentas individuales. Su naturaleza centralizada hace
+que tales intervenciones sean económicas y fáciles de aplicar contra
+individuos o grupos. Incluso en las democracias, hay muchos ejemplos de
+abusos de vigilancia dirigidos a críticos y opositores políticos. Se
+podría argumentar que los bancos centrales independientes puedan
+salvaguardar tal información del escrutinio del gobierno y el abuso
+político, pero esto solo abriría una nueva vía para la presión política,
+amenazando la independencia del banco central. Además, la base de datos
+central sería un objetivo importante para los atacantes: incluso el
+acceso de solo lectura a partes de la base de datos podría crear riesgos
+significativos para las personas cuyos datos fueran expuestos.
+
+Proveyendo cuentas bancarias al público, un banco central estaría
+también en competición directa con los bancos comerciales. Esta
+competición implicaría dos riesgos. Primero, podría amenazar la base de
+depósitos de los bancos y, en el extremo, desintermediar el sector
+bancario. Esto podría afectar de manera adversa la disponibilidad de
+crédito para el sector privado y, como resultado, la actividad
+económica~\cite{Agur}. La desintermediación de los bancos también podría
+conducir a la centralización del proceso de asignación de crédito dentro
+del banco central, lo que afectaría negativamente la productividad y el
+crecimiento económico. En segundo lugar, permitir que la gente traslade
+sus depósitos al refugio seguro de un banco central podría acelerar las
+caídas bancarias durante crisis financieras.
+
+Existen sin embargo argumentos contrarios. \citet{Brunnermeier} argumentan
+que la transferencia de fondos desde un
+depósito hacia una cuenta de CBDC conduciría a una sustitución automática de
+la financiación de depósitos por la financiación del banco central,
+simplemente haciendo explicita la garantía implícita del banco central como
+prestamista de última instancia. \citet{Berentsen}
+sostienen que la competencia de los bancos centrales podría incluso tener un
+efecto disciplinario sobre los bancos comerciales y, por lo tanto, incrementar
+la estabilidad del sistema financiero, ya que los bancos comerciales tendrían
+que hacer sus modelos de negocio más seguros para evitar las caídas bancarias.
+
+También hay propuestas para mitigar el riesgo de la desintermediación
+que tienen como objetivo limitar o desincentivar el uso de CBDC como
+depósito de valor. Una propuesta es limitar la cantidad de CBDC que se
+puede poseer. Una segunda propuesta es aplicar una tasa de interés
+ajustable a las cuentas de CBDC, de manera que la remuneración esté
+siempre lo bastante por debajo de la remuneración de las cuentas de los
+bancos comerciales (posiblemente incluyendo un rendimiento negativo)
+para hacer que las CBDC resulten menos atractivas como depósitos de
+valor~\cite{Kumhof,Bindseil}. Además, para disuadir las
+caídas bancarias, \citet{Kumhof} sugieren que las CBDC no
+deberían ser emitidas contra depósitos bancarios, sino solo contra
+valores tales como bonos del Estado. En general, una CBDC basada en
+cuentas requeriría un análisis más profundo de estas cuestiones.
+
+
+\subsection{CBDC basada en tokens y dependiente del hardware}
+\label{cbdc-basada-en-tokens-y-dependiente-del-hardware}
+
+Un banco central podría también emitir tokens electrónicos en lugar de
+cuentas. Técnicamente esto requiere de un sistema para asegurar que los tokens
+electrónicos no se puedan copiar fácilmente. Las funciones físicamente
+imposibles de clonar~\cite[véase][]{Katzenbeisser} y las zonas seguras en
+el hardware~\cite[véase][]{Alves,Pinto} son dos tecnologías potenciales para
+la prevención de la copia digital. Las funciones físicas imposibles de clonar,
+sin embargo, no se pueden intercambiar a través de Internet (eliminando así el
+uso principal de las CBDC), y anteriores funciones de seguridad en el hardware
+para la prevención de copias se han visto comprometidas
+repetidamente~\cite[véase p. ej.][]{Wojtczuk,Johnston,Lapid}.
+
+Una ventaja fundamental de las CBDC basadas en tokens sobre las basadas
+en cuentas del banco central es que los sistemas basados en tokens
+funcionarían sin conexión, es decir, los usuarios podrían intercambiar
+tokens (peer-to-peer) sin involucrar al banco central, lo que protegería
+la privacidad y la libertad de las personas. Sin embargo, la
+desintermediación que se produce cuando los usuarios pueden intercambiar
+tokens electrónicos sin los bancos como intermediarios que realizan los
+controles KYC, AML y CFT dificultarían la limitación de los abusos por
+parte de delincuentes.
+
+Las tarjetas SIM son actualmente las candidatas más extensivamente
+disponibles para un sistema de pago seguro basado en hardware, pero
+estas también conllevan riesgos. La experiencia~\cite[véase p. ej.][]{Soukup,Garcia,Kasper,CCC} sugiere
+que cualquier dispositivo económicamente producible que almacene tokens
+con un valor monetario en posesión de una persona, y que permita
+transacciones sin conexión -- y por tanto el robo de la información que
+contiene -- será el objetivo de ataques de falsificación exitosos tan
+pronto como el valor económico del ataque fuera los suficientemente
+elevado. Tales ataques incluyen usuarios que atacan su propio
+hardware~\cite[véase también]{Allen}. Los sistemas de pago con tarjeta que
+se han desplegado previamente dependen de la resistencia a la
+manipulación en combinación con la detección del fraude para limitar el
+impacto de una situación de peligro. Sin embargo, la detección del
+fraude requiere la habilidad de identificar a los pagadores y seguir la
+pista de los clientes, lo cual no es compatible con la privacidad de la
+transacción.
+
+\section{Diseño de CBDC basado en tokens para salvaguardar la
+privacidad}
+\label{4.-diseuxf1o-de-cbdc-basado-en-tokens-para-salvaguardar-la-privacidad}
+
+La CBDC que se propone aquí es de tipo ``solo software'', simplemente una
+aplicación para teléfonos inteligentes que no requiere ningún hardware
+adicional por parte de los usuarios. La CBDC se basa en eCash y GNU
+Taler. Taler es parte del Proyecto GNU, cuyo fundador, Richard Stallman, acuñó
+el término \emph{Software Libre}, actualmente denominado \emph{Software Libre
+y de Código Abierto} (Free/Libre Open Source Software -- FLOSS).\footnote{Para
+más información sobre GNU, véase \url{https://www.gnu.org} y
+\citet{Stallman}. GNU Taler se publica gratuitamente bajo la Licencia Pública
+General Affero del Proyecto GNU. Otros programas del Proyecto GNU populares
+entre los economistas son «R» y ``GNU Regression, Econometrics and Time-series
+Library'' (GRETL). Un análisis de los beneficios del FLOSS en comparación con
+el software privativo en el campo de la investigación puede consultarse
+en~\citet{Baiocchi}, \citet{Yalta2008} y \citet{Yalta2010}. Sobre el
+licenciamiento de código abierto véase \citet{Lerner}.} Un programa se
+considera ``Software Libre'' si la licencia otorga a los usuarios cuatro
+libertades esenciales: la libertad de ejecutar el programa como deseen, la
+libertad de estudiar el programa y modificarlo, la libertad de redistribuir
+copias del programa y la libertad de distribuir copias de las versiones
+modificadas del programa. El software libre no tiene por qué ser no
+comercial: proporcionar soporte técnico para software es un modelo de negocio
+estándar para el FLOSS.
+
+Dado el gran número de partes interesadas involucradas en una CBDC al
+por menor (el banco central, el sector financiero, comerciantes y
+clientes) y la importancia crítica de la infraestructura, una CBDC al
+por menor debe basarse en el FLOSS. Imponer una solución propietaria que
+requiera la dependencia de un proveedor en particular sería
+probablemente un obstáculo para la adopción desde el principio. Con el
+FLOSS, todas las partes interesadas tienen acceso a cada detalle de la
+solución y el derecho de adaptar el software a sus necesidades. Esto
+conduce a una integración más fácil y una mejor interoperabilidad y
+competencia entre proveedores.\footnote{Sin embargo, puede haber otros
+roles para hardware privado. Por ejemplo, proteger los depósitos de
+claves y ciertas funciones de auditoría, en la medida en que tal
+seguridad pueda demostrarse solo como aditiva, puede ser un área donde
+el hardware dedicado evaluado por solo un número limitado de expertos
+podría tener ventajas.} Además, permite que el banco central cumpla
+con los requisitos de transparencia y responsabilidad. Los beneficios
+del FLOSS para la seguridad son también ampliamente reconocidos. La
+disponibilidad del código fuente y el derecho a modificarlo facilitan la
+detección de fallos y su rápida solución.\footnote{Por ejemplo, un
+boletín de seguridad cibernética emitido por la Agencia de Seguridad
+Nacional de EE. UU. en abril de 2020 insta a los usuarios a priorizar
+el software de código abierto en la selección y el uso de servicios de
+colaboración para la comunicación por Internet: ``El desarrollo de
+código abierto puede proporcionar confiabilidad de que el código está
+escrito para asegurar las mejores prácticas de programación y no es
+probable que introduzca vulnerabilidades o debilidades que puedan
+poner en riesgo a los usuarios y los datos '' (U/OO/134598-20).}
+
+En esta nuestra arquitectura que proponemos todas las interacciones del
+consumidor y el comerciante son con bancos comerciales. Sin embargo, la
+creación de dinero y la base de datos las proporcionan exclusivamente el
+banco central. Los bancos comerciales autentican a los clientes cuando
+retiran CBDC y a los comerciantes/beneficiarios cuando reciben CBDC,
+pero cuando gastan CBDC, los clientes/pagadores solo tienen que
+autorizar sus transacciones y no necesitan identificarse. Esto hace que
+los pagos resulten más baratos, fáciles y rápidos, y evita una fácil
+interferencia con la privacidad~\cite{Dold}. Además, autenticar a los
+clientes cuando retiran CBDC y a los comerciantes/beneficiarios cuando
+reciben CBDC garantiza el cumplimiento del KYC, AML y CFT.
+
+La CBDC que se propone en el presente documento es un auténtico
+instrumento digital al portador porque cuando el usuario retira una suma
+de dinero en forma de número, el número es ``cegado'' u ocultado por el
+teléfono inteligente con un cifrado especial. En el sistema real, una
+moneda es un par de claves pública / privada, y la clave privada solo la
+conoce el propietario de la moneda.\footnote{En Bitcoin, que es un
+sistema basado en cuentas, el par de claves es una cuenta, siendo la
+clave pública la ``dirección'' de la cuenta y por tanto un tipo de
+``identidad'', incluso si se trata de un pseudónimo.} La moneda deriva
+su valor financiero de la firma del banco central en la clave pública de
+la moneda. El banco central hace la firma con su clave privada y dispone
+de múltiples pares de claves de denominación para la firma ciega de
+monedas de diferentes valores. Un comerciante puede utilizar la
+correspondiente ``clave pública'' del banco central para verificar la
+firma. Sin embargo, para asegurarse de que la moneda no haya sido
+copiada y ya canjeada por otro beneficiario (es decir, que no se haya
+``gastado dos veces''), el comerciante debe depositar la moneda para que
+el banco central pueda comparar la moneda con un archivo de monedas
+canjeadas. Debido a que ni el banco comercial ni el banco central ven el
+número de la moneda durante el retiro, más tarde, cuando el comerciante
+deposita la moneda, se desconoce qué usuario la retiró. El cegamiento y
+la privacidad resultante son los que hacen de este tipo de CBDC un
+verdadero instrumento digital al portador.
+
+En el análisis que sigue proporcionamos una introducción de alto nivel a
+la tecnología y demostramos cómo se puede integrar con el sistema
+bancario existente para crear una CBDC. \citet{Dold} describe detalles
+adicionales.
+
+\subsection{Componentes fundamentales}\label{componentes-fundamentales}
+
+A continuación describimos los principales componentes del protocolo,
+incluido el trasfondo matemático para una posible instanciación de las
+primitivas criptográficas utilizadas, para ilustrar cómo podría
+funcionar una implementación. Observamos que existen diseños matemáticos
+alternativos y equivalentes para cada componente, y simplemente
+presentamos los diseños seguros más sencillos de los que tenemos
+conocimiento.
+
+\emph{Firmas digitales.} La idea básica de las firmas digitales en un esquema
+de firma con clave pública es que el propietario de una clave privada es el
+único que puede firmar un mensaje, mientras que la clave pública permite a
+cualquiera verificar la validez de la firma.\footnote{La criptografía de clave
+pública fue introducida por~\citet{Diffie}, y la primera implementación de
+firmas digitales fue introducida por~\citet{Rivest}.} El resultado de la
+función de verificación es la declaración binaria ``verdadero'' o ``falso''. Si el
+mensaje está firmado con la clave privada que pertenece a la clave pública de
+verificación, el resultado es verdadero, de lo contrario es falso. En nuestra
+propuesta, el mensaje es una ``moneda'' o ``billete'' con un número de serie, y la
+firma del banco central confirma su validez. Si bien GNU Taler usa por defecto
+firmas EdDSA modernas~\cite[véase][]{Bernstein2012}, presentamos un esquema de
+firma criptográfica simple basado en el bien estudiado sistema criptográfico
+RSA~\cite{Rivest}.\footnote{Para un análisis de la larga historia del
+criptosistema RSA y un estudio de los ataques al criptosistema RSA,
+consulte~\citet{Boneh}.} Sin embargo, en principio se puede utilizar cualquier
+esquema de firma criptográfica (DSA, ECDSA, EdDSA, RSA, etc.).
+
+Para generar las claves RSA, el firmante elige primero dos grandes e
+independientes números primos $p$ y $q$ y calcula $n = \emph{pq}$
+así como la función totient de Euler
+$\phi(n) = (p - 1)(q - 1)$.
+Entonces, cualquier $e$ con $1 < e < \phi(n)$ y
+$\gcd(e, \phi(n)) = 1$ se puede usar para
+definir una clave pública $(e,n)$. La condición de que el
+máximo común divisor (greatest common divisor - $\gcd$) de $e$ y
+$\phi(n)$ tiene que ser 1 (p. ej., que deben ser
+relativamente primos) asegura que la inversa de
+$e \mod \phi(n)$ existe.
+Esta inversa es la
+correspondiente clave privada $d$. Dado $\phi(n)$, la clave
+privada $d$ se puede calcular usando el algoritmo extendido
+Euclídeo de modo que
+$d \cdot e \equiv 1 \mod \phi(n)$.
+
+Dada la clave privada $d$ y la clave pública $(e, n)$, una firma simple RSA
+$s$ sobre un mensaje $m$ es
+$s \equiv m^{d} \mod n$.
+Para verificar la firma, se calcula
+$m' \equiv s^{e} \mod n$.
+Si $m'$ y $m$ coinciden, la firma es válida, lo que prueba que el
+mensaje fue firmado con la clave privada que pertenece a la clave
+publica de verificación (autenticación de mensaje) y que ese mensaje no
+ha sido cambiado en tránsito (integridad de mensaje). En la práctica,
+las firmas se colocan sobre lo hashes de los mensajes en vez de los
+propios mensajes. Las funciones hash calculan el resumen de los
+mensajes, que son identificadores únicos y cortos para los mensajes.
+Firmar un hash corto es mucho más rápido que firmar un mensaje largo, y
+la mayoría de los algoritmos de firma solo funcionan con entradas
+relativamente cortas.\footnote{En el caso del criptosistema RSA el
+límite de la longitud es $\log_{2}n$ bits.}
+
+\emph{Firmas ciegas.} Usamos firmas ciegas, introducidas
+por~\citet{Chaum1983}, para proteger la privacidad de los compradores. Una
+firma ciega se usa para crear una firma criptográfica para un mensaje sin que
+el firmante conozca el contenido del mensaje que se firma. En nuestra
+propuesta, esto evita que los bancos comerciales y el banco central puedan
+rastrear las compras identificando a los compradores. Nuestra propuesta
+funciona en principio con cualquier esquema de firma ciega, pero la mejor
+solución es la variante basada en RSA descrita por~\citet{Chaum1983}.
+
+El cegamiento lo realizan los clientes, quienes ciegan sus monedas antes
+de transmitirlas al banco central para ser firmadas. Los clientes por
+tanto no necesitan confiar al banco central la protección de su
+privacidad. Además, el cegamiento RSA proveería de protección de la
+privacidad incluso contra ataques informáticos cuánticos. El banco
+central, por su parte, establece múltiples denominaciones de pares de
+claves disponibles para realizar la firma ciega de monedas con
+diferentes valores, y publica/provee las correspondientes claves
+públicas $(e, n)$ para estos valores.
+
+Sea $f$ el valor hash de una moneda y por tanto un identificador único
+para esta moneda. El cliente que retira la moneda primero genera una
+factor ciego aleatorio $b$ y calcula
+$f' \equiv fb^{e} \mod n$
+con la clave pública del banco central para ese valor.
+La moneda cegada $f'$ se transmite luego
+al banco central para ser firmada. El banco central firma $f'$ con su
+clave privada $d$ calculando la firma ciega
+$s' \equiv \left(f' \right)^{d} \mod n$ y devuelve
+$s'$ al cliente.
+El cliente puede entonces des-cegar la firma calculando
+$s \equiv s'b^{- 1} \mod n$.
+Esto funciona porque
+$\left( f' \right)^d = f^db^{ed} = f^db$ y, así,
+multiplicar $s'$ con $b^{- 1}$ produce $f^d$, que es una firma RSA
+válida sobre $f$ como antes:
+$s^e \equiv f^{de} \equiv f \mod n$.
+
+En la propuesta original de Chaum, las monedas eran solo tokens. Sin
+embargo, nosotros queremos que los consumidores puedan realizar
+contratos usando firmas digitales. Para lograrlo, cuando una billetera
+digital retira una moneda, primero crea una clave privada aleatoria
+$c$ y calcula la correspondiente clave publica $C$ de esta moneda
+para crear firmas digitales con esquemas de firma criptográfica
+regulares (como DSA, ECDSA, EdDSA y RSA). Entonces, se deriva $f$
+usando una hash criptográfica de la clave pública $C$, que luego es
+firmada en modalidad ciega por el banco central (usando un factor
+aleatorio ciego actualizado para cada moneda). Ahora el cliente puede
+usar $c$ para firmar compras electrónicamente, gastando así la moneda.
+
+Como se ha señalado anteriormente, el banco central establecería pares
+de claves para los diferentes valores de las monedas y publicaría las
+claves públicas que los clientes podrían usar para retirar dinero. Estas
+claves de denominación, y por tanto las monedas, tendrían una fecha de
+vencimiento antes de la cual deberían ser gastadas o intercambiadas por
+nuevas monedas. A los clientes se les daría una cierta cantidad de
+tiempo durante el cual podrían intercambiar sus monedas. Un proceso
+similar existe para los billetes físicos, donde las series de los
+billetes se renuevan regularmente para que los billetes vayan equipados
+con las últimas características de seguridad, excepto que los billetes
+generalmente permanecen en circulación durante décadas en vez de por
+unos pocos meses o años.\footnote{En Suiza, por ejemplo, el Swiss
+National Bank empezó la eliminación paulatina la serie octava de
+billetes en abril de 2016. Estos billetes fueron puestos en
+circulación al final de los 90. A partir del día 1 de enero de 2020,
+sin embargo, todos los billetes que empiezan por la serie sexta
+emitidos en 1976, así como cualquier futura serie, permanecen válidas
+y se pueden cambiar por billetes actuales de forma indefinida.}
+
+Desde un punto de vista técnico, una fecha de vencimiento tiene dos
+ventajas. Primero, mejora la eficiencia del sistema porque el banco
+central puede descartar entradas vencidas y no tiene que almacenar y
+buscar una lista siempre creciente de monedas (gastadas) para detectar
+el doble gasto. Segundo, reduce los riesgos de seguridad porque el banco
+central no tiene que preocuparse sobre ataques contra sus claves
+($d$) de denominación (privadas) vencidas. Además , incluso si una
+clave privada se ve comprometida, el tiempo durante el cual el atacante
+puede usar la clave es limitado. Además cobrar una comisión por el
+cambio permitiría al banco central implementar tasas de interés
+negativas, si se considera necesario. El banco central podría también
+imponer un límite de conversión por cliente en consideración del AML y
+el CFT (límites de ``efectivo'') o por razones de estabilidad
+financiera (para prevenir el acaparamiento o las caídas bancarias), si
+así se deseara.
+
+\emph{Protocolo de intercambio de claves.} GNU Taler utiliza un
+protocolo de intercambio de claves de manera inusual para proporcionar
+un vínculo entre la moneda original y el cambio (también llamado
+``vuelto'') entregado por esa moneda original. Esto asegura que siempre
+se pueda entregar el cambio sin comprometer la transparencia de los
+ingresos o la privacidad del consumidor. El mismo mecanismo se puede
+usar también para realizar devoluciones anónimas a los clientes. El
+protocolo también maneja fallos en la red y en los componentes,
+asegurando que los pagos se hayan realizado definitivamente o se hayan
+cancelado definitivamente y que todas las partes tengan una prueba
+criptográfica del resultado. Esto es aproximadamente equivalente a los
+intercambios atómicos de los protocolos \emph{interledger} o al
+intercambio justo en sistemas tradicionales de efectivo electrónico.
+
+La construcción matemática más común para un protocolo de intercambio de
+claves es la construcción Diffie-Hellman~\cite{Diffie}. Esta
+permite que dos partes puedan derivar una clave secreta compartida. Para
+hacerlo, comparten dos parámetros del dominio $p$ y $g$, que
+pueden ser públicos, donde $p$ es un número primo grande y $g$
+es una raíz primitiva módulo $p$.\footnote{Un entero $g$ es una raíz
+primitiva módulo $p$ si para cada entero $a$ coprimo a $p$ hay
+algún entero $k$ para el cual
+$g^k \equiv a \mod p$.
+En la práctica, $g$ debería ser tal raíz primitiva $p-1$, que se
+llama también generador, para prevenir ataques de subgrupo tales como ataques
+Pohlig-Hellman~\cite[véase][]{Lim}.} Ahora, las dos partes eligen sus claves
+privadas \emph{a} y \emph{b}, que son dos números enteros grandes. Con estas claves
+privadas y los parámetros del dominio, generan sus respectivas claves
+públicas $A \equiv g^{a} \mod p$ y $B \equiv g^{b} \mod p$.
+Cada una de las partes ahora puede usar su propia clave privada y la
+clave pública de la otra parte para calcular la clave secreta compartida
+$k \equiv \left( g^b \right)^{a} \equiv \left( g^{a} \right)^{b} \equiv g^{\text{ab}} \mod p$.
+\footnote{El mismo mecanismo también se podría usar para garantizar que
+las monedas no se transfieran a un tercero durante el retiro. Para
+lograr esto, los consumidores tendrían que salvaguardar una clave de
+identidad a largo plazo. Luego, el proceso de retiro podría usar la
+misma construcción que usa GNU Taler para obtener el cambio, excepto
+que se usaría la clave de identidad a largo plazo de un cliente en
+lugar de la moneda original cuando se retira de la cuenta bancaria del
+cliente. Sin embargo, si el cliente no proteje la clave de identidad a
+largo plazo las garantías de privacidad podrían quedar anuladas con
+consecuente riesgo de robo de todas las monedas restantes. Dado el
+riesgo limitado en las transferencias a terceros al retirar monedas,
+no está claro si esta mitigación sería una buena compensación.}
+
+Para obtener el cambio (también llamado ``vuelto''), el cliente empieza
+con la clave privada de la moneda $c$. gastada parcialmente. Sea $C$ la
+correspondiente clave pública, p. ej.
+$C = g^{c} \mod p$.
+Cuando la moneda se gastó parcialmente, el banco central grabó en su base de
+datos la transacción en la que se incluye a $C$. Para simplificar, daremos
+por sentado que existe una denominación que coincide exactamente con el
+valor residual. De no ser así, se puede simplemente ejecutar
+repetidamente el protocolo de cambio hasta obtener todo el cambio
+necesario. Sea $(e,n)$ la clave de denominación para el
+cambio que se tiene que emitir.
+
+Para obtener el cambio, el cliente primero crea $\kappa$ claves de
+transferencia privada $t_{i}$ para
+$i \in \left\{ 1,\ldots,\kappa \right\}$ y calcula las
+correspondientes claves públicas $T_{i}$. Estas claves de
+transferencia $\kappa$ son simplemente pares de claves pública-privada
+que permiten al cliente ejecutar localmente el protocolo de intercambio
+de claves -- con el cliente jugando en ambos lados -- $\kappa$ veces
+entre $c$ y cada $t_{i}$. Si se usa Diffie-Hellman para el protocolo de
+intercambio de claves, tendremos
+$T_{i} \equiv g^{t_{i}} \mod p$.
+
+El resultado son tres secretos de transferencia
+$K_{i} \equiv \emph{KX}(c,t_{i})$. El protocolo de
+intercambio de claves se puede usar de diferentes maneras para llegar al
+mismo valor
+$K_{i} \equiv \emph{KX}(C,t_{i}) = \emph{KX}(c,T_{i})$.
+Dada $K_{i}$, el cliente usa una función criptográfica hash $H$ para
+derivar valores
+$(b_{i},c_{i}) \equiv H(K_{i})$, donde
+$b_{i}$ es un factor ciego válido para la clave de denominación
+$(e,n)$ y $c_{i}$ es una clave privada para obtener la
+moneda recién creada como cambio. $c_{i}$ debe ser adecuada tanto para
+crear firmas criptográficas como para su futuro uso con el protocolo de
+intercambio de claves (como $c$, para obtener cambio a partir del cambio).
+Sea $C_{i}$ la clave pública correspondiente a $c_{i}$. El cliente
+solicita entonces al banco central que cree una firma ciega sobre
+$C_{i}$ para $i \in \{ 1,\ldots,\kappa\}$.\footnote{Si se usara el
+criptosistema RSA para firmas ciegas, usaríamos
+$f \equiv \emph{FDH}_{n}(C_{i})$, donde
+$\emph{FDH}_{n}()$ es el hash de dominio completo sobre
+el dominio $n$.} En esta petición, el cliente también se compromete a
+las claves públicas $T_{i}$. La petición es autorizada usando una
+firma hecha con la clave privada $c$.
+
+En lugar de devolver directamente la firma ciega, el banco central
+primero desafía al cliente para comprobar que el cliente haya usado
+correctamente la construcción mencionada anteriormente proveyendo
+$\gamma \in \left\{ 1,\ldots,\kappa \right\}$. El cliente debe
+entonces revelar al banco central la $t_{i}$ para $i \neq \gamma$ .
+El banco central puede entonces calcular
+$K_{i} \equiv \emph{KX}(C,t_{i})$ y derivar los valores
+de $(b_{i},c_{i})$. Si para todas las $i \neq \gamma$
+la $t_{i}$ provista demuestra que el cliente usó la construcción
+correctamente, el banco central devuelve la firma ciega sobre
+$C_{\gamma}$. Si el cliente no provee una prueba correcta, se pierde
+el valor residual de la moneda original. Esto penaliza efectivamente a
+quienes intentan evadir la transparencia de sus ingresos con una tasa de
+impuestos estimada de $1 - \frac{1}{\kappa}$.
+
+Para evitar que un cliente conspire con un comerciante que está tratando
+de ocultar sus ingresos, el banco central permite que cualquiera que
+conozca $C$ pueda obtener, en cualquier momento, los valores de
+$T_{\gamma}$ y las correspondientes firmas ciegas de todas las monedas
+vinculadas a la moneda original $C$. Esto permite que el propietario de la
+moneda original -- que conoce $c$ -- calcule
+$K_{\gamma} \equiv \emph{KX}( c,T_{\gamma})$ y, a partir de
+allí, pueda derivar $(b_{i},c_{i})$ y descifrar la firma
+ciega. En consecuencia, un comerciante que oculte sus ingresos de este
+modo formaría básicamente una unión económica limitada con el cliente en
+lugar de obtener un control exclusivo.
+
+\hypertarget{arquitectura-del-sistema}{%
+\subsection{Arquitectura del sistema}\label{arquitectura-del-sistema}}
+
+El objetivo principal de nuestra arquitectura es asegurar que los bancos
+centrales no tengan que interactuar directamente con los clientes o
+guardar ninguna información sobre ellos, sino simplemente mantener una
+lista de las monedas que se gastan. La autenticación se delega a los
+bancos comerciales, que tienen ya la infraestructura necesaria. Los
+protocolos de retiro y depósito llegan al banco central a través del
+banco comercial como intermediario. Desde el punto de vista del cliente,
+el proceso es análogo a retirar dinero efectivo desde un cajero
+automático. La transacción entre el banco comercial del usuario y el
+banco central tiene lugar en segundo plano. El procedimiento para
+retirar CBDC sería como se muestra en la Figura~\ref{fig:fig1}.
+
+\begin{figure}[h!]
+ \includegraphics[width=\textwidth]{retirada.pdf}
+ \caption{Retiro de CBDC}
+ \label{fig:fig1}
+\end{figure}
+
+Un cliente (1) proporciona autenticación a su banco comercial usando la
+autenticación respectiva del banco comercial y los procedimientos de
+autorización. A continuación, el teléfono (u ordenador) del cliente
+obtiene la clave de denominación $(e, n)$ provista por el banco central
+para ese valor; calcula entonces (2) un par de claves para una moneda,
+con la clave privada c y la clave pública $C$, y elige un factor de cegado
+$b$. A la clave pública de la moneda se le aplica una función hash
+($\to$ $f$) y es cegada ($\to$ $f'$). A continuación, (3) el teléfono
+del cliente envía $f'$ junto con una autorización para retirar la
+moneda y debitar de la cuenta del cliente en el banco comercial a través
+de un canal seguro establecido. El banco comercial entonces (4) debita
+la cantidad en la cuenta de depósito del cliente, (5) autoriza
+digitalmente la petición con la propia firma digital de su sucursal
+bancaria y reenvía la petición y la moneda cegada al banco central para
+su firma. El banco central (6) deduce el valor de la moneda en la cuenta
+del banco comercial, firma la moneda de forma ciega con la clave privada
+del banco central para el valor respectivo, y (7) devuelve la firma
+ciega $s'$ al banco comercial. (8) reenvía la firma ciega $s'$
+a la billetera electrónica del cliente. Finalmente, el teléfono del
+cliente (9) usa $b$ para descifrar la firma ($\to$ $f$) y almacena la
+moneda recién acuñada $(c, s)$.
+
+Cuando se gastan CBDC, el proceso es análogo a pagar al vendedor en
+efectivo. Sin embargo, para asegurar el acuerdo, el vendedor debe
+depositar las monedas. El procedimiento para gastar CBDC se indica en la
+Figura~\ref{fig:fig2}.
+
+Un cliente y un vendedor negocian un contrato comercial, y (1) el
+cliente usa una moneda electrónica para firmar el contrato o factura de
+venta con la clave privada $c$ de la moneda y transmite la firma al
+vendedor. La firma de una moneda en un contrato con una moneda válida es
+una instrucción del cliente para pagar al vendedor que es identificado
+por la cuenta bancaria en el contrato. Los clientes pueden firmar
+contratos con múltiples monedas en caso de que una sola moneda fuera
+insuficiente para pagar la cantidad total. El vendedor (2) valida
+entonces la firma de la moneda sobre el contrato y la firma s del banco
+central sobre $f$ que corresponde a la $C$ de la moneda con las
+respectivas claves públicas y reenvía la moneda firmada (junto con la
+información de la cuenta del vendedor) al banco comercial del vendedor.
+El banco comercial del vendedor (3) confirma que el vendedor es uno de
+sus clientes y envía la moneda firmada al banco central. El banco
+central (4) verifica las firmas y comprueba su base de datos para
+asegurar que la moneda no haya sido previamente gastada. Si todo está en
+orden, (5) el banco central añade la moneda a la lista de monedas
+gastadas, acredita la cuenta del banco comercial en el banco central y
+(6) envía la confirmación al banco comercial a tal efecto. A
+continuación, (7) el banco comercial acredita la cuenta del vendedor e
+(8) informa al vendedor. El vendedor (9) entrega el producto o servicio
+al cliente. Todo el proceso dura solo unos pocos milisegundos.
+
+\begin{figure}[h!]
+ \includegraphics[width=\textwidth]{deposito.pdf}
+ \caption{Gastar y depositar CBDC}
+ \label{fig:fig2}
+\end{figure}
+
+\hypertarget{consideraciones-acerca-de-la-seguridad}{%
+\subsection{Consideraciones acerca de la Seguridad}
+\label{consideraciones-acerca-de-la-seguridad}}
+
+Nuestra propuesta requiere que el banco central opere un servicio en
+línea y una base de datos de alta disponibilidad. Debido a que los
+usuarios pueden copiar las monedas electrónicas, solo los controles en
+línea pueden prevenir eficientemente el doble gasto. Si bien existen
+soluciones teóricas para identificar de manera retroactiva a usuarios
+que se dediquen al doble gasto~\cite[véase][]{Chaum1990}, tales
+soluciones crean un riesgo económico tanto para los usuarios como para
+el banco central, debido al retraso en la identificación de
+transacciones fraudulentas. La detección del doble gasto en línea
+elimina este riesgo, pero a su vez implica que las transacciones serán
+imposibles de realizar si la conexión con el banco central no estará
+disponible.
+
+El banco central también tendrá que proteger la confidencialidad de las
+claves privadas que utiliza para firmar las monedas y otros mensajes del
+protocolo. De manera que si las claves de las firmas del banco central
+se vieran en algún momento comprometidas, como por ejemplo por una
+computadora cuántica, un ataque físico en su centro de datos, o quizás
+por algún nuevo algoritmo imprevisto, los usuarios puedan de forma
+segura, y sin comprometer su privacidad, ser reembolsados con todas las
+monedas que no han gastado. El banco central anunciaría la revocación de
+clave mediante la API (Application Programming Interface), que sería
+detectada por las billeteras e iniciarían el siguiente protocolo de
+actualización: el usuario revela al banco central la clave pública
+$C$ de la moneda, la firma $s$ del banco central, y el factor
+ciego $b$, posibilitando así que el banco central verifique el
+retiro legítimo del usuario y devuelva el valor de la moneda no gastada.
+Para detectar un posible compromiso de esta clave, el banco central
+puede monitorear la base de datos en busca de casos de depósitos que
+superen los retiros.
+
+\subsection{Escalabilidad y Costes}\label{escalabilidad-y-costes}
+
+El esquema que proponemos sería tan eficiente y rentable como los
+modernos sistemas RTGS que utilizan actualmente los bancos centrales.
+
+La escalabilidad se refiere al costo de aumentar la capacidad de
+procesamiento para que se pueda procesar un número cada vez mayor de
+transacciones en un tiempo adecuado para la finalidad. El costo global
+del sistema puede ser bajo, ya que la CBDC que se propone aquí se basa
+en software solamente. Las monedas gastadas deben guardarse hasta que
+caduque el par de claves de denominación que se usó para firmar las
+monedas; por ejemplo, mediante un calendario anual renovable, que
+mantiene limitado el tamaño de la base de datos. La cantidad de potencia
+de procesamiento adicional y ancho de banda necesarios aumenta en la
+misma cantidad por cada transacción, gasto o depósito adicional, porque
+las transacciones son esencialmente independientes una de la otra. Esta
+potencia adicional se logra simplemente añadiendo más hardware,
+comúnmente llamado partición o fragmentación. Con el llamado hash
+consistente, las adiciones de hardware no tienen por qué ser
+disruptivas. Se puede utilizar cualquier tecnología de base de datos
+subyacente.
+
+Más concretamente, la lógica del front-end en el banco central solo tiene que
+realizar unas cuantas operaciones de firma, y un único procesador puede hacer
+miles de operaciones por segundo~\cite[véase][]{Bernstein2020}. Si un solo
+sistema es insuficiente, es fácil desplegar servidores front-end adicionales y
+solicitar a los varios bancos comerciales que balanceen sus peticiones en la
+granja de servidores o que utilicen un balanceador de carga para distribuir
+las peticiones dentro de la infraestructura del banco central.
+
+Los servidores front-end deben comunicarse con una base de datos para
+hacer transacciones y prevenir el doble gasto. Un solo servidor moderno
+para la base de datos debería ser suficiente para manejar de manera
+fiable decenas de miles de estas operaciones por segundo. Las
+operaciones se reparten fácilmente entre varios servidores de bases de
+datos simplemente asignando a cada servidor un rango de valores de los
+que es responsable. Este diseño asegura que las transacciones
+individuales nunca crucen fragmentos. Así, se espera que también los
+sistemas de back-end escalen linealmente con los recursos
+computacionales disponibles, de nuevo partiendo de una línea de base
+alta para un solo sistema.
+
+Los front-end también deben comunicarse con los back-end mediante una
+interconexión. Las interconexiones puede soportar grandes cantidades de
+transacciones por segundo. El tamaño de una transacción individual suele
+ser de 1-10 kilobytes aproximadamente. Así, las interconexiones de un
+centro de datos moderno, con velocidades de conmutación de 400 Gbit/s,
+pueden soportar millones de transacciones por segundo.
+
+En fin, el costo total del sistema es bajo. Es probable que el
+almacenamiento seguro de 1 a 10 kilobytes por transacción durante muchos
+años sea el costo predominante del sistema. Utilizando los precios de
+Amazon Web Services, experimentamos con un prototipo anterior de GNU
+Taler y descubrimos que el costo del sistema (almacenamiento, ancho de
+banda y computación) a escala estaría por debajo de USD 0,0001 por
+transacción (para obtener detalles sobre los datos, consulte~\citet{Dold}).
+
+
+\section{Consideraciones normativas y políticas}
+ \label{5.-consideraciones-normativas-y-poluxedticas}
+
+En el esquema propuesto, los bancos centrales no conocen la identidad de
+los consumidores o comerciantes ni los montos totales de las
+transacciones. Los bancos centrales solo ven cuándo se lanzan las
+monedas electrónicas y cuándo se canjean. Los bancos comerciales siguen
+proporcionando autenticación crucial de clientes y comerciantes y, en
+particular, siguen siendo los guardianes de la información del KYC. Los
+bancos comerciales observan cuándo los comerciantes reciben fondos y
+pueden limitar la cantidad de CBDC por transacción que un comerciante
+individual puede recibir, si así se requiere.
+
+Además, las transacciones están asociadas con los contratos pertinentes
+de los clientes. La transparencia de ingresos que se obtiene permite que
+el sistema cumpla con los requisitos del AML y CFT. Si se detectan
+patrones inusuales de ingresos comerciales, el banco comercial, las
+autoridades fiscales o las fuerzas del orden pueden obtener e
+inspeccionar los contratos comerciales subyacentes a los pagos para
+determinar si la actividad sospechosa es ilegal. La transparencia de los
+ingresos que se obtiene es también una fuerte medida contra la evasión
+fiscal porque los comerciantes no pueden declarar menos ingresos o
+evadir los impuestos sobre las ventas. En general, el sistema implementa
+privacidad por diseño y privacidad por omisión (como lo exige, por
+ejemplo, el Reglamento General de Protección de Datos de la Unión
+Europea). Los comerciantes no infieren inherentemente la identidad de
+sus clientes, los bancos solo tienen la información necesaria sobre las
+actividades de sus propios clientes y los bancos centrales están
+felizmente divorciados del conocimiento detallado de las actividades de
+los ciudadanos.
+
+Por razones reglamentarias, en algunos países existen límites para los
+retiros y pagos en efectivo. Dichas restricciones también podrían
+implementarse para la CBDC en el diseño propuesto. Por ejemplo, se
+podría limitar la cantidad que los consumidores puedan retirar por día,
+o limitar la cantidad total de CBDC que los bancos comerciales puedan
+convertir.
+
+Un problema potencial de estabilidad financiera que a menudo se plantea
+con las CBDC al por menor es la desintermediación del sector bancario.
+En particular, la venta de CBDC al por menor podría facilitar el
+acaparamiento de grandes cantidades de dinero del banco central. Esto
+podría afectar negativamente a la financiación de depósitos de los
+bancos porque el público tendría menos dinero en forma de depósitos
+bancarios. Para los países cuyas monedas sirven como monedas de refugio
+seguro, podría conducir a un aumento de las entradas de capital durante
+períodos de riesgo global, lo que resultaría en presiones adicionales en
+la apreciación del tipo de cambio.
+
+Si bien esto podría representar una preocupación seria en el caso de una
+CBDC basada en cuentas, la preocupación sería menor con una CBDC basada
+en tokens. En primer lugar, acumular una CBDC basada en tokens conlleva
+riesgos de robo o pérdida similares a los de acumular efectivo. Tener
+unos cientos de dólares en un teléfono inteligente es probablemente un
+riesgo aceptable para muchos, pero tener una cantidad muy grande es
+probablemente un riesgo menos aceptable. Por tanto, no esperaríamos un
+acaparamiento significativamente mayor que en el caso del efectivo
+físico.
+
+Sin embargo, si el acaparamiento o la conversión masiva a CBDC de dinero
+proveniente de depósitos bancarios se convirtieran en un problema, los bancos
+centrales tendrían varias opciones. Como se señaló, en el diseño propuesto los
+bancos centrales configuran una fecha de vencimiento para todas las claves de
+firma, lo que implica que en una fecha establecida las monedas firmadas con
+esas claves dejan de ser válidas. Cuando las claves de denominación caducan y
+los clientes tienen que cambiar monedas firmadas con claves de denominación
+antiguas por monedas nuevas, el regulador podría fácilmente imponer un límite
+de conversión por cliente para hacer cumplir un límite estricto a la cantidad
+de CBDC que cualquier individuo puede acumular. Además, los bancos centrales
+podrían cobrar una tarifa si fuera necesario. Una tarifa de actualización de
+este tipo, cuando las monedas están programadas para caducar, implicaría de
+hecho tasas de interés negativas en la CBDC, y haría que la CBDC resultara
+menos atractiva como depósito de valor, tal como sugiere Bindseil (2020). De
+hecho, sería la implementación directa de la idea de Silvio Gesell de aplicar
+un ``impuesto de posesión'' sobre la moneda, al que hace célebremente
+referencia~\citet{Keynes}, y reviven~\citet{Goodfriend}, \citet{Buiter}
+y~\citet{Agarwal}.
+
+En cuanto a las posibles implicaciones para las políticas monetarias, no
+anticipamos efectos materiales porque nuestra CBDC está diseñada para
+replicar el dinero en efectivo en lugar de los depósitos bancarios. La
+emisión, retiro y depósito de nuestra CBCD corresponden exactamente a la
+emisión, retiro y depósito de billetes. Es posible que una CBDC al por
+menor tenga un ritmo de circulación diferente a la del efectivo físico,
+pero esto no sería un problema material para las políticas monetarias.
+
+\hypertarget{trabajos-relacionados}{%
+\section{Trabajos relacionados}\label{6.-trabajos-relacionados}}
+
+Como se señaló anteriormente, la CBDC propuesta en el presente documento se
+basa en eCash y GNU Taler.\footnote{La implementación de eCash por la compañía
+DigiCash en los años noventa está documentada en
+\url{https://www.chaum.com/ecash}.} A partir de la propuesta original de Chaum
+para el efectivo electrónico, la investigación se ha centrado en tres
+cuestiones principales. Primero, en la propuesta original de Chaum las monedas
+tenían un valor fijo y solo podían gastarse en su totalidad. Pagar grandes
+cantidades con monedas denominadas en centavos sería ineficiente, por lo
+que~\citet{Okamoto}, \citet{Camenisch2005}, \citet{Canard} y~\citet{Dold}
+idearon formas de abordar este problema. Estas soluciones involucran
+protocolos para dar cambio o para posibilitar la divisibilidad de las monedas.
+
+Una segunda cuestión es que las transacciones a veces fallan debido a
+caídas de la red, por ejemplo. En este caso, el sistema debe permitir
+que los fondos permanezcan con el consumidor sin impacto negativo sobre
+privacidad. \citet{Camenisch2007} y~\citet{Dold} abordan este tema en
+su propuesta de dinero electrónico respaldado. Varias de las soluciones
+anteriores violan las garantías de privacidad para los clientes que
+utilizan estas funciones, y todas, excepto Taler, violan el requisito de
+transparencia de ingresos.
+
+La tercera cuestión importante, a menudo desatendida, es conservar la
+transparencia de los ingresos y, por lo tanto, el cumplimiento del AML y
+KYC. \citet{Fuchsbauer} diseñaron deliberadamente un sistema que
+posibilita la desintermediación para proporcionar una semántica más
+similar al efectivo. Sin embargo, la desintermediación ilimitada
+generalmente no concuerda con las regulaciones del AML y KYC, ya que no
+permite lograr ningún nivel de responsabilidad. Un ejemplo de tal diseño
+es ZCash, un libro mayor distribuido que oculta a la red la información
+sobre el pagador, el beneficiario y el monto de la transacción, siendo
+por lo tanto el sistema de pago perfecto para la delincuencia en línea.
+Solo Taler ofrece tanto la privacidad constante del cliente como la
+transparencia de los ingresos, al mismo tiempo que proporciona un cambio
+eficiente, intercambios atómicos~\cite[consulte][]{Camenisch2007} y la
+capacidad de restaurar billeteras desde una copia de seguridad.
+
+Con respecto a los sistemas de pago para las CBDC, \citet{Danezis} diseñaron
+un libro mayor escalable con RSCoin. Básicamente es un sistema RTGS que es
+protegido utilizando la misma criptografía que se usa en Bitcoin. Al igual que
+Taler, el diseño utiliza la fragmentación de la base de datos para lograr una
+escalabilidad lineal. Sin embargo, el diseño de~\citet{Danezis} no tiene
+ninguna disposición para la privacidad y carece de consideraciones sobre cómo
+integrar prácticamente el diseño con los sistemas y procesos bancarios
+existentes.
+
+La EUROchain del Banco Central Europeo\cite[véase][]{ECB} es otro
+prototipo para CBDC con libro mayor distribuido. Similar a la
+arquitectura propuesta en el presente documento, la EUROchain utiliza
+una arquitectura de dos niveles donde los bancos comerciales actúan como
+intermediarios. Una diferencia crucial es la manera en que los sistemas
+intentan combinar la privacidad y el cumplimiento del AML. En nuestro
+diseño, los reguladores podrían imponer un límite a la cantidad de
+efectivo electrónico que el titular de una cuenta bancaria puede retirar
+durante un cierto tiempo, mientras que la EUROchain emite un número
+limitado de ``vales de anonimato'' que conceden al receptor un número
+limitado de transacciones sin verificación del AML. Como estos vales
+parecen no tener ninguna relación con ningún token de valor, no queda
+claro de qué manera el diseño evitaría la aparición de un mercado negro
+de ``vales de anonimato''. Además, la noción de anonimato de la
+EUROchain es muy diferente, ya que sus ``vales de anonimato'' simplemente
+eliminan ciertas verificaciones del AML, al mismo tiempo que preservan
+la capacidad de los bancos comerciales de ver cómo los consumidores
+gastan el efectivo electrónico. Mientras que los pagadores usuarios de
+Taler interactúan directamente con los comerciantes para gastar su
+efectivo electrónico, el sistema EUROchain requiere que los pagadores
+instruyan a sus bancos comerciales para que accedan a su CBDC. Por lo
+tanto, la EUROchain no emite tokens de valor directamente a los
+consumidores y, en cambio, depende de que los consumidores se
+autentiquen ellos mismos en sus bancos comerciales para acceder a la
+CBDC que el banco central mantiene efectivamente en custodia. Por lo
+tanto, no está claro qué ventajas de privacidad, rendimiento o seguridad
+tiene la EUROchain sobre el dinero existente en depósito.
+
+\section{Conclusión}\label{7.-conclusiuxf3n}
+
+Con la aparición de Bitcoin y monedas digitales recientemente propuestas
+por grandes empresas tecnológicas como Diem (antes Libra), los bancos
+centrales se enfrentan a una competencia cada vez mayor de actores que
+ofrecen su propia alternativa digital al efectivo físico. Las decisiones
+de los bancos centrales sobre la emisión o no de una CBDC dependen de
+cómo evalúen los beneficios y los riesgos de una CBDC. Estos beneficios
+y riesgos, así como las circunstancias jurisdiccionales específicas que
+definen el alcance de las CBDC al por menor, probablemente difieran de
+un país a otro.
+
+Si un banco central decide emitir una CBDC al por menor, proponemos una
+CBDC basada en tokens que combina la privacidad de las transacciones con
+el cumplimiento del KYC, AML y CFT. Dicha CBDC no competiría con los
+depósitos de los bancos comerciales, sino que reproduciría el efectivo
+físico, lo que limitaría los riesgos de estabilidad financiera y
+políticas monetarias.
+
+Hemos demostrado que el esquema propuesto aquí sería tan eficiente y
+rentable como los sistemas RTGS modernos operados por los bancos
+centrales. Los pagos electrónicos con nuestra CBDC solo necesitarían una
+simple base de datos para las transacciones y cantidades minúsculas de
+ancho de banda. La eficiencia y la rentabilidad, junto con la facilidad
+de uso mejorada para el consumidor provocada por el cambio de la
+autenticación a la autorización, hacen que este esquema sea
+probablemente el primero en respaldar el objetivo largamente previsto de
+los micropagos en línea. Además, el uso de monedas para firmar
+criptográficamente contratos electrónicos permitiría el uso de contratos
+inteligentes. Esto también podría conducir a la aparición de
+aplicaciones completamente nuevas para los sistemas de pago. Aunque
+nuestro sistema no se basa en la DLT, podría integrarse fácilmente con
+dichas tecnologías si así lo requirieran las infraestructuras del
+mercado financiero en el futuro.
+
+Igualmente importante, sin embargo, es que una CBDC al por menor debe
+preservar el efectivo como un bien común respetuoso de la privacidad
+bajo el control individual de los ciudadanos. Esto se puede lograr con
+el esquema propuesto en este documento, y los bancos centrales pueden
+evitar perturbaciones significativas en sus políticas monetarias y
+estabilidad financiera cosechando al mismo tiempo los beneficios de la
+digitalización.
+
+
+\newpage
+%REFERENCIAS
+\bibliographystyle{agsm}
+\bibliography{cbdc}
+
+\end{document}
diff --git a/doc/cbdc-es/cbdc.bib b/doc/cbdc-es/cbdc.bib
new file mode 100644
index 00000000..fe0ea626
--- /dev/null
+++ b/doc/cbdc-es/cbdc.bib
@@ -0,0 +1,566 @@
+@article{Adrian,
+ author = {Adrian, Tobias and Tommaso Mancini-Griffoli},
+ year = {2019},
+ title = {The Rise of Digital Money},
+ journal = {IMF Fintech Note},
+ volume = {19/01},
+}
+
+@article{Agarwal,
+ author = {Agarwal, Ruchir and Miles S. Kimball},
+ year = {2019},
+ title = {Enabling Deep Negative Rates to Fight Recessions: A Guide},
+ journal = {IMF Working Paper},
+ volume = {19/84},
+}
+
+
+@article{Agur,
+ author = {Agur, Itai and Anil Ari and Giovanni Dell'Ariccia},
+ year = {2019},
+ title = {Designing Central Bank Digital Currencies},
+ journal = {IMF Working Paper},
+ volume = {19/252},
+}
+
+@article{Allen,
+ author = {Allen, Sarah and Srđjan Čapkun and Ittay Eyal and Giulia Fanti and Bryan A. Ford and James Grimmelmann and Ari Juels and Kari Kostiainen and Sarah Meiklejohn and Andrew Miller and Eswar Prasad and Karl Wüst and Fan Zhang},
+ year = {2020},
+ title = {Design Choices for Central Bank Digital Currency: Policy and Technical Considerations},
+ journal = {NBER Working Paper},
+ volume = {27634},
+}
+
+@article{Alves,
+ author = {Alves, Tiago and Don Felton},
+ year = {2004},
+ title = {TrustZone: Integrated hardware and software security},
+ journal = {ARM IQ},
+ volume = {3},
+ number = {4},
+ pages = {18--24},
+}
+
+@article{AuerBoehme,
+ author = {Auer, Raphael and Rainer Böhme},
+ year = {2020},
+ title = {The technology of retail central bank digital currency},
+ journal = {BIS Quarterly Review},
+ month = {March},
+ pages = {85--96},
+}
+
+@article{AuerCornelli,
+ author = {Auer, Raphael and Giulio Cornelli and Jon Frost},
+ year = {2020},
+ title = {Taking stock: ongoing retail {CBDC} projects},
+ journal = {BIS Quarterly Review},
+ month = {March},
+ pages = {97--98},
+}
+
+@booklet{BIS,
+ author = {{Bank for International Settlements}},
+ year = {2018},
+ title = {Central Bank Digital Currencies. Joint Report of the Committee on Payments and Market Infrastructures and Markets Committee},
+}
+
+@booklet{BoE,
+ author = {{Bank of England}},
+ year = {2020},
+ title = {Central Bank Digital Currency: Opportunities, Challenges and Design. Discussion Paper},
+ month = {March},
+}
+
+@article{Baiocchi,
+ author = {Baiocchi, Giovanni and Walter Distaso},
+ year = {2003},
+ title = {{GRETL}: Econometric Software for the {GNU} Generation},
+ journal = {Journal of Applied Econometrics},
+ volume = {18},
+ pages = {105-110},
+}
+
+@article{Bech,
+ author = {Bech, Morten and Rodney Garratt},
+ year = {2017},
+ title = {Central bank cryptocurrencies},
+ journal = {BIS Quarterly Review},
+ month = {September},
+ pages = {55--70},
+}
+
+@article{Berentsen,
+ author = {Berentsen, Aleksander and Fabian Schär},
+ year = {2018},
+ title = {The Case for Central Bank Electronic Money and the Non-case for Central Bank Cryptocurrencies},
+ journal = {Federal Reserve Bank of St. Louis Review},
+ volume = {100},
+ number = {2},
+ pages = {97--106},
+}
+
+@article{Bernstein2020,
+ author = {Bernstein, Daniel J. and Tanja Lange},
+ year = {2020},
+ title = {{eBACS}: {ECRYPT} Benchmarking of Cryptographic Systems},
+ url = {\url{https://bench.cr.yp.to}, accessed 17 March 2020},
+}
+
+@article{Bernstein2012,
+ author = {Bernstein, Daniel J. and Niels Duif and Tanja Lange and Peter Schwabe and Bo-Yin Yang},
+ year = {2012},
+ title = {High-speed high-security signatures},
+ journal = {Journal of Cryptographic Engineering},
+ volume = {2},
+ pages = {77--89},
+}
+
+@InCollection{Bindseil,
+ author = {Bindseil, Ulrich},
+ year = {2020},
+ title = {Tiered {CBDC} and the financial system},
+ publisher = {European Central Bank},
+ series = {ECB Working Paper},
+ number = {2351},
+ month = {January},
+}
+
+@article{Boar,
+ author = {Boar, Codruta and Henry Holden and Amber Wadsworth},
+ year = {2020},
+ title = {Impending arrival - a sequel to the survey on central bank digital currency},
+ journal = {BIS Papers},
+ volume = {107},
+}
+
+@article{Boneh,
+ author = {Boneh, Dan},
+ year = {1999},
+ title = {Twenty Years of Attacks on the {RSA} Cryptosystem},
+ journal = {Notices of the AMS},
+ volume = {42},
+ number = {2},
+ pages = {202--213},
+}
+
+
+@InCollection{Bordo,
+ author = {Bordo, Michael D. and Andrew T. Levin},
+ year = {2017},
+ title = {Central bank digital currency and the future of monetary policy},
+ publisher = {National Bureau of Economic Research},
+ series = {NBER Working Paper Series},
+ number = {23711},
+}
+
+@article{Brunnermeier,
+ author = {Brunnermeier, Markus and Dirk Niepelt},
+ year = {2019},
+ title = {On the Equivalence of Private and Public Money},
+ journal = {Journal of Monetary Economics},
+ volume = {106},
+ pages = {27--41},
+}
+
+@article{Buiter,
+ author = {Buiter, Willem H. and Nikolaos Panigirtzoglou},
+ year = {2003},
+ title = {Overcoming the Zero Bound on Nominal Interest Rates with Negative Interest on Currency: Gesell's Solution},
+ journal = {The Economic Journal},
+ volume = {113},
+ number = {490},
+ pages = {723--746},
+}
+
+@InCollection{Bullmann,
+ author = {Bullmann, Dirk and Jonas Klemm and Andrea Pinna},
+ year = {2019},
+ title = {In search for stability in crypto-assets: are stablecoins the solution?},
+ publisher = {European Central Bank},
+ series = {ECB Occasional Paper Series},
+ number = {230},
+}
+
+@inproceedings{Camenisch2007,
+ author = {Camenisch, Jan and Aanna Lysyanskaya and Mira Meyerovich},
+ year = {2007},
+ title = {Endorsed E-Cash},
+ booktitle = {2007 IEEE Symposium on Security and Privacy (SP'07)},
+ month = {May},
+ pages = {101--115},
+}
+
+@inproceedings{Camenisch2005,
+ author = {Camenisch, Jan and Susan Hohenberger and Anna Lysyanskaya},
+ year = {2005},
+ title = {Compact E-Cash},
+ booktitle = {Advances in Cryptology -- EUROCRYPT 2005: 24th Annual International Conference on the Theory and Applications of Cryptographic Techniques},
+ address = {Aarhus, Denmark},
+ month = {May},
+ day = {22-26},
+ editor = {Ed. by Ronald Cramer},
+ publisher = {Springer-Verlag Berlin Heidelberg},
+}
+
+
+
+@inproceedings{Canard,
+ author = {Canard, Sébastien and Aline Gouget},
+ year = {2007},
+ title = {Divisible e-cash systems can be truly anonymous},
+ booktitle = {Annual International Conference on the Theory and Applications of Cryptographic Techniques},
+ pages = {482--497},
+}
+
+
+
+@misc{CCC,
+ author = {{CCC e.V.}},
+ year = {2017},
+ title = {Chaos Computer Club hacks e-motor charging stations},
+ howpublished = {34c3},
+}
+
+@article{Chapman,
+ author = {Chapman, James and Rodney Garratt and Scott Hendry and Andrew McCormack and Wade McMahon},
+ year = {2017},
+ title = {Project {J}asper: Are Distributed Wholesale Payment Systems Feasible Yet?},
+ journal = {Financial System Review},
+ publisher = {Bank of Canada},
+ month = {June},
+ pages = {59--69},
+}
+
+@inproceedings{Chaum1983,
+ author = {Chaum, David},
+ year = {1983},
+ title = {Blind signatures for untraceable payments},
+ booktitle = {Advances in Cryptology: Proceedings of Crypto `82},
+ pages = {199--203},
+}
+
+@inproceedings{Chaum1990,
+ author = {Chaum, David and Amos Fiat and Moni Naor},
+ year = {1990},
+ title = {Untraceable electronic cash},
+ booktitle = {Advances in Cryptology: Proceedings of CRYPTO '88},
+ pages = {319--327},
+}
+
+@inproceedings{Danezis,
+ author = {Danezis, George and Sarah Meiklejohn},
+ year = {2016},
+ title = {Centrally Banked Cryptocurrencies},
+ booktitle = {23nd Annual Network and Distributed System Security Symposium, NDSS2016},
+ address = {San Diego, California, USA},
+ month = {February},
+ day = {21--24},
+ publisher = {The Internet Society},
+}
+
+@article{Diffie,
+ author = {Diffie, Whitfield and Martin Hellmann},
+ year = {1976},
+ title = {New Directions in Cryptography},
+ journal = {IEEE Trans. on Inf. Theory, IT-22},
+ pages = {644--654},
+}
+
+@phdthesis{Dold,
+ author = {Dold, Florian},
+ year = {2019},
+ title = {The {GNU} {T}aler System: Practical and Provably Secure Electronic Payments. PhD Thesis},
+ school = {University of Rennes 1},
+}
+
+@article{ECB,
+ author = {{European Central Bank}},
+ year = {2019},
+ title = {Exploring anonymity in central bank digital currencies},
+ journal = {In Focus},
+ number = {4},
+ month = {December},
+}
+
+@inproceedings{Fuchsbauer,
+ author = {Fuchsbauer, Georg and David Pointcheval and Damien Vergnaud},
+ year = {2009},
+ title = {Transferable constant-size fair e-cash},
+ booktitle = {International Conference on Cryptology and Network Security},
+ publisher = {Springer-Verlag Berlin Heidelberg},
+ pages = {226--247},
+}
+
+@inproceedings{Garcia,
+ author = {Garcia, Flavio and Gerhard de Koning Gans and Ruben Muijrers and Peter van Rossum and Roel Verdult and Ronny Wichers Schreur and Bart Jacobs},
+ year = {2008},
+ title = {Dismantling MIFARE Classic},
+ booktitle = {European Symposium on Research in Computer Security},
+}
+
+@article{Garratt,
+ author = {Garratt, Rod and Michael Lee and Brendan Malone and Antoine Martin},
+ year = {2020},
+ title = {Token- or Account-Based? A Digital Currency Can Be Both},
+ journal = {Liberty Street Economics},
+ publisher = {Federal Reserve Bank of New York},
+ month = {August},
+ day = {12},
+}
+
+@article{Goodfriend,
+ author = {Goodfriend, Marvin},
+ year = {2000},
+ title = {Overcoming the Zero Bound on Interest Rate Policy},
+ journal = {Journal of Money, Credit, and Banking},
+ volume = {32},
+ number = {4},
+ pages = {1007--1035},
+}
+
+@article{Johnston,
+ author = {Johnston, Casey},
+ year = {2010},
+ title = {PS3 hacked through poor cryptography implementation},
+ journal = {Ars Technica},
+ month = {December},
+ day = {30},
+}
+
+
+
+@Misc{Jordan,
+ note = {Speech given at the 30th anniversary of the WWZ and VBÖ},
+ author = {Jordan, Thomas J.},
+ year = {2019},
+ title = {Currencies, money and digital tokens},
+ publisher = {University of Basel},
+ month = {September},
+ howpublished = {\url{https://www.snb.ch/en/mmr/speeches/id/ref\_20190905\_tjn/source/ref\_20190905\_tjn.en.pdf}},
+}
+
+
+@article{Kahn2009,
+ author = {Kahn, Charles M. and William Roberds},
+ year = {2009},
+ title = {Why Pay? An Introduction to Payments Economics},
+ journal = {Journal of Financial Intermediation},
+ number = {18},
+ pages = {1--23},
+}
+
+@article{Kahn2005,
+ author = {Kahn, Charles M. and James McAndrews and William Roberds},
+ year = {2005},
+ title = {Money is Privacy},
+ journal = {International Economic Review},
+ volume = {46},
+ number = {2},
+ pages = {377--399},
+}
+
+@article{Kasper,
+ author = {Kasper, Timo and Michael Silbermann and Christof Paar},
+ year = {2010},
+ title = {All you can eat or breaking a real-world contactless payment system},
+ journal = {Financial Cryptography and Data Security, Lecture Notes in Computer Science},
+ volume = {6052},
+ pages = {343--50},
+}
+
+@inproceedings{Katzenbeisser,
+ author = {Katzenbeisser, Stefan and Ünal Kocabaş and Vladimir Rožić and Ahmad-Reza Sadeghi and Ingrid Verbauwhede and Christian Wachsmann},
+ year = {2012},
+ title = {{PUF}s: Myth, Fact or Busted? A Security Evaluation of Physically Unclonable Functions ({PUF}s) Cast in Silicon},
+ booktitle = {Cryptographic Hardware and Embedded Systems -- CHES 2012. Lecture Notes in Computer Science},
+ volume = {7428},
+ pages = {283--301},
+}
+
+@book{Keynes,
+ author = {Keynes, John Maynard},
+ year = {1936},
+ title = {The General Theory of Employment, Interest and Money},
+ publisher = {Macmillan},
+}
+
+@article{Kiff,
+ author = {Kiff, John and Jihad Alwazir and Sonja Davidovic and Aquiles Farias and Ashraf Khan and Tanai Khiaonarong and Majid Malaika and Hunter Monroe and Nobu Sugimoto and Hervé Tourpe and Peter Zhou},
+ year = {2020},
+ title = {A Survey of Research on Retail Central Bank Digital Currency},
+ journal = {IMF Working Paper},
+ volume = {20/104},
+}
+
+@InCollection{Kumhof,
+ author = {Kumhof, Michael and Clare Noone},
+ year = {2018},
+ title = {Central bank digital currencies - design principles and balance sheet implications},
+ publisher = {Bank of England},
+ series = {Staff Working Paper},
+ number = {725},
+}
+
+@inproceedings{Lapid,
+ author = {Lapid, Ben and Avishai Wool},
+ year = {2018},
+ title = {Cache-Attacks on the {ARM} TrustZone Implementations of {AES}-256 and {AES}-256-{GCM} via {GPU}-Based Analysis},
+ booktitle = {International Conference on Selected Areas in Cryptography. Lecture Notes in Computer Science},
+ volume = {11349},
+}
+
+@article{Lerner,
+ author = {Lerner, Josh and Jean Tirole},
+ year = {2005},
+ title = {The Scope of Open Source Licensing},
+ journal = {Journal of Law, Economics \& Organization},
+ volume = {21},
+ pages = {20-56},
+}
+
+@misc{Libra,
+ author = {{Libra Association}},
+ year = {2020},
+ title = {Libra White Paper v2.0},
+ url = {\url{https://libra.org/en-US/white-paper}},
+}
+
+@inproceedings{Lim,
+ author = {Lim, Chae Hoon and Phil Joong Lee},
+ year = {1997},
+ title = {A key recovery attack on discrete log-based schemes using a prime order subgroup},
+ booktitle = {CRYPTO 1997. Lecture Notes in Computer Science},
+ volume = {1294},
+}
+
+@InCollection{Lyons,
+ author = {Lyons, Richard K. and Ganesh Viswanath-Natraj},
+ year = {2020},
+ title = {What Keeps Stablecoins Stable?},
+ publisher = {National Bureau of Economic Research},
+ series = {NBER Working Paper Series},
+ number = {27136},
+ month = {May},
+}
+
+@article{Mancini-Griffoli,
+ author = {Mancini-Griffoli, Tommaso and Maria Soledad Martinez Peria and Itai Agur and Anil Ari and John Kiff and Adina Popescu and Celine Rochon},
+ year = {2018},
+ title = {Casting Light on Central Bank Digital Currency},
+ journal = {IMF Staff Discussion Notes},
+ volume = {18/08},
+ publisher = {International Monetary Fund},
+}
+
+@misc{Nakamoto,
+ author = {Nakamoto, Satoshi},
+ year = {2008},
+ title = {Bitcoin: A Peer-to-Peer Electronic Cash System},
+ url = {\url{https://www.bitcoin.com/bitcoin.pdf}},
+}
+
+@book{Narayanan,
+ author = {Narayanan, Arvind and Joseph Bonneau and Edward Felten and Andrew Miller and Steven Goldfeder},
+ year = {2016},
+ title = {Bitcoin and Cryptocurrency Technologies: A Comprehensive Introduction},
+ publisher = {Princeton University Press},
+}
+
+@misc{Niepelt,
+ author = {Niepelt, Dirk},
+ year = {2020},
+ title = {Digital money and central bank digital currency: An executive summary for policymakers},
+ url = {https://voxeu.org/article/digital-money-and-central-bank-digital-currency-executive-summary},
+}
+
+@inproceedings{Okamoto,
+ author = {Okamoto, Tatsuaki},
+ year = {1995},
+ title = {An Efficient Divisible Electronic Cash Scheme},
+ booktitle = {Advances in Cryptology --- CRYPT0'95: 15th Annual International Cryptology Conference Santa Barbara, California, USA, August 27--31, 1995 Proceedings},
+ editor = {Ed. by Don Coppersmith},
+ publisher = {Springer-Verlag Berlin Heidelberg},
+ pages = {438--451},
+}
+
+@article{Pinto,
+ author = {Pinto, S. and N. Santos},
+ year = {2019},
+ title = {Demystifying {ARM} TrustZone: A Comprehensive Survey},
+ journal = {ACM Computing Surveys},
+ volume = {51},
+ number = {6},
+ month = {January},
+ pages = {1--31}
+}
+
+@article{Rivest,
+ author = {Rivest, Ronald L. and Adi Shamir and Leonard Adleman},
+ year = {1978},
+ title = {A Method for Obtaining Digital Signatures and Public Key Cryptosystems},
+ journal = {Comm. ACM},
+ volume = {21},
+ number = {2},
+}
+
+@book{Solove,
+ author = {Solove, Daniel J.},
+ year = {2011},
+ title = {Nothing to Hide: The false tradeoff between privacy and security},
+ publisher = {New Haven \& London: Yale University Press},
+}
+
+@article{Soukup,
+ author = {Soukup, Michael and Bruno Muff},
+ year = {2007},
+ title = {Die {P}ostcard lässt sich fälschen},
+ journal = {Sonntagszeitung},
+ month = {April},
+ day = {22},
+}
+
+@article{Stallman,
+ author = {Stallman, Richard},
+ year = {1985},
+ title = {The {GNU} manifesto},
+ journal = {Dr. Dobb's Journal of Software Tools},
+ volume = {10},
+ number = {3},
+ pages = {30--35},
+}
+
+
+@TechReport{Riksbank,
+ author = {{Sveriges Riksbank}},
+ year = {2020},
+ title = {The {R}iksbank's e-krona project},
+ month = {Feb},
+ institution = {Sveriges Riksbank},
+ url = {\url{https://www.riksbank.se/globalassets/media/rapporter/e-krona/2019/the-riksbanks-e-krona-pilot.pdf}},
+}
+
+@misc{Wojtczuk,
+ author = {Wojtczuk, Rafal and Joanna Rutkowska},
+ year = {2009},
+ title = {Attacking {I}ntel Trusted Execution Technology},
+ howpublished = {BlackHat-DC 2009},
+}
+
+@article{Yalta2010,
+ author = {Yalta, A. Talha and A. Yasemin Yalta},
+ year = {2010},
+ title = {Should Economists Use Open Source Software for Doing Research?},
+ journal = {Computational Economics},
+ volume = {35},
+ pages = {371--394},
+}
+
+@article{Yalta2008,
+ author = {Yalta, A. Talha and Riccardo Lucchetti},
+ year = {2008},
+ title = {The {GNU/L}inux Platform and Freedom Respecting Software for Economists},
+ journal = {Journal of Applied Econometrics},
+ volume = {23},
+ pages = {279-286},
+}
diff --git a/doc/cbdc-es/deposito.pdf b/doc/cbdc-es/deposito.pdf
new file mode 100644
index 00000000..b798478d
--- /dev/null
+++ b/doc/cbdc-es/deposito.pdf
Binary files differ
diff --git a/doc/cbdc-es/eshyphexh.tex b/doc/cbdc-es/eshyphexh.tex
new file mode 100644
index 00000000..4d4efe02
--- /dev/null
+++ b/doc/cbdc-es/eshyphexh.tex
@@ -0,0 +1,1367 @@
+% Copyright (C) 2019 Javier Bezos, CervanTeX
+% Hyphenation exceptions for Spanish related to the h.
+%
+% Las recientes normas de las Academias de la Lengua establecen la
+% prohibición de partir delante de una hache, salvo cuando se trata de
+% un prefijo productivo. En la practica editorial, dado que la
+% aplicación de este norma puede acarrear dificultades en el ajuste de
+% líneas, se siguen practicando las normas tradicionales, más flexibles.
+% Los nuevos patrones para el español (v. 5.0) se adaptan a lo
+% establecido por las Academias, por lo que se suministra como
+% complemento este archivo de excepciones con los casos más habituales
+% de división ante hache.
+%
+% licence:
+% name: MIT/X11
+% url: https://opensource.org/licenses/MIT
+% text: >
+% Permission is hereby granted, free of charge, to any person obtaining a copy
+% of this software and associated documentation files (the "Software"), to deal
+% in the Software without restriction, including without limitation the rights
+% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+% copies of the Software, and to permit persons to whom the Software is
+% furnished to do so, subject to the following conditions:
+%
+% The above copyright notice and this permission notice shall be included in
+% all copies or substantial portions of the Software.
+%
+% THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+% SOFTWARE.
+% ==========================================
+
+\hyphenation{
+ad-he-re-cer
+ad-he-ren-cia
+ad-he-ren-cias
+ad-he-ren-te
+ad-he-ren-tes
+ad-he-ri-da
+ad-he-ri-das
+ad-he-ri-do
+ad-he-ri-dos
+ad-he-ri-mos
+ad-he-ri-re-mos
+ad-he-ri-ros
+ad-he-ri-rá
+ad-he-ri-rán
+ad-he-ri-rás
+ad-he-ri-ré
+ad-he-ri-réis
+ad-he-ri-ría
+ad-he-ri-ría-mos
+ad-he-ri-ríais
+ad-he-ri-rían
+ad-he-ri-rías
+ad-he-rid
+ad-he-rir
+ad-he-rir-la
+ad-he-rir-las
+ad-he-rir-le
+ad-he-rir-les
+ad-he-rir-lo
+ad-he-rir-los
+ad-he-rir-me
+ad-he-rir-nos
+ad-he-rir-se
+ad-he-rir-te
+ad-he-ris-te
+ad-he-ris-teis
+ad-he-rí
+ad-he-rí-ros-la
+ad-he-rí-ros-las
+ad-he-rí-ros-le
+ad-he-rí-ros-les
+ad-he-rí-ros-lo
+ad-he-rí-ros-los
+ad-he-ría
+ad-he-ría-mos
+ad-he-ríais
+ad-he-rían
+ad-he-rías
+ad-he-rír-me-la
+ad-he-rír-me-las
+ad-he-rír-me-le
+ad-he-rír-me-les
+ad-he-rír-me-lo
+ad-he-rír-me-los
+ad-he-rír-nos-la
+ad-he-rír-nos-las
+ad-he-rír-nos-le
+ad-he-rír-nos-les
+ad-he-rír-nos-lo
+ad-he-rír-nos-los
+ad-he-rír-se-la
+ad-he-rír-se-las
+ad-he-rír-se-le
+ad-he-rír-se-les
+ad-he-rír-se-lo
+ad-he-rír-se-los
+ad-he-rír-te-la
+ad-he-rír-te-las
+ad-he-rír-te-le
+ad-he-rír-te-les
+ad-he-rír-te-lo
+ad-he-rír-te-los
+ad-he-rís
+ad-he-si-va
+ad-he-si-vas
+ad-he-si-vi-da-des
+ad-he-si-vi-dad
+ad-he-si-vo
+ad-he-si-vos
+ad-he-sio-nes
+ad-he-sión
+ad-hi-ra-mos
+ad-hi-rie-ra
+ad-hi-rie-rais
+ad-hi-rie-ran
+ad-hi-rie-ras
+ad-hi-rie-re
+ad-hi-rie-reis
+ad-hi-rie-ren
+ad-hi-rie-res
+ad-hi-rie-ron
+ad-hi-rie-se
+ad-hi-rie-seis
+ad-hi-rie-sen
+ad-hi-rie-ses
+ad-hi-rien-do
+ad-hi-rié-ra-mos
+ad-hi-rié-re-mos
+ad-hi-rié-se-mos
+ad-hi-rién-do-la
+ad-hi-rién-do-las
+ad-hi-rién-do-le
+ad-hi-rién-do-les
+ad-hi-rién-do-lo
+ad-hi-rién-do-los
+ad-hi-rién-do-me
+ad-hi-rién-do-nos
+ad-hi-rién-do-se
+ad-hi-rién-do-te
+ad-hi-rién-doos
+ad-hi-rió
+ad-hi-ráis
+ad-hie-ra
+ad-hie-ran
+ad-hie-ras
+ad-hie-re
+ad-hie-ren
+ad-hie-res
+ad-hie-ro
+ad-hor-tar
+al-ha-ce-na
+al-ha-ce-nas
+al-ha-di-da
+al-ha-di-das
+al-ha-ja
+al-ha-ja-ba
+al-ha-ja-bais
+al-ha-ja-ban
+al-ha-ja-bas
+al-ha-ja-da
+al-ha-ja-das
+al-ha-ja-do
+al-ha-ja-dos
+al-ha-ja-mos
+al-ha-ja-ra
+al-ha-ja-rais
+al-ha-ja-ran
+al-ha-ja-ras
+al-ha-ja-re
+al-ha-ja-re-mos
+al-ha-ja-reis
+al-ha-ja-ren
+al-ha-ja-res
+al-ha-ja-ron
+al-ha-ja-rá
+al-ha-ja-rán
+al-ha-ja-rás
+al-ha-ja-ré
+al-ha-ja-réis
+al-ha-ja-ría
+al-ha-ja-ría-mos
+al-ha-ja-ríais
+al-ha-ja-rían
+al-ha-ja-rías
+al-ha-ja-se
+al-ha-ja-seis
+al-ha-ja-sen
+al-ha-ja-ses
+al-ha-jad
+al-ha-jan
+al-ha-jan-do
+al-ha-jar
+al-ha-jas
+al-ha-jas-te
+al-ha-jas-teis
+al-ha-je
+al-ha-je-mos
+al-ha-je-ra
+al-ha-je-ro
+al-ha-jen
+al-ha-jes
+al-ha-ji-ta
+al-ha-ji-to
+al-ha-jo
+al-ha-jue-la
+al-ha-jue-las
+al-ha-já-ba-mos
+al-ha-já-ra-mos
+al-ha-já-re-mos
+al-ha-já-se-mos
+al-ha-jáis
+al-ha-jé
+al-ha-jéis
+al-ha-jó
+al-ha-jú
+al-ha-mar
+al-ha-me-les
+al-ha-mel
+al-ha-mí
+al-ha-nía
+al-ha-quín
+al-ha-ra-ca
+al-ha-ra-cas
+al-ha-ra-que-ro
+al-ha-ra-quien-ta
+al-ha-ra-quien-tas
+al-ha-ra-quien-to
+al-ha-ra-quien-tos
+al-ha-re-me
+al-ha-va-ra
+al-hai-te
+al-ham-bra
+al-ham-bri-lla
+al-han-da-les
+al-han-dal
+al-har-ma
+al-har-mas
+al-he-lí
+al-he-ña
+al-he-ña-ba
+al-he-ña-bais
+al-he-ña-ban
+al-he-ña-bas
+al-he-ña-da
+al-he-ña-das
+al-he-ña-do
+al-he-ña-dos
+al-he-ña-mos
+al-he-ña-ra
+al-he-ña-rais
+al-he-ña-ran
+al-he-ña-ras
+al-he-ña-re
+al-he-ña-re-mos
+al-he-ña-reis
+al-he-ña-ren
+al-he-ña-res
+al-he-ña-ron
+al-he-ña-rá
+al-he-ña-rán
+al-he-ña-rás
+al-he-ña-ré
+al-he-ña-réis
+al-he-ña-ría
+al-he-ña-ría-mos
+al-he-ña-ríais
+al-he-ña-rían
+al-he-ña-rías
+al-he-ña-se
+al-he-ña-seis
+al-he-ña-sen
+al-he-ña-ses
+al-he-ñad
+al-he-ñan
+al-he-ñan-do
+al-he-ñar
+al-he-ñar-se
+al-he-ñas
+al-he-ñas-te
+al-he-ñas-teis
+al-he-ñe
+al-he-ñe-mos
+al-he-ñen
+al-he-ñes
+al-he-ño
+al-he-ñá-ba-mos
+al-he-ñá-ra-mos
+al-he-ñá-re-mos
+al-he-ñá-se-mos
+al-he-ñáis
+al-he-ñé
+al-he-ñéis
+al-he-ñó
+al-hen-dal
+al-hi-da-da
+al-ho-ja
+al-ho-lí
+al-ho-lía
+al-ho-rra
+al-ho-rre
+al-ho-rro
+al-ho-rría
+al-ho-rí
+al-ho-rín
+al-hol-va
+al-hol-var
+al-hol-vas
+al-hom-bra
+al-hom-brar
+al-hon-di-gue-ro
+al-hor-za
+al-hoz
+al-hu-ce-ma
+al-hu-ce-mas
+al-hu-ce-mi-lla
+al-hu-ce-mi-llas
+al-hu-ce-ña
+al-hu-ma-jo
+al-hu-ma-jos
+al-hu-rre-ca
+al-hu-rre-cas
+al-há-be-ga
+al-há-me-ga
+al-hár-ga-ma
+al-hó-ci-go
+al-hón-di-ga
+al-hón-di-gas
+an-he-do-nia
+an-he-la
+an-he-la-ba
+an-he-la-bais
+an-he-la-ban
+an-he-la-bas
+an-he-la-cio-nes
+an-he-la-ción
+an-he-la-da
+an-he-la-das
+an-he-la-do
+an-he-la-dos
+an-he-la-mos
+an-he-la-ra
+an-he-la-rais
+an-he-la-ran
+an-he-la-ras
+an-he-la-re
+an-he-la-re-mos
+an-he-la-reis
+an-he-la-ren
+an-he-la-res
+an-he-la-ron
+an-he-la-rá
+an-he-la-rán
+an-he-la-rás
+an-he-la-ré
+an-he-la-réis
+an-he-la-ría
+an-he-la-ría-mos
+an-he-la-ríais
+an-he-la-rían
+an-he-la-rías
+an-he-la-se
+an-he-la-seis
+an-he-la-sen
+an-he-la-ses
+an-he-lad
+an-he-lan
+an-he-lan-do
+an-he-lan-te
+an-he-lan-te
+an-he-lan-tes
+an-he-lan-tes
+an-he-lar
+an-he-las
+an-he-las-te
+an-he-las-teis
+an-he-le
+an-he-le-mos
+an-he-len
+an-he-les
+an-he-li-to
+an-he-lo
+an-he-lo-sa
+an-he-lo-sa-men-te
+an-he-lo-sas
+an-he-lo-so
+an-he-lo-sos
+an-he-los
+an-he-lá-ba-mos
+an-he-lá-ra-mos
+an-he-lá-re-mos
+an-he-lá-se-mos
+an-he-láis
+an-he-lé
+an-he-léis
+an-he-ló
+an-hi-dra
+an-hi-dra-sa
+an-hi-dras
+an-hi-dri-do
+an-hi-dri-ta
+an-hi-dri-tas
+an-hi-dro
+an-hi-dro-sis
+an-hi-dros
+an-hé-li-to
+an-hé-li-tos
+an-hí-dri-da
+an-hí-dri-das
+an-hí-dri-do
+an-hí-dri-dos
+apre-hen-da
+apre-hen-da-mos
+apre-hen-dan
+apre-hen-das
+apre-hen-de
+apre-hen-de-mos
+apre-hen-de-re-mos
+apre-hen-de-rá
+apre-hen-de-rán
+apre-hen-de-rás
+apre-hen-de-ré
+apre-hen-de-réis
+apre-hen-de-ría
+apre-hen-de-ría-mos
+apre-hen-de-ríais
+apre-hen-de-rían
+apre-hen-de-rías
+apre-hen-ded
+apre-hen-den
+apre-hen-der
+apre-hen-der-la
+apre-hen-der-las
+apre-hen-der-le
+apre-hen-der-les
+apre-hen-der-lo
+apre-hen-der-los
+apre-hen-des
+apre-hen-di-da
+apre-hen-di-das
+apre-hen-di-do
+apre-hen-di-dos
+apre-hen-di-mos
+apre-hen-die-ra
+apre-hen-die-rais
+apre-hen-die-ran
+apre-hen-die-ras
+apre-hen-die-re
+apre-hen-die-reis
+apre-hen-die-ren
+apre-hen-die-res
+apre-hen-die-ron
+apre-hen-die-se
+apre-hen-die-seis
+apre-hen-die-sen
+apre-hen-die-ses
+apre-hen-dien-do
+apre-hen-dien-te
+apre-hen-dien-tes
+apre-hen-dis-te
+apre-hen-dis-teis
+apre-hen-dié-ra-mos
+apre-hen-dié-re-mos
+apre-hen-dié-se-mos
+apre-hen-dién-do-la
+apre-hen-dién-do-las
+apre-hen-dién-do-le
+apre-hen-dién-do-les
+apre-hen-dién-do-lo
+apre-hen-dién-do-los
+apre-hen-dió
+apre-hen-do
+apre-hen-dáis
+apre-hen-déis
+apre-hen-dí
+apre-hen-día
+apre-hen-día-mos
+apre-hen-díais
+apre-hen-dían
+apre-hen-días
+apre-hen-si-va
+apre-hen-si-vas
+apre-hen-si-vo
+apre-hen-si-vos
+apre-hen-sio-nes
+apre-hen-sión
+apre-hen-so-ra
+apre-hen-so-ras
+apre-hen-so-res
+apre-hen-so-rio
+apre-hen-sor
+ara-hua-co
+chi-hua-hua
+chi-hua-huas
+chi-hua-hue-ño
+chi-hua-huen-se
+co-he-ta-zo
+co-he-te
+co-he-te-ra
+co-he-te-ras
+co-he-te-ro
+co-he-te-ros
+co-he-te-ría
+co-he-tes
+co-hi-ba-mos
+co-hi-bi-cio-nes
+co-hi-bi-ción
+co-hi-bi-da
+co-hi-bi-das
+co-hi-bi-do
+co-hi-bi-dos
+co-hi-bi-mos
+co-hi-bi-ros
+co-hi-bid
+co-hi-bie-ra
+co-hi-bie-rais
+co-hi-bie-ran
+co-hi-bie-ras
+co-hi-bie-re
+co-hi-bie-reis
+co-hi-bie-ren
+co-hi-bie-res
+co-hi-bie-ron
+co-hi-bie-se
+co-hi-bie-seis
+co-hi-bie-sen
+co-hi-bie-ses
+co-hi-bien-do
+co-hi-bir
+co-hi-bir-la
+co-hi-bir-las
+co-hi-bir-le
+co-hi-bir-les
+co-hi-bir-lo
+co-hi-bir-los
+co-hi-bir-me
+co-hi-bir-nos
+co-hi-bir-se
+co-hi-bir-te
+co-hi-bié-ra-mos
+co-hi-bié-re-mos
+co-hi-bié-se-mos
+co-hi-bién-do-la
+co-hi-bién-do-las
+co-hi-bién-do-le
+co-hi-bién-do-les
+co-hi-bién-do-lo
+co-hi-bién-do-los
+co-hi-bién-do-me
+co-hi-bién-do-nos
+co-hi-bién-do-se
+co-hi-bién-do-te
+co-hi-bién-doos
+co-hi-bió
+co-hi-báis
+co-hi-bía
+co-hi-bía-mos
+co-hi-bíais
+co-hi-bían
+co-hi-bías
+co-hi-bís
+dír-ham
+dír-hem
+ex-ha-la
+ex-ha-la-ba
+ex-ha-la-bais
+ex-ha-la-ban
+ex-ha-la-bas
+ex-ha-la-cio-nes
+ex-ha-la-ción
+ex-ha-la-da
+ex-ha-la-das
+ex-ha-la-do
+ex-ha-la-do-ra
+ex-ha-la-do-ras
+ex-ha-la-do-res
+ex-ha-la-dor
+ex-ha-la-dos
+ex-ha-la-mos
+ex-ha-la-ra
+ex-ha-la-rais
+ex-ha-la-ran
+ex-ha-la-ras
+ex-ha-la-re
+ex-ha-la-re-mos
+ex-ha-la-reis
+ex-ha-la-ren
+ex-ha-la-res
+ex-ha-la-ron
+ex-ha-la-ros
+ex-ha-la-rá
+ex-ha-la-rán
+ex-ha-la-rás
+ex-ha-la-ré
+ex-ha-la-réis
+ex-ha-la-ría
+ex-ha-la-ría-mos
+ex-ha-la-ríais
+ex-ha-la-rían
+ex-ha-la-rías
+ex-ha-la-se
+ex-ha-la-seis
+ex-ha-la-sen
+ex-ha-la-ses
+ex-ha-lad
+ex-ha-lan
+ex-ha-lan-do
+ex-ha-lan-te
+ex-ha-lar
+ex-ha-lar-la
+ex-ha-lar-las
+ex-ha-lar-le
+ex-ha-lar-les
+ex-ha-lar-lo
+ex-ha-lar-los
+ex-ha-lar-me
+ex-ha-lar-nos
+ex-ha-lar-se
+ex-ha-lar-te
+ex-ha-las
+ex-ha-las-te
+ex-ha-las-teis
+ex-ha-le
+ex-ha-le-mos
+ex-ha-len
+ex-ha-les
+ex-ha-lo
+ex-ha-lá-ba-mos
+ex-ha-lá-ra-mos
+ex-ha-lá-re-mos
+ex-ha-lá-ros-la
+ex-ha-lá-ros-las
+ex-ha-lá-ros-lo
+ex-ha-lá-ros-los
+ex-ha-lá-se-mos
+ex-ha-láis
+ex-ha-lán-do-la
+ex-ha-lán-do-las
+ex-ha-lán-do-le
+ex-ha-lán-do-les
+ex-ha-lán-do-lo
+ex-ha-lán-do-los
+ex-ha-lán-do-me
+ex-ha-lán-do-me-la
+ex-ha-lán-do-me-las
+ex-ha-lán-do-me-lo
+ex-ha-lán-do-me-los
+ex-ha-lán-do-nos
+ex-ha-lán-do-nos-la
+ex-ha-lán-do-nos-las
+ex-ha-lán-do-nos-lo
+ex-ha-lán-do-nos-los
+ex-ha-lán-do-se
+ex-ha-lán-do-se-la
+ex-ha-lán-do-se-las
+ex-ha-lán-do-se-lo
+ex-ha-lán-do-se-los
+ex-ha-lán-do-te
+ex-ha-lán-do-te-la
+ex-ha-lán-do-te-las
+ex-ha-lán-do-te-lo
+ex-ha-lán-do-te-los
+ex-ha-lán-doos
+ex-ha-lán-doos-la
+ex-ha-lán-doos-las
+ex-ha-lán-doos-lo
+ex-ha-lán-doos-los
+ex-ha-lár-me-la
+ex-ha-lár-me-las
+ex-ha-lár-me-lo
+ex-ha-lár-me-los
+ex-ha-lár-nos-la
+ex-ha-lár-nos-las
+ex-ha-lár-nos-lo
+ex-ha-lár-nos-los
+ex-ha-lár-se-la
+ex-ha-lár-se-las
+ex-ha-lár-se-lo
+ex-ha-lár-se-los
+ex-ha-lár-te-la
+ex-ha-lár-te-las
+ex-ha-lár-te-lo
+ex-ha-lár-te-los
+ex-ha-lé
+ex-ha-léis
+ex-ha-ló
+ex-haus-ta
+ex-haus-ta-ción
+ex-haus-tas
+ex-haus-ti-va
+ex-haus-ti-va-men-te
+ex-haus-ti-vas
+ex-haus-ti-vi-dad
+ex-haus-ti-vo
+ex-haus-ti-vos
+ex-haus-to
+ex-haus-tos
+ex-hi-ba
+ex-hi-ba-mos
+ex-hi-ban
+ex-hi-bas
+ex-hi-be
+ex-hi-ben
+ex-hi-bes
+ex-hi-bi-cio-nes
+ex-hi-bi-cio-nis-mo
+ex-hi-bi-cio-nis-mos
+ex-hi-bi-cio-nis-ta
+ex-hi-bi-cio-nis-tas
+ex-hi-bi-ción
+ex-hi-bi-da
+ex-hi-bi-das
+ex-hi-bi-do
+ex-hi-bi-dor
+ex-hi-bi-dos
+ex-hi-bi-mos
+ex-hi-bi-re-mos
+ex-hi-bi-ros
+ex-hi-bi-rá
+ex-hi-bi-rán
+ex-hi-bi-rás
+ex-hi-bi-ré
+ex-hi-bi-réis
+ex-hi-bi-ría
+ex-hi-bi-ría-mos
+ex-hi-bi-ríais
+ex-hi-bi-rían
+ex-hi-bi-rías
+ex-hi-bid
+ex-hi-bie-ra
+ex-hi-bie-rais
+ex-hi-bie-ran
+ex-hi-bie-ras
+ex-hi-bie-re
+ex-hi-bie-reis
+ex-hi-bie-ren
+ex-hi-bie-res
+ex-hi-bie-ron
+ex-hi-bie-se
+ex-hi-bie-seis
+ex-hi-bie-sen
+ex-hi-bie-ses
+ex-hi-bien-do
+ex-hi-bir
+ex-hi-bir-la
+ex-hi-bir-las
+ex-hi-bir-le
+ex-hi-bir-les
+ex-hi-bir-lo
+ex-hi-bir-los
+ex-hi-bir-me
+ex-hi-bir-nos
+ex-hi-bir-se
+ex-hi-bir-te
+ex-hi-bis-te
+ex-hi-bis-teis
+ex-hi-bié-ra-mos
+ex-hi-bié-re-mos
+ex-hi-bié-se-mos
+ex-hi-bién-do-la
+ex-hi-bién-do-las
+ex-hi-bién-do-le
+ex-hi-bién-do-les
+ex-hi-bién-do-lo
+ex-hi-bién-do-los
+ex-hi-bién-do-me
+ex-hi-bién-do-me-la
+ex-hi-bién-do-me-las
+ex-hi-bién-do-me-lo
+ex-hi-bién-do-me-los
+ex-hi-bién-do-nos
+ex-hi-bién-do-nos-la
+ex-hi-bién-do-nos-las
+ex-hi-bién-do-nos-lo
+ex-hi-bién-do-nos-los
+ex-hi-bién-do-se
+ex-hi-bién-do-se-la
+ex-hi-bién-do-se-las
+ex-hi-bién-do-se-lo
+ex-hi-bién-do-se-los
+ex-hi-bién-do-te
+ex-hi-bién-do-te-la
+ex-hi-bién-do-te-las
+ex-hi-bién-do-te-lo
+ex-hi-bién-do-te-los
+ex-hi-bién-doos
+ex-hi-bién-doos-la
+ex-hi-bién-doos-las
+ex-hi-bién-doos-lo
+ex-hi-bién-doos-los
+ex-hi-bió
+ex-hi-bo
+ex-hi-báis
+ex-hi-bí
+ex-hi-bí-ros-la
+ex-hi-bí-ros-las
+ex-hi-bí-ros-lo
+ex-hi-bí-ros-los
+ex-hi-bía
+ex-hi-bía-mos
+ex-hi-bíais
+ex-hi-bían
+ex-hi-bías
+ex-hi-bír-me-la
+ex-hi-bír-me-las
+ex-hi-bír-me-lo
+ex-hi-bír-me-los
+ex-hi-bír-nos-la
+ex-hi-bír-nos-las
+ex-hi-bír-nos-lo
+ex-hi-bír-nos-los
+ex-hi-bír-se-la
+ex-hi-bír-se-las
+ex-hi-bír-se-lo
+ex-hi-bír-se-los
+ex-hi-bír-te-la
+ex-hi-bír-te-las
+ex-hi-bír-te-lo
+ex-hi-bír-te-los
+ex-hi-bís
+ex-hor-ta
+ex-hor-ta-ba
+ex-hor-ta-bais
+ex-hor-ta-ban
+ex-hor-ta-bas
+ex-hor-ta-cio-nes
+ex-hor-ta-ción
+ex-hor-ta-da
+ex-hor-ta-das
+ex-hor-ta-do
+ex-hor-ta-do-ra
+ex-hor-ta-do-ras
+ex-hor-ta-do-res
+ex-hor-ta-dor
+ex-hor-ta-dos
+ex-hor-ta-mos
+ex-hor-ta-ra
+ex-hor-ta-rais
+ex-hor-ta-ran
+ex-hor-ta-ras
+ex-hor-ta-re
+ex-hor-ta-re-mos
+ex-hor-ta-reis
+ex-hor-ta-ren
+ex-hor-ta-res
+ex-hor-ta-ron
+ex-hor-ta-ros
+ex-hor-ta-rá
+ex-hor-ta-rán
+ex-hor-ta-rás
+ex-hor-ta-ré
+ex-hor-ta-réis
+ex-hor-ta-ría
+ex-hor-ta-ría-mos
+ex-hor-ta-ríais
+ex-hor-ta-rían
+ex-hor-ta-rías
+ex-hor-ta-se
+ex-hor-ta-seis
+ex-hor-ta-sen
+ex-hor-ta-ses
+ex-hor-ta-ti-va
+ex-hor-ta-ti-va-men-te
+ex-hor-ta-ti-vas
+ex-hor-ta-ti-vo
+ex-hor-ta-ti-vos
+ex-hor-ta-to-ria
+ex-hor-ta-to-rias
+ex-hor-ta-to-rio
+ex-hor-ta-to-rios
+ex-hor-tad
+ex-hor-tan
+ex-hor-tan-do
+ex-hor-tar
+ex-hor-tar-la
+ex-hor-tar-las
+ex-hor-tar-le
+ex-hor-tar-les
+ex-hor-tar-lo
+ex-hor-tar-los
+ex-hor-tar-me
+ex-hor-tar-nos
+ex-hor-tar-se
+ex-hor-tar-te
+ex-hor-tas
+ex-hor-tas-te
+ex-hor-tas-teis
+ex-hor-te
+ex-hor-te-mos
+ex-hor-ten
+ex-hor-tes
+ex-hor-to
+ex-hor-tos
+ex-hor-tá-ba-mos
+ex-hor-tá-ra-mos
+ex-hor-tá-re-mos
+ex-hor-tá-ros-la
+ex-hor-tá-ros-las
+ex-hor-tá-ros-lo
+ex-hor-tá-ros-los
+ex-hor-tá-se-mos
+ex-hor-táis
+ex-hor-tán-do-la
+ex-hor-tán-do-las
+ex-hor-tán-do-le
+ex-hor-tán-do-les
+ex-hor-tán-do-lo
+ex-hor-tán-do-los
+ex-hor-tán-do-me
+ex-hor-tán-do-me-la
+ex-hor-tán-do-me-las
+ex-hor-tán-do-me-lo
+ex-hor-tán-do-me-los
+ex-hor-tán-do-nos
+ex-hor-tán-do-nos-la
+ex-hor-tán-do-nos-las
+ex-hor-tán-do-nos-lo
+ex-hor-tán-do-nos-los
+ex-hor-tán-do-se
+ex-hor-tán-do-se-la
+ex-hor-tán-do-se-las
+ex-hor-tán-do-se-lo
+ex-hor-tán-do-se-los
+ex-hor-tán-do-te
+ex-hor-tán-do-te-la
+ex-hor-tán-do-te-las
+ex-hor-tán-do-te-lo
+ex-hor-tán-do-te-los
+ex-hor-tán-doos
+ex-hor-tán-doos-la
+ex-hor-tán-doos-las
+ex-hor-tán-doos-lo
+ex-hor-tán-doos-los
+ex-hor-tár-me-la
+ex-hor-tár-me-las
+ex-hor-tár-me-lo
+ex-hor-tár-me-los
+ex-hor-tár-nos-la
+ex-hor-tár-nos-las
+ex-hor-tár-nos-lo
+ex-hor-tár-nos-los
+ex-hor-tár-se-la
+ex-hor-tár-se-las
+ex-hor-tár-se-lo
+ex-hor-tár-se-los
+ex-hor-tár-te-la
+ex-hor-tár-te-las
+ex-hor-tár-te-lo
+ex-hor-tár-te-los
+ex-hor-té
+ex-hor-téis
+ex-hor-tó
+ex-hu-ma
+ex-hu-ma-ba
+ex-hu-ma-bais
+ex-hu-ma-ban
+ex-hu-ma-bas
+ex-hu-ma-cio-nes
+ex-hu-ma-ción
+ex-hu-ma-da
+ex-hu-ma-das
+ex-hu-ma-do
+ex-hu-ma-do-ra
+ex-hu-ma-do-ras
+ex-hu-ma-do-res
+ex-hu-ma-dor
+ex-hu-ma-dos
+ex-hu-ma-mos
+ex-hu-ma-ra
+ex-hu-ma-rais
+ex-hu-ma-ran
+ex-hu-ma-ras
+ex-hu-ma-re
+ex-hu-ma-re-mos
+ex-hu-ma-reis
+ex-hu-ma-ren
+ex-hu-ma-res
+ex-hu-ma-ron
+ex-hu-ma-ros
+ex-hu-ma-rá
+ex-hu-ma-rán
+ex-hu-ma-rás
+ex-hu-ma-ré
+ex-hu-ma-réis
+ex-hu-ma-ría
+ex-hu-ma-ría-mos
+ex-hu-ma-ríais
+ex-hu-ma-rían
+ex-hu-ma-rías
+ex-hu-ma-se
+ex-hu-ma-seis
+ex-hu-ma-sen
+ex-hu-ma-ses
+ex-hu-mad
+ex-hu-man
+ex-hu-man-do
+ex-hu-mar
+ex-hu-mar-la
+ex-hu-mar-las
+ex-hu-mar-le
+ex-hu-mar-les
+ex-hu-mar-lo
+ex-hu-mar-los
+ex-hu-mar-me
+ex-hu-mar-nos
+ex-hu-mar-se
+ex-hu-mar-te
+ex-hu-mas
+ex-hu-mas-te
+ex-hu-mas-teis
+ex-hu-me
+ex-hu-me-mos
+ex-hu-men
+ex-hu-mes
+ex-hu-mo
+ex-hu-má-ba-mos
+ex-hu-má-ra-mos
+ex-hu-má-re-mos
+ex-hu-má-se-mos
+ex-hu-máis
+ex-hu-mán-do-la
+ex-hu-mán-do-las
+ex-hu-mán-do-le
+ex-hu-mán-do-les
+ex-hu-mán-do-lo
+ex-hu-mán-do-los
+ex-hu-mán-do-me
+ex-hu-mán-do-nos
+ex-hu-mán-do-se
+ex-hu-mán-do-te
+ex-hu-mán-doos
+ex-hu-mé
+ex-hu-méis
+ex-hu-mó
+fluor-hí-dri-co
+fluor-hí-dri-cos
+in-ha-la
+in-ha-la-ba
+in-ha-la-bais
+in-ha-la-ban
+in-ha-la-bas
+in-ha-la-ble
+in-ha-la-cio-nes
+in-ha-la-ción
+in-ha-la-da
+in-ha-la-das
+in-ha-la-do
+in-ha-la-do-ra
+in-ha-la-do-ras
+in-ha-la-do-res
+in-ha-la-dor
+in-ha-la-dos
+in-ha-la-mos
+in-ha-la-ra
+in-ha-la-rais
+in-ha-la-ran
+in-ha-la-ras
+in-ha-la-re
+in-ha-la-re-mos
+in-ha-la-reis
+in-ha-la-ren
+in-ha-la-res
+in-ha-la-ron
+in-ha-la-rá
+in-ha-la-rán
+in-ha-la-rás
+in-ha-la-ré
+in-ha-la-réis
+in-ha-la-ría
+in-ha-la-ría-mos
+in-ha-la-ríais
+in-ha-la-rían
+in-ha-la-rías
+in-ha-la-se
+in-ha-la-seis
+in-ha-la-sen
+in-ha-la-ses
+in-ha-lad
+in-ha-lan
+in-ha-lan-do
+in-ha-lan-te
+in-ha-lar
+in-ha-lar-la
+in-ha-lar-las
+in-ha-lar-le
+in-ha-lar-les
+in-ha-lar-lo
+in-ha-lar-los
+in-ha-las
+in-ha-las-te
+in-ha-las-teis
+in-ha-le
+in-ha-le-mos
+in-ha-len
+in-ha-les
+in-ha-lla-ble
+in-ha-lo
+in-ha-lá-ba-mos
+in-ha-lá-ra-mos
+in-ha-lá-re-mos
+in-ha-lá-se-mos
+in-ha-láis
+in-ha-lán-do-la
+in-ha-lán-do-las
+in-ha-lán-do-le
+in-ha-lán-do-les
+in-ha-lán-do-lo
+in-ha-lán-do-los
+in-ha-lé
+in-ha-léis
+in-ha-ló
+in-he-ren-te
+in-he-ren-te-men-te
+in-he-ren-tes
+in-he-sión
+in-hes-ta
+in-hes-ta-ba
+in-hes-ta-bais
+in-hes-ta-ban
+in-hes-ta-bas
+in-hes-ta-da
+in-hes-ta-das
+in-hes-ta-do
+in-hes-ta-dos
+in-hes-ta-mos
+in-hes-ta-ra
+in-hes-ta-rais
+in-hes-ta-ran
+in-hes-ta-ras
+in-hes-ta-re
+in-hes-ta-re-mos
+in-hes-ta-reis
+in-hes-ta-ren
+in-hes-ta-res
+in-hes-ta-ron
+in-hes-ta-rá
+in-hes-ta-rán
+in-hes-ta-rás
+in-hes-ta-ré
+in-hes-ta-réis
+in-hes-ta-ría
+in-hes-ta-ría-mos
+in-hes-ta-ríais
+in-hes-ta-rían
+in-hes-ta-rías
+in-hes-ta-se
+in-hes-ta-seis
+in-hes-ta-sen
+in-hes-ta-ses
+in-hes-tad
+in-hes-tan
+in-hes-tan-do
+in-hes-tar
+in-hes-tar-la
+in-hes-tar-las
+in-hes-tar-le
+in-hes-tar-les
+in-hes-tar-lo
+in-hes-tar-los
+in-hes-tas
+in-hes-tas-te
+in-hes-tas-teis
+in-hes-te
+in-hes-te-mos
+in-hes-ten
+in-hes-tes
+in-hes-to
+in-hes-tá-ba-mos
+in-hes-tá-ra-mos
+in-hes-tá-re-mos
+in-hes-tá-se-mos
+in-hes-táis
+in-hes-tán-do-la
+in-hes-tán-do-las
+in-hes-tán-do-le
+in-hes-tán-do-les
+in-hes-tán-do-lo
+in-hes-tán-do-los
+in-hes-té
+in-hes-téis
+in-hes-tó
+in-hi-ba
+in-hi-ba-mos
+in-hi-ban
+in-hi-bas
+in-hi-be
+in-hi-ben
+in-hi-bes
+in-hi-bi-cio-nes
+in-hi-bi-ción
+in-hi-bi-da
+in-hi-bi-das
+in-hi-bi-do
+in-hi-bi-do-ra
+in-hi-bi-do-ra
+in-hi-bi-do-ras
+in-hi-bi-dor
+in-hi-bi-dos
+in-hi-bi-mos
+in-hi-bi-re-mos
+in-hi-bi-ros
+in-hi-bi-rá
+in-hi-bi-rán
+in-hi-bi-rás
+in-hi-bi-ré
+in-hi-bi-réis
+in-hi-bi-ría
+in-hi-bi-ría-mos
+in-hi-bi-ríais
+in-hi-bi-rían
+in-hi-bi-rías
+in-hi-bi-to-ria
+in-hi-bi-to-rio
+in-hi-bid
+in-hi-bie-ra
+in-hi-bie-rais
+in-hi-bie-ran
+in-hi-bie-ras
+in-hi-bie-re
+in-hi-bie-reis
+in-hi-bie-ren
+in-hi-bie-res
+in-hi-bie-ron
+in-hi-bie-se
+in-hi-bie-seis
+in-hi-bie-sen
+in-hi-bie-ses
+in-hi-bien-do
+in-hi-bir
+in-hi-bir-la
+in-hi-bir-las
+in-hi-bir-le
+in-hi-bir-les
+in-hi-bir-lo
+in-hi-bir-los
+in-hi-bir-me
+in-hi-bir-nos
+in-hi-bir-se
+in-hi-bir-te
+in-hi-bis-te
+in-hi-bis-teis
+in-hi-bié-ra-mos
+in-hi-bié-re-mos
+in-hi-bié-se-mos
+in-hi-bién-do-la
+in-hi-bién-do-las
+in-hi-bién-do-le
+in-hi-bién-do-les
+in-hi-bién-do-lo
+in-hi-bién-do-los
+in-hi-bién-do-me
+in-hi-bién-do-nos
+in-hi-bién-do-se
+in-hi-bién-do-te
+in-hi-bién-doos
+in-hi-bió
+in-hi-bo
+in-hi-báis
+in-hi-bí
+in-hi-bía
+in-hi-bía-mos
+in-hi-bíais
+in-hi-bían
+in-hi-bías
+in-hi-bís
+in-hies-ta
+in-hies-tas
+in-hies-to
+in-hies-tos
+in-hu-ma
+in-hu-ma-ba
+in-hu-ma-bais
+in-hu-ma-ban
+in-hu-ma-bas
+in-hu-ma-cio-nes
+in-hu-ma-ción
+in-hu-ma-da
+in-hu-ma-das
+in-hu-ma-do
+in-hu-ma-dos
+in-hu-ma-mos
+in-hu-ma-ni-da-des
+in-hu-ma-ni-dad
+in-hu-ma-ra
+in-hu-ma-rais
+in-hu-ma-ran
+in-hu-ma-ras
+in-hu-ma-re
+in-hu-ma-re-mos
+in-hu-ma-reis
+in-hu-ma-ren
+in-hu-ma-res
+in-hu-ma-ron
+in-hu-ma-rá
+in-hu-ma-rán
+in-hu-ma-rás
+in-hu-ma-ré
+in-hu-ma-réis
+in-hu-ma-ría
+in-hu-ma-ría-mos
+in-hu-ma-ríais
+in-hu-ma-rían
+in-hu-ma-rías
+in-hu-ma-se
+in-hu-ma-seis
+in-hu-ma-sen
+in-hu-ma-ses
+in-hu-mad
+in-hu-man
+in-hu-man-do
+in-hu-mar
+in-hu-mar-la
+in-hu-mar-las
+in-hu-mar-le
+in-hu-mar-les
+in-hu-mar-lo
+in-hu-mar-los
+in-hu-mas
+in-hu-mas-te
+in-hu-mas-teis
+in-hu-me
+in-hu-me-mos
+in-hu-men
+in-hu-mes
+in-hu-mo
+in-hu-má-ba-mos
+in-hu-má-ra-mos
+in-hu-má-re-mos
+in-hu-má-se-mos
+in-hu-máis
+in-hu-mán-do-la
+in-hu-mán-do-las
+in-hu-mán-do-le
+in-hu-mán-do-les
+in-hu-mán-do-lo
+in-hu-mán-do-los
+in-hu-mé
+in-hu-méis
+in-hu-mó
+in-hós-pi-ta
+in-hós-pi-tas
+in-hós-pi-to
+in-hós-pi-tos
+ma-ri-hua-na
+ma-ri-hua-nas
+ma-ri-hua-ne-ro
+men-hi-res
+men-hir
+pa-ri-hue-la
+pa-ri-hue-las
+sa-bi-hon-da
+sa-bi-hon-das
+sa-bi-hon-de-ces
+sa-bi-hon-dez
+sa-bi-hon-do
+sa-bi-hon-dos
+sa-ha-raui
+sa-ha-ria-na
+sa-ha-ria-nas
+sa-ha-ria-nos
+sa-ha-riano} \ No newline at end of file
diff --git a/doc/cbdc-es/graphic-es.odp b/doc/cbdc-es/graphic-es.odp
new file mode 100644
index 00000000..818c2b18
--- /dev/null
+++ b/doc/cbdc-es/graphic-es.odp
Binary files differ
diff --git a/doc/cbdc-es/retirada.pdf b/doc/cbdc-es/retirada.pdf
new file mode 100644
index 00000000..7efc1549
--- /dev/null
+++ b/doc/cbdc-es/retirada.pdf
Binary files differ
diff --git a/doc/cbdc-es/taler_figure_1_dora_SPANISH.jpg b/doc/cbdc-es/taler_figure_1_dora_SPANISH.jpg
new file mode 100644
index 00000000..0dfd64ae
--- /dev/null
+++ b/doc/cbdc-es/taler_figure_1_dora_SPANISH.jpg
Binary files differ
diff --git a/doc/cbdc-es/taler_figure_2_dora_SPANISH.jpg b/doc/cbdc-es/taler_figure_2_dora_SPANISH.jpg
new file mode 100644
index 00000000..75f476a9
--- /dev/null
+++ b/doc/cbdc-es/taler_figure_2_dora_SPANISH.jpg
Binary files differ
diff --git a/src/auditor/taler-helper-auditor-reserves.c b/src/auditor/taler-helper-auditor-reserves.c
index aa9c241b..c27574d1 100644
--- a/src/auditor/taler-helper-auditor-reserves.c
+++ b/src/auditor/taler-helper-auditor-reserves.c
@@ -1083,10 +1083,13 @@ verify_reserve_balance (void *cls,
internal audit, as otherwise the balance of the 'reserves' table
is not replicated at the auditor. */
struct TALER_EXCHANGEDB_Reserve reserve;
+ struct TALER_EXCHANGEDB_KycStatus kyc;
reserve.pub = rs->reserve_pub;
qs = TALER_ARL_edb->reserves_get (TALER_ARL_edb->cls,
- &reserve);
+ &reserve,
+ &kyc);
+ // FIXME: figure out what to do with KYC status!
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
/* If the exchange doesn't have this reserve in the summary, it
diff --git a/src/auditor/test-auditor.sh b/src/auditor/test-auditor.sh
index 44b3c7b5..45498d69 100755
--- a/src/auditor/test-auditor.sh
+++ b/src/auditor/test-auditor.sh
@@ -472,7 +472,7 @@ echo "===========4: deposit wire target wrong================="
# Original target bank account was 43, changing to 44
SERIAL=`echo "SELECT deposit_serial_id FROM deposits WHERE amount_with_fee_val=3 AND amount_with_fee_frac=0 ORDER BY deposit_serial_id LIMIT 1" | psql $DB -Aqt`
OLD_WIRE=`echo "SELECT wire FROM deposits WHERE deposit_serial_id=${SERIAL};" | psql $DB -Aqt`
-echo "UPDATE deposits SET wire='{\"payto_uri\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"test-salt\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB
+echo "UPDATE deposits SET wire='{\"payto_uri\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"9PE256FT5N3YX8H3F1QCHXVNGWAGG3MHDN4J360TSVWTA6WSSMNB8MY4GN5HQAP89TDZH8ANKEG1FB1FJZMN7ZC6NH6QRB0CDDR4TJ8\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB
run_audit
@@ -1500,7 +1500,7 @@ echo "===========26: deposit wire target malformed ================="
# Expects 'payto_uri', not 'url' (also breaks signature, but we cannot even check that).
SERIAL=`echo "SELECT deposit_serial_id FROM deposits WHERE amount_with_fee_val=3 AND amount_with_fee_frac=0 ORDER BY deposit_serial_id LIMIT 1" | psql $DB -Aqt`
OLD_WIRE=`echo "SELECT wire FROM deposits WHERE deposit_serial_id=${SERIAL};" | psql $DB -Aqt`
-echo "UPDATE deposits SET wire='{\"url\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"test-salt\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB
+echo "UPDATE deposits SET wire='{\"url\":\"payto://x-taler-bank/localhost:8082/44\",\"salt\":\"9PE256FT5N3YX8H3F1QCHXVNGWAGG3MHDN4J360TSVWTA6WSSMNB8MY4GN5HQAP89TDZH8ANKEG1FB1FJZMN7ZC6NH6QRB0CDDR4TJ8\"}' WHERE deposit_serial_id=${SERIAL}" | psql -Aqt $DB
run_audit
diff --git a/src/auditor/test-revocation.sh b/src/auditor/test-revocation.sh
index ad62b518..76682572 100755
--- a/src/auditor/test-revocation.sh
+++ b/src/auditor/test-revocation.sh
@@ -120,8 +120,9 @@ function audit_only () {
# Cleanup to run after the auditor
function post_audit () {
+ echo -n "Cleanup ..."
cleanup
- echo "DONE"
+ echo " DONE"
echo -n "TeXing ."
taler-helper-auditor-render.py test-audit-aggregation.json test-audit-coins.json test-audit-deposits.json test-audit-reserves.json test-audit-wire.json < ../../contrib/auditor-report.tex.j2 > test-report.tex || exit_fail "Renderer failed"
@@ -305,28 +306,6 @@ jq -e .wire_format_inconsistencies[0] < test-audit-wire.json > /dev/null && exit
echo PASS
-echo -n "Check for lag detection... "
-
-# Check wire transfer lag reported (no aggregator!)
-# NOTE: This test is EXPECTED to fail for ~1h after
-# re-generating the test database as we do not
-# report lag of less than 1h (see GRACE_PERIOD in
-# taler-helper-auditor-wire.c)
-if [ $DATABASE_AGE -gt 3600 ]
-then
- jq -e .lag_details[0] < test-audit-wire.json > /dev/null || exit_fail "Lag not detected in run without aggregator at age $DELTA"
-
- LAG=`jq -r .total_amount_lag < test-audit-wire.json`
- if test $LAG = "TESTKUDOS:0"
- then
- exit_fail "Expected total lag to be non-zero"
- fi
- echo "PASS"
-else
- echo "SKIP (database too new)"
-fi
-
-
echo -n "Test for wire amounts... "
WIRED=`jq -r .total_wire_in_delta_plus < test-audit-wire.json`
if test $WIRED != "TESTKUDOS:0"
diff --git a/src/bank-lib/bank_api_credit.c b/src/bank-lib/bank_api_credit.c
index 91fbe506..eff2ad97 100644
--- a/src/bank-lib/bank_api_credit.c
+++ b/src/bank-lib/bank_api_credit.c
@@ -30,6 +30,13 @@
/**
+ * How much longer than the application-specified timeout
+ * do we wait (giving the server a chance to respond)?
+ */
+#define GRACE_PERIOD_MS 1000
+
+
+/**
* @brief A /history/incoming Handle
*/
struct TALER_BANK_CreditHistoryHandle
@@ -66,7 +73,7 @@ struct TALER_BANK_CreditHistoryHandle
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_account_history (struct TALER_BANK_CreditHistoryHandle *hh,
const json_t *history)
{
@@ -305,7 +312,7 @@ TALER_BANK_credit_history (struct GNUNET_CURL_Context *ctx,
GNUNET_break (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_TIMEOUT_MS,
- (long) tms));
+ (long) tms + GRACE_PERIOD_MS));
}
hh->job = GNUNET_CURL_job_add2 (ctx,
eh,
diff --git a/src/bank-lib/bank_api_debit.c b/src/bank-lib/bank_api_debit.c
index 8cca0cc5..339dfef4 100644
--- a/src/bank-lib/bank_api_debit.c
+++ b/src/bank-lib/bank_api_debit.c
@@ -30,6 +30,13 @@
/**
+ * How much longer than the application-specified timeout
+ * do we wait (giving the server a chance to respond)?
+ */
+#define GRACE_PERIOD_MS 1000
+
+
+/**
* @brief A /history/outgoing Handle
*/
struct TALER_BANK_DebitHistoryHandle
@@ -307,7 +314,7 @@ TALER_BANK_debit_history (struct GNUNET_CURL_Context *ctx,
GNUNET_break (CURLE_OK ==
curl_easy_setopt (eh,
CURLOPT_TIMEOUT_MS,
- (long) tms));
+ (long) tms + GRACE_PERIOD_MS));
}
hh->job = GNUNET_CURL_job_add2 (ctx,
eh,
diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c
index 2a53419b..24878bdd 100644
--- a/src/bank-lib/fakebank.c
+++ b/src/bank-lib/fakebank.c
@@ -425,6 +425,11 @@ struct TALER_FAKEBANK_Handle
*/
bool in_shutdown;
+ /**
+ * Should we run MHD immediately again?
+ */
+ bool mhd_again;
+
#if EPOLL_SUPPORT
/**
* Boxed @e mhd_fd.
@@ -474,6 +479,7 @@ lp_trigger (struct LongPoller *lp,
lp);
MHD_resume_connection (lp->conn);
GNUNET_free (lp);
+ h->mhd_again = true;
if (NULL != h->mhd_task)
GNUNET_SCHEDULER_cancel (h->mhd_task);
h->mhd_task =
@@ -508,12 +514,8 @@ lp_expiration_thread (void *cls)
{
GNUNET_assert (lp ==
GNUNET_CONTAINER_heap_remove_root (h->lp_heap));
- GNUNET_assert (0 ==
- pthread_mutex_lock (&h->big_lock));
lp_trigger (lp,
h);
- GNUNET_assert (0 ==
- pthread_mutex_unlock (&h->big_lock));
lp = GNUNET_CONTAINER_heap_peek (h->lp_heap);
}
if (NULL != lp)
@@ -674,7 +676,7 @@ check_log (struct TALER_FAKEBANK_Handle *h)
}
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
@@ -722,7 +724,7 @@ TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
}
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_credit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
@@ -866,36 +868,6 @@ post_transaction (struct TALER_FAKEBANK_Handle *h,
ca->in_tail,
old);
}
- {
- struct LongPoller *nxt;
-
- for (struct LongPoller *lp = debit_acc->lp_head;
- NULL != lp;
- lp = nxt)
- {
- nxt = lp->next;
- if (LP_DEBIT == lp->type)
- {
- GNUNET_assert (lp ==
- GNUNET_CONTAINER_heap_remove_node (lp->hn));
- lp_trigger (lp,
- h);
- }
- }
- for (struct LongPoller *lp = credit_acc->lp_head;
- NULL != lp;
- lp = nxt)
- {
- nxt = lp->next;
- if (LP_CREDIT == lp->type)
- {
- GNUNET_assert (lp ==
- GNUNET_CONTAINER_heap_remove_node (lp->hn));
- lp_trigger (lp,
- h);
- }
- }
- }
GNUNET_assert (0 ==
pthread_mutex_unlock (&h->big_lock));
if ( (NULL != old) &&
@@ -915,6 +887,54 @@ post_transaction (struct TALER_FAKEBANK_Handle *h,
/**
+ * Trigger long pollers that might have been waiting
+ * for @a t.
+ *
+ * @param h fakebank handle
+ * @param t transaction to notify on
+ */
+static void
+notify_transaction (struct TALER_FAKEBANK_Handle *h,
+ struct Transaction *t)
+{
+ struct Account *debit_acc = t->debit_account;
+ struct Account *credit_acc = t->credit_account;
+ struct LongPoller *nxt;
+
+ GNUNET_assert (0 ==
+ pthread_mutex_lock (&h->big_lock));
+ for (struct LongPoller *lp = debit_acc->lp_head;
+ NULL != lp;
+ lp = nxt)
+ {
+ nxt = lp->next;
+ if (LP_DEBIT == lp->type)
+ {
+ GNUNET_assert (lp ==
+ GNUNET_CONTAINER_heap_remove_node (lp->hn));
+ lp_trigger (lp,
+ h);
+ }
+ }
+ for (struct LongPoller *lp = credit_acc->lp_head;
+ NULL != lp;
+ lp = nxt)
+ {
+ nxt = lp->next;
+ if (LP_CREDIT == lp->type)
+ {
+ GNUNET_assert (lp ==
+ GNUNET_CONTAINER_heap_remove_node (lp->hn));
+ lp_trigger (lp,
+ h);
+ }
+ }
+ GNUNET_assert (0 ==
+ pthread_mutex_unlock (&h->big_lock));
+}
+
+
+/**
* Tell the fakebank to create another wire transfer *from* an exchange.
*
* @param h fake bank handle
@@ -1030,6 +1050,8 @@ make_transfer (
TALER_B2S (subject),
exchange_base_url);
*ret_row_id = t->row_id;
+ notify_transaction (h,
+ t);
return GNUNET_OK;
}
@@ -1124,11 +1146,13 @@ make_admin_transfer (
TALER_amount2s (amount),
TALER_B2S (reserve_pub),
(unsigned long long) t->row_id);
+ notify_transaction (h,
+ t);
return GNUNET_OK;
}
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h)
{
for (uint64_t i = 0; i<h->ram_limit; i++)
@@ -1852,6 +1876,7 @@ handle_debit_history (struct TALER_FAKEBANK_Handle *h,
connection,
&ha)))
{
+ GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
}
if (&special_ptr == *con_cls)
@@ -2056,13 +2081,15 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
enum GNUNET_GenericReturnValue ret;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
- "Handling /history/incoming connection %p\n",
- connection);
+ "Handling /history/incoming connection %p (%d)\n",
+ connection,
+ (*con_cls == &special_ptr));
if (GNUNET_OK !=
(ret = parse_history_common_args (h,
connection,
&ha)))
{
+ GNUNET_break_op (0);
return (GNUNET_SYSERR == ret) ? MHD_NO : MHD_YES;
}
if (&special_ptr == *con_cls)
@@ -2107,6 +2134,8 @@ handle_credit_history (struct TALER_FAKEBANK_Handle *h,
if ( (NULL == t) ||
overflow)
{
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "No transactions available, suspending request\n");
GNUNET_free (credit_payto);
if (GNUNET_TIME_relative_is_zero (ha.lp_timeout) &&
(0 < ha.delta))
@@ -2478,7 +2507,12 @@ run_mhd (void *cls)
struct TALER_FAKEBANK_Handle *h = cls;
h->mhd_task = NULL;
- MHD_run (h->mhd_bank);
+ h->mhd_again = true;
+ while (h->mhd_again)
+ {
+ h->mhd_again = false;
+ MHD_run (h->mhd_bank);
+ }
schedule_httpd (h);
}
diff --git a/src/bank-lib/test_bank.sh b/src/bank-lib/test_bank.sh
index 694fb82f..46be326b 100755
--- a/src/bank-lib/test_bank.sh
+++ b/src/bank-lib/test_bank.sh
@@ -2,6 +2,12 @@
set -eu
+# Exit, with status code "skip" (no 'real' failure)
+function exit_skip() {
+ echo $1
+ exit 77
+}
+
# Cleanup to run whenever we exit
function cleanup()
{
diff --git a/src/curl/curl.c b/src/curl/curl.c
index 1410294e..73fcf86a 100644
--- a/src/curl/curl.c
+++ b/src/curl/curl.c
@@ -37,7 +37,7 @@
* @param body JSON body to add to @e ctx
* @return #GNUNET_OK on success #GNUNET_SYSERR on failure
*/
-int
+enum GNUNET_GenericReturnValue
TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx,
CURL *eh,
const json_t *body)
diff --git a/src/exchange-tools/taler-exchange-dbinit.c b/src/exchange-tools/taler-exchange-dbinit.c
index b187cff3..acc37be8 100644
--- a/src/exchange-tools/taler-exchange-dbinit.c
+++ b/src/exchange-tools/taler-exchange-dbinit.c
@@ -128,7 +128,7 @@ run (void *cls,
*
* @param argc number of arguments from the command line
* @param argv command line arguments
- * @return 0 ok, 1 on error
+ * @return 0 ok, non-zero on error
*/
int
main (int argc,
diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am
index 1f53b012..7779c38b 100644
--- a/src/exchange/Makefile.am
+++ b/src/exchange/Makefile.am
@@ -83,6 +83,9 @@ taler_exchange_httpd_SOURCES = \
taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \
taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \
taler-exchange-httpd_keys.c taler-exchange-httpd_keys.h \
+ taler-exchange-httpd_kyc-check.c taler-exchange-httpd_kyc-check.h \
+ taler-exchange-httpd_kyc-proof.c taler-exchange-httpd_kyc-proof.h \
+ taler-exchange-httpd_kyc-wallet.c taler-exchange-httpd_kyc-wallet.h \
taler-exchange-httpd_link.c taler-exchange-httpd_link.h \
taler-exchange-httpd_management.h \
taler-exchange-httpd_management_auditors.c \
@@ -120,6 +123,7 @@ taler_exchange_httpd_LDADD = \
-lgnunetutil \
-lgnunetjson \
-ljansson \
+ -lcurl \
-lz \
$(XLIB)
diff --git a/src/exchange/exchange.conf b/src/exchange/exchange.conf
index c4115042..3bcea08f 100644
--- a/src/exchange/exchange.conf
+++ b/src/exchange/exchange.conf
@@ -77,9 +77,32 @@ TERMS_DIR = $DATADIR/exchange/tos/
# Etag / filename for the terms of service.
TERMS_ETAG = 0
-
# Directory with our privacy policy.
PRIVACY_DIR = $DATADIR/exchange/pp/
# Etag / filename for the privacy policy.
PRIVACY_ETAG = 0
+
+# Set to NONE to disable KYC checks.
+# Set to "OAUTH2" to use OAuth 2.0 for KYC authorization.
+KYC_MODE = NONE
+
+# Balance threshold above which wallets are told
+# to undergo a KYC check at the exchange. Optional,
+# if not given there is no limit.
+# KYC_WALLET_BALANCE_LIMIT = 150:CURRENCY
+
+[exchange-kyc-oauth2]
+
+# URL of the OAuth endpoint for KYC checks
+# KYC_OAUTH2_URL =
+
+# KYC Oauth client ID.
+# KYC_OAUTH2_CLIENT_ID =
+
+# KYC Client secret used to obtain access tokens.
+# KYC_OAUTH2_CLIENT_SECRET =
+
+# Where to redirect clients after successful
+# authorization?
+# KYC_OAUTH_POST_URL = https://bank.com/
diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c
index caa4528d..afedd7e3 100644
--- a/src/exchange/taler-exchange-aggregator.c
+++ b/src/exchange/taler-exchange-aggregator.c
@@ -144,7 +144,7 @@ static struct TALER_Amount currency_round_unit;
/**
* What is the base URL of this exchange? Used in the
- * wire transfer subjects to that merchants and governments
+ * wire transfer subjects so that merchants and governments
* can ask for the list of aggregated deposits.
*/
static char *exchange_base_url;
diff --git a/src/exchange/taler-exchange-closer.c b/src/exchange/taler-exchange-closer.c
index 19cc06c7..91ececc8 100644
--- a/src/exchange/taler-exchange-closer.c
+++ b/src/exchange/taler-exchange-closer.c
@@ -37,7 +37,7 @@ static struct TALER_Amount currency_round_unit;
/**
* What is the base URL of this exchange? Used in the
- * wire transfer subjects to that merchants and governments
+ * wire transfer subjects so that merchants and governments
* can ask for the list of aggregated deposits.
*/
static char *exchange_base_url;
diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c
index af0a4908..1feede1a 100644
--- a/src/exchange/taler-exchange-httpd.c
+++ b/src/exchange/taler-exchange-httpd.c
@@ -33,6 +33,9 @@
#include "taler-exchange-httpd_deposit.h"
#include "taler-exchange-httpd_deposits_get.h"
#include "taler-exchange-httpd_keys.h"
+#include "taler-exchange-httpd_kyc-check.h"
+#include "taler-exchange-httpd_kyc-proof.h"
+#include "taler-exchange-httpd_kyc-wallet.h"
#include "taler-exchange-httpd_link.h"
#include "taler-exchange-httpd_management.h"
#include "taler-exchange-httpd_melt.h"
@@ -69,6 +72,11 @@ int TEH_allow_keys_timetravel;
const struct GNUNET_CONFIGURATION_Handle *TEH_cfg;
/**
+ * Our KYC configuration.
+ */
+struct TEH_KycOptions TEH_kyc_config;
+
+/**
* How long is caching /keys allowed at most? (global)
*/
struct GNUNET_TIME_Relative TEH_max_keys_caching;
@@ -95,6 +103,11 @@ struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
char *TEH_currency;
/**
+ * Our base URL.
+ */
+char *TEH_base_url;
+
+/**
* Default timeout in seconds for HTTP requests.
*/
static unsigned int connection_timeout = 30;
@@ -126,6 +139,17 @@ static unsigned long long req_count;
*/
static unsigned long long req_max;
+/**
+ * Context for all CURL operations (useful to the event loop)
+ */
+struct GNUNET_CURL_Context *TEH_curl_ctx;
+
+/**
+ * Context for integrating #exchange_curl_ctx with the
+ * GNUnet event loop.
+ */
+static struct GNUNET_CURL_RescheduleContext *exchange_curl_rc;
+
/**
* Signature of functions that handle operations on coins.
@@ -827,6 +851,25 @@ handle_mhd_request (void *cls,
.handler.get = &TEH_handler_deposits_get,
.nargs = 4
},
+ /* KYC endpoints */
+ {
+ .url = "kyc-check",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler.get = &TEH_handler_kyc_check,
+ .nargs = 1
+ },
+ {
+ .url = "kyc-proof",
+ .method = MHD_HTTP_METHOD_GET,
+ .handler.get = &TEH_handler_kyc_proof,
+ .nargs = 1
+ },
+ {
+ .url = "kyc-wallet",
+ .method = MHD_HTTP_METHOD_POST,
+ .handler.post = &TEH_handler_kyc_wallet,
+ .nargs = 0
+ },
/* POST management endpoints */
{
.url = "management",
@@ -1071,6 +1114,129 @@ handle_mhd_request (void *cls,
/**
+ * Load general KYC configuration parameters for the exchange server into the
+ * #TEH_kyc_config variable.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+parse_kyc_settings (void)
+{
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (TEH_cfg,
+ "exchange",
+ "KYC_WITHDRAW_PERIOD",
+ &TEH_kyc_config.withdraw_period))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_WITHDRAW_PERIOD",
+ "valid relative time expected");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_TIME_relative_is_zero (TEH_kyc_config.withdraw_period))
+ return GNUNET_OK;
+ if (GNUNET_OK !=
+ TALER_config_get_amount (TEH_cfg,
+ "exchange",
+ "KYC_WITHDRAW_LIMIT",
+ &TEH_kyc_config.withdraw_limit))
+ return GNUNET_SYSERR;
+ if (0 != strcasecmp (TEH_kyc_config.withdraw_limit.currency,
+ TEH_currency))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_WITHDRAW_LIMIT",
+ "currency mismatch");
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Load OAuth2.0 configuration parameters for the exchange server into the
+ * #TEH_kyc_config variable.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+parse_kyc_oauth_cfg (void)
+{
+ char *s;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_URL",
+ &s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_URL");
+ return GNUNET_SYSERR;
+ }
+ if ( (! TALER_url_valid_charset (s)) ||
+ ( (0 != strncasecmp (s,
+ "http://",
+ strlen ("http://"))) &&
+ (0 != strncasecmp (s,
+ "https://",
+ strlen ("https://"))) ) )
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_URL",
+ "not a valid URL");
+ GNUNET_free (s);
+ return GNUNET_SYSERR;
+ }
+ TEH_kyc_config.details.oauth2.url = s;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_CLIENT_ID",
+ &s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_CLIENT_ID");
+ return GNUNET_SYSERR;
+ }
+ TEH_kyc_config.details.oauth2.client_id = s;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_CLIENT_SECRET",
+ &s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_CLIENT_SECRET");
+ return GNUNET_SYSERR;
+ }
+ TEH_kyc_config.details.oauth2.client_secret = s;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_POST_URL",
+ &s))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange-kyc-oauth2",
+ "KYC_OAUTH2_POST_URL");
+ return GNUNET_SYSERR;
+ }
+ TEH_kyc_config.details.oauth2.post_kyc_redirect_url = s;
+ return GNUNET_OK;
+}
+
+
+/**
* Load configuration parameters for the exchange
* server into the corresponding global variables.
*
@@ -1079,6 +1245,47 @@ handle_mhd_request (void *cls,
static enum GNUNET_GenericReturnValue
exchange_serve_process_config (void)
{
+ {
+ char *kyc_mode;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange",
+ "KYC_MODE",
+ &kyc_mode))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_MODE");
+ return GNUNET_SYSERR;
+ }
+ if (0 == strcasecmp (kyc_mode,
+ "NONE"))
+ {
+ TEH_kyc_config.mode = TEH_KYC_NONE;
+ }
+ else if (0 == strcasecmp (kyc_mode,
+ "OAUTH2"))
+ {
+ TEH_kyc_config.mode = TEH_KYC_OAUTH2;
+ if (GNUNET_OK !=
+ parse_kyc_oauth_cfg ())
+ {
+ GNUNET_free (kyc_mode);
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_MODE",
+ "Must be 'NONE' or 'OAUTH2'");
+ GNUNET_free (kyc_mode);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (kyc_mode);
+ }
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_number (TEH_cfg,
"exchange",
@@ -1123,6 +1330,55 @@ exchange_serve_process_config (void)
"CURRENCY");
return GNUNET_SYSERR;
}
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (TEH_cfg,
+ "exchange",
+ "BASE_URL",
+ &TEH_base_url))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL");
+ return GNUNET_SYSERR;
+ }
+ if (! TALER_url_valid_charset (TEH_base_url))
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "BASE_URL",
+ "invalid URL");
+ return GNUNET_SYSERR;
+ }
+
+ if (TEH_KYC_NONE != TEH_kyc_config.mode)
+ {
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_have_value (TEH_cfg,
+ "exchange",
+ "KYC_WALLET_BALANCE_LIMIT"))
+ {
+ if ( (GNUNET_OK !=
+ TALER_config_get_amount (TEH_cfg,
+ "exchange",
+ "KYC_WALLET_BALANCE_LIMIT",
+ &TEH_kyc_config.wallet_balance_limit)) ||
+ (0 != strcasecmp (TEH_currency,
+ TEH_kyc_config.wallet_balance_limit.currency)) )
+ {
+ GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
+ "exchange",
+ "KYC_WALLET_BALANCE_LIMIT",
+ "valid amount expected");
+ return GNUNET_SYSERR;
+ }
+ }
+ else
+ {
+ memset (&TEH_kyc_config.wallet_balance_limit,
+ 0,
+ sizeof (TEH_kyc_config.wallet_balance_limit));
+ }
+ }
{
char *master_public_key_str;
@@ -1151,6 +1407,12 @@ exchange_serve_process_config (void)
}
GNUNET_free (master_public_key_str);
}
+ if (TEH_KYC_NONE != TEH_kyc_config.mode)
+ {
+ if (GNUNET_OK !=
+ parse_kyc_settings ())
+ return GNUNET_SYSERR;
+ }
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Launching exchange with public key `%s'...\n",
GNUNET_p2s (&TEH_master_public_key.eddsa_pub));
@@ -1380,11 +1642,26 @@ do_shutdown (void *cls)
mhd = TALER_MHD_daemon_stop ();
TEH_resume_keys_requests (true);
TEH_reserves_get_cleanup ();
+ TEH_kyc_proof_cleanup ();
if (NULL != mhd)
MHD_stop_daemon (mhd);
TEH_WIRE_done ();
TEH_keys_finished ();
- TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
+ if (NULL != TEH_plugin)
+ {
+ TALER_EXCHANGEDB_plugin_unload (TEH_plugin);
+ TEH_plugin = NULL;
+ }
+ if (NULL != TEH_curl_ctx)
+ {
+ GNUNET_CURL_fini (TEH_curl_ctx);
+ TEH_curl_ctx = NULL;
+ }
+ if (NULL != exchange_curl_rc)
+ {
+ GNUNET_CURL_gnunet_rc_destroy (exchange_curl_rc);
+ exchange_curl_rc = NULL;
+ }
}
@@ -1442,6 +1719,17 @@ run (void *cls,
}
TEH_load_terms (TEH_cfg);
+ TEH_curl_ctx
+ = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
+ &exchange_curl_rc);
+ if (NULL == TEH_curl_ctx)
+ {
+ GNUNET_break (0);
+ global_ret = EXIT_FAILURE;
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ exchange_curl_rc = GNUNET_CURL_gnunet_rc_create (TEH_curl_ctx);
GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
NULL);
fh = TALER_MHD_bind (TEH_cfg,
@@ -1534,7 +1822,6 @@ main (int argc,
#endif
GNUNET_GETOPT_option_help (
"HTTP server providing a RESTful API to access a Taler exchange"),
- GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
GNUNET_GETOPT_OPTION_END
};
enum GNUNET_GenericReturnValue ret;
diff --git a/src/exchange/taler-exchange-httpd.h b/src/exchange/taler-exchange-httpd.h
index e4342648..f66626b3 100644
--- a/src/exchange/taler-exchange-httpd.h
+++ b/src/exchange/taler-exchange-httpd.h
@@ -30,6 +30,96 @@
/**
+ * Enumeration for our KYC modes.
+ */
+enum TEH_KycMode
+{
+ /**
+ * KYC is disabled.
+ */
+ TEH_KYC_NONE = 0,
+
+ /**
+ * We use Oauth2.0.
+ */
+ TEH_KYC_OAUTH2 = 1
+};
+
+
+/**
+ * Structure describing our KYC configuration.
+ */
+struct TEH_KycOptions
+{
+ /**
+ * What KYC mode are we in?
+ */
+ enum TEH_KycMode mode;
+
+ /**
+ * Maximum amount that can be withdrawn in @e withdraw_period without
+ * needing KYC.
+ * Only valid if @e mode is not #TEH_KYC_NONE and
+ * if @e withdraw_period is non-zero.
+ */
+ struct TALER_Amount withdraw_limit;
+
+ /**
+ * Maximum balance a wallet can hold without
+ * needing KYC.
+ * Only valid if @e mode is not #TEH_KYC_NONE and
+ * if the amount specified is valid.
+ */
+ struct TALER_Amount wallet_balance_limit;
+
+ /**
+ * Time period over which @e withdraw_limit applies.
+ * Only valid if @e mode is not #TEH_KYC_NONE.
+ */
+ struct GNUNET_TIME_Relative withdraw_period;
+
+ /**
+ * Details depending on @e mode.
+ */
+ union
+ {
+
+ /**
+ * Configuration details if @e mode is #TEH_KYC_OAUTH2.
+ */
+ struct
+ {
+
+ /**
+ * URL of tue OAuth2.0 endpoint for KYC checks.
+ */
+ char *url;
+
+ /**
+ * Our client ID for OAuth2.0.
+ */
+ char *client_id;
+
+ /**
+ * Our client secret for OAuth2.0.
+ */
+ char *client_secret;
+
+ /**
+ * Where to redirect clients after the
+ * Web-based KYC process is done?
+ */
+ char *post_kyc_redirect_url;
+
+ } oauth2;
+
+ } details;
+};
+
+
+extern struct TEH_KycOptions TEH_kyc_config;
+
+/**
* How long is caching /keys allowed at most?
*/
extern struct GNUNET_TIME_Relative TEH_max_keys_caching;
@@ -79,10 +169,19 @@ extern struct TALER_EXCHANGEDB_Plugin *TEH_plugin;
extern char *TEH_currency;
/**
+ * Our (externally visible) base URL.
+ */
+extern char *TEH_base_url;
+
+/**
* Are we shutting down?
*/
extern volatile bool MHD_terminating;
+/**
+ * Context for all CURL operations (useful to the event loop)
+ */
+extern struct GNUNET_CURL_Context *TEH_curl_ctx;
/**
* @brief Struct describing an URL and the handler for it.
diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c
index 9c4cfdc7..38dfd447 100644
--- a/src/exchange/taler-exchange-httpd_deposit.c
+++ b/src/exchange/taler-exchange-httpd_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -121,6 +121,10 @@ struct DepositContext
*/
struct TALER_Amount value;
+ /**
+ * payto:// URI of the credited account.
+ */
+ char *payto_uri;
};
@@ -158,7 +162,7 @@ deposit_precheck (void *cls,
*mhd_ret = TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_DB_FETCH_FAILED,
- NULL);
+ "have_deposit");
return GNUNET_DB_STATUS_HARD_ERROR;
}
return qs;
@@ -218,7 +222,6 @@ deposit_transaction (void *cls,
mhd_ret);
if (qs < 0)
return qs;
-
/* Theoretically, someone other threat may have received
and committed the deposit in the meantime. Check now
that we are in the transaction scope. */
@@ -351,7 +354,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
sizeof (deposit));
deposit.coin.coin_pub = *coin_pub;
{
- int res;
+ enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_data (connection,
root,
@@ -369,11 +372,10 @@ TEH_handler_deposit (struct MHD_Connection *connection,
}
/* validate merchant's wire details (as far as we can) */
{
- char *payto;
char *emsg;
- payto = TALER_JSON_wire_to_payto (wire);
- if (NULL == payto)
+ dc.payto_uri = TALER_JSON_wire_to_payto (wire);
+ if (NULL == dc.payto_uri)
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
@@ -382,8 +384,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"wire");
}
- emsg = TALER_payto_validate (payto);
- GNUNET_free (payto);
+ emsg = TALER_payto_validate (dc.payto_uri);
if (NULL != emsg)
{
MHD_RESULT ret;
@@ -395,6 +396,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
emsg);
GNUNET_free (emsg);
+ GNUNET_free (dc.payto_uri);
return ret;
}
}
@@ -403,6 +405,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE,
@@ -415,6 +418,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_LOG_WARNING (
"Failed to parse JSON wire format specification for /deposit request\n");
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_JSON,
@@ -425,6 +429,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{
/* Client hashed wire details differently than we did, reject */
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_INVALID_WIRE_FORMAT_CONTRACT_HASH_CONFLICT,
@@ -444,6 +449,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&dc))
{
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return mhd_ret;
}
}
@@ -462,6 +468,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
if (NULL == dk)
{
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return mret;
}
if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit))
@@ -472,6 +479,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection,
&deposit.coin.denom_pub_hash,
@@ -487,6 +495,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection,
&deposit.coin.denom_pub_hash,
@@ -502,6 +511,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
(void) GNUNET_TIME_round_abs (&now);
/* This denomination has been revoked */
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TEH_RESPONSE_reply_expired_denom_pub_hash (
connection,
&deposit.coin.denom_pub_hash,
@@ -518,6 +528,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{
TALER_LOG_WARNING ("Invalid coin passed for /deposit\n");
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_UNAUTHORIZED,
TALER_EC_EXCHANGE_DENOMINATION_SIGNATURE_INVALID,
@@ -530,6 +541,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE,
@@ -562,6 +574,7 @@ TEH_handler_deposit (struct MHD_Connection *connection,
{
TALER_LOG_WARNING ("Invalid signature on /deposit request\n");
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_UNAUTHORIZED,
TALER_EC_EXCHANGE_DEPOSIT_COIN_SIGNATURE_INVALID,
@@ -581,9 +594,11 @@ TEH_handler_deposit (struct MHD_Connection *connection,
&dc))
{
GNUNET_JSON_parse_free (spec);
+ GNUNET_free (dc.payto_uri);
return mhd_ret;
}
}
+ GNUNET_free (dc.payto_uri);
/* generate regular response */
{
diff --git a/src/exchange/taler-exchange-httpd_deposits_get.c b/src/exchange/taler-exchange-httpd_deposits_get.c
index 04e2acb0..2423cc96 100644
--- a/src/exchange/taler-exchange-httpd_deposits_get.c
+++ b/src/exchange/taler-exchange-httpd_deposits_get.c
@@ -137,61 +137,20 @@ struct DepositWtidContext
struct TALER_Amount coin_delta;
/**
+ * KYC status information for the receiving account.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ /**
* Set to #GNUNET_YES by #handle_wtid if the wire transfer is still pending
* (and the above were not set).
* Set to #GNUNET_SYSERR if there was a serious error.
*/
- int pending;
+ enum GNUNET_GenericReturnValue pending;
};
/**
- * Function called with the results of the lookup of the
- * wire transfer identifier information.
- *
- * @param cls our context for transmission, a `struct DepositWtidContext *`
- * @param wtid raw wire transfer identifier, NULL
- * if the transaction was not yet done
- * @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value including fee)
- * @param coin_fee how much did the exchange charge for the deposit fee
- * @param execution_time when was the transaction done, or
- * when we expect it to be done (if @a wtid was NULL);
- * #GNUNET_TIME_UNIT_FOREVER_ABS if the /deposit is unknown
- * to the exchange
- */
-static void
-handle_wtid_data (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- struct DepositWtidContext *ctx = cls;
-
- if (NULL == wtid)
- {
- ctx->pending = GNUNET_YES;
- ctx->execution_time = execution_time;
- return;
- }
- if (0 >
- TALER_amount_subtract (&ctx->coin_delta,
- coin_contribution,
- coin_fee))
- {
- GNUNET_break (0);
- ctx->pending = GNUNET_SYSERR;
- return;
- }
- ctx->wtid = *wtid;
- ctx->execution_time = execution_time;
- ctx->coin_contribution = *coin_contribution;
- ctx->coin_fee = *coin_fee;
-}
-
-
-/**
* Execute a "deposits" GET. Returns the transfer information
* associated with the given deposit.
*
@@ -214,14 +173,21 @@ deposits_get_transaction (void *cls,
{
struct DepositWtidContext *ctx = cls;
enum GNUNET_DB_QueryStatus qs;
+ bool pending;
+ struct TALER_Amount fee;
qs = TEH_plugin->lookup_transfer_by_deposit (TEH_plugin->cls,
&ctx->tps->h_contract_terms,
&ctx->tps->h_wire,
&ctx->tps->coin_pub,
ctx->merchant_pub,
- &handle_wtid_data,
- ctx);
+
+ &pending,
+ &ctx->wtid,
+ &ctx->execution_time,
+ &ctx->coin_contribution,
+ &fee,
+ &ctx->kyc);
if (0 > qs)
{
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -242,6 +208,17 @@ deposits_get_transaction (void *cls,
NULL);
return GNUNET_DB_STATUS_HARD_ERROR;
}
+
+ if (0 >
+ TALER_amount_subtract (&ctx->coin_delta,
+ &ctx->coin_contribution,
+ &fee))
+ {
+ GNUNET_break (0);
+ ctx->pending = GNUNET_SYSERR;
+ return qs;
+ }
+ ctx->pending = (pending) ? GNUNET_YES : GNUNET_NO;
return qs;
}
@@ -262,7 +239,6 @@ handle_track_transaction_request (
{
MHD_RESULT mhd_ret;
struct DepositWtidContext ctx = {
- .pending = GNUNET_NO,
.tps = tps,
.merchant_pub = merchant_pub
};
@@ -274,17 +250,21 @@ handle_track_transaction_request (
&deposits_get_transaction,
&ctx))
return mhd_ret;
+ if (GNUNET_SYSERR == ctx.pending)
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
+ "wire fees exceed aggregate in database");
if (GNUNET_YES == ctx.pending)
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_ACCEPTED,
+ GNUNET_JSON_pack_uint64 ("payment_target_uuid",
+ ctx.kyc.payment_target_uuid),
+ GNUNET_JSON_pack_bool ("kyc_ok",
+ ctx.kyc.ok),
GNUNET_JSON_pack_time_abs ("execution_time",
ctx.execution_time));
- if (GNUNET_SYSERR == ctx.pending)
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_GENERIC_DB_INVARIANT_FAILURE,
- "wire fees exceed aggregate in database");
return reply_deposit_details (connection,
&tps->h_contract_terms,
&tps->h_wire,
diff --git a/src/exchange/taler-exchange-httpd_keys.c b/src/exchange/taler-exchange-httpd_keys.c
index 72c2de12..70590020 100644
--- a/src/exchange/taler-exchange-httpd_keys.c
+++ b/src/exchange/taler-exchange-httpd_keys.c
@@ -1345,7 +1345,7 @@ get_date_string (struct GNUNET_TIME_Absolute at,
* @param[in,out] response the response to modify
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
setup_general_response_headers (const struct TEH_KeyStateHandle *ksh,
struct MHD_Response *response)
{
@@ -1473,6 +1473,18 @@ create_krd (struct TEH_KeyStateHandle *ksh,
GNUNET_JSON_pack_data_auto ("eddsa_sig",
&exchange_sig));
GNUNET_assert (NULL != keys);
+ if ( (TEH_KYC_NONE != TEH_kyc_config.mode) &&
+ (GNUNET_OK ==
+ TALER_amount_is_valid (&TEH_kyc_config.wallet_balance_limit)) )
+ {
+ GNUNET_assert (
+ 0 ==
+ json_object_set_new (
+ keys,
+ "wallet_balance_limit_without_kyc",
+ TALER_JSON_from_amount (
+ &TEH_kyc_config.wallet_balance_limit)));
+ }
{
char *keys_json;
@@ -2504,6 +2516,21 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
.signkeys = json_array ()
};
+ if (GNUNET_is_zero (&denom_sm_pub))
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_GATEWAY,
+ TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE,
+ NULL);
+ }
+ if (GNUNET_is_zero (&esign_sm_pub))
+ {
+ return TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_BAD_GATEWAY,
+ TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE,
+ NULL);
+ }
+ // then a secmod helper is not yet running and we should return an MHD_HTTP_BAD_GATEWAY!
GNUNET_assert (NULL != fbc.denoms);
GNUNET_assert (NULL != fbc.signkeys);
GNUNET_CONTAINER_multihashmap_iterate (ksh->helpers->denom_keys,
diff --git a/src/exchange/taler-exchange-httpd_kyc-check.c b/src/exchange/taler-exchange-httpd_kyc-check.c
new file mode 100644
index 00000000..ae1ab34f
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-check.c
@@ -0,0 +1,207 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-check.c
+ * @brief Handle request for generic KYC check.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler_signatures.h"
+#include "taler-exchange-httpd_keys.h"
+#include "taler-exchange-httpd_kyc-wallet.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Context for the request.
+ */
+struct KycCheckContext
+{
+ /**
+ * UUID being checked.
+ */
+ uint64_t payment_target_uuid;
+
+ /**
+ * Current KYC status.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ /**
+ * Hash of the payto:// URI we are confirming to
+ * have finished the KYC for.
+ */
+ struct GNUNET_HashCode h_payto;
+};
+
+
+/**
+ * Function implementing database transaction to check wallet's KYC status.
+ * Runs the transaction logic; 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. IF it
+ * returns the soft error code, the function MAY be called again to retry and
+ * MUST not queue a MHD response.
+ *
+ * @param cls closure with a `struct KycCheckContext *`
+ * @param connection MHD request which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+kyc_check (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+ struct KycCheckContext *kcc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = TEH_plugin->select_kyc_status (TEH_plugin->cls,
+ kcc->payment_target_uuid,
+ &kcc->h_payto,
+ &kcc->kyc);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "inselect_wallet_status");
+ return qs;
+ }
+ return qs;
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_check (
+ struct TEH_RequestContext *rc,
+ const char *const args[])
+{
+ unsigned long long payment_target_uuid;
+ MHD_RESULT res;
+ enum GNUNET_GenericReturnValue ret;
+ char dummy;
+
+ if (1 !=
+ sscanf (args[0],
+ "%llu%c",
+ &payment_target_uuid,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "payment_target_uuid");
+ }
+
+ if (TEH_KYC_NONE == TEH_kyc_config.mode)
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ {
+ struct GNUNET_TIME_Absolute now;
+ struct KycCheckContext kcc = {
+ .payment_target_uuid = payment_target_uuid
+ };
+
+ now = GNUNET_TIME_absolute_get ();
+ (void) GNUNET_TIME_round_abs (&now);
+ ret = TEH_DB_run_transaction (rc->connection,
+ "kyc check",
+ &res,
+ &kyc_check,
+ &kcc);
+ if (GNUNET_SYSERR == ret)
+ return res;
+ if (! kcc.kyc.ok)
+ {
+ char *url;
+ char *redirect_uri;
+ char *redirect_uri_encoded;
+
+ GNUNET_assert (TEH_KYC_OAUTH2 == TEH_kyc_config.mode);
+ GNUNET_asprintf (&redirect_uri,
+ "%s/kyc-proof/%llu",
+ TEH_base_url,
+ payment_target_uuid);
+ redirect_uri_encoded = TALER_urlencode (redirect_uri);
+ GNUNET_free (redirect_uri);
+ GNUNET_asprintf (&url,
+ "%s/login?client_id=%s&redirect_uri=%s",
+ TEH_kyc_config.details.oauth2.url,
+ TEH_kyc_config.details.oauth2.client_id,
+ redirect_uri_encoded);
+ GNUNET_free (redirect_uri_encoded);
+
+ res = TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_ACCEPTED,
+ GNUNET_JSON_pack_string ("kyc_url",
+ url));
+ GNUNET_free (url);
+ return res;
+ }
+ {
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+ struct TALER_ExchangeAccountSetupSuccessPS as = {
+ .purpose.purpose = htonl (
+ TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
+ .purpose.size = htonl (sizeof (as)),
+ .h_payto = kcc.h_payto,
+ .timestamp = GNUNET_TIME_absolute_hton (now)
+ };
+ enum TALER_ErrorCode ec;
+
+ if (TALER_EC_NONE !=
+ (ec = TEH_keys_exchange_sign (&as,
+ &pub,
+ &sig)))
+ {
+ return TALER_MHD_reply_with_ec (rc->connection,
+ ec,
+ NULL);
+ }
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_data_auto ("exchange_sig",
+ &sig),
+ GNUNET_JSON_pack_data_auto ("exchange_pub",
+ &pub),
+ GNUNET_JSON_pack_time_abs ("now",
+ now));
+ }
+ }
+}
+
+
+/* end of taler-exchange-httpd_kyc-check.c */
diff --git a/src/exchange/taler-exchange-httpd_kyc-check.h b/src/exchange/taler-exchange-httpd_kyc-check.h
new file mode 100644
index 00000000..8120a173
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-check.h
@@ -0,0 +1,42 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-check.h
+ * @brief Handle /kyc-check requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_KYC_CHECK_H
+#define TALER_EXCHANGE_HTTPD_KYC_CHECK_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/kyc-check" request. Checks the KYC
+ * status of the given account and returns it.
+ *
+ * @param connection request to handle
+ * @param args one argument with the payment_target_uuid
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_kyc_check (
+ struct TEH_RequestContext *rc,
+ const char *const args[]);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.c b/src/exchange/taler-exchange-httpd_kyc-proof.c
new file mode 100644
index 00000000..842e5dfd
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.c
@@ -0,0 +1,519 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-proof.c
+ * @brief Handle request for proof for KYC check.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_kyc-proof.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Context for the proof.
+ */
+struct KycProofContext
+{
+
+ /**
+ * Kept in a DLL while suspended.
+ */
+ struct KycProofContext *next;
+
+ /**
+ * Kept in a DLL while suspended.
+ */
+ struct KycProofContext *prev;
+
+ /**
+ * Details about the connection we are processing.
+ */
+ struct TEH_RequestContext *rc;
+
+ /**
+ * Handle for the OAuth 2.0 CURL request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * OAuth 2.0 authorization code.
+ */
+ const char *authorization_code;
+
+ /**
+ * OAuth 2.0 token URL we are using for the
+ * request.
+ */
+ char *token_url;
+
+ /**
+ * Body of the POST request.
+ */
+ char *post_body;
+
+ /**
+ * Payment target this is about.
+ */
+ unsigned long long payment_target_uuid;
+
+ /**
+ * HTTP response to return.
+ */
+ struct MHD_Response *response;
+
+ /**
+ * HTTP response code to return.
+ */
+ unsigned int response_code;
+
+ /**
+ * #GNUNET_YES if we are suspended,
+ * #GNUNET_NO if not.
+ * #GNUNET_SYSERR if we had some error.
+ */
+ enum GNUNET_GenericReturnValue suspended;
+
+};
+
+
+/**
+ * Contexts are kept in a DLL while suspended.
+ */
+static struct KycProofContext *kpc_head;
+
+/**
+ * Contexts are kept in a DLL while suspended.
+ */
+static struct KycProofContext *kpc_tail;
+
+
+void
+TEH_kyc_proof_cleanup (void)
+{
+ struct KycProofContext *kpc;
+
+ while (NULL != (kpc = kpc_head))
+ {
+ if (NULL != kpc->job)
+ {
+ GNUNET_CURL_job_cancel (kpc->job);
+ kpc->job = NULL;
+ }
+ GNUNET_CONTAINER_DLL_remove (kpc_head,
+ kpc_tail,
+ kpc);
+ kpc->suspended = GNUNET_NO;
+ MHD_resume_connection (kpc->rc->connection);
+ }
+}
+
+
+/**
+ * Function implementing database transaction to check proof's KYC status.
+ * Runs the transaction logic; 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. IF it
+ * returns the soft error code, the function MAY be called again to retry and
+ * MUST not queue a MHD response.
+ *
+ * @param cls closure with a `struct KycProofContext *`
+ * @param connection MHD proof which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+persist_kyc_ok (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+ struct KycProofContext *kpc = cls;
+
+ return TEH_plugin->set_kyc_ok (TEH_plugin->cls,
+ kpc->payment_target_uuid);
+}
+
+
+/**
+ * After we are done with the CURL interaction we
+ * need to update our database state.
+ *
+ * @param cls our `struct KycProofContext`
+ * @param response_code HTTP response code from server, 0 on hard error
+ * @param response in JSON, NULL if response was not in JSON format
+ */
+static void
+handle_curl_login_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct KycProofContext *kpc = cls;
+ const json_t *j = response;
+
+ kpc->job = NULL;
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ const char *access_token;
+ const char *token_type;
+ uint64_t expires_in_s;
+ const char *refresh_token;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("access_token",
+ &access_token),
+ GNUNET_JSON_spec_string ("token_type",
+ &token_type),
+ GNUNET_JSON_spec_uint64 ("expires_in",
+ &expires_in_s),
+ GNUNET_JSON_spec_string ("refresh_token",
+ &refresh_token),
+ GNUNET_JSON_spec_end ()
+ };
+
+ {
+ enum GNUNET_GenericReturnValue res;
+ const char *emsg;
+ unsigned int line;
+
+ res = GNUNET_JSON_parse (j,
+ spec,
+ &emsg,
+ &line);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ MHD_resume_connection (kpc->rc->connection);
+ TALER_MHD_daemon_trigger ();
+ return;
+ }
+ }
+ if (0 != strcasecmp (token_type,
+ "bearer"))
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected token type in response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ MHD_resume_connection (kpc->rc->connection);
+ TALER_MHD_daemon_trigger ();
+ return;
+ }
+
+ /* TODO: Here we might want to keep something to persist in the DB, and
+ possibly use the access_token to download information we should
+ persist; then continue! */
+
+ MHD_resume_connection (kpc->rc->connection);
+ TALER_MHD_daemon_trigger ();
+ return;
+ }
+ default:
+ {
+ const char *msg;
+ const char *desc;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("error",
+ &msg),
+ GNUNET_JSON_spec_string ("error_description",
+ &desc),
+ GNUNET_JSON_spec_end ()
+ };
+
+ {
+ enum GNUNET_GenericReturnValue res;
+ const char *emsg;
+ unsigned int line;
+
+ res = GNUNET_JSON_parse (j,
+ spec,
+ &emsg,
+ &line);
+ if (GNUNET_OK != res)
+ {
+ GNUNET_break_op (0);
+ kpc->response
+ = TALER_MHD_make_error (
+ TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_INVALID_RESPONSE,
+ "Unexpected response from KYC gateway");
+ kpc->response_code
+ = MHD_HTTP_BAD_GATEWAY;
+ MHD_resume_connection (kpc->rc->connection);
+ TALER_MHD_daemon_trigger ();
+ return;
+ }
+ }
+ /* case TALER_EC_EXCHANGE_KYC_PROOF_BACKEND_AUTHORZATION_FAILED,
+ we MAY want to in the future look at the requested content type
+ and possibly respond in JSON if indicated. */
+ {
+ char *reply;
+
+ GNUNET_asprintf (&reply,
+ "<html><head><title>%s</title></head><body><h1>%s</h1><p>%s</p></body></html>",
+ msg,
+ msg,
+ desc);
+ kpc->response
+ = MHD_create_response_from_buffer (strlen (reply),
+ reply,
+ MHD_RESPMEM_MUST_COPY);
+ GNUNET_assert (NULL != kpc->response);
+ GNUNET_free (reply);
+ }
+ kpc->response_code = MHD_HTTP_FORBIDDEN;
+ MHD_resume_connection (kpc->rc->connection);
+ TALER_MHD_daemon_trigger ();
+ }
+ break;
+ }
+}
+
+
+/**
+ * Function called to clean up a context.
+ *
+ * @param rc request context
+ */
+static void
+clean_kpc (struct TEH_RequestContext *rc)
+{
+ struct KycProofContext *kpc = rc->rh_ctx;
+
+ if (NULL != kpc->job)
+ {
+ GNUNET_CURL_job_cancel (kpc->job);
+ kpc->job = NULL;
+ }
+ if (NULL != kpc->response)
+ {
+ MHD_destroy_response (kpc->response);
+ kpc->response = NULL;
+ }
+ GNUNET_free (kpc->post_body);
+ GNUNET_free (kpc->token_url);
+ GNUNET_free (kpc);
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_proof (
+ struct TEH_RequestContext *rc,
+ const char *const args[])
+{
+ struct KycProofContext *kpc = rc->rh_ctx;
+
+ if (NULL == kpc)
+ { /* first time */
+ char dummy;
+
+ kpc = GNUNET_new (struct KycProofContext);
+ kpc->rc = rc;
+ rc->rh_ctx = kpc;
+ rc->rh_cleaner = &clean_kpc;
+
+ if (1 !=
+ sscanf (args[0],
+ "%llu%c",
+ &kpc->payment_target_uuid,
+ &dummy))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "payment_target_uuid");
+ }
+ kpc->authorization_code
+ = MHD_lookup_connection_value (rc->connection,
+ MHD_GET_ARGUMENT_KIND,
+ "code");
+ if (NULL == kpc->authorization_code)
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_BAD_REQUEST,
+ TALER_EC_GENERIC_PARAMETER_MALFORMED,
+ "code");
+ }
+ if (TEH_KYC_NONE == TEH_kyc_config.mode)
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+
+ {
+ CURL *eh;
+
+ eh = curl_easy_init ();
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ return TALER_MHD_reply_with_error (rc->connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_ALLOCATION_FAILURE,
+ "curl_easy_init");
+ }
+ GNUNET_asprintf (&kpc->token_url,
+ "%s/token",
+ TEH_kyc_config.details.oauth2.url);
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ kpc->token_url));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POST,
+ 1));
+ {
+ char *client_id;
+ char *redirect_uri;
+ char *client_secret;
+ char *authorization_code;
+
+ client_id = curl_easy_escape (eh,
+ TEH_kyc_config.details.oauth2.client_id,
+ 0);
+ GNUNET_assert (NULL != client_id);
+ {
+ char *request_uri;
+
+ GNUNET_asprintf (&request_uri,
+ "%s/login?client_id=%s",
+ TEH_kyc_config.details.oauth2.url,
+ TEH_kyc_config.details.oauth2.client_id);
+ redirect_uri = curl_easy_escape (eh,
+ request_uri,
+ 0);
+ GNUNET_free (request_uri);
+ }
+ GNUNET_assert (NULL != redirect_uri);
+ client_secret = curl_easy_escape (eh,
+ TEH_kyc_config.details.oauth2.
+ client_secret,
+ 0);
+ GNUNET_assert (NULL != client_secret);
+ authorization_code = curl_easy_escape (eh,
+ kpc->authorization_code,
+ 0);
+ GNUNET_assert (NULL != authorization_code);
+ GNUNET_asprintf (&kpc->post_body,
+ "client_id=%s&redirect_uri=%s&client_secret=%s&code=%s&grant_type=authorization_code",
+ client_id,
+ redirect_uri,
+ client_secret,
+ authorization_code);
+ curl_free (authorization_code);
+ curl_free (client_secret);
+ curl_free (redirect_uri);
+ curl_free (client_id);
+ }
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_POSTFIELDS,
+ kpc->post_body));
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_FOLLOWLOCATION,
+ 1L));
+ /* limit MAXREDIRS to 5 as a simple security measure against
+ a potential infinite loop caused by a malicious target */
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_MAXREDIRS,
+ 5L));
+
+ kpc->job = GNUNET_CURL_job_add (TEH_curl_ctx,
+ eh,
+ &handle_curl_login_finished,
+ kpc);
+ kpc->suspended = GNUNET_YES;
+ GNUNET_CONTAINER_DLL_insert (kpc_head,
+ kpc_tail,
+ kpc);
+ MHD_suspend_connection (rc->connection);
+ return MHD_YES;
+ }
+ }
+
+ if (NULL != kpc->response)
+ {
+ /* handle _failed_ resumed cases */
+ return MHD_queue_response (rc->connection,
+ kpc->response_code,
+ kpc->response);
+ }
+
+ /* _successfully_ resumed case */
+ {
+ MHD_RESULT res;
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = TEH_DB_run_transaction (kpc->rc->connection,
+ "check proof kyc",
+ &res,
+ &persist_kyc_ok,
+ kpc);
+ if (GNUNET_SYSERR == ret)
+ return res;
+ }
+
+ {
+ struct MHD_Response *response;
+ MHD_RESULT res;
+
+ response = MHD_create_response_from_buffer (0,
+ "",
+ MHD_RESPMEM_PERSISTENT);
+ if (NULL == response)
+ {
+ GNUNET_break (0);
+ return MHD_NO;
+ }
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (
+ response,
+ MHD_HTTP_HEADER_LOCATION,
+ TEH_kyc_config.details.oauth2.post_kyc_redirect_url));
+ res = MHD_queue_response (rc->connection,
+ MHD_HTTP_SEE_OTHER,
+ response);
+ MHD_destroy_response (response);
+ return res;
+ }
+}
+
+
+/* end of taler-exchange-httpd_kyc-proof.c */
diff --git a/src/exchange/taler-exchange-httpd_kyc-proof.h b/src/exchange/taler-exchange-httpd_kyc-proof.h
new file mode 100644
index 00000000..c075b242
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-proof.h
@@ -0,0 +1,49 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-proof.h
+ * @brief Handle /kyc-proof requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_KYC_PROOF_H
+#define TALER_EXCHANGE_HTTPD_KYC_PROOF_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Shutdown kyc-proof subsystem. Resumes all suspended long-polling clients
+ * and cleans up data structures.
+ */
+void
+TEH_kyc_proof_cleanup (void);
+
+
+/**
+ * Handle a "/kyc-proof" request.
+ *
+ * @param rc request to handle
+ * @param args one argument with the payment_target_uuid
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_kyc_proof (
+ struct TEH_RequestContext *rc,
+ const char *const args[]);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.c b/src/exchange/taler-exchange-httpd_kyc-wallet.c
new file mode 100644
index 00000000..dcab3dca
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-wallet.c
@@ -0,0 +1,155 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-wallet.c
+ * @brief Handle request for wallet for KYC check.
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <microhttpd.h>
+#include <pthread.h>
+#include "taler_json_lib.h"
+#include "taler_mhd_lib.h"
+#include "taler-exchange-httpd_kyc-wallet.h"
+#include "taler-exchange-httpd_responses.h"
+
+
+/**
+ * Context for the request.
+ */
+struct KycRequestContext
+{
+ /**
+ * Public key of the reserve/wallet this is about.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Current KYC status.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+};
+
+
+/**
+ * Function implementing database transaction to check wallet's KYC status.
+ * Runs the transaction logic; 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. IF it
+ * returns the soft error code, the function MAY be called again to retry and
+ * MUST not queue a MHD response.
+ *
+ * @param cls closure with a `struct KycRequestContext *`
+ * @param connection MHD request which triggered the transaction
+ * @param[out] mhd_ret set to MHD response status for @a connection,
+ * if transaction failed (!)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+wallet_kyc_check (void *cls,
+ struct MHD_Connection *connection,
+ MHD_RESULT *mhd_ret)
+{
+ struct KycRequestContext *krc = cls;
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = TEH_plugin->inselect_wallet_kyc_status (TEH_plugin->cls,
+ &krc->reserve_pub,
+ &krc->kyc);
+ if (qs < 0)
+ {
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ return qs;
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "inselect_wallet_status");
+ return qs;
+ }
+ return qs;
+}
+
+
+MHD_RESULT
+TEH_handler_kyc_wallet (
+ struct TEH_RequestContext *rc,
+ const json_t *root,
+ const char *const args[])
+{
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct KycRequestContext krc;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("reserve_sig",
+ &reserve_sig),
+ GNUNET_JSON_spec_fixed_auto ("reserve_pub",
+ &krc.reserve_pub),
+ GNUNET_JSON_spec_end ()
+ };
+ MHD_RESULT res;
+ enum GNUNET_GenericReturnValue ret;
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP)
+ };
+
+ ret = TALER_MHD_parse_json_data (rc->connection,
+ root,
+ spec);
+ if (GNUNET_SYSERR == ret)
+ return MHD_NO; /* hard failure */
+ if (GNUNET_NO == ret)
+ return MHD_YES; /* failure */
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP,
+ &purpose,
+ &reserve_sig.eddsa_signature,
+ &krc.reserve_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ return TALER_MHD_reply_with_error (
+ rc->connection,
+ MHD_HTTP_FORBIDDEN,
+ TALER_EC_EXCHANGE_KYC_WALLET_SIGNATURE_INVALID,
+ NULL);
+ }
+ if (TEH_KYC_NONE == TEH_kyc_config.mode)
+ return TALER_MHD_reply_static (
+ rc->connection,
+ MHD_HTTP_NO_CONTENT,
+ NULL,
+ NULL,
+ 0);
+ ret = TEH_DB_run_transaction (rc->connection,
+ "check wallet kyc",
+ &res,
+ &wallet_kyc_check,
+ &krc);
+ if (GNUNET_SYSERR == ret)
+ return res;
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_OK,
+ GNUNET_JSON_pack_uint64 ("payment_target_uuid",
+ krc.kyc.payment_target_uuid));
+}
+
+
+/* end of taler-exchange-httpd_kyc-wallet.c */
diff --git a/src/exchange/taler-exchange-httpd_kyc-wallet.h b/src/exchange/taler-exchange-httpd_kyc-wallet.h
new file mode 100644
index 00000000..bd8ae1b0
--- /dev/null
+++ b/src/exchange/taler-exchange-httpd_kyc-wallet.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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
+ 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file taler-exchange-httpd_kyc-wallet.h
+ * @brief Handle /kyc-wallet requests
+ * @author Christian Grothoff
+ */
+#ifndef TALER_EXCHANGE_HTTPD_KYC_WALLET_H
+#define TALER_EXCHANGE_HTTPD_KYC_WALLET_H
+
+#include <microhttpd.h>
+#include "taler-exchange-httpd.h"
+
+
+/**
+ * Handle a "/kyc-wallet" request. Parses the "reserve_pub" EdDSA key of the
+ * reserve and the signature "reserve_sig" which affirms the operation. If OK,
+ * a KYC record is created (if missing) and the KYC status returned.
+ *
+ * @param rc request to handle
+ * @param root uploaded JSON data
+ * @param args empty array
+ * @return MHD result code
+ */
+MHD_RESULT
+TEH_handler_kyc_wallet (
+ struct TEH_RequestContext *rc,
+ const json_t *root,
+ const char *const args[]);
+
+
+#endif
diff --git a/src/exchange/taler-exchange-httpd_withdraw.c b/src/exchange/taler-exchange-httpd_withdraw.c
index d9cba045..4839ec97 100644
--- a/src/exchange/taler-exchange-httpd_withdraw.c
+++ b/src/exchange/taler-exchange-httpd_withdraw.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2019 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -129,10 +129,45 @@ struct WithdrawContext
*/
struct TALER_EXCHANGEDB_CollectableBlindcoin collectable;
+ /**
+ * KYC status for the operation.
+ */
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ /**
+ * Set to true if the operation was denied due to
+ * failing @e kyc checks.
+ */
+ bool kyc_denied;
+
};
/**
+ * Function called with another amount that was
+ * already withdrawn. Accumulates all amounts in
+ * @a cls.
+ *
+ * @param[in,out] cls a `struct TALER_Amount`
+ * @param val value to add to @a cls
+ */
+static void
+accumulate_withdraws (void *cls,
+ const struct TALER_Amount *val)
+{
+ struct TALER_Amount *acc = cls;
+
+ if (GNUNET_OK !=
+ TALER_amount_is_valid (acc))
+ return; /* ignore */
+ GNUNET_break (0 <=
+ TALER_amount_add (acc,
+ acc,
+ val));
+}
+
+
+/**
* Function implementing withdraw transaction. Runs the
* transaction logic; IF it returns a non-error code, the transaction
* logic MUST NOT queue a MHD response. IF it returns an hard error,
@@ -209,7 +244,8 @@ withdraw_transaction (void *cls,
"Trying to withdraw from reserve: %s\n",
TALER_B2S (&r.pub));
qs = TEH_plugin->reserves_get (TEH_plugin->cls,
- &r);
+ &r,
+ &wc->kyc);
if (0 > qs)
{
if (GNUNET_DB_STATUS_HARD_ERROR == qs)
@@ -268,6 +304,62 @@ withdraw_transaction (void *cls,
return GNUNET_DB_STATUS_HARD_ERROR;
}
+ if ( (! wc->kyc.ok) &&
+ (TEH_KYC_NONE != TEH_kyc_config.mode) &&
+ (TALER_EXCHANGEDB_KYC_W2W == wc->kyc.type) )
+ {
+ /* Wallet-to-wallet payments _always_ require KYC */
+ wc->kyc_denied = true;
+ return qs;
+ }
+ if ( (! wc->kyc.ok) &&
+ (TEH_KYC_NONE != TEH_kyc_config.mode) &&
+ (TALER_EXCHANGEDB_KYC_WITHDRAW == wc->kyc.type) &&
+ (! GNUNET_TIME_relative_is_zero (TEH_kyc_config.withdraw_period)) )
+ {
+ /* Withdraws require KYC if above threshold */
+ struct TALER_Amount acc;
+ enum GNUNET_DB_QueryStatus qs2;
+
+ TALER_amount_set_zero (TEH_currency,
+ &acc);
+ accumulate_withdraws (&acc,
+ &wc->amount_required);
+ qs2 = TEH_plugin->select_withdraw_amounts_by_account (
+ TEH_plugin->cls,
+ &wc->wsrd.reserve_pub,
+ TEH_kyc_config.withdraw_period,
+ &accumulate_withdraws,
+ &acc);
+ if (0 > qs2)
+ {
+ GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs2);
+ if (GNUNET_DB_STATUS_HARD_ERROR == qs2)
+ *mhd_ret = TALER_MHD_reply_with_error (connection,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_GENERIC_DB_FETCH_FAILED,
+ "withdraw details");
+ return qs2;
+ }
+
+ if (GNUNET_OK !=
+ TALER_amount_is_valid (&acc))
+ {
+ GNUNET_break (0);
+ *mhd_ret = TALER_MHD_reply_with_ec (connection,
+ TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
+ NULL);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ if (1 == /* 1: acc > withdraw_limit */
+ TALER_amount_cmp (&acc,
+ &TEH_kyc_config.withdraw_limit))
+ {
+ wc->kyc_denied = true;
+ return qs;
+ }
+ }
+
/* Balance is good, sign the coin! */
#if ! OPTIMISTIC_SIGN
if (NULL == wc->collectable.sig.rsa_signature)
@@ -329,6 +421,9 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
enum TALER_ErrorCode ec;
struct TEH_DenominationKey *dk;
+ memset (&wc,
+ 0,
+ sizeof (wc));
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (args[0],
strlen (args[0]),
@@ -471,6 +566,7 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
#endif
/* run transaction and sign (if not optimistically signed before) */
+ wc.kyc_denied = false;
{
MHD_RESULT mhd_ret;
@@ -490,9 +586,21 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
}
}
- /* Clean up and send back final (positive) response */
+ /* Clean up and send back final response */
GNUNET_JSON_parse_free (spec);
+ if (wc.kyc_denied)
+ {
+ if (NULL != wc.collectable.sig.rsa_signature)
+ GNUNET_CRYPTO_rsa_signature_free (wc.collectable.sig.rsa_signature);
+
+ return TALER_MHD_REPLY_JSON_PACK (
+ rc->connection,
+ MHD_HTTP_ACCEPTED,
+ GNUNET_JSON_pack_uint64 ("payment_target_uuid",
+ wc.kyc.payment_target_uuid));
+ }
+
{
MHD_RESULT ret;
diff --git a/src/exchangedb/Makefile.am b/src/exchangedb/Makefile.am
index eae03726..37b5f015 100644
--- a/src/exchangedb/Makefile.am
+++ b/src/exchangedb/Makefile.am
@@ -19,9 +19,7 @@ sql_DATA = \
exchange-0001.sql \
exchange-0002.sql \
exchange-0003.sql \
- drop0001.sql \
- drop0002.sql \
- drop0003.sql
+ drop0001.sql
EXTRA_DIST = \
exchangedb.conf \
diff --git a/src/exchangedb/drop0001.sql b/src/exchangedb/drop0001.sql
index f5a28192..507393e5 100644
--- a/src/exchangedb/drop0001.sql
+++ b/src/exchangedb/drop0001.sql
@@ -22,6 +22,19 @@ BEGIN;
-- Unlike the other SQL files, it SHOULD be updated to reflect the
-- latest requirements for dropping tables.
+
+-- Drops for exchange-0003.sql
+DROP TABLE IF EXISTS revolving_work_shards CASCADE;
+
+
+-- Drops for exchange-0002.sql
+DROP TABLE IF EXISTS auditors CASCADE;
+DROP TABLE IF EXISTS auditor_denom_sigs CASCADE;
+DROP TABLE IF EXISTS exchange_sign_keys CASCADE;
+DROP TABLE IF EXISTS wire_accounts CASCADE;
+DROP TABLE IF EXISTS signkey_revocations CASCADE;
+DROP TABLE IF EXISTS work_shards CASCADE;
+
-- Drops for 0001.sql
DROP TABLE IF EXISTS prewire CASCADE;
DROP TABLE IF EXISTS recoup CASCADE;
@@ -42,8 +55,15 @@ DROP TABLE IF EXISTS reserves CASCADE;
DROP TABLE IF EXISTS denomination_revocations CASCADE;
DROP TABLE IF EXISTS denominations CASCADE;
--- Unregister patch (0001.sql)
+
+-- Unregister patch (exchange-0001.sql)
SELECT _v.unregister_patch('exchange-0001');
+-- Unregister patch (exchange-0002.sql)
+SELECT _v.unregister_patch('exchange-0002');
+
+-- Unregister patch (exchange-0003.sql)
+SELECT _v.unregister_patch('exchange-0003');
+
-- And we're out of here...
COMMIT;
diff --git a/src/exchangedb/drop0002.sql b/src/exchangedb/drop0002.sql
deleted file mode 100644
index 12db64c5..00000000
--- a/src/exchangedb/drop0002.sql
+++ /dev/null
@@ -1,31 +0,0 @@
---
--- 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/>
---
-
--- Everything in one big transaction
-BEGIN;
-
--- Unregister patch (0002.sql)
-SELECT _v.unregister_patch('exchange-0002');
-
-DROP TABLE IF EXISTS auditors CASCADE;
-DROP TABLE IF EXISTS auditor_denom_sigs CASCADE;
-DROP TABLE IF EXISTS exchange_sign_keys CASCADE;
-DROP TABLE IF EXISTS wire_accounts CASCADE;
-DROP TABLE IF EXISTS signkey_revocations CASCADE;
-DROP TABLE IF EXISTS work_shards CASCADE;
-
--- And we're out of here...
-COMMIT;
diff --git a/src/exchangedb/drop0003.sql b/src/exchangedb/drop0003.sql
deleted file mode 100644
index fbdab04c..00000000
--- a/src/exchangedb/drop0003.sql
+++ /dev/null
@@ -1,26 +0,0 @@
---
--- 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/>
---
-
--- Everything in one big transaction
-BEGIN;
-
--- Unregister patch (0003.sql)
-SELECT _v.unregister_patch('exchange-0003');
-
-DROP TABLE IF EXISTS revolving_work_shards CASCADE;
-
--- And we're out of here...
-COMMIT;
diff --git a/src/exchangedb/plugin_exchangedb_postgres.c b/src/exchangedb/plugin_exchangedb_postgres.c
index 817c1a18..4b3ae19d 100644
--- a/src/exchangedb/plugin_exchangedb_postgres.c
+++ b/src/exchangedb/plugin_exchangedb_postgres.c
@@ -131,12 +131,6 @@ struct PostgresClosure
const char *transaction_name;
/**
- * Number of registered listerners. @e event_thread
- * should terminate if this value reaches 0.
- */
- uint64_t listener_count;
-
- /**
* Did we initialize the prepared statements
* for this session?
*/
@@ -151,7 +145,7 @@ struct PostgresClosure
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_drop_tables (void *cls)
{
struct PostgresClosure *pg = cls;
@@ -175,7 +169,7 @@ postgres_drop_tables (void *cls)
* @param cls the `struct PostgresClosure` with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_create_tables (void *cls)
{
struct PostgresClosure *pg = cls;
@@ -353,6 +347,62 @@ prepare_statements (struct PostgresClosure *pg)
" WHERE denom_pub_hash=$1);",
1),
/* Used in #postgres_reserves_get() */
+ GNUNET_PQ_make_prepare ("reserves_get_with_kyc",
+ "SELECT"
+ " current_balance_val"
+ ",current_balance_frac"
+ ",expiration_date"
+ ",gc_date"
+ ",FALSE AS kyc_ok" // FIXME
+ ",CAST (0 AS INT8) AS payment_target_uuid" // FIXME
+ " FROM reserves"
+ " WHERE reserve_pub=$1"
+ " LIMIT 1;",
+ 1),
+#if FIXME_DD23
+ /* Used in #postgres_set_kyc_ok() */
+ GNUNET_PQ_make_prepare ("set_kyc_ok",
+ "UPDATE wire_targets"
+ " SET kyc_ok=TRUE"
+ " WHERE wire_target_serial_id=$1",
+ 1),
+ /* Used in #postgres_get_kyc_status() */
+ GNUNET_PQ_make_prepare ("get_kyc_status",
+ "SELECT"
+ ",kyc_ok"
+ ",wire_target_serial_id AS payment_target_uuid"
+ " FROM wire_targets"
+ " WHERE payto_uri=$1"
+ " LIMIT 1;",
+ 1),
+ /* Used in #postgres_select_kyc_status() */
+ GNUNET_PQ_make_prepare ("select_kyc_status",
+ "SELECT"
+ ",kyc_ok"
+ ",h_payto"
+ " FROM wire_targets"
+ " WHERE"
+ " wire_target_serial_id=$1",
+ 1),
+ /* Used in #postgres_inselect_wallet_kyc_status() */
+ // FIXME: Note that this statement has not been debugged at all...
+ // It just represents the _idea_.
+ GNUNET_PQ_make_prepare ("inselect_wallet_kyc_status",
+ "INSERT INTO wire_targets"
+ "(payto_uri"
+ ") VALUES "
+ "($1)"
+ " ON CONFLICT (wire_target_serial_id) DO "
+ " (SELECT "
+ " kyc_ok"
+ " ,wire_target_serial_id"
+ " )"
+ " RETURNING "
+ " FALSE AS kyc_ok"
+ " wire_target_serial_id;",
+ 1),
+#endif
+ /* Used in #reserves_get() */
GNUNET_PQ_make_prepare ("reserves_get",
"SELECT"
" current_balance_val"
@@ -930,7 +980,9 @@ prepare_statements (struct PostgresClosure *pg)
Used in #postgres_lookup_transfer_by_deposit(). */
GNUNET_PQ_make_prepare ("get_deposit_for_wtid",
"SELECT"
- " amount_with_fee_val"
+ " FALSE AS kyc_ok" // FIXME
+ ",CAST (0 AS INT8) AS payment_target_uuid" // FIXME
+ ",amount_with_fee_val"
",amount_with_fee_frac"
",denom.fee_deposit_val"
",denom.fee_deposit_frac"
@@ -939,9 +991,9 @@ prepare_statements (struct PostgresClosure *pg)
" JOIN known_coins USING (known_coin_id)"
" JOIN denominations denom USING (denominations_serial)"
" WHERE ((coin_pub=$1)"
- " AND (merchant_pub=$2)"
- " AND (h_contract_terms=$3)"
- " AND (h_wire=$4)"
+ " AND (merchant_pub=$4)"
+ " AND (h_contract_terms=$2)"
+ " AND (h_wire=$3)"
" );",
4),
/* Used in #postgres_get_ready_deposit() */
@@ -2613,7 +2665,7 @@ postgres_preflight (void *cls)
* must point to a constant
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_start (void *cls,
const char *name)
{
@@ -2651,7 +2703,7 @@ postgres_start (void *cls,
* must point to a constant
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
postgres_start_read_committed (void *cls,
const char *name)
{
@@ -3470,10 +3522,233 @@ postgres_iterate_auditor_denominations (
* @param[in,out] reserve the reserve data. The public key of the reserve should be
* set in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
+ * @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
static enum GNUNET_DB_QueryStatus
postgres_reserves_get (void *cls,
+ struct TALER_EXCHANGEDB_Reserve *reserve,
+ struct TALER_EXCHANGEDB_KycStatus *kyc)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (&reserve->pub),
+ GNUNET_PQ_query_param_end
+ };
+ uint8_t ok8;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ &reserve->balance),
+ TALER_PQ_result_spec_absolute_time ("expiration_date",
+ &reserve->expiry),
+ TALER_PQ_result_spec_absolute_time ("gc_date",
+ &reserve->gc),
+ GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
+ &kyc->payment_target_uuid),
+ GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
+ &ok8),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "reserves_get_with_kyc",
+ params,
+ rs);
+ kyc->type = TALER_EXCHANGEDB_KYC_WITHDRAW;
+ kyc->ok = (0 != ok8);
+ return qs;
+}
+
+
+/**
+ * Set the KYC status to "OK" for a bank account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payment_target_uuid which account has been checked
+ * @param ... possibly additional data to persist (TODO)
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_set_kyc_ok (void *cls,
+ uint64_t payment_target_uuid,
+ ...)
+{
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (&payment_target_uuid),
+ GNUNET_PQ_query_param_end
+ };
+
+ return GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "set_kyc_ok",
+ params);
+}
+
+
+/**
+ * Get the KYC status for a bank account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payto_uri payto:// URI that identifies the bank account
+ * @param[out] kyc set to the KYC status of the reserve
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_kyc_status (void *cls,
+ const char *payto_uri,
+ struct TALER_EXCHANGEDB_KycStatus *kyc)
+{
+#if FIXME_DD23
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_string (payto_uri),
+ GNUNET_PQ_query_param_end
+ };
+#endif
+ uint8_t ok8;
+#if FIXME_DD23
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
+ &kyc->payment_target_uuid),
+ GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
+ &ok8),
+ GNUNET_PQ_result_spec_end
+ };
+#endif
+ enum GNUNET_DB_QueryStatus qs;
+
+#if FIXME_DD23
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "get_kyc_status",
+ params,
+ rs);
+#else
+ qs = 1;
+ ok8 = 0;
+ kyc->payment_target_uuid = 0;
+#endif
+ kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
+ kyc->ok = (0 != ok8);
+ return qs;
+}
+
+
+/**
+ * Get the @a kyc status and @a h_payto by UUID.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payment_target_uuid which account to get the KYC status for
+ * @param[out] h_payto set to the hash of the account's payto URI (unsalted)
+ * @param[out] kyc set to the KYC status of the account
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_select_kyc_status (void *cls,
+ uint64_t payment_target_uuid,
+ struct GNUNET_HashCode *h_payto,
+ struct TALER_EXCHANGEDB_KycStatus *kyc)
+{
+#if FIXME_DD23
+ struct PostgresClosure *pg = cls;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_uint64 (payment_target_uuid),
+ GNUNET_PQ_query_param_end
+ };
+#endif
+ uint8_t ok8;
+#if FIXME_DD23
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("h_payto",
+ h_payto),
+ GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
+ &ok8),
+ GNUNET_PQ_result_spec_end
+ };
+#endif
+ enum GNUNET_DB_QueryStatus qs;
+
+#if FIXME_DD23
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "select_kyc_status",
+ params,
+ rs);
+#else
+ qs = 1;
+ ok8 = 0;
+#endif
+ kyc->type = TALER_EXCHANGEDB_KYC_UNKNOWN;
+ kyc->ok = (0 != ok8);
+ kyc->payment_target_uuid = payment_target_uuid;
+ return qs;
+}
+
+
+/**
+ * Get the KYC status for a wallet. If the status is unknown,
+ * inserts a new status record (hence INsertSELECT).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param reserve_pub public key of the wallet
+ * @param[out] kyc set to the KYC status of the wallet
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_inselect_wallet_kyc_status (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct TALER_EXCHANGEDB_KycStatus *kyc)
+{
+#if FIXME_DD23
+ struct PostgresClosure *pg = cls;
+ /* FIXME: maybe prepared statement will take
+ a payto:// URI instead of the reserve public key?
+ => figure out once DB schema is stable! */
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_result_spec_auto_from_type ("reserve_pub",
+ reserve_pub),
+ GNUNET_PQ_query_param_end
+ };
+#endif
+ uint8_t ok8;
+#if FIXME_DD23
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
+ &kyc->payment_target_uuid),
+ GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
+ &ok8),
+ GNUNET_PQ_result_spec_end
+ };
+#endif
+ enum GNUNET_DB_QueryStatus qs;
+
+#if FIXME_DD23
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "inselect_wallet_kyc_status",
+ params,
+ rs);
+#else
+ qs = 1;
+ ok8 = 0;
+ kyc->payment_target_uuid = 0;
+#endif
+ kyc->type = TALER_EXCHANGEDB_KYC_BALANCE;
+ kyc->ok = (0 != ok8);
+ return qs;
+}
+
+
+/**
+ * Get the summary of a reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param[in,out] reserve the reserve data. The public key of the reserve should be
+ * set in this structure; it is used to query the database. The balance
+ * and expiration are then filled accordingly.
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+reserves_get_internal (void *cls,
struct TALER_EXCHANGEDB_Reserve *reserve)
{
struct PostgresClosure *pg = cls;
@@ -3482,9 +3757,12 @@ postgres_reserves_get (void *cls,
GNUNET_PQ_query_param_end
};
struct GNUNET_PQ_ResultSpec rs[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance", &reserve->balance),
- TALER_PQ_result_spec_absolute_time ("expiration_date", &reserve->expiry),
- TALER_PQ_result_spec_absolute_time ("gc_date", &reserve->gc),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("current_balance",
+ &reserve->balance),
+ TALER_PQ_result_spec_absolute_time ("expiration_date",
+ &reserve->expiry),
+ TALER_PQ_result_spec_absolute_time ("gc_date",
+ &reserve->gc),
GNUNET_PQ_result_spec_end
};
@@ -3705,7 +3983,7 @@ postgres_reserves_in_insert (void *cls,
{
enum GNUNET_DB_QueryStatus reserve_exists;
- reserve_exists = postgres_reserves_get (pg,
+ reserve_exists = reserves_get_internal (pg,
&reserve);
switch (reserve_exists)
{
@@ -3922,7 +4200,7 @@ postgres_insert_withdraw_info (
/* update reserve balance */
reserve.pub = collectable->reserve_pub;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- (qs = postgres_reserves_get (pg,
+ (qs = reserves_get_internal (pg,
&reserve)))
{
/* Should have been checked before we got here... */
@@ -4333,6 +4611,126 @@ postgres_get_reserve_history (void *cls,
/**
+ * Closure for withdraw_amount_by_account_cb()
+ */
+struct WithdrawAmountByAccountContext
+{
+ /**
+ * Function to call on each amount.
+ */
+ TALER_EXCHANGEDB_WithdrawHistoryCallback cb;
+
+ /**
+ * Closure for @e cb
+ */
+ void *cb_cls;
+
+ /**
+ * Our plugin's context.
+ */
+ struct PostgresClosure *pg;
+
+ /**
+ * Set to true on failures.
+ */
+ bool failed;
+};
+
+
+/**
+ * Helper function for #postgres_select_withdraw_amounts_by_account().
+ * To be called with the results of a SELECT statement
+ * that has returned @a num_results results.
+ *
+ * @param cls closure of type `struct WithdrawAmountByAccountContext *`
+ * @param result the postgres result
+ * @param num_results the number of results in @a result
+ */
+static void
+withdraw_amount_by_account_cb (void *cls,
+ PGresult *result,
+ unsigned int num_results)
+{
+ struct WithdrawAmountByAccountContext *wac = cls;
+ struct PostgresClosure *pg = wac->pg;
+
+ for (unsigned int i = 0; num_results; i++)
+ {
+ struct TALER_Amount val;
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ TALER_PQ_RESULT_SPEC_AMOUNT ("val",
+ &val),
+ GNUNET_PQ_result_spec_end
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_PQ_extract_result (result,
+ rs,
+ i))
+ {
+ GNUNET_break (0);
+ wac->failed = true;
+ return;
+ }
+ wac->cb (wac->cb_cls,
+ &val);
+ }
+}
+
+
+/**
+ * Find out all of the amounts that have been withdrawn
+ * so far from the same bank account that created the
+ * given reserve.
+ *
+ * @param cls the `struct PostgresClosure` with the plugin-specific state
+ * @param reserve_pub reserve to select withdrawals by
+ * @param duration how far back should we select withdrawals
+ * @param cb function to call on each amount withdrawn
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_select_withdraw_amounts_by_account (
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct GNUNET_TIME_Relative duration,
+ TALER_EXCHANGEDB_WithdrawHistoryCallback cb,
+ void *cb_cls)
+{
+ struct PostgresClosure *pg = cls;
+ struct WithdrawAmountByAccountContext wac = {
+ .pg = pg,
+ .cb = cb,
+ .cb_cls = cb_cls
+ };
+ struct GNUNET_TIME_Absolute start
+ = GNUNET_TIME_absolute_subtract (GNUNET_TIME_absolute_get (),
+ duration);
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (reserve_pub),
+ GNUNET_PQ_query_param_absolute_time (&start),
+ GNUNET_PQ_query_param_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_multi_select (
+ pg->conn,
+ "select_XXX",
+ params,
+ &withdraw_amount_by_account_cb,
+ &wac);
+
+ if (wac.failed)
+ {
+ GNUNET_break (0);
+ qs = GNUNET_DB_STATUS_HARD_ERROR;
+ }
+ return qs;
+}
+
+
+/**
* Check if we have the specified deposit already in the database.
*
* @param cls the `struct PostgresClosure` with the plugin-specific state
@@ -6455,10 +6853,16 @@ postgres_lookup_wire_transfer (
* @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin
* @param merchant_pub merchant public key
- * @param cb function to call with the result
- * @param cb_cls closure to pass to @a cb
+ * @param[out] pending set to true if the transaction is still pending
+ * @param[out] wtid wire transfer identifier, only set if @a pending is false
+ * @param[out] coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param[out] coin_fee how much did the exchange charge for the deposit fee
+ * @param[out] execution_time when was the transaction done, or
+ * when we expect it to be done (if @a pending is false)
+ * @param[out] kyc set to the kyc status of the receiver (if @a pending)
* @return transaction status code
- - */
+ */
static enum GNUNET_DB_QueryStatus
postgres_lookup_transfer_by_deposit (
void *cls,
@@ -6466,8 +6870,12 @@ postgres_lookup_transfer_by_deposit (
const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- TALER_EXCHANGEDB_WireTransferByCoinCallback cb,
- void *cb_cls)
+ bool *pending,
+ struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute *exec_time,
+ struct TALER_Amount *amount_with_fee,
+ struct TALER_Amount *deposit_fee,
+ struct TALER_EXCHANGEDB_KycStatus *kyc)
{
struct PostgresClosure *pg = cls;
enum GNUNET_DB_QueryStatus qs;
@@ -6478,39 +6886,39 @@ postgres_lookup_transfer_by_deposit (
GNUNET_PQ_query_param_auto_from_type (merchant_pub),
GNUNET_PQ_query_param_end
};
- struct TALER_WireTransferIdentifierRawP wtid;
- struct GNUNET_TIME_Absolute exec_time;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
- &wtid),
+ wtid),
TALER_PQ_result_spec_absolute_time ("execution_date",
- &exec_time),
+ exec_time),
TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
- &amount_with_fee),
+ amount_with_fee),
TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
- &deposit_fee),
+ deposit_fee),
GNUNET_PQ_result_spec_end
};
- /* check if the melt record exists and get it */
+ /* check if the aggregation record exists and get it */
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"lookup_deposit_wtid",
params,
rs);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
{
- cb (cb_cls,
- &wtid,
- &amount_with_fee,
- &deposit_fee,
- exec_time);
+ *pending = false;
+ memset (kyc,
+ 0,
+ sizeof (*kyc));
+ kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
+ kyc->ok = true;
return qs;
}
if (0 > qs)
return qs;
-
+ *pending = true;
+ memset (wtid,
+ 0,
+ sizeof (*wtid));
GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"lookup_deposit_wtid returned 0 matching rows\n");
@@ -6518,38 +6926,27 @@ postgres_lookup_transfer_by_deposit (
/* Check if transaction exists in deposits, so that we just
do not have a WTID yet, if so, do call the CB with a NULL wtid
and return #GNUNET_YES! */
- struct GNUNET_PQ_QueryParam params2[] = {
- GNUNET_PQ_query_param_auto_from_type (coin_pub),
- GNUNET_PQ_query_param_auto_from_type (merchant_pub),
- GNUNET_PQ_query_param_auto_from_type (h_contract_terms),
- GNUNET_PQ_query_param_auto_from_type (h_wire),
- GNUNET_PQ_query_param_end
- };
- struct GNUNET_TIME_Absolute exec_time;
- struct TALER_Amount amount_with_fee;
- struct TALER_Amount deposit_fee;
+ uint8_t ok8 = 0;
struct GNUNET_PQ_ResultSpec rs2[] = {
- TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee", &amount_with_fee),
- TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit", &deposit_fee),
- TALER_PQ_result_spec_absolute_time ("wire_deadline", &exec_time),
+ GNUNET_PQ_result_spec_uint64 ("payment_target_uuid",
+ &kyc->payment_target_uuid),
+ GNUNET_PQ_result_spec_auto_from_type ("kyc_ok",
+ &ok8),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("amount_with_fee",
+ amount_with_fee),
+ TALER_PQ_RESULT_SPEC_AMOUNT ("fee_deposit",
+ deposit_fee),
+ TALER_PQ_result_spec_absolute_time ("wire_deadline",
+ exec_time),
GNUNET_PQ_result_spec_end
};
qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
"get_deposit_for_wtid",
- params2,
+ params,
rs2);
- if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
- {
- /* Ok, we're aware of the transaction, but it has not yet been
- executed */
- cb (cb_cls,
- NULL,
- &amount_with_fee,
- &deposit_fee,
- exec_time);
- return qs;
- }
+ kyc->type = TALER_EXCHANGEDB_KYC_DEPOSIT;
+ kyc->ok = (0 != ok8);
return qs;
}
}
@@ -6881,7 +7278,7 @@ postgres_insert_reserve_closed (
/* update reserve balance */
reserve.pub = *reserve_pub;
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- (qs = postgres_reserves_get (cls,
+ (qs = reserves_get_internal (cls,
&reserve)))
{
/* Existence should have been checked before we got here... */
@@ -8673,7 +9070,7 @@ postgres_insert_recoup_request (
/* Update reserve balance */
reserve.pub = *reserve_pub;
- qs = postgres_reserves_get (pg,
+ qs = reserves_get_internal (pg,
&reserve);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != qs)
{
@@ -10895,12 +11292,18 @@ libtaler_plugin_exchangedb_postgres_init (void *cls)
plugin->iterate_auditor_denominations =
&postgres_iterate_auditor_denominations;
plugin->reserves_get = &postgres_reserves_get;
+ plugin->set_kyc_ok = &postgres_set_kyc_ok;
+ plugin->get_kyc_status = &postgres_get_kyc_status;
+ plugin->select_kyc_status = &postgres_select_kyc_status;
+ plugin->inselect_wallet_kyc_status = &postgres_inselect_wallet_kyc_status;
plugin->reserves_in_insert = &postgres_reserves_in_insert;
plugin->get_latest_reserve_in_reference =
&postgres_get_latest_reserve_in_reference;
plugin->get_withdraw_info = &postgres_get_withdraw_info;
plugin->insert_withdraw_info = &postgres_insert_withdraw_info;
plugin->get_reserve_history = &postgres_get_reserve_history;
+ plugin->select_withdraw_amounts_by_account
+ = &postgres_select_withdraw_amounts_by_account;
plugin->free_reserve_history = &common_free_reserve_history;
plugin->count_known_coins = &postgres_count_known_coins;
plugin->ensure_coin_known = &postgres_ensure_coin_known;
diff --git a/src/exchangedb/test_exchangedb.c b/src/exchangedb/test_exchangedb.c
index b332cd6d..c68cba81 100644
--- a/src/exchangedb/test_exchangedb.c
+++ b/src/exchangedb/test_exchangedb.c
@@ -154,22 +154,25 @@ drop:
* @return #GNUNET_OK if the given reserve has the same balance and expiration
* as the given parameters; #GNUNET_SYSERR if not
*/
-static int
+static enum GNUNET_GenericReturnValue
check_reserve (const struct TALER_ReservePublicKeyP *pub,
uint64_t value,
uint32_t fraction,
const char *currency)
{
struct TALER_EXCHANGEDB_Reserve reserve;
+ struct TALER_EXCHANGEDB_KycStatus kyc;
reserve.pub = *pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
- &reserve));
+ &reserve,
+ &kyc));
FAILIF (value != reserve.balance.value);
FAILIF (fraction != reserve.balance.fraction);
- FAILIF (0 != strcmp (currency, reserve.balance.currency));
-
+ FAILIF (0 != strcmp (currency,
+ reserve.balance.currency));
+ FAILIF (kyc.ok);
return GNUNET_OK;
drop:
return GNUNET_SYSERR;
@@ -713,20 +716,6 @@ cb_wt_never (void *cls,
}
-/**
- * Callback that should never be called.
- */
-static void
-cb_wtid_never (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- GNUNET_assert (0);
-}
-
-
static struct TALER_MerchantPublicKeyP merchant_pub_wt;
static struct GNUNET_HashCode h_wire_wt;
static struct GNUNET_HashCode h_contract_terms_wt;
@@ -775,28 +764,6 @@ cb_wt_check (void *cls,
/**
- * Callback that should be called with the WT data.
- */
-static void
-cb_wtid_check (void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time)
-{
- GNUNET_assert (cls == &cb_wtid_never);
- GNUNET_assert (0 == GNUNET_memcmp (wtid,
- &wire_out_wtid));
- GNUNET_assert (execution_time.abs_value_us ==
- wire_out_date.abs_value_us);
- GNUNET_assert (0 == TALER_amount_cmp (coin_contribution,
- &coin_value_wt));
- GNUNET_assert (0 == TALER_amount_cmp (coin_fee,
- &coin_fee_wt));
-}
-
-
-/**
* Here #deposit_cb() will store the row ID of the deposit.
*/
static uint64_t deposit_rowid;
@@ -1282,6 +1249,12 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
{
struct GNUNET_HashCode h_contract_terms_wt2 = h_contract_terms_wt;
+ bool pending;
+ struct TALER_WireTransferIdentifierRawP wtid2;
+ struct TALER_Amount coin_contribution2;
+ struct TALER_Amount coin_fee2;
+ struct GNUNET_TIME_Absolute execution_time2;
+ struct TALER_EXCHANGEDB_KycStatus kyc;
h_contract_terms_wt2.bits[0]++;
FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
@@ -1290,8 +1263,12 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&h_wire_wt,
&coin_pub_wt,
&merchant_pub_wt,
- &cb_wtid_never,
- NULL));
+ &pending,
+ &wtid2,
+ &execution_time2,
+ &coin_contribution2,
+ &coin_fee2,
+ &kyc));
}
/* insert WT data */
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@@ -1303,12 +1280,16 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
putting in the WTID into the wire_out table */
{
json_t *wire_out_account;
+ struct TALER_WireSalt salt;
+ memset (&salt,
+ 44,
+ sizeof (salt));
wire_out_account = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri",
"payto://x-taler-bank/localhost:8080/1"),
- GNUNET_JSON_pack_string ("salt",
- "this-is-my-salt"));
+ GNUNET_JSON_pack_data_auto ("salt",
+ &salt));
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->store_wire_transfer_out (plugin->cls,
wire_out_date,
@@ -1331,14 +1312,35 @@ test_wire_out (const struct TALER_EXCHANGEDB_Deposit *deposit)
&wire_out_wtid,
&cb_wt_check,
&cb_wt_never));
- FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
- plugin->lookup_transfer_by_deposit (plugin->cls,
- &h_contract_terms_wt,
- &h_wire_wt,
- &coin_pub_wt,
- &merchant_pub_wt,
- &cb_wtid_check,
- &cb_wtid_never));
+ {
+ bool pending;
+ struct TALER_WireTransferIdentifierRawP wtid2;
+ struct TALER_Amount coin_contribution2;
+ struct TALER_Amount coin_fee2;
+ struct GNUNET_TIME_Absolute execution_time2;
+ struct TALER_EXCHANGEDB_KycStatus kyc;
+
+ FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ plugin->lookup_transfer_by_deposit (plugin->cls,
+ &h_contract_terms_wt,
+ &h_wire_wt,
+ &coin_pub_wt,
+ &merchant_pub_wt,
+ &pending,
+ &wtid2,
+ &execution_time2,
+ &coin_contribution2,
+ &coin_fee2,
+ &kyc));
+ GNUNET_assert (0 == GNUNET_memcmp (&wtid2,
+ &wire_out_wtid));
+ GNUNET_assert (execution_time2.abs_value_us ==
+ wire_out_date.abs_value_us);
+ GNUNET_assert (0 == TALER_amount_cmp (&coin_contribution2,
+ &coin_value_wt));
+ GNUNET_assert (0 == TALER_amount_cmp (&coin_fee2,
+ &coin_fee_wt));
+ }
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->select_wire_out_above_serial_id (plugin->cls,
0,
@@ -1513,15 +1515,19 @@ run (void *cls)
uint64_t rr;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Absolute now;
+ struct TALER_WireSalt salt;
dkp = NULL;
rh = NULL;
deposit.coin.denom_sig.rsa_signature = NULL;
+ memset (&salt,
+ 45,
+ sizeof (salt));
wire = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri",
"payto://iban/DE67830654080004822650?receiver-name=Test"),
- GNUNET_JSON_pack_string ("salt",
- "this-is-a-salt-value"));
+ GNUNET_JSON_pack_data_auto ("salt",
+ &salt));
ZR_BLK (&cbc);
ZR_BLK (&cbc2);
if (NULL ==
@@ -1684,11 +1690,13 @@ run (void *cls)
struct TALER_EXCHANGEDB_Reserve pre_reserve;
struct TALER_EXCHANGEDB_Reserve post_reserve;
struct TALER_Amount delta;
+ struct TALER_EXCHANGEDB_KycStatus kyc;
pre_reserve.pub = reserve_pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
- &pre_reserve));
+ &pre_reserve,
+ &kyc));
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->insert_recoup_request (plugin->cls,
&reserve_pub,
@@ -1701,7 +1709,8 @@ run (void *cls)
post_reserve.pub = reserve_pub;
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->reserves_get (plugin->cls,
- &post_reserve));
+ &post_reserve,
+ &kyc));
FAILIF (0 >=
TALER_amount_subtract (&delta,
&post_reserve.balance,
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index 71579170..0284fc55 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -359,6 +359,20 @@ struct TALER_ClaimTokenP
};
+/**
+ * Salt used to hash a merchant's payto:// URI to
+ * compute the "h_wire" (say for deposit requests).
+ */
+struct TALER_WireSalt
+{
+ /**
+ * Actual salt value.
+ * FIXME: #7032: change to 16 byte value!
+ */
+ struct GNUNET_HashCode data;
+};
+
+
GNUNET_NETWORK_STRUCT_END
@@ -1658,7 +1672,7 @@ TALER_exchange_wire_signature_make (
*/
void
TALER_merchant_wire_signature_hash (const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
struct GNUNET_HashCode *hc);
@@ -1674,7 +1688,7 @@ TALER_merchant_wire_signature_hash (const char *payto_uri,
enum GNUNET_GenericReturnValue
TALER_merchant_wire_signature_check (
const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
const struct TALER_MerchantPublicKeyP *merch_pub,
const struct TALER_MerchantSignatureP *merch_sig);
@@ -1690,7 +1704,7 @@ TALER_merchant_wire_signature_check (
void
TALER_merchant_wire_signature_make (
const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
const struct TALER_MerchantPrivateKeyP *merch_priv,
struct TALER_MerchantSignatureP *merch_sig);
diff --git a/src/include/taler_curl_lib.h b/src/include/taler_curl_lib.h
index 42d7f9d1..5151f4cf 100644
--- a/src/include/taler_curl_lib.h
+++ b/src/include/taler_curl_lib.h
@@ -59,7 +59,7 @@ struct TALER_CURL_PostContext
* @param body JSON body to add to @e ctx
* @return #GNUNET_OK on success #GNUNET_SYSERR on failure
*/
-int
+enum GNUNET_GenericReturnValue
TALER_curl_easy_post (struct TALER_CURL_PostContext *ctx,
CURL *eh,
const json_t *body);
diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h
index f95577d0..0b624391 100644
--- a/src/include/taler_exchange_service.h
+++ b/src/include/taler_exchange_service.h
@@ -265,6 +265,12 @@ struct TALER_EXCHANGE_Keys
struct GNUNET_TIME_Relative reserve_closing_delay;
/**
+ * Maximum amount a wallet is allowed to hold from
+ * this exchange before it must undergo a KYC check.
+ */
+ struct TALER_Amount wallet_balance_limit_without_kyc;
+
+ /**
* Timestamp indicating the /keys generation.
*/
struct GNUNET_TIME_Absolute list_issue_date;
@@ -794,22 +800,72 @@ struct TALER_EXCHANGE_DepositHandle;
/**
+ * Structure with information about a deposit
+ * operation's result.
+ */
+struct TALER_EXCHANGE_DepositResult
+{
+ /**
+ * HTTP response data
+ */
+ struct TALER_EXCHANGE_HttpResponse hr;
+
+ union
+ {
+
+ /**
+ * Information returned if the HTTP status is
+ * #MHD_HTTP_OK.
+ */
+ struct
+ {
+ /**
+ * Time when the exchange generated the deposit confirmation
+ */
+ struct GNUNET_TIME_Absolute deposit_timestamp;
+
+ /**
+ * signature provided by the exchange
+ */
+ const struct TALER_ExchangeSignatureP *exchange_sig;
+
+ /**
+ * exchange key used to sign @a exchange_sig.
+ */
+ const struct TALER_ExchangePublicKeyP *exchange_pub;
+
+ /**
+ * Base URL for looking up wire transfers, or
+ * NULL to use the default base URL.
+ */
+ const char *transaction_base_url;
+
+ } success;
+
+ /**
+ * Information returned if the HTTP status is
+ * #MHD_HTTP_CONFLICT.
+ */
+ struct
+ {
+ /* TODO: returning full details is not implemented */
+ } conflict;
+
+ } details;
+};
+
+
+/**
* Callbacks of this type are used to serve the result of submitting a
* deposit permission request to a exchange.
*
* @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
+ * @param dr deposit response details
*/
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);
+ const struct TALER_EXCHANGE_DepositResult *dr);
/**
@@ -1201,18 +1257,74 @@ struct TALER_EXCHANGE_WithdrawHandle;
/**
+ * Details about a response for a withdraw request.
+ */
+struct TALER_EXCHANGE_WithdrawResponse
+{
+ /**
+ * HTTP response data.
+ */
+ struct TALER_EXCHANGE_HttpResponse hr;
+
+ /**
+ * Details about the response.
+ */
+ union
+ {
+ /**
+ * Details if the status is #MHD_HTTP_OK.
+ */
+ struct
+ {
+ /**
+ * Signature over the coin.
+ */
+ struct TALER_DenominationSignature sig;
+ } success;
+
+ /**
+ * Details if the status is #MHD_HTTP_ACCEPTED.
+ */
+ struct
+ {
+ /**
+ * Payment target that the merchant should use
+ * to check for its KYC status.
+ */
+ uint64_t payment_target_uuid;
+ } accepted;
+
+ /**
+ * Details if the status is #MHD_HTTP_CONFLICT.
+ */
+ struct
+ {
+ /* TODO: returning full details is not implemented */
+ } conflict;
+
+ /**
+ * Details if the status is #MHD_HTTP_GONE.
+ */
+ struct
+ {
+ /* TODO: returning full details is not implemented */
+ } gone;
+
+ } details;
+};
+
+
+/**
* Callbacks of this type are used to serve the result of submitting a
* withdraw request to a exchange.
*
* @param cls closure
- * @param hr HTTP response data
- * @param sig signature over the coin, NULL on error
+ * @param wr response details
*/
typedef void
(*TALER_EXCHANGE_WithdrawCallback) (
void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_DenominationSignature *sig);
+ const struct TALER_EXCHANGE_WithdrawResponse *wr);
/**
@@ -1684,41 +1796,88 @@ 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.
+ * Data returned for a successful GET /deposits/ request.
*/
-struct TALER_EXCHANGE_DepositData
+struct TALER_EXCHANGE_GetDepositResponse
{
/**
- * exchange key used to sign, all zeros if exchange did not
- * yet execute the transaction
+ * HTTP response data.
*/
- struct TALER_ExchangePublicKeyP exchange_pub;
+ struct TALER_EXCHANGE_HttpResponse hr;
/**
- * signature from the exchange over the deposit data, all zeros if exchange did not
- * yet execute the transaction
+ * Details about the response.
*/
- struct TALER_ExchangeSignatureP exchange_sig;
+ union
+ {
- /**
- * wire transfer identifier used by the exchange, all zeros if exchange did not
- * yet execute the transaction
- */
- struct TALER_WireTransferIdentifierRawP wtid;
+ /**
+ * Response if the status was #MHD_HTTP_OK
+ */
+ struct TALER_EXCHANGE_DepositData
+ {
+ /**
+ * exchange key used to sign, all zeros if exchange did not
+ * yet execute the transaction
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
- /**
- * actual or planned execution time for the wire transfer
- */
- struct GNUNET_TIME_Absolute execution_time;
+ /**
+ * signature from the exchange over the deposit data, all zeros if exchange did not
+ * yet execute the transaction
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
- /**
- * contribution to the total amount by this coin, all zeros if exchange did not
- * yet execute the transaction
- */
- struct TALER_Amount coin_contribution;
+ /**
+ * wire transfer identifier used by the exchange, all zeros if exchange did not
+ * yet execute the transaction
+ */
+ struct TALER_WireTransferIdentifierRawP wtid;
+
+ /**
+ * actual 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;
+
+ /**
+ * Payment target that the merchant should use
+ * to check for its KYC status.
+ */
+ uint64_t payment_target_uuid;
+ } success;
+
+ /**
+ * Response if the status was #MHD_HTTP_ACCEPTED
+ */
+ struct
+ {
+
+ /**
+ * planned execution time for the wire transfer
+ */
+ struct GNUNET_TIME_Absolute execution_time;
+
+ /**
+ * Payment target that the merchant should use
+ * to check for its KYC status.
+ */
+ uint64_t payment_target_uuid;
+
+ /**
+ * Set to 'true' if the KYC check is already finished and
+ * the exchange is merely waiting for the @e execution_time.
+ */
+ bool kyc_ok;
+ } accepted;
+
+ } details;
};
@@ -1732,8 +1891,7 @@ struct TALER_EXCHANGE_DepositData
typedef void
(*TALER_EXCHANGE_DepositGetCallback)(
void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_EXCHANGE_DepositData *dd);
+ const struct TALER_EXCHANGE_GetDepositResponse *dr);
/**
@@ -1784,7 +1942,7 @@ TALER_EXCHANGE_deposits_get_cancel (
* @param[out] total how much of the coin has been spent according to @a history
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
*/
-int
+enum GNUNET_GenericReturnValue
TALER_EXCHANGE_verify_coin_history (
const struct TALER_EXCHANGE_DenomPublicKey *dk,
const char *currency,
@@ -1810,7 +1968,7 @@ TALER_EXCHANGE_verify_coin_history (
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
-int
+enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *history,
@@ -1899,6 +2057,179 @@ void
TALER_EXCHANGE_recoup_cancel (struct TALER_EXCHANGE_RecoupHandle *ph);
+/* ********************* /kyc* *********************** */
+
+/**
+ * Handle for a ``/kyc-check`` operation.
+ */
+struct TALER_EXCHANGE_KycCheckHandle;
+
+
+/**
+ * KYC status response details.
+ */
+struct TALER_EXCHANGE_KycStatus
+{
+ /**
+ * HTTP status code returned by the exchange.
+ */
+ unsigned int http_status;
+
+ /**
+ * Taler error code, if any.
+ */
+ enum TALER_ErrorCode ec;
+
+ union
+ {
+
+ /**
+ * KYC is OK, affirmation returned by the exchange.
+ */
+ struct
+ {
+
+ /**
+ * Time of the affirmation.
+ */
+ struct GNUNET_TIME_Absolute timestamp;
+
+ /**
+ * The signing public key used for @e exchange_sig.
+ */
+ struct TALER_ExchangePublicKeyP exchange_pub;
+
+ /**
+ * Signature of purpose
+ * #TALER_SIGNATURE_ACCOUNT_SETUP_SUCCESS affirming
+ * the successful KYC process.
+ */
+ struct TALER_ExchangeSignatureP exchange_sig;
+
+ } kyc_ok;
+
+ /**
+ * URL the user should open in a browser if
+ * the KYC process is to be run. Returned if
+ * @e http_status is #MHD_HTTP_ACCEPTED.
+ */
+ const char *kyc_url;
+
+ } details;
+
+};
+
+/**
+ * Function called with the result of a KYC check.
+ *
+ * @param cls closure
+ * @param ks the account's KYC status details
+ */
+typedef void
+(*TALER_EXCHANGE_KycStatusCallback)(
+ void *cls,
+ const struct TALER_EXCHANGE_KycStatus *ks);
+
+
+/**
+ * Run interaction with exchange to check KYC status
+ * of a merchant.
+ *
+ * @param eh exchange handle to use
+ * @param payment_target number identifying the target
+ * @param h_payto hash of the payto:// URI at @a payment_target
+ * @param timeout how long to wait for a positive KYC status
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct TALER_EXCHANGE_KycCheckHandle *
+TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *eh,
+ uint64_t payment_target,
+ const struct GNUNET_HashCode *h_payto,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_EXCHANGE_KycStatusCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel KYC check operation.
+ *
+ * @param kyc handle for operation to cancel
+ */
+void
+TALER_EXCHANGE_kyc_check_cancel (struct TALER_EXCHANGE_KycCheckHandle *kyc);
+
+
+/**
+ * Handle for a ``/kyc-wallet`` operation.
+ */
+struct TALER_EXCHANGE_KycWalletHandle;
+
+
+/**
+ * KYC status response details.
+ */
+struct TALER_EXCHANGE_WalletKycResponse
+{
+
+ /**
+ * HTTP status code returned by the exchange.
+ */
+ unsigned int http_status;
+
+ /**
+ * Taler error code, if any.
+ */
+ enum TALER_ErrorCode ec;
+
+ /**
+ * Wallet's payment target UUID. Only valid if
+ * @e http_status is #MHD_HTTP_OK
+ */
+ uint64_t payment_target_uuid;
+
+};
+
+/**
+ * Function called with the result for a wallet looking
+ * up its KYC payment target.
+ *
+ * @param cls closure
+ * @param ks the wallets KYC payment target details
+ */
+typedef void
+(*TALER_EXCHANGE_KycWalletCallback)(
+ void *cls,
+ const struct TALER_EXCHANGE_WalletKycResponse *ks);
+
+
+/**
+ * Run interaction with exchange to find out the wallet's KYC
+ * identifier.
+ *
+ * @param eh exchange handle to use
+ * @param reserve_priv wallet private key to check
+ * @param cb function to call with the result
+ * @param cb_cls closure for @a cb
+ * @return NULL on error
+ */
+struct TALER_EXCHANGE_KycWalletHandle *
+TALER_EXCHANGE_kyc_wallet (struct TALER_EXCHANGE_Handle *eh,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ TALER_EXCHANGE_KycWalletCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel KYC wallet operation
+ *
+ * @param kwh handle for operation to cancel
+ */
+void
+TALER_EXCHANGE_kyc_wallet_cancel (struct TALER_EXCHANGE_KycWalletHandle *kwh);
+
+
/* ********************* /management *********************** */
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index 4037ebac..5a3313ca 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -1533,7 +1533,7 @@ typedef void
* @param done flag set if the deposit was already executed (or not)
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_DepositCallback)(
void *cls,
uint64_t rowid,
@@ -1565,7 +1565,7 @@ typedef int
* @param rc what is the commitment
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_RefreshesCallback)(
void *cls,
uint64_t rowid,
@@ -1585,7 +1585,7 @@ typedef int
* @param amount_with_fee amount being refunded
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_RefundCoinCallback)(
void *cls,
const struct TALER_Amount *amount_with_fee);
@@ -1626,6 +1626,73 @@ struct TALER_EXCHANGEDB_RefreshRevealedCoin
/**
+ * Types of operations that require KYC checks.
+ */
+enum TALER_EXCHANGEDB_KycType
+{
+
+ /**
+ * It is unclear for which type of KYC operation
+ * this information is.
+ */
+ TALER_EXCHANGEDB_KYC_UNKNOWN = 0,
+
+ /**
+ * KYC to be applied for simple withdraws without
+ * the involvement of wallet-to-wallet payments.
+ * Tied to the payto:// of the debited account.
+ */
+ TALER_EXCHANGEDB_KYC_WITHDRAW = 1,
+
+ /**
+ * KYC to be applied for simple deposits to a
+ * merchant's bank account. Tied to the payto://
+ * of the credited account.
+ */
+ TALER_EXCHANGEDB_KYC_DEPOSIT = 2,
+
+ /**
+ * KYC that is self-applied by a wallet that is exceeding the amount
+ * threshold. Tied to the reserve-account public key that identifies the
+ * funds-holding wallet.
+ */
+ TALER_EXCHANGEDB_KYC_BALANCE = 3,
+
+ /**
+ * KYC that is triggered upon wallet-to-wallet
+ * payments for the recipient of funds. Tied to the
+ * reserve public key that identifies the receiving
+ * wallet.
+ */
+ TALER_EXCHANGEDB_KYC_W2W = 4
+};
+
+
+/**
+ * Generic KYC status for some operation.
+ */
+struct TALER_EXCHANGEDB_KycStatus
+{
+ /**
+ * Number that identifies the KYC target the operation
+ * was about.
+ */
+ uint64_t payment_target_uuid;
+
+ /**
+ * What kind of KYC operation is this?
+ */
+ enum TALER_EXCHANGEDB_KycType type;
+
+ /**
+ * True if the KYC status is "satisfied".
+ */
+ bool ok;
+
+};
+
+
+/**
* Function called with information about a refresh order.
*
* @param cls closure
@@ -1660,7 +1727,7 @@ typedef void
* @param amount_with_fee amount that was deposited including fee
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_RefundCallback)(
void *cls,
uint64_t rowid,
@@ -1685,7 +1752,7 @@ typedef int
* @param execution_date when did we receive the funds
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_ReserveInCallback)(
void *cls,
uint64_t rowid,
@@ -1745,7 +1812,7 @@ typedef void
* @param amount_with_fee amount that was withdrawn
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_WithdrawCallback)(
void *cls,
uint64_t rowid,
@@ -1773,29 +1840,6 @@ typedef void
/**
- * Function called with the results of the lookup of the wire transfer
- * identifier information. Only called if we are at least aware of the
- * transaction existing.
- *
- * @param cls closure
- * @param wtid wire transfer identifier, NULL
- * if the transaction was not yet done
- * @param coin_contribution how much did the coin we asked about
- * contribute to the total transfer value? (deposit value including fee)
- * @param coin_fee how much did the exchange charge for the deposit fee
- * @param execution_time when was the transaction done, or
- * when we expect it to be done (if @a wtid was NULL)
- */
-typedef void
-(*TALER_EXCHANGEDB_WireTransferByCoinCallback)(
- void *cls,
- const struct TALER_WireTransferIdentifierRawP *wtid,
- const struct TALER_Amount *coin_contribution,
- const struct TALER_Amount *coin_fee,
- struct GNUNET_TIME_Absolute execution_time);
-
-
-/**
* Function called with the results of the lookup of the
* transaction data associated with a wire transfer identifier.
*
@@ -1838,7 +1882,7 @@ typedef void
* @param amount amount that was wired
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_WireTransferOutCallback)(
void *cls,
uint64_t rowid,
@@ -1859,7 +1903,7 @@ typedef int
* @param finished did we complete the transfer yet?
* @return #GNUNET_OK to continue, #GNUNET_SYSERR to stop iteration
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_WirePreparationCallback)(void *cls,
uint64_t rowid,
const char *wire_method,
@@ -1882,7 +1926,7 @@ typedef int
* @param coin_blind blinding factor used to blind the coin
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_RecoupCallback)(
void *cls,
uint64_t rowid,
@@ -1911,7 +1955,7 @@ typedef int
* @param coin_blind blinding factor used to blind the coin
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_RecoupRefreshCallback)(
void *cls,
uint64_t rowid,
@@ -1939,7 +1983,7 @@ typedef int
* @param wtid identifier used for the wire transfer
* @return #GNUNET_OK to continue to iterate, #GNUNET_SYSERR to stop
*/
-typedef int
+typedef enum GNUNET_GenericReturnValue
(*TALER_EXCHANGEDB_ReserveClosedCallback)(
void *cls,
uint64_t rowid,
@@ -1952,6 +1996,18 @@ typedef int
/**
+ * Function called with the amounts historically
+ * withdrawn from the same origin account.
+ *
+ * @param cls closure
+ * @param val one of the withdrawn amounts
+ */
+typedef void
+(*TALER_EXCHANGEDB_WithdrawHistoryCallback)(
+ void *cls,
+ const struct TALER_Amount *val);
+
+/**
* Function called with details about expired reserves.
*
* @param cls closure
@@ -2059,8 +2115,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
- int
- (*drop_tables) (void *cls);
+ enum GNUNET_GenericReturnValue
+ (*drop_tables)(void *cls);
/**
@@ -2069,8 +2125,8 @@ struct TALER_EXCHANGEDB_Plugin
* @param cls the @e cls of this struct with the plugin-specific state
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
*/
- int
- (*create_tables) (void *cls);
+ enum GNUNET_GenericReturnValue
+ (*create_tables)(void *cls);
/**
@@ -2081,9 +2137,9 @@ struct TALER_EXCHANGEDB_Plugin
* must point to a constant
* @return #GNUNET_OK on success
*/
- int
- (*start) (void *cls,
- const char *name);
+ enum GNUNET_GenericReturnValue
+ (*start)(void *cls,
+ const char *name);
/**
@@ -2094,7 +2150,7 @@ struct TALER_EXCHANGEDB_Plugin
* must point to a constant
* @return #GNUNET_OK on success
*/
- int
+ enum GNUNET_GenericReturnValue
(*start_read_committed)(void *cls,
const char *name);
@@ -2295,11 +2351,73 @@ struct TALER_EXCHANGEDB_Plugin
* @param[in,out] reserve the reserve data. The public key of the reserve should be set
* in this structure; it is used to query the database. The balance
* and expiration are then filled accordingly.
+ * @param[out] kyc set to the KYC status of the reserve
* @return transaction status
*/
enum GNUNET_DB_QueryStatus
(*reserves_get)(void *cls,
- struct TALER_EXCHANGEDB_Reserve *reserve);
+ struct TALER_EXCHANGEDB_Reserve *reserve,
+ struct TALER_EXCHANGEDB_KycStatus *kyc);
+
+
+ /**
+ * Set the KYC status to "OK" for a bank account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payment_target_uuid which account has been checked
+ * @param ... possibly additional data to persist (TODO)
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*set_kyc_ok)(void *cls,
+ uint64_t payment_target_uuid,
+ ...);
+
+
+ /**
+ * Get the KYC status for a bank account.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payto_uri payto:// URI that identifies the bank account
+ * @param[out] kyc set to the KYC status of the reserve
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*get_kyc_status)(void *cls,
+ const char *payto_uri,
+ struct TALER_EXCHANGEDB_KycStatus *kyc);
+
+
+ /**
+ * Get the @a kyc status and @a h_payto by UUID.
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param payment_target_uuid which account to get the KYC status for
+ * @param[out] h_payto set to the hash of the account's payto URI (unsalted)
+ * @param[out] kyc set to the KYC status of the account
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_kyc_status)(void *cls,
+ uint64_t payment_target_uuid,
+ struct GNUNET_HashCode *h_payto,
+ struct TALER_EXCHANGEDB_KycStatus *kyc);
+
+
+ /**
+ * Get the KYC status for a wallet. If the status is unknown,
+ * inserts a new status record (hence INsertSELECT).
+ *
+ * @param cls the @e cls of this struct with the plugin-specific state
+ * @param reserve_pub public key of the wallet
+ * @param[out] kyc set to the KYC status of the wallet
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*inselect_wallet_kyc_status)(
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
@@ -2389,6 +2507,27 @@ struct TALER_EXCHANGEDB_Plugin
/**
+ * Find out all of the amounts that have been withdrawn
+ * so far from the same bank account that created the
+ * given reserve.
+ *
+ * @param cls closure
+ * @param reserve_pub reserve to select withdrawals by
+ * @param duration how far back should we select withdrawals
+ * @param cb function to call on each amount withdrawn
+ * @param cb_cls closure for @a cb
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*select_withdraw_amounts_by_account)(
+ void *cls,
+ const struct TALER_ReservePublicKeyP *reserve_pub,
+ struct GNUNET_TIME_Relative duration,
+ TALER_EXCHANGEDB_WithdrawHistoryCallback cb,
+ void *cb_cls);
+
+
+ /**
* Free memory associated with the given reserve history.
*
* @param cls the @e cls of this struct with the plugin-specific state
@@ -2807,8 +2946,14 @@ struct TALER_EXCHANGEDB_Plugin
* @param h_wire hash of merchant wire details
* @param coin_pub public key of deposited coin
* @param merchant_pub merchant public key
- * @param cb function to call with the result
- * @param cb_cls closure to pass to @a cb
+ * @param[out] pending set to true if the transaction is still pending
+ * @param[out] wtid wire transfer identifier, only set if @a pending is false
+ * @param[out] coin_contribution how much did the coin we asked about
+ * contribute to the total transfer value? (deposit value including fee)
+ * @param[out] coin_fee how much did the exchange charge for the deposit fee
+ * @param[out] execution_time when was the transaction done, or
+ * when we expect it to be done (if @a pending is false)
+ * @param[out] kyc set to the kyc status of the receiver (if @a pending)
* @return transaction status code
*/
enum GNUNET_DB_QueryStatus
@@ -2818,8 +2963,12 @@ struct TALER_EXCHANGEDB_Plugin
const struct GNUNET_HashCode *h_wire,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_MerchantPublicKeyP *merchant_pub,
- TALER_EXCHANGEDB_WireTransferByCoinCallback cb,
- void *cb_cls);
+ bool *pending,
+ struct TALER_WireTransferIdentifierRawP *wtid,
+ struct GNUNET_TIME_Absolute *exec_time,
+ struct TALER_Amount *amount_with_fee,
+ struct TALER_Amount *deposit_fee,
+ struct TALER_EXCHANGEDB_KycStatus *kyc);
/**
diff --git a/src/include/taler_fakebank_lib.h b/src/include/taler_fakebank_lib.h
index dc6ba1da..16135a4d 100644
--- a/src/include/taler_fakebank_lib.h
+++ b/src/include/taler_fakebank_lib.h
@@ -87,7 +87,7 @@ TALER_FAKEBANK_start2 (uint16_t port,
* @param h bank instance
* @return #GNUNET_OK on success
*/
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h);
@@ -109,7 +109,7 @@ TALER_FAKEBANK_check_empty (struct TALER_FAKEBANK_Handle *h);
* @param[out] wtid set to the wire transfer identifier
* @return #GNUNET_OK on success
*/
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
@@ -133,7 +133,7 @@ TALER_FAKEBANK_check_debit (struct TALER_FAKEBANK_Handle *h,
* @param reserve_pub reserve public key expected in wire subject
* @return #GNUNET_OK on success
*/
-int
+enum GNUNET_GenericReturnValue
TALER_FAKEBANK_check_credit (struct TALER_FAKEBANK_Handle *h,
const struct TALER_Amount *want_amount,
const char *want_debit,
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index 3581252c..068dea7d 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -503,7 +503,7 @@ TALER_JSON_get_error_code2 (const void *data,
* @param[out] hc set to the hash
* @return #GNUNET_OK on success, #GNUNET_SYSERR if @a wire_s is malformed
*/
-int
+enum GNUNET_GenericReturnValue
TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
struct GNUNET_HashCode *hc);
@@ -516,7 +516,7 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
* @param master_pub master public key of the exchange
* @return #GNUNET_OK if signature is valid
*/
-int
+enum GNUNET_GenericReturnValue
TALER_JSON_exchange_wire_signature_check (
const json_t *wire_s,
const struct TALER_MasterPublicKeyP *master_pub);
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 6b5d3768..38c2dc25 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -167,6 +167,12 @@
*/
#define TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED 1043
+/**
+ * Signature by which an exchange affirms that an account
+ * successfully passed the KYC checks.
+ */
+#define TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS 1044
+
/**********************/
/* Auditor signatures */
@@ -247,6 +253,16 @@
*/
#define TALER_SIGNATURE_WALLET_COIN_LINK 1204
+/**
+ * Signature using a reserve key by which a wallet
+ * requests a payment target UUID for itself.
+ * Signs over just a purpose (no body), as the
+ * signature only serves to demonstrate that the request
+ * comes from the wallet controlling the private key,
+ * and not some third party.
+ */
+#define TALER_SIGNATURE_WALLET_ACCOUNT_SETUP 1205
+
/******************************/
/* Security module signatures */
@@ -286,11 +302,6 @@
*/
#define TALER_SIGNATURE_ANASTASIS_POLICY_UPLOAD 1400
-/**
- * EdDSA signature for a policy download.
- */
-#define TALER_SIGNATURE_ANASTASIS_POLICY_DOWNLOAD 1401
-
/*******************/
/* Sync signatures */
@@ -819,6 +830,31 @@ struct TALER_ExchangeKeySetPS
/**
+ * @brief Signature by which an exchange affirms that an account
+ * successfully passed the KYC checks.
+ */
+struct TALER_ExchangeAccountSetupSuccessPS
+{
+ /**
+ * Purpose is #TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS. Signed by a
+ * `struct TALER_ExchangePublicKeyP` using EdDSA.
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+
+ /**
+ * Hash over the payto for which the signature was
+ * made.
+ */
+ struct GNUNET_HashCode h_payto;
+
+ /**
+ * When was the signature made.
+ */
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+};
+
+
+/**
* @brief Signature made by the exchange offline key over the information of
* an auditor to be added to the exchange's set of auditors.
*/
diff --git a/src/include/taler_util.h b/src/include/taler_util.h
index 4b03fefa..2c556be2 100644
--- a/src/include/taler_util.h
+++ b/src/include/taler_util.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -136,7 +136,7 @@ TALER_b2s (const void *buf,
* @param[out] denom set to the amount found in configuration
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-int
+enum GNUNET_GenericReturnValue
TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
const char *option,
@@ -151,7 +151,7 @@ TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg,
* @param[out] currency where to write the result
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
-int
+enum GNUNET_GenericReturnValue
TALER_config_get_currency (const struct GNUNET_CONFIGURATION_Handle *cfg,
char **currency);
@@ -196,6 +196,7 @@ TALER_OS_init (void);
char *
TALER_urlencode (const char *s);
+
/**
* Test if all characters in @a url are valid for
* a URL.
@@ -206,6 +207,7 @@ TALER_urlencode (const char *s);
bool
TALER_url_valid_charset (const char *url);
+
/**
* Check if @a lang matches the @a language_pattern, and if so with
* which preference.
diff --git a/src/json/json_wire.c b/src/json/json_wire.c
index e8620728..f88daefc 100644
--- a/src/json/json_wire.c
+++ b/src/json/json_wire.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018 Taler Systems SA
+ Copyright (C) 2018, 2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -24,26 +24,17 @@
#include "taler_json_lib.h"
-/**
- * Compute the hash of the given wire details. The resulting
- * hash is what is put into the contract.
- *
- * @param wire_s wire details to hash
- * @param[out] hc set to the hash
- * @return #GNUNET_OK on success, #GNUNET_SYSERR if @a wire_s is malformed
- */
-int
+enum GNUNET_GenericReturnValue
TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
struct GNUNET_HashCode *hc)
{
const char *payto_uri;
- const char *salt;
- /* Current merchant backend will always make the salt
- a `struct GNUNET_HashCode`, but *we* do not insist
- on that. */
+ struct TALER_WireSalt salt;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("payto_uri", &payto_uri),
- GNUNET_JSON_spec_string ("salt", &salt),
+ GNUNET_JSON_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("salt",
+ &salt),
GNUNET_JSON_spec_end ()
};
@@ -73,21 +64,13 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
}
}
TALER_merchant_wire_signature_hash (payto_uri,
- salt,
+ &salt,
hc);
return GNUNET_OK;
}
-/**
- * Check the signature in @a wire_s. Also performs rudimentary
- * checks on the account data *if* supported.
- *
- * @param wire_s signed wire information of an exchange
- * @param master_pub master public key of the exchange
- * @return #GNUNET_OK if signature is valid
- */
-int
+enum GNUNET_GenericReturnValue
TALER_JSON_exchange_wire_signature_check (
const json_t *wire_s,
const struct TALER_MasterPublicKeyP *master_pub)
@@ -95,8 +78,10 @@ TALER_JSON_exchange_wire_signature_check (
const char *payto_uri;
struct TALER_MasterSignatureP master_sig;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_string ("payto_uri", &payto_uri),
- GNUNET_JSON_spec_fixed_auto ("master_sig", &master_sig),
+ GNUNET_JSON_spec_string ("payto_uri",
+ &payto_uri),
+ GNUNET_JSON_spec_fixed_auto ("master_sig",
+ &master_sig),
GNUNET_JSON_spec_end ()
};
@@ -130,13 +115,6 @@ TALER_JSON_exchange_wire_signature_check (
}
-/**
- * Create a signed wire statement for the given account.
- *
- * @param payto_uri account specification
- * @param master_priv private key to sign with
- * @return NULL if @a payto_uri is malformed
- */
json_t *
TALER_JSON_exchange_wire_signature_make (
const char *payto_uri,
@@ -166,13 +144,6 @@ TALER_JSON_exchange_wire_signature_make (
}
-/**
- * Obtain the wire method associated with the given
- * wire account details. @a wire_s must contain a payto://-URL
- * under 'payto_uri'.
- *
- * @return NULL on error
- */
char *
TALER_JSON_wire_to_payto (const json_t *wire_s)
{
@@ -203,13 +174,6 @@ TALER_JSON_wire_to_payto (const json_t *wire_s)
}
-/**
- * Obtain the wire method associated with the given
- * wire account details. @a wire_s must contain a payto://-URL
- * under 'url'.
- *
- * @return NULL on error
- */
char *
TALER_JSON_wire_to_method (const json_t *wire_s)
{
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 22209de4..518b725a 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -27,6 +27,8 @@ libtalerexchange_la_SOURCES = \
exchange_api_handle.c exchange_api_handle.h \
exchange_api_deposit.c \
exchange_api_deposits_get.c \
+ exchange_api_kyc_check.c \
+ exchange_api_kyc_wallet.c \
exchange_api_link.c \
exchange_api_management_auditor_disable.c \
exchange_api_management_auditor_enable.c \
diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c
index da1400b9..9c4a95ad 100644
--- a/src/lib/exchange_api_common.c
+++ b/src/lib/exchange_api_common.c
@@ -42,7 +42,7 @@
* were set,
* #GNUNET_SYSERR if there was a protocol violation in @a history
*/
-int
+enum GNUNET_GenericReturnValue
TALER_EXCHANGE_parse_reserve_history (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *history,
@@ -445,7 +445,7 @@ TALER_EXCHANGE_free_reserve_history (
* @param[out] total how much of the coin has been spent according to @a history
* @return #GNUNET_OK if @a history is valid, #GNUNET_SYSERR if not
*/
-int
+enum GNUNET_GenericReturnValue
TALER_EXCHANGE_verify_coin_history (
const struct TALER_EXCHANGE_DenomPublicKey *dk,
const char *currency,
diff --git a/src/lib/exchange_api_deposit.c b/src/lib/exchange_api_deposit.c
index 86f5034a..35e09bd0 100644
--- a/src/lib/exchange_api_deposit.c
+++ b/src/lib/exchange_api_deposit.c
@@ -179,65 +179,6 @@ auditor_cb (void *cls,
/**
- * Verify that the signature on the "200 OK" response
- * from the exchange is valid.
- *
- * @param dh deposit handle
- * @param json json reply with the signature
- * @param[out] exchange_sig set to the exchange's signature
- * @param[out] exchange_pub set to the exchange's public key
- * @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
- */
-static int
-verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
- const json_t *json,
- struct TALER_ExchangeSignatureP *exchange_sig,
- struct TALER_ExchangePublicKeyP *exchange_pub)
-{
- 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),
- TALER_JSON_spec_absolute_time_nbo ("exchange_timestamp",
- &dh->depconf.exchange_timestamp),
- 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 (dh->exchange);
- if (GNUNET_OK !=
- TALER_EXCHANGE_test_signing_key (key_state,
- exchange_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
- &dh->depconf,
- &exchange_sig->eddsa_signature,
- &exchange_pub->eddsa_pub))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- dh->exchange_sig = *exchange_sig;
- dh->exchange_pub = *exchange_pub;
- TEAH_get_auditors_for_dc (dh->exchange,
- &auditor_cb,
- dh);
- return GNUNET_OK;
-}
-
-
-/**
* Verify that the signatures on the "403 FORBIDDEN" response from the
* exchange demonstrating customer double-spending are valid.
*
@@ -245,7 +186,7 @@ verify_deposit_signature_ok (struct TALER_EXCHANGE_DepositHandle *dh,
* @param json json reply with the signature(s) and transaction history
* @return #GNUNET_OK if the signature(s) is valid, #GNUNET_SYSERR if not
*/
-static int
+static enum GNUNET_GenericReturnValue
verify_deposit_signature_conflict (
const struct TALER_EXCHANGE_DepositHandle *dh,
const json_t *json)
@@ -322,55 +263,93 @@ handle_deposit_finished (void *cls,
const void *response)
{
struct TALER_EXCHANGE_DepositHandle *dh = cls;
- struct TALER_ExchangeSignatureP exchange_sig;
- struct TALER_ExchangePublicKeyP exchange_pub;
- struct TALER_ExchangeSignatureP *es = NULL;
- struct TALER_ExchangePublicKeyP *ep = NULL;
const json_t *j = response;
- struct TALER_EXCHANGE_HttpResponse hr = {
- .reply = j,
- .http_status = (unsigned int) response_code
+ struct TALER_EXCHANGE_DepositResult dr = {
+ .hr.reply = j,
+ .hr.http_status = (unsigned int) response_code
};
dh->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
- if (GNUNET_OK !=
- verify_deposit_signature_ok (dh,
- j,
- &exchange_sig,
- &exchange_pub))
- {
- GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
- }
- else
{
- es = &exchange_sig;
- ep = &exchange_pub;
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &dh->exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &dh->exchange_pub),
+ GNUNET_JSON_spec_mark_optional (
+ GNUNET_JSON_spec_string ("transaction_base_url",
+ &dr.details.success.transaction_base_url)),
+ TALER_JSON_spec_absolute_time_nbo ("exchange_timestamp",
+ &dh->depconf.exchange_timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ key_state = TALER_EXCHANGE_get_keys (dh->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &dh->exchange_pub))
+ {
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
+ break;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT,
+ &dh->depconf,
+ &dh->exchange_sig.eddsa_signature,
+ &dh->exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
+ break;
+ }
+
+ TEAH_get_auditors_for_dc (dh->exchange,
+ &auditor_cb,
+ dh);
+
}
+ dr.details.success.exchange_sig = &dh->exchange_sig;
+ dr.details.success.exchange_pub = &dh->exchange_pub;
+ dr.details.success.deposit_timestamp
+ = GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp);
break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_FORBIDDEN:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
break;
case MHD_HTTP_NOT_FOUND:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Nothing really to verify, this should never
happen, we should pass the JSON reply to the application */
break;
@@ -381,13 +360,13 @@ handle_deposit_finished (void *cls,
j))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_EXCHANGE_DEPOSIT_INVALID_SIGNATURE_BY_EXCHANGE;
}
else
{
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
}
break;
case MHD_HTTP_GONE:
@@ -395,31 +374,28 @@ handle_deposit_finished (void *cls,
/* Note: one might want to check /keys for revocation
signature here, alas tricky in case our /keys
is outdated => left to clients */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
break;
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange deposit\n",
(unsigned int) response_code,
- hr.ec);
+ dr.hr.ec);
GNUNET_break_op (0);
break;
}
dh->cb (dh->cb_cls,
- &hr,
- GNUNET_TIME_absolute_ntoh (dh->depconf.exchange_timestamp),
- es,
- ep);
+ &dr);
TALER_EXCHANGE_deposit_cancel (dh);
}
@@ -441,7 +417,7 @@ handle_deposit_finished (void *cls,
* @param coin_sig the signature made with purpose #TALER_SIGNATURE_WALLET_COIN_DEPOSIT made by the customer with the coin’s private key.
* @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not
*/
-static int
+static enum GNUNET_GenericReturnValue
verify_signatures (const struct TALER_EXCHANGE_DenomPublicKey *dki,
const struct TALER_Amount *amount,
const struct GNUNET_HashCode *h_wire,
diff --git a/src/lib/exchange_api_deposits_get.c b/src/lib/exchange_api_deposits_get.c
index efe9070f..e449aefb 100644
--- a/src/lib/exchange_api_deposits_get.c
+++ b/src/lib/exchange_api_deposits_get.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -88,7 +88,7 @@ struct TALER_EXCHANGE_DepositGetHandle
* @param exchange_sig the exchange's signature
* @return #GNUNET_OK if the signature is valid, #GNUNET_SYSERR if not
*/
-static int
+static enum GNUNET_GenericReturnValue
verify_deposit_wtid_signature_ok (
const struct TALER_EXCHANGE_DepositGetHandle *dwh,
const json_t *json,
@@ -133,26 +133,30 @@ handle_deposit_wtid_finished (void *cls,
{
struct TALER_EXCHANGE_DepositGetHandle *dwh = cls;
const json_t *j = response;
- struct TALER_EXCHANGE_HttpResponse hr = {
- .reply = j,
- .http_status = (unsigned int) response_code
+ struct TALER_EXCHANGE_GetDepositResponse dr = {
+ .hr.reply = j,
+ .hr.http_status = (unsigned int) response_code
};
dwh->job = NULL;
switch (response_code)
{
case 0:
- hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ dr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
- struct TALER_EXCHANGE_DepositData dd;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("wtid", &dwh->depconf.wtid),
- TALER_JSON_spec_absolute_time ("execution_time", &dd.execution_time),
- TALER_JSON_spec_amount_any ("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_fixed_auto ("wtid",
+ &dr.details.success.wtid),
+ TALER_JSON_spec_absolute_time ("execution_time",
+ &dr.details.success.execution_time),
+ TALER_JSON_spec_amount_any ("coin_contribution",
+ &dr.details.success.coin_contribution),
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &dr.details.success.exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &dr.details.success.exchange_pub),
GNUNET_JSON_spec_end ()
};
@@ -162,41 +166,41 @@ handle_deposit_wtid_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
dwh->depconf.execution_time = GNUNET_TIME_absolute_hton (
- dd.execution_time);
+ dr.details.success.execution_time);
+ dwh->depconf.wtid = dr.details.success.wtid;
TALER_amount_hton (&dwh->depconf.coin_contribution,
- &dd.coin_contribution);
+ &dr.details.success.coin_contribution);
if (GNUNET_OK !=
verify_deposit_wtid_signature_ok (dwh,
j,
- &dd.exchange_pub,
- &dd.exchange_sig))
+ &dr.details.success.exchange_pub,
+ &dr.details.success.exchange_sig))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_SIGNATURE_BY_EXCHANGE;
- }
- else
- {
- dd.wtid = dwh->depconf.wtid;
- dwh->cb (dwh->cb_cls,
- &hr,
- &dd);
- TALER_EXCHANGE_deposits_get_cancel (dwh);
- return;
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_EXCHANGE_DEPOSITS_GET_INVALID_SIGNATURE_BY_EXCHANGE;
+ break;
}
+ dwh->cb (dwh->cb_cls,
+ &dr);
+ 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[] = {
- TALER_JSON_spec_absolute_time ("execution_time", &execution_time),
+ TALER_JSON_spec_absolute_time ("execution_time",
+ &dr.details.accepted.execution_time),
+ GNUNET_JSON_spec_uint64 ("payment_target_uuid",
+ &dr.details.accepted.payment_target_uuid),
+ GNUNET_JSON_spec_bool ("kyc_ok",
+ &dr.details.accepted.kyc_ok),
GNUNET_JSON_spec_end ()
};
@@ -206,63 +210,53 @@ handle_deposit_wtid_finished (void *cls,
NULL, NULL))
{
GNUNET_break_op (0);
- hr.http_status = 0;
- hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ dr.hr.http_status = 0;
+ dr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
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;
- }
+ dwh->cb (dwh->cb_cls,
+ &dr);
+ TALER_EXCHANGE_deposits_get_cancel (dwh);
+ return;
}
- break;
case MHD_HTTP_BAD_REQUEST:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
break;
case MHD_HTTP_FORBIDDEN:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Nothing really to verify, exchange says one of the signatures is
invalid; as we checked them, this should never happen, we
should pass the JSON reply to the application */
break;
case MHD_HTTP_NOT_FOUND:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Exchange does not know about transaction;
we should pass the reply to the application */
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
break;
default:
/* unexpected response code */
- hr.ec = TALER_JSON_get_error_code (j);
- hr.hint = TALER_JSON_get_error_hint (j);
+ dr.hr.ec = TALER_JSON_get_error_code (j);
+ dr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for exchange GET deposits\n",
(unsigned int) response_code,
- (int) hr.ec);
+ (int) dr.hr.ec);
GNUNET_break_op (0);
break;
}
dwh->cb (dwh->cb_cls,
- &hr,
- NULL);
+ &dr);
TALER_EXCHANGE_deposits_get_cancel (dwh);
}
diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c
index dfd5a3dc..215f122b 100644
--- a/src/lib/exchange_api_handle.c
+++ b/src/lib/exchange_api_handle.c
@@ -257,7 +257,7 @@ free_keys_request (struct KeysRequest *kr)
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
int check_sigs,
json_t *sign_key_obj,
@@ -317,7 +317,7 @@ parse_json_signkey (struct TALER_EXCHANGE_SigningPublicKey *sign_key,
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_json_denomkey (struct TALER_EXCHANGE_DenomPublicKey *denom_key,
int check_sigs,
json_t *denom_key_obj,
@@ -402,7 +402,7 @@ EXITIF_exit:
* @return #GNUNET_OK if all is fine, #GNUNET_SYSERR if the signature is
* invalid or the json malformed.
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor,
int check_sigs,
json_t *auditor_obj,
@@ -670,7 +670,7 @@ denoms_cmp (struct TALER_EXCHANGE_DenomPublicKey *denom1,
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
* (malformed JSON)
*/
-static int
+static enum GNUNET_GenericReturnValue
decode_keys_json (const json_t *resp_obj,
bool check_sig,
struct TALER_EXCHANGE_Keys *key_data,
@@ -685,8 +685,6 @@ decode_keys_json (const json_t *resp_obj,
&sig),
GNUNET_JSON_spec_fixed_auto ("eddsa_pub",
&pub),
- /* sig and pub must be first, as we skip those if
- check_sig is false! */
GNUNET_JSON_spec_fixed_auto ("master_public_key",
&key_data->master_pub),
TALER_JSON_spec_absolute_time ("list_issue_date",
@@ -695,6 +693,9 @@ decode_keys_json (const json_t *resp_obj,
&key_data->reserve_closing_delay),
GNUNET_JSON_spec_string ("currency",
&currency),
+ GNUNET_JSON_spec_mark_optional (
+ TALER_JSON_spec_amount_any ("wallet_balance_limit_without_kyc",
+ &key_data->wallet_balance_limit_without_kyc)),
GNUNET_JSON_spec_end ()
};
@@ -761,6 +762,17 @@ decode_keys_json (const json_t *resp_obj,
(check_sig) ? mspec : &mspec[2],
NULL, NULL));
key_data->currency = GNUNET_strdup (currency);
+
+ if (GNUNET_OK ==
+ TALER_amount_is_valid (&key_data->wallet_balance_limit_without_kyc))
+ {
+ if (0 != strcasecmp (currency,
+ key_data->wallet_balance_limit_without_kyc.currency))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ }
/* parse the master public key and issue date of the response */
if (check_sig)
hash_context = GNUNET_CRYPTO_hash_context_start ();
@@ -1314,7 +1326,7 @@ TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h)
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
-int
+enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h)
{
return (MHS_CERT == h->state) ? GNUNET_YES : GNUNET_NO;
@@ -1352,7 +1364,7 @@ TEAH_path_to_url (struct TALER_EXCHANGE_Handle *h,
* @param at where to write the result
* @return #GNUNET_OK on success
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_date_string (const char *dateline,
struct GNUNET_TIME_Absolute *at)
{
diff --git a/src/lib/exchange_api_handle.h b/src/lib/exchange_api_handle.h
index 1a7e8ee7..df0ccf7f 100644
--- a/src/lib/exchange_api_handle.h
+++ b/src/lib/exchange_api_handle.h
@@ -229,7 +229,7 @@ TEAH_handle_to_context (struct TALER_EXCHANGE_Handle *h);
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
-int
+enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
/**
@@ -238,7 +238,7 @@ TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
* @param h the exchange handle to query
* @return #GNUNET_YES if we are ready, #GNUNET_NO if not
*/
-int
+enum GNUNET_GenericReturnValue
TEAH_handle_is_ready (struct TALER_EXCHANGE_Handle *h);
diff --git a/src/lib/exchange_api_kyc_check.c b/src/lib/exchange_api_kyc_check.c
new file mode 100644
index 00000000..82fddd45
--- /dev/null
+++ b/src/lib/exchange_api_kyc_check.c
@@ -0,0 +1,297 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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 lib/exchange_api_kyc_check.c
+ * @brief Implementation of the /kyc-check request
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <microhttpd.h> /* just for HTTP check codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+#include "exchange_api_curl_defaults.h"
+
+
+/**
+ * @brief A ``/kyc-check`` handle
+ */
+struct TALER_EXCHANGE_KycCheckHandle
+{
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_KycStatusCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Hash of the payto:// URL that is being KYC'ed.
+ */
+ struct GNUNET_HashCode h_payto;
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /kyc-check request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_KycCheckHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response parsed JSON result, NULL on error
+ */
+static void
+handle_kyc_check_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_EXCHANGE_KycCheckHandle *kch = cls;
+ const json_t *j = response;
+ struct TALER_EXCHANGE_KycStatus ks = {
+ .http_status = (unsigned int) response_code
+ };
+
+ kch->job = NULL;
+ switch (response_code)
+ {
+ case 0:
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_OK:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_fixed_auto ("exchange_sig",
+ &ks.details.kyc_ok.exchange_sig),
+ GNUNET_JSON_spec_fixed_auto ("exchange_pub",
+ &ks.details.kyc_ok.exchange_pub),
+ TALER_JSON_spec_absolute_time ("now",
+ &ks.details.kyc_ok.timestamp),
+ GNUNET_JSON_spec_end ()
+ };
+ const struct TALER_EXCHANGE_Keys *key_state;
+ struct TALER_ExchangeAccountSetupSuccessPS kyc_purpose = {
+ .purpose.size = htonl (sizeof (kyc_purpose)),
+ .purpose.purpose = htonl (
+ TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS),
+ .h_payto = kch->h_payto
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ks.http_status = 0;
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ kyc_purpose.timestamp = GNUNET_TIME_absolute_hton (
+ ks.details.kyc_ok.timestamp);
+ key_state = TALER_EXCHANGE_get_keys (kch->exchange);
+ if (GNUNET_OK !=
+ TALER_EXCHANGE_test_signing_key (key_state,
+ &ks.details.kyc_ok.exchange_pub))
+ {
+ GNUNET_break_op (0);
+ ks.http_status = 0;
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_JSON_parse_free (spec);
+ break;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_eddsa_verify (
+ TALER_SIGNATURE_EXCHANGE_ACCOUNT_SETUP_SUCCESS,
+ &kyc_purpose,
+ &ks.details.kyc_ok.exchange_sig.eddsa_signature,
+ &ks.details.kyc_ok.exchange_pub.eddsa_pub))
+ {
+ GNUNET_break_op (0);
+ ks.http_status = 0;
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ GNUNET_JSON_parse_free (spec);
+ break;
+ }
+ kch->cb (kch->cb_cls,
+ &ks);
+ GNUNET_JSON_parse_free (spec);
+ TALER_EXCHANGE_kyc_check_cancel (kch);
+ return;
+ }
+ case MHD_HTTP_ACCEPTED:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("kyc_url",
+ &ks.details.kyc_url),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ks.http_status = 0;
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ kch->cb (kch->cb_cls,
+ &ks);
+ GNUNET_JSON_parse_free (spec);
+ TALER_EXCHANGE_kyc_check_cancel (kch);
+ return;
+ }
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ ks.ec = TALER_JSON_get_error_code (j);
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ ks.ec = TALER_JSON_get_error_code (j);
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ ks.ec = TALER_JSON_get_error_code (j);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ ks.ec = TALER_JSON_get_error_code (j);
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_break_op (0);
+ ks.ec = TALER_JSON_get_error_code (j);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d for exchange kyc_check\n",
+ (unsigned int) response_code,
+ (int) ks.ec);
+ break;
+ }
+ kch->cb (kch->cb_cls,
+ &ks);
+ TALER_EXCHANGE_kyc_check_cancel (kch);
+}
+
+
+struct TALER_EXCHANGE_KycCheckHandle *
+TALER_EXCHANGE_kyc_check (struct TALER_EXCHANGE_Handle *exchange,
+ uint64_t payment_target,
+ const struct GNUNET_HashCode *h_payto,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_EXCHANGE_KycStatusCallback cb,
+ void *cb_cls)
+{
+ struct TALER_EXCHANGE_KycCheckHandle *kch;
+ CURL *eh;
+ struct GNUNET_CURL_Context *ctx;
+ char *arg_str;
+
+ if (GNUNET_YES !=
+ TEAH_handle_is_ready (exchange))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ {
+ char payto_str[sizeof (*h_payto) * 2];
+ char *end;
+ unsigned long long timeout_ms;
+
+ end = GNUNET_STRINGS_data_to_string (
+ h_payto,
+ sizeof (*h_payto),
+ payto_str,
+ sizeof (payto_str) - 1);
+ *end = '\0';
+ timeout_ms = timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
+ GNUNET_asprintf (&arg_str,
+ "/kyc-check/%llu?h_payto=%s&timeout_ms=%llu",
+ (unsigned long long) payment_target,
+ payto_str,
+ timeout_ms);
+ }
+ kch = GNUNET_new (struct TALER_EXCHANGE_KycCheckHandle);
+ kch->exchange = exchange;
+ kch->h_payto = *h_payto;
+ kch->cb = cb;
+ kch->cb_cls = cb_cls;
+ kch->url = TEAH_path_to_url (exchange,
+ arg_str);
+ GNUNET_free (arg_str);
+ if (NULL == kch->url)
+ {
+ GNUNET_free (kch);
+ return NULL;
+ }
+ eh = TALER_EXCHANGE_curl_easy_get_ (kch->url);
+ if (NULL == eh)
+ {
+ GNUNET_break (0);
+ GNUNET_free (kch->url);
+ GNUNET_free (kch);
+ return NULL;
+ }
+ ctx = TEAH_handle_to_context (exchange);
+ kch->job = GNUNET_CURL_job_add_with_ct_json (ctx,
+ eh,
+ &handle_kyc_check_finished,
+ kch);
+ return kch;
+}
+
+
+void
+TALER_EXCHANGE_kyc_check_cancel (struct TALER_EXCHANGE_KycCheckHandle *kch)
+{
+ if (NULL != kch->job)
+ {
+ GNUNET_CURL_job_cancel (kch->job);
+ kch->job = NULL;
+ }
+ GNUNET_free (kch->url);
+ GNUNET_free (kch);
+}
+
+
+/* end of exchange_api_kyc_check.c */
diff --git a/src/lib/exchange_api_kyc_wallet.c b/src/lib/exchange_api_kyc_wallet.c
new file mode 100644
index 00000000..16d4253e
--- /dev/null
+++ b/src/lib/exchange_api_kyc_wallet.c
@@ -0,0 +1,232 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2021 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 lib/exchange_api_kyc_wallet.c
+ * @brief Implementation of the /kyc-wallet request
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <microhttpd.h> /* just for HTTP wallet codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_exchange_service.h"
+#include "taler_json_lib.h"
+#include "exchange_api_handle.h"
+#include "taler_signatures.h"
+#include "exchange_api_curl_defaults.h"
+
+
+/**
+ * @brief A ``/kyc-wallet`` handle
+ */
+struct TALER_EXCHANGE_KycWalletHandle
+{
+
+ /**
+ * Context for #TEH_curl_easy_post(). Keeps the data that must
+ * persist for Curl to make the upload.
+ */
+ struct TALER_CURL_PostContext ctx;
+
+ /**
+ * The connection to exchange this request handle will use
+ */
+ struct TALER_EXCHANGE_Handle *exchange;
+
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_EXCHANGE_KycWalletCallback cb;
+
+ /**
+ * Closure for @e cb.
+ */
+ void *cb_cls;
+
+};
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /kyc-wallet request.
+ *
+ * @param cls the `struct TALER_EXCHANGE_KycWalletHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param response parsed JSON result, NULL on error
+ */
+static void
+handle_kyc_wallet_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_EXCHANGE_KycWalletHandle *kwh = cls;
+ const json_t *j = response;
+ struct TALER_EXCHANGE_WalletKycResponse ks = {
+ .http_status = (unsigned int) response_code
+ };
+
+ kwh->job = NULL;
+ switch (response_code)
+ {
+ case 0:
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ case MHD_HTTP_OK:
+ {
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint64 ("payment_target_uuid",
+ &ks.payment_target_uuid),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ks.http_status = 0;
+ ks.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
+ break;
+ }
+ break;
+ }
+ case MHD_HTTP_NO_CONTENT:
+ break;
+ case MHD_HTTP_BAD_REQUEST:
+ ks.ec = TALER_JSON_get_error_code (j);
+ /* This should never happen, either us or the exchange is buggy
+ (or API version conflict); just pass JSON reply to the application */
+ break;
+ case MHD_HTTP_UNAUTHORIZED:
+ ks.ec = TALER_JSON_get_error_code (j);
+ break;
+ case MHD_HTTP_NOT_FOUND:
+ ks.ec = TALER_JSON_get_error_code (j);
+ break;
+ case MHD_HTTP_INTERNAL_SERVER_ERROR:
+ ks.ec = TALER_JSON_get_error_code (j);
+ /* Server had an internal issue; we should retry, but this API
+ leaves this to the application */
+ break;
+ default:
+ /* unexpected response code */
+ GNUNET_break_op (0);
+ ks.ec = TALER_JSON_get_error_code (j);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d for exchange /kyc-wallet\n",
+ (unsigned int) response_code,
+ (int) ks.ec);
+ break;
+ }
+ kwh->cb (kwh->cb_cls,
+ &ks);
+ TALER_EXCHANGE_kyc_wallet_cancel (kwh);
+}
+
+
+struct TALER_EXCHANGE_KycWalletHandle *
+TALER_EXCHANGE_kyc_wallet (struct TALER_EXCHANGE_Handle *exchange,
+ const struct TALER_ReservePrivateKeyP *reserve_priv,
+ TALER_EXCHANGE_KycWalletCallback cb,
+ void *cb_cls)
+{
+ struct TALER_EXCHANGE_KycWalletHandle *kwh;
+ CURL *eh;
+ json_t *req;
+ struct GNUNET_CURL_Context *ctx;
+ struct TALER_ReservePublicKeyP reserve_pub;
+ struct TALER_ReserveSignatureP reserve_sig;
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose = {
+ .size = htonl (sizeof (purpose)),
+ .purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP)
+ };
+
+ GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv,
+ &reserve_pub.eddsa_pub);
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv,
+ &purpose,
+ &reserve_sig.eddsa_signature));
+ req = GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_data_auto ("reserve_pub",
+ &reserve_pub),
+ GNUNET_JSON_pack_data_auto ("reserve_sig",
+ &reserve_sig));
+ GNUNET_assert (NULL != req);
+ kwh = GNUNET_new (struct TALER_EXCHANGE_KycWalletHandle);
+ kwh->exchange = exchange;
+ kwh->cb = cb;
+ kwh->cb_cls = cb_cls;
+ kwh->url = TEAH_path_to_url (exchange,
+ "/kyc-wallet");
+ if (NULL == kwh->url)
+ {
+ GNUNET_free (kwh);
+ return NULL;
+ }
+ ctx = TEAH_handle_to_context (exchange);
+ eh = TALER_EXCHANGE_curl_easy_get_ (kwh->url);
+ if ( (NULL == eh) ||
+ (GNUNET_OK !=
+ TALER_curl_easy_post (&kwh->ctx,
+ eh,
+ req)) )
+ {
+ GNUNET_break (0);
+ if (NULL != eh)
+ curl_easy_cleanup (eh);
+ json_decref (req);
+ GNUNET_free (kwh->url);
+ GNUNET_free (kwh);
+ return NULL;
+ }
+ json_decref (req);
+ kwh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ &handle_kyc_wallet_finished,
+ kwh);
+ return kwh;
+}
+
+
+void
+TALER_EXCHANGE_kyc_wallet_cancel (struct TALER_EXCHANGE_KycWalletHandle *kwh)
+{
+ if (NULL != kwh->job)
+ {
+ GNUNET_CURL_job_cancel (kwh->job);
+ kwh->job = NULL;
+ }
+ GNUNET_free (kwh->url);
+ TALER_curl_easy_post_finished (&kwh->ctx);
+ GNUNET_free (kwh);
+}
+
+
+/* end of exchange_api_kyc_wallet.c */
diff --git a/src/lib/exchange_api_link.c b/src/lib/exchange_api_link.c
index 7f29b3b8..ceb31884 100644
--- a/src/lib/exchange_api_link.c
+++ b/src/lib/exchange_api_link.c
@@ -82,7 +82,7 @@ struct TALER_EXCHANGE_LinkHandle
* @param[out] pub where to return the public key for the coin
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
const json_t *json,
uint32_t coin_num,
@@ -175,7 +175,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
* @param json json reply with the data for one coin
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-static int
+static enum GNUNET_GenericReturnValue
parse_link_ok (struct TALER_EXCHANGE_LinkHandle *lh,
const json_t *json)
{
diff --git a/src/lib/exchange_api_withdraw.c b/src/lib/exchange_api_withdraw.c
index b96adacd..85b7e7db 100644
--- a/src/lib/exchange_api_withdraw.c
+++ b/src/lib/exchange_api_withdraw.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -91,44 +91,58 @@ handle_reserve_withdraw_finished (
const struct GNUNET_CRYPTO_RsaSignature *blind_sig)
{
struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
+ struct TALER_EXCHANGE_WithdrawResponse wr = {
+ .hr = *hr
+ };
wh->wh2 = NULL;
- if (MHD_HTTP_OK != hr->http_status)
+ switch (hr->http_status)
{
- wh->cb (wh->cb_cls,
- hr,
- NULL);
- }
- else
- {
- struct TALER_FreshCoin fc;
-
- if (GNUNET_OK !=
- TALER_planchet_to_coin (&wh->pk.key,
- blind_sig,
- &wh->ps,
- &wh->c_hash,
- &fc))
+ case MHD_HTTP_OK:
{
- struct TALER_EXCHANGE_HttpResponse hrx = {
- .reply = hr->reply,
- .http_status = 0,
- .ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE
- };
-
- wh->cb (wh->cb_cls,
- &hrx,
- NULL);
+ struct TALER_FreshCoin fc;
+
+ if (GNUNET_OK !=
+ TALER_planchet_to_coin (&wh->pk.key,
+ blind_sig,
+ &wh->ps,
+ &wh->c_hash,
+ &fc))
+ {
+ wr.hr.http_status = 0;
+ wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE;
+ break;
+ }
+ wr.details.success.sig = fc.sig;
+ break;
}
- else
+ case MHD_HTTP_ACCEPTED:
{
- wh->cb (wh->cb_cls,
- hr,
- &fc.sig);
- GNUNET_CRYPTO_rsa_signature_free (fc.sig.rsa_signature);
- }
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint64 ("payment_target_uuid",
+ &wr.details.accepted.payment_target_uuid),
+ GNUNET_JSON_spec_end ()
+ };
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (hr->reply,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ wr.hr.http_status = 0;
+ wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
}
+ wh->cb (wh->cb_cls,
+ &wr);
+ if (MHD_HTTP_OK == hr->http_status)
+ GNUNET_CRYPTO_rsa_signature_free (wr.details.success.sig.rsa_signature);
TALER_EXCHANGE_withdraw_cancel (wh);
}
diff --git a/src/lib/exchange_api_withdraw2.c b/src/lib/exchange_api_withdraw2.c
index c8a95968..330f93d7 100644
--- a/src/lib/exchange_api_withdraw2.c
+++ b/src/lib/exchange_api_withdraw2.c
@@ -95,7 +95,7 @@ struct TALER_EXCHANGE_Withdraw2Handle
* @param json reply from the exchange
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
-static int
+static enum GNUNET_GenericReturnValue
reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh,
const json_t *json)
{
@@ -142,7 +142,7 @@ reserve_withdraw_ok (struct TALER_EXCHANGE_Withdraw2Handle *wh,
* @param json reply from the exchange
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
-static int
+static enum GNUNET_GenericReturnValue
reserve_withdraw_payment_required (
struct TALER_EXCHANGE_Withdraw2Handle *wh,
const json_t *json)
@@ -269,6 +269,28 @@ handle_reserve_withdraw_finished (void *cls,
GNUNET_assert (NULL == wh->cb);
TALER_EXCHANGE_withdraw2_cancel (wh);
return;
+ case MHD_HTTP_ACCEPTED:
+ /* only validate reply is well-formed */
+ {
+ uint64_t ptu;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_uint64 ("payment_target_uuid",
+ &ptu),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (j,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ hr.http_status = 0;
+ hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
+ break;
+ }
+ }
+ break;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
diff --git a/src/mhd/mhd_responses.c b/src/mhd/mhd_responses.c
index c993436c..d9338106 100644
--- a/src/mhd/mhd_responses.c
+++ b/src/mhd/mhd_responses.c
@@ -268,6 +268,11 @@ TALER_MHD_reply_cors_preflight (struct MHD_Connection *connection)
/* Not available as MHD constant yet */
"Access-Control-Allow-Methods",
"*"));
+ GNUNET_break (MHD_YES ==
+ MHD_add_response_header (response,
+ /* Not available as MHD constant yet */
+ "Access-Control-Expose-Headers",
+ "*"));
{
MHD_RESULT ret;
diff --git a/src/mhd/mhd_run.c b/src/mhd/mhd_run.c
index 8141390c..cb073e83 100644
--- a/src/mhd/mhd_run.c
+++ b/src/mhd/mhd_run.c
@@ -29,9 +29,9 @@
/**
- * Set if we should immediately MHD_run() again.
+ * Set to true if we should immediately MHD_run() again.
*/
-static int triggered;
+static bool triggered;
/**
* Task running the HTTP server.
@@ -63,10 +63,10 @@ run_daemon (void *cls)
{
mhd_task = NULL;
do {
- triggered = 0;
+ triggered = false;
GNUNET_assert (MHD_YES ==
MHD_run (mhd));
- } while (0 != triggered);
+ } while (triggered);
mhd_task = prepare_daemon ();
}
@@ -166,7 +166,7 @@ TALER_MHD_daemon_trigger (void)
}
else
{
- triggered = 1;
+ triggered = true;
}
}
diff --git a/src/testing/testing_api_cmd_deposit.c b/src/testing/testing_api_cmd_deposit.c
index a392884a..58322b1d 100644
--- a/src/testing/testing_api_cmd_deposit.c
+++ b/src/testing/testing_api_cmd_deposit.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -207,38 +207,30 @@ do_retry (void *cls)
* check if the response code is acceptable.
*
* @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,
- * used for signing the response.
+ * @param dr deposit response details
*/
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)
+ const struct TALER_EXCHANGE_DepositResult *dr)
{
struct DepositState *ds = cls;
ds->dh = NULL;
- if (ds->expected_response_code != hr->http_status)
+ if (ds->expected_response_code != dr->hr.http_status)
{
if (0 != ds->do_retry)
{
ds->do_retry--;
- if ( (0 == hr->http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
+ if ( (0 == dr->hr.http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == dr->hr.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying deposit failed with %u/%d\n",
- hr->http_status,
- (int) hr->ec);
+ dr->hr.http_status,
+ (int) dr->hr.ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == dr->hr.ec)
ds->backoff = GNUNET_TIME_UNIT_ZERO;
else
ds->backoff = GNUNET_TIME_randomized_backoff (ds->backoff,
@@ -253,22 +245,22 @@ deposit_cb (void *cls,
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u to command %s in %s:%u\n",
- hr->http_status,
+ dr->hr.http_status,
ds->is->commands[ds->is->ip].label,
__FILE__,
__LINE__);
- json_dumpf (hr->reply,
+ json_dumpf (dr->hr.reply,
stderr,
0);
TALER_TESTING_interpreter_fail (ds->is);
return;
}
- if (MHD_HTTP_OK == hr->http_status)
+ if (MHD_HTTP_OK == dr->hr.http_status)
{
ds->deposit_succeeded = GNUNET_YES;
- ds->exchange_timestamp = exchange_timestamp;
- ds->exchange_pub = *exchange_pub;
- ds->exchange_sig = *exchange_sig;
+ ds->exchange_timestamp = dr->details.success.deposit_timestamp;
+ ds->exchange_pub = *dr->details.success.exchange_pub;
+ ds->exchange_sig = *dr->details.success.exchange_sig;
}
TALER_TESTING_interpreter_next (ds->is);
}
diff --git a/src/testing/testing_api_cmd_deposits_get.c b/src/testing/testing_api_cmd_deposits_get.c
index f2f3f0e3..61358291 100644
--- a/src/testing/testing_api_cmd_deposits_get.c
+++ b/src/testing/testing_api_cmd_deposits_get.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2020 Taler Systems SA
+ Copyright (C) 2014-2021 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
@@ -80,38 +80,36 @@ struct TrackTransactionState
* line matches our expectations.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param dd data about the wire transfer associated with the deposit
+ * @param dr GET deposit response details
*/
static void
deposit_wtid_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_EXCHANGE_DepositData *dd)
+ const struct TALER_EXCHANGE_GetDepositResponse *dr)
{
struct TrackTransactionState *tts = cls;
struct TALER_TESTING_Interpreter *is = tts->is;
struct TALER_TESTING_Command *cmd = &is->commands[is->ip];
tts->tth = NULL;
- if (tts->expected_response_code != hr->http_status)
+ if (tts->expected_response_code != dr->hr.http_status)
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
+ dr->hr.http_status,
+ (int) dr->hr.ec,
cmd->label,
__FILE__,
__LINE__);
- json_dumpf (hr->reply,
+ json_dumpf (dr->hr.reply,
stderr,
0);
TALER_TESTING_interpreter_fail (is);
return;
}
- switch (hr->http_status)
+ switch (dr->hr.http_status)
{
case MHD_HTTP_OK:
- tts->wtid = dd->wtid;
+ tts->wtid = dr->details.success.wtid;
if (NULL != tts->bank_transfer_reference)
{
const struct TALER_TESTING_Command *bank_transfer_cmd;
@@ -139,7 +137,7 @@ deposit_wtid_cb (void *cls,
}
/* Compare that expected and gotten subjects match. */
- if (0 != GNUNET_memcmp (&dd->wtid,
+ if (0 != GNUNET_memcmp (&dr->details.success.wtid,
wtid_want))
{
GNUNET_break (0);
@@ -147,8 +145,6 @@ deposit_wtid_cb (void *cls,
return;
}
}
-
-
break;
case MHD_HTTP_ACCEPTED:
/* allowed, nothing to check here */
diff --git a/src/testing/testing_api_cmd_insert_deposit.c b/src/testing/testing_api_cmd_insert_deposit.c
index 0d57ab6c..0a0d5db2 100644
--- a/src/testing/testing_api_cmd_insert_deposit.c
+++ b/src/testing/testing_api_cmd_insert_deposit.c
@@ -200,14 +200,18 @@ insert_deposit_run (void *cls,
&hc);
{
char *str;
+ struct TALER_WireSalt salt;
GNUNET_asprintf (&str,
"payto://x-taler-bank/localhost/%s",
ids->merchant_account);
+ memset (&salt,
+ 46,
+ sizeof (salt));
deposit.receiver_wire_account
= GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("salt",
- "this-is-a-salt-value"),
+ GNUNET_JSON_pack_data_auto ("salt",
+ &salt),
GNUNET_JSON_pack_string ("payto_uri",
str));
GNUNET_free (str);
diff --git a/src/testing/testing_api_cmd_withdraw.c b/src/testing/testing_api_cmd_withdraw.c
index cfbdc177..23beb606 100644
--- a/src/testing/testing_api_cmd_withdraw.c
+++ b/src/testing/testing_api_cmd_withdraw.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2018-2020 Taler Systems SA
+ Copyright (C) 2018-2021 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
@@ -178,38 +178,36 @@ do_retry (void *cls)
* in the state.
*
* @param cls closure.
- * @param hr HTTP response details
- * @param sig signature over the coin, NULL on error.
+ * @param wr withdraw response details
*/
static void
reserve_withdraw_cb (void *cls,
- const struct TALER_EXCHANGE_HttpResponse *hr,
- const struct TALER_DenominationSignature *sig)
+ const struct TALER_EXCHANGE_WithdrawResponse *wr)
{
struct WithdrawState *ws = cls;
struct TALER_TESTING_Interpreter *is = ws->is;
ws->wsh = NULL;
- if (ws->expected_response_code != hr->http_status)
+ if (ws->expected_response_code != wr->hr.http_status)
{
if (0 != ws->do_retry)
{
- if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec)
+ if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)
ws->do_retry--; /* we don't count reserve unknown as failures here */
- if ( (0 == hr->http_status) ||
- (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec) ||
- (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == hr->ec) ||
- (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == hr->ec) ||
- (MHD_HTTP_INTERNAL_SERVER_ERROR == hr->http_status) )
+ if ( (0 == wr->hr.http_status) ||
+ (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec) ||
+ (TALER_EC_EXCHANGE_WITHDRAW_INSUFFICIENT_FUNDS == wr->hr.ec) ||
+ (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN == wr->hr.ec) ||
+ (MHD_HTTP_INTERNAL_SERVER_ERROR == wr->hr.http_status) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Retrying withdraw failed with %u/%d\n",
- hr->http_status,
- (int) hr->ec);
+ wr->hr.http_status,
+ (int) wr->hr.ec);
/* on DB conflicts, do not use backoff */
- if (TALER_EC_GENERIC_DB_SOFT_FAILURE == hr->ec)
+ if (TALER_EC_GENERIC_DB_SOFT_FAILURE == wr->hr.ec)
ws->backoff = GNUNET_TIME_UNIT_ZERO;
- else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != hr->ec)
+ else if (TALER_EC_EXCHANGE_WITHDRAW_RESERVE_UNKNOWN != wr->hr.ec)
ws->backoff = EXCHANGE_LIB_BACKOFF (ws->backoff);
else
ws->backoff = GNUNET_TIME_relative_max (UNKNOWN_MIN_BACKOFF,
@@ -227,29 +225,23 @@ reserve_withdraw_cb (void *cls,
}
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d to command %s in %s:%u\n",
- hr->http_status,
- (int) hr->ec,
+ wr->hr.http_status,
+ (int) wr->hr.ec,
TALER_TESTING_interpreter_get_current_label (is),
__FILE__,
__LINE__);
- json_dumpf (hr->reply,
+ json_dumpf (wr->hr.reply,
stderr,
0);
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
- switch (hr->http_status)
+ switch (wr->hr.http_status)
{
case MHD_HTTP_OK:
- if (NULL == sig)
- {
- GNUNET_break (0);
- TALER_TESTING_interpreter_fail (is);
- return;
- }
ws->sig.rsa_signature = GNUNET_CRYPTO_rsa_signature_dup (
- sig->rsa_signature);
+ wr->details.success.sig.rsa_signature);
if (0 != ws->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@@ -259,23 +251,27 @@ reserve_withdraw_cb (void *cls,
GNUNET_YES));
}
break;
+ case MHD_HTTP_ACCEPTED:
+ /* nothing to check */
+ /* TODO: trait for returned uuid! */
+ break;
case MHD_HTTP_FORBIDDEN:
/* nothing to check */
break;
+ case MHD_HTTP_NOT_FOUND:
+ /* nothing to check */
+ break;
case MHD_HTTP_CONFLICT:
/* nothing to check */
break;
case MHD_HTTP_GONE:
/* theoretically could check that the key was actually */
break;
- case MHD_HTTP_NOT_FOUND:
- /* nothing to check */
- break;
default:
/* Unsupported status code (by test harness) */
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Withdraw test command does not support status code %u\n",
- hr->http_status);
+ wr->hr.http_status);
GNUNET_break (0);
break;
}
diff --git a/src/testing/testing_api_helpers_bank.c b/src/testing/testing_api_helpers_bank.c
index d7cce01b..2876c247 100644
--- a/src/testing/testing_api_helpers_bank.c
+++ b/src/testing/testing_api_helpers_bank.c
@@ -670,11 +670,17 @@ TALER_TESTING_prepare_fakebank (const char *config_filename,
json_t *
TALER_TESTING_make_wire_details (const char *payto)
{
+ struct TALER_WireSalt salt;
+
+ /* salt must be constant for aggregation tests! */
+ memset (&salt,
+ 47,
+ sizeof (salt));
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("payto_uri",
payto),
- GNUNET_JSON_pack_string ("salt",
- "test-salt (must be constant for aggregation tests)"));
+ GNUNET_JSON_pack_data_auto ("salt",
+ &salt));
}
diff --git a/src/util/config.c b/src/util/config.c
index e533a4ec..d368d346 100644
--- a/src/util/config.c
+++ b/src/util/config.c
@@ -32,7 +32,7 @@
* @param[out] denom set to the amount found in configuration
* @return #GNUNET_OK on success, #GNUNET_SYSERR on error
*/
-int
+enum GNUNET_GenericReturnValue
TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg,
const char *section,
const char *option,
@@ -59,7 +59,7 @@ TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg,
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
section,
option,
- "valid amount");
+ "invalid amount");
return GNUNET_SYSERR;
}
GNUNET_free (str);
@@ -75,7 +75,7 @@ TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg,
* @param[out] currency where to write the result
* @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
*/
-int
+enum GNUNET_GenericReturnValue
TALER_config_get_currency (const struct GNUNET_CONFIGURATION_Handle *cfg,
char **currency)
{
@@ -92,10 +92,10 @@ TALER_config_get_currency (const struct GNUNET_CONFIGURATION_Handle *cfg,
}
if (strlen (*currency) >= TALER_CURRENCY_LEN)
{
- fprintf (stderr,
- "Currency `%s' longer than the allowed limit of %u characters.",
- *currency,
- (unsigned int) TALER_CURRENCY_LEN);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Currency `%s' longer than the allowed limit of %u characters.",
+ *currency,
+ (unsigned int) TALER_CURRENCY_LEN);
GNUNET_free (*currency);
*currency = NULL;
return GNUNET_SYSERR;
diff --git a/src/util/crypto_helper_denom.c b/src/util/crypto_helper_denom.c
index 4f8c921f..f8e77ae4 100644
--- a/src/util/crypto_helper_denom.c
+++ b/src/util/crypto_helper_denom.c
@@ -441,7 +441,11 @@ TALER_CRYPTO_helper_denom_poll (struct TALER_CRYPTO_DenominationHelper *dh)
try_connect (dh);
if (-1 == dh->sock)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot poll denom helper: socket down\n");
return; /* give up */
+ }
while (1)
{
ret = recv (dh->sock,
@@ -464,10 +468,18 @@ TALER_CRYPTO_helper_denom_poll (struct TALER_CRYPTO_DenominationHelper *dh)
"Restarting connection to RSA helper, did not come up properly\n");
do_disconnect (dh);
if (0 == retry_limit)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot poll denom helper: retry limit reached\n");
return; /* give up */
+ }
try_connect (dh);
if (-1 == dh->sock)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Cannot poll denom helper: failed to connect\n");
return; /* give up */
+ }
retry_limit--;
flag = MSG_DONTWAIT;
}
diff --git a/src/util/crypto_wire.c b/src/util/crypto_wire.c
index 0d31720a..ee3215ca 100644
--- a/src/util/crypto_wire.c
+++ b/src/util/crypto_wire.c
@@ -110,19 +110,39 @@ TALER_exchange_wire_signature_make (
*/
void
TALER_merchant_wire_signature_hash (const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
struct GNUNET_HashCode *hc)
{
+#if FIXED_7032
+ /* new logic to use once #7032 is being addressed */
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (hc,
sizeof (*hc),
salt,
- strlen (salt) + 1,
+ sizeof (*salt),
payto_uri,
strlen (payto_uri) + 1,
"merchant-wire-signature",
strlen ("merchant-wire-signature"),
NULL, 0));
+#else
+ /* compatibility logic to avoid protocol breakage... */
+ char *sstr;
+
+ sstr = GNUNET_STRINGS_data_to_string_alloc (salt,
+ sizeof (*salt));
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CRYPTO_kdf (hc,
+ sizeof (*hc),
+ sstr,
+ strlen (sstr) + 1,
+ payto_uri,
+ strlen (payto_uri) + 1,
+ "merchant-wire-signature",
+ strlen ("merchant-wire-signature"),
+ NULL, 0));
+ GNUNET_free (sstr);
+#endif
}
@@ -146,7 +166,7 @@ TALER_merchant_wire_signature_hash (const char *payto_uri,
enum GNUNET_GenericReturnValue
TALER_merchant_wire_signature_check (
const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
const struct TALER_MerchantPublicKeyP *merch_pub,
const struct TALER_MerchantSignatureP *merch_sig)
{
@@ -176,7 +196,7 @@ TALER_merchant_wire_signature_check (
void
TALER_merchant_wire_signature_make (
const char *payto_uri,
- const char *salt,
+ const struct TALER_WireSalt *salt,
const struct TALER_MerchantPrivateKeyP *merch_priv,
struct TALER_MerchantSignatureP *merch_sig)
{
diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c
index af5b6d5e..27e48b9e 100644
--- a/src/util/test_crypto.c
+++ b/src/util/test_crypto.c
@@ -158,21 +158,24 @@ static int
test_merchant_sigs ()
{
const char *pt = "payto://x-taler-bank/localhost/Account";
- const char *salt = "my test salt";
+ struct TALER_WireSalt salt;
struct TALER_MerchantPrivateKeyP priv;
struct TALER_MerchantPublicKeyP pub;
struct TALER_MerchantSignatureP sig;
GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
+ memset (&salt,
+ 42,
+ sizeof (salt));
TALER_merchant_wire_signature_make (pt,
- salt,
+ &salt,
&priv,
&sig);
GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
&pub.eddsa_pub);
if (GNUNET_OK !=
TALER_merchant_wire_signature_check (pt,
- salt,
+ &salt,
&pub,
&sig))
{
@@ -182,16 +185,19 @@ test_merchant_sigs ()
if (GNUNET_OK ==
TALER_merchant_wire_signature_check (
"payto://x-taler-bank/localhost/Other",
- salt,
+ &salt,
&pub,
&sig))
{
GNUNET_break (0);
return 1;
}
+ memset (&salt,
+ 43,
+ sizeof (salt));
if (GNUNET_OK ==
TALER_merchant_wire_signature_check (pt,
- "other salt",
+ &salt,
&pub,
&sig))
{