diff options
70 files changed, 899 insertions, 333 deletions
diff --git a/configure.ac b/configure.ac index 8c7769a83..a64ddb2f3 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. # # This file is part of TALER -# Copyright (C) 2014-2023 Taler Systems SA +# Copyright (C) 2014-2024 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 @@ -17,7 +17,7 @@ # # AC_PREREQ([2.69]) -AC_INIT([taler-exchange],[0.9.3b],[taler-bug@gnunet.org]) +AC_INIT([taler-exchange],[0.9.4],[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/Makefile.am.in b/contrib/Makefile.am.in index 73dee525b..5f9c93d5e 100644 --- a/contrib/Makefile.am.in +++ b/contrib/Makefile.am.in @@ -31,8 +31,7 @@ rdata_DATA = \ bin_SCRIPTS = \ taler-auditor-dbconfig \ taler-exchange-dbconfig \ - taler-terms-generator \ - taler-bank-manage-testing + taler-terms-generator EXTRA_DIST = \ diff --git a/contrib/ci/jobs/2-test/test.sh b/contrib/ci/jobs/2-test/test.sh index 3681f51cb..6566e7e08 100755 --- a/contrib/ci/jobs/2-test/test.sh +++ b/contrib/ci/jobs/2-test/test.sh @@ -31,7 +31,7 @@ print_logs() for FAILURE in $(grep '^FAIL:' ${i} | cut -d' ' -f2) do echo "Printing ${FAILURE}.log" - tail "$(dirname $i)/${FAILURE}.log" + cat "$(dirname $i)/${FAILURE}.log" done done } diff --git a/contrib/taler-bank-manage-testing b/contrib/taler-bank-manage-testing deleted file mode 100755 index cd9e41a1c..000000000 --- a/contrib/taler-bank-manage-testing +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/sh -# This file is in the public domain -# Wrapper around libeufin to first configure the required -# testing accounts before launching the bank properly. -# -# Takes 4 arguments: -# $1: the Nexus port (Sandbox port prepends 1 to it) -# $2: the database name -# $3: exchange base URL (used to specify the default exchange) -# $4: config file (needs patch to specify exchange's PAYTO_URI) - -set -eu - -if [ "$1" = "--help" ]; -then - echo "This is a tool to launch a libeufin based bank for testing." - echo "Call using: Nexus port number, SQLite file path, exchange base URL, config file path." - exit 0 -fi -if [ "$#" -ne 4 ]; -then - echo "illegal number of parameters. \ -Give: Nexus port number, SQLite file path, exchange base URL, config file path." - exit 1 -fi - -# Must not terminate jobs here, as they are needed -# by the script _importing_ this one. Those script -# will then manage the termination. -# trap cleanup EXIT - -export LIBEUFIN_SANDBOX_DB_CONNECTION="jdbc:sqlite:$2" -# Create the default demobank. -libeufin-sandbox config --currency TESTKUDOS default -export LIBEUFIN_SANDBOX_ADMIN_PASSWORD=secret -libeufin-sandbox serve --port "1$1" \ - > libeufin-sandbox-stdout.log \ - 2> libeufin-sandbox-stderr.log & -echo $! > libeufin-sandbox.pid -export LIBEUFIN_SANDBOX_URL="http://localhost:1$1/" -set +e -echo -n "Waiting for Sandbox.." -for n in `seq 1 50`; do - echo -n "." - sleep 1 - if wget --timeout=1 \ - --tries=3 --waitretry=0 \ - -o /dev/null -O /dev/null \ - $LIBEUFIN_SANDBOX_URL; then - break - fi -done -echo OK - -register_sandbox_account() { - export LIBEUFIN_SANDBOX_USERNAME=$1 - export LIBEUFIN_SANDBOX_PASSWORD=$2 - libeufin-cli sandbox \ - demobank \ - register --name "$3" - unset LIBEUFIN_SANDBOX_USERNAME - unset LIBEUFIN_SANDBOX_PASSWORD -} -set -e -echo -n "Register the 'fortytwo' Sandbox user.." -register_sandbox_account fortytwo x "Forty Two" -echo OK -echo -n "Register the 'fortythree' Sandbox user.." -register_sandbox_account fortythree x "Forty Three" -echo OK -echo -n "Register 'exchange' Sandbox user.." -register_sandbox_account exchange x "Exchange Company" -echo OK -echo -n "Register 'tor' Sandbox user.." -register_sandbox_account tor x "Tor Project" -echo OK -echo -n "Register 'gnunet' Sandbox user.." -register_sandbox_account gnunet x "GNUnet" -echo OK -echo -n "Register 'tutorial' Sandbox user.." -register_sandbox_account tutorial x "Tutorial" -echo OK -echo -n "Register 'survey' Sandbox user.." -register_sandbox_account survey x "Survey" -echo OK -echo -n "Specify exchange's PAYTO_URI in the config ..." -export LIBEUFIN_SANDBOX_USERNAME=exchange -export LIBEUFIN_SANDBOX_PASSWORD=x -PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'` -taler-config -c $4 -s exchange-account-1 -o PAYTO_URI -V $PAYTO -echo " OK" -echo -n "Setting this exchange as the bank's default ..." -EXCHANGE_PAYTO=`libeufin-cli sandbox demobank info --bank-account exchange | jq --raw-output '.paytoUri'` -libeufin-sandbox default-exchange "$3" "$EXCHANGE_PAYTO" -echo " OK" -# Prepare EBICS: create Ebics host and Exchange subscriber. -# Shortly becoming admin to setup Ebics. -export LIBEUFIN_SANDBOX_USERNAME=admin -export LIBEUFIN_SANDBOX_PASSWORD=secret -echo -n "Create EBICS host at Sandbox.." -libeufin-cli sandbox \ - --sandbox-url http://localhost:1$1 \ - ebicshost create --host-id talerebics -echo OK -echo -n "Create exchange EBICS subscriber at Sandbox.." -libeufin-cli sandbox \ - demobank new-ebicssubscriber --host-id talerebics \ - --user-id exchangeebics --partner-id talerpartner \ - --bank-account exchange # that's a username _and_ a bank account name -echo OK -unset LIBEUFIN_SANDBOX_USERNAME -unset LIBEUFIN_SANDBOX_PASSWORD -# Prepare Nexus, which is the side actually talking -# to the exchange. -export LIBEUFIN_NEXUS_DB_CONNECTION="jdbc:sqlite:$2" -# For convenience, username and password are -# identical to those used at the Sandbox. -echo -n Create exchange Nexus user.. -libeufin-nexus superuser exchange --password x -echo OK -libeufin-nexus serve --port $1 \ - 2> libeufin-nexus-stderr.log \ - > libeufin-nexus-stdout.log & -echo $! > libeufin-nexus.pid -export LIBEUFIN_NEXUS_URL=http://localhost:$1 -echo -n Waiting for Nexus.. -set +e -for n in `seq 1 50`; do - echo -n "." - sleep 1 - if wget --timeout=1 \ - --tries=3 --waitretry=0 \ - -o /dev/null -O /dev/null \ - $LIBEUFIN_NEXUS_URL; then - break - fi -done -set -e -echo OK -export LIBEUFIN_NEXUS_USERNAME=exchange -export LIBEUFIN_NEXUS_PASSWORD=x -echo -n Creating a EBICS connection at Nexus.. -libeufin-cli connections new-ebics-connection \ - --ebics-url "http://localhost:1$1/ebicsweb" \ - --host-id talerebics \ - --partner-id talerpartner \ - --ebics-user-id exchangeebics \ - talerconn -echo OK -echo -n Setup EBICS keying.. -libeufin-cli connections connect talerconn > /dev/null -echo OK -echo -n Download bank account name from Sandbox.. -libeufin-cli connections download-bank-accounts talerconn -echo OK -echo -n Importing bank account info into Nexus.. -libeufin-cli connections import-bank-account \ - --offered-account-id exchange \ - --nexus-bank-account-id exchange-nexus \ - talerconn -echo OK -echo -n Setup payments submission task.. -# Tries every second. -libeufin-cli accounts task-schedule \ - --task-type submit \ - --task-name exchange-payments \ - --task-cronspec "* * *" \ - exchange-nexus -echo OK -# Tries every second. Ask C52 -echo -n Setup history fetch task.. -libeufin-cli accounts task-schedule \ - --task-type fetch \ - --task-name exchange-history \ - --task-cronspec "* * *" \ - --task-param-level report \ - --task-param-range-type latest \ - exchange-nexus -echo OK -# TBD: create Taler facade. -echo -n Create the Taler facade at Nexus.. -libeufin-cli facades \ - new-taler-wire-gateway-facade \ - --currency TESTKUDOS --facade-name test-facade \ - talerconn exchange-nexus -echo OK -# Facade schema: http://localhost:$1/facades/test-facade/taler-wire-gateway/ diff --git a/contrib/wallet-core b/contrib/wallet-core -Subproject a17a7a51dd50e2f508b078b9aada038fe124ff9 +Subproject d6ea0db963a73fa67eac98122ba2600ec7314fb diff --git a/debian/changelog b/debian/changelog index a712cdc5a..aa97b82f2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +taler-exchange (0.9.4) unstable; urgency=low + + * Preparations for v0.9.4 release. + + -- Christian Grothoff <grothoff@gnu.org> Sun, 21 Jan 2024 03:50:12 +0200 + taler-exchange (0.9.3-7) unstable; urgency=low * Move currencies.conf into libtalerexchange base package. diff --git a/debian/libtalerexchange-dev.install b/debian/libtalerexchange-dev.install index 5d8edd3bb..aa1de818a 100644 --- a/debian/libtalerexchange-dev.install +++ b/debian/libtalerexchange-dev.install @@ -5,16 +5,14 @@ usr/bin/taler-exchange-benchmark usr/bin/taler-exchange-kyc-tester usr/bin/taler-fakebank-run usr/bin/taler-unified-setup.sh - -# Only used in test cases. Maybe these -# shouldn't even be installed? -usr/bin/taler-bank-manage-testing +usr/bin/taler-exchange-kyc-oauth2-test-converter.sh # Man pages -usr/share/man/man1/taler-exchange-kyc-tester* usr/share/man/man1/taler-aggregator-benchmark* usr/share/man/man1/taler-bank-benchmark* +usr/share/man/man1/taler-exchange-kyc-tester* usr/share/man/man1/taler-exchange-benchmark* +usr/share/man/man1/taler-fakebank-run* usr/share/man/man1/taler-unified-setup* diff --git a/debian/taler-auditor.install b/debian/taler-auditor.install index 5cd1fbf5c..4f3d5a1b2 100644 --- a/debian/taler-auditor.install +++ b/debian/taler-auditor.install @@ -5,12 +5,16 @@ usr/bin/taler-auditor-httpd usr/bin/taler-auditor-offline usr/bin/taler-auditor-sync usr/bin/taler-helper-auditor-* + usr/lib/*/taler/libtaler_plugin_auditor*.so usr/lib/*/libauditor* usr/lib/*/libtalerauditordb* + usr/share/man/man1/taler-auditor* usr/share/man/man1/taler-helper-auditor* + usr/share/info/taler-auditor* + usr/share/taler/config.d/auditor* usr/share/taler/sql/auditor/* diff --git a/debian/taler-exchange.install b/debian/taler-exchange.install index 9c3cd8f47..fe5b71546 100644 --- a/debian/taler-exchange.install +++ b/debian/taler-exchange.install @@ -3,6 +3,10 @@ usr/bin/taler-exchange-closer usr/bin/taler-exchange-drain usr/bin/taler-exchange-expire usr/bin/taler-exchange-httpd +usr/bin/taler-exchange-kyc-aml-pep-trigger.sh +usr/bin/taler-exchange-kyc-oauth2-challenger.sh +usr/bin/taler-exchange-kyc-kycaid-converter.sh +usr/bin/taler-exchange-kyc-persona-converter.sh usr/bin/taler-exchange-router usr/bin/taler-exchange-secmod-cs usr/bin/taler-exchange-secmod-eddsa @@ -14,17 +18,19 @@ usr/lib/*/taler/libtaler_plugin_kyclogic_*.so usr/lib/*/taler/libtaler_extension_*.so usr/share/man/man1/taler-exchange-aggregator* usr/share/man/man1/taler-exchange-closer* +usr/share/man/man1/taler-exchange-dbconfig* +usr/share/man/man1/taler-exchange-dbinit* usr/share/man/man1/taler-exchange-drain* usr/share/man/man1/taler-exchange-expire* usr/share/man/man1/taler-exchange-httpd* +usr/share/man/man1/taler-exchange-kyc-aml-pep-trigger* usr/share/man/man1/taler-exchange-router* +usr/share/man/man1/taler-exchange-secmod-cs* usr/share/man/man1/taler-exchange-secmod-eddsa* usr/share/man/man1/taler-exchange-secmod-rsa* -usr/share/man/man1/taler-exchange-secmod-cs* usr/share/man/man1/taler-exchange-transfer* -usr/share/man/man1/taler-exchange-wirewatch* -usr/share/man/man1/taler-bank* usr/share/man/man1/taler-exchange-wire-gateway-client* +usr/share/man/man1/taler-exchange-wirewatch* usr/share/info/taler-bank* usr/share/info/taler-exchange* usr/share/taler/config.d/* diff --git a/debian/taler-exchange.taler-exchange-aggregator.service b/debian/taler-exchange.taler-exchange-aggregator.service index 095945981..f92dfb178 100644 --- a/debian/taler-exchange.taler-exchange-aggregator.service +++ b/debian/taler-exchange.taler-exchange-aggregator.service @@ -7,8 +7,9 @@ After=postgres.service User=taler-exchange-aggregator Type=simple Restart=always +RestartMode=direct RestartSec=1s -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 ExecStart=/usr/bin/taler-exchange-aggregator -c /etc/taler/taler.conf StandardOutput=journal StandardError=journal diff --git a/debian/taler-exchange.taler-exchange-closer.service b/debian/taler-exchange.taler-exchange-closer.service index ab9c6d98f..c6315375c 100644 --- a/debian/taler-exchange.taler-exchange-closer.service +++ b/debian/taler-exchange.taler-exchange-closer.service @@ -7,8 +7,9 @@ After=network.target postgres.service User=taler-exchange-closer Type=simple Restart=always +RestartMode=direct RestartSec=1s -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 ExecStart=/usr/bin/taler-exchange-closer -c /etc/taler/taler.conf StandardOutput=journal StandardError=journal diff --git a/debian/taler-exchange.taler-exchange-expire.service b/debian/taler-exchange.taler-exchange-expire.service index a34cdccb7..7bbccc2aa 100644 --- a/debian/taler-exchange.taler-exchange-expire.service +++ b/debian/taler-exchange.taler-exchange-expire.service @@ -7,8 +7,9 @@ After=postgres.service User=taler-exchange-expire Type=simple Restart=always +RestartMode=direct RestartSec=1s -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 ExecStart=/usr/bin/taler-exchange-expire -c /etc/taler/taler.conf StandardOutput=journal StandardError=journal diff --git a/debian/taler-exchange.taler-exchange-httpd.service b/debian/taler-exchange.taler-exchange-httpd.service index 2a4cf72e4..1fb538a15 100644 --- a/debian/taler-exchange.taler-exchange-httpd.service +++ b/debian/taler-exchange.taler-exchange-httpd.service @@ -12,8 +12,9 @@ Type=simple # Depending on the configuration, the service process kills itself and then # needs to be restarted. Thus no significant delay on restarts. Restart=always +RestartMode=direct RestartSec=1ms -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 # Disable the service if more than 5 restarts are encountered within 5s. # These are usually the systemd defaults, but can be overwritten, thus we set diff --git a/debian/taler-exchange.taler-exchange-transfer.service b/debian/taler-exchange.taler-exchange-transfer.service index 40d47b09c..2557dbdf6 100644 --- a/debian/taler-exchange.taler-exchange-transfer.service +++ b/debian/taler-exchange.taler-exchange-transfer.service @@ -7,8 +7,9 @@ PartOf=taler-exchange.target User=taler-exchange-wire Type=simple Restart=always +RestartMode=direct RestartSec=1s -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 ExecStart=/usr/bin/taler-exchange-transfer -c /etc/taler/taler.conf StandardOutput=journal StandardError=journal diff --git a/debian/taler-exchange.taler-exchange-wirewatch.service b/debian/taler-exchange.taler-exchange-wirewatch.service index 14023c12b..2a549977d 100644 --- a/debian/taler-exchange.taler-exchange-wirewatch.service +++ b/debian/taler-exchange.taler-exchange-wirewatch.service @@ -7,8 +7,9 @@ PartOf=taler-exchange.target User=taler-exchange-wire Type=simple Restart=always +RestartMode=direct RestartSec=1s -RestartPreventExitStatus=9 +RestartPreventExitStatus=2 3 4 5 6 9 RuntimeMaxSec=3600s ExecStart=/usr/bin/taler-exchange-wirewatch -c /etc/taler/taler.conf StandardOutput=journal diff --git a/doc/Makefile.am b/doc/Makefile.am index 06835561d..96bded9ba 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -17,7 +17,6 @@ man_MANS = \ prebuilt/man/taler-auditor-sign.1 \ prebuilt/man/taler-auditor-sync.1 \ prebuilt/man/taler-bank-benchmark.1 \ - prebuilt/man/taler-bank-transfer.1 \ prebuilt/man/taler-exchange-aggregator.1 \ prebuilt/man/taler-exchange-benchmark.1 \ prebuilt/man/taler-exchange-closer.1 \ @@ -36,6 +35,7 @@ man_MANS = \ prebuilt/man/taler-exchange-transfer.1\ prebuilt/man/taler-exchange-wire-gateway-client.1\ prebuilt/man/taler-exchange-wirewatch.1 \ + prebuilt/man/taler-fakebank-run.1 \ prebuilt/man/taler-helper-auditor-aggregation.1 \ prebuilt/man/taler-helper-auditor-coins.1\ prebuilt/man/taler-helper-auditor-deposits.1\ diff --git a/doc/prebuilt b/doc/prebuilt -Subproject bd40be2fd4ce80106dc40a5ac4cc5c169513406 +Subproject 14e26d5fe2c0ceed27e27d8c79db14775ddfd79 diff --git a/src/auditor/generate-auditor-basedb.conf b/src/auditor/generate-auditor-basedb.conf index 8efb81a3e..bcdc31860 100644 --- a/src/auditor/generate-auditor-basedb.conf +++ b/src/auditor/generate-auditor-basedb.conf @@ -84,11 +84,11 @@ DB_CONNECTION="postgresql:///auditor-basedb" DB_CONNECTION="postgresql:///auditor-basedb" [libeufin-bank] -CURRENCY = EUR -DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200 # dead -DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000 +CURRENCY = TESTKUDOS +DEFAULT_CUSTOMER_DEBT_LIMIT = TESTKUDOS:200 # dead +DEFAULT_ADMIN_DEBT_LIMIT = TESTKUDOS:2000 REGISTRATION_BONUS_ENABLED = yes -REGISTRATION_BONUS = EUR:100 +REGISTRATION_BONUS = TESTKUDOS:100 SUGGESTED_WITHDRAWAL_EXCHANGE = http://localhost:8081/ SERVE = tcp PORT = 8082 diff --git a/src/auditor/taler-auditor-httpd.c b/src/auditor/taler-auditor-httpd.c index 7b7bf98a7..d9cdff8d2 100644 --- a/src/auditor/taler-auditor-httpd.c +++ b/src/auditor/taler-auditor-httpd.c @@ -50,6 +50,7 @@ */ #define AUDITOR_PROTOCOL_VERSION "1:0:1" + /** * Backlog for listen operation on unix domain sockets. */ @@ -167,6 +168,8 @@ handle_config (struct TAH_RequestHandler *rh, "taler-auditor"), GNUNET_JSON_pack_string ("version", AUDITOR_PROTOCOL_VERSION), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:auditor:c-reference"), GNUNET_JSON_pack_string ("currency", TAH_currency), GNUNET_JSON_pack_data_auto ("auditor_public_key", diff --git a/src/auditor/taler-helper-auditor-deposits.c b/src/auditor/taler-helper-auditor-deposits.c index b5c4a386d..25697bbbc 100644 --- a/src/auditor/taler-helper-auditor-deposits.c +++ b/src/auditor/taler-helper-auditor-deposits.c @@ -60,6 +60,14 @@ static int global_ret; /** + * Run in test mode. Exit when idle instead of + * going to sleep and waiting for more work. + * + * FIXME: not yet implemented! + */ +static int test_mode; + +/** * Array of reports about missing deposit confirmations. */ static json_t *report_deposit_confirmation_inconsistencies; @@ -272,14 +280,6 @@ analyze_deposit_confirmations (void *cls) return dcc.qs; } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "getting in here when i shouldnt\n"); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "lastseencoinserialid %lu\n", - dcc.last_seen_coin_serial); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "dcc.qs %u\n", - dcc.qs); /* if (UINT64_MAX == dcc.first_missed_coin_serial) ppdc.last_deposit_confirmation_serial_id = dcc.last_seen_coin_serial; else @@ -334,13 +334,6 @@ db_notify (void *cls, (void) extra; (void) extra_size; - if (GNUNET_OK != - TALER_ARL_init (cfg)) - { - global_ret = EXIT_FAILURE; - return; - } - if (NULL == (db_plugin = TALER_AUDITORDB_plugin_load (cfg))) { @@ -360,7 +353,8 @@ db_notify (void *cls, return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deposit audit complete\n"); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Deposit audit complete\n"); TALER_ARL_done ( GNUNET_JSON_PACK ( GNUNET_JSON_pack_array_steal ("deposit_confirmation_inconsistencies", @@ -377,6 +371,22 @@ db_notify (void *cls, /** + * Function called on shutdown. + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + + db_plugin->event_listen_cancel (eh); + eh = NULL; + TALER_AUDITORDB_plugin_unload (db_plugin); + db_plugin = NULL; + TALER_ARL_done (NULL); +} + + +/** * Main function that will be run. * * @param cls closure @@ -394,6 +404,9 @@ run (void *cls, (void) args; (void) cfgfile; cfg = c; + + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Launching deposit auditor\n"); if (GNUNET_OK != @@ -479,6 +492,10 @@ main (int argc, "KEY", "public key of the exchange (Crockford base32 encoded)", &TALER_ARL_master_pub), + GNUNET_GETOPT_option_flag ('t', + "test", + "run in test mode and exit when idle", + &test_mode), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_OPTION_END diff --git a/src/auditordb/drop.sql b/src/auditordb/drop.sql index b7421b1c3..3dff35ec5 100644 --- a/src/auditordb/drop.sql +++ b/src/auditordb/drop.sql @@ -20,7 +20,7 @@ BEGIN; -- Drop versioning (auditor-0001.sql) SELECT _v.unregister_patch('auditor-0001'); -SELECT _v.unregister_patch('auditor-0002'); +-- SELECT _v.unregister_patch('auditor-0002'); DROP SCHEMA auditor CASCADE; -- And we're out of here... diff --git a/src/bank-lib/Makefile.am b/src/bank-lib/Makefile.am index 3458b7a01..b849db5d8 100644 --- a/src/bank-lib/Makefile.am +++ b/src/bank-lib/Makefile.am @@ -74,6 +74,7 @@ libtalerfakebank_la_SOURCES = \ fakebank_bank_post_accounts_withdrawals.c fakebank_bank_post_accounts_withdrawals.h \ fakebank_bank_post_withdrawals_abort.c fakebank_bank_post_withdrawals_abort.h \ fakebank_bank_post_withdrawals_confirm.c fakebank_bank_post_withdrawals_confirm.h \ + fakebank_bank_post_withdrawals_id_op.c fakebank_bank_post_withdrawals_id_op.h \ fakebank_bank_testing_register.c fakebank_bank_testing_register.h \ fakebank_tbr.c fakebank_tbr.h \ fakebank_tbr_get_history.c fakebank_tbr_get_history.h \ diff --git a/src/bank-lib/fakebank.c b/src/bank-lib/fakebank.c index 12302be7b..3a004dc80 100644 --- a/src/bank-lib/fakebank.c +++ b/src/bank-lib/fakebank.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/src/bank-lib/fakebank_bank.c b/src/bank-lib/fakebank_bank.c index 483a3228c..7c2d39ab4 100644 --- a/src/bank-lib/fakebank_bank.c +++ b/src/bank-lib/fakebank_bank.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -36,6 +36,7 @@ #include "fakebank_bank_post_accounts_withdrawals.h" #include "fakebank_bank_post_withdrawals_abort.h" #include "fakebank_bank_post_withdrawals_confirm.h" +#include "fakebank_bank_post_withdrawals_id_op.h" #include "fakebank_bank_testing_register.h" @@ -73,9 +74,11 @@ TALER_FAKEBANK_bank_main_ ( connection, MHD_HTTP_OK, GNUNET_JSON_pack_string ("version", - "0:0:0"), + "4:0:4"), /* not sure, API versions are not properly marked up! */ GNUNET_JSON_pack_string ("currency", h->currency), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:bank:fakebank"), GNUNET_JSON_pack_string ("name", "taler-corebank")); } @@ -477,6 +480,36 @@ TALER_FAKEBANK_bank_main_ ( GNUNET_free (acc); return ret; } + + if (0 == strncmp (end_acc, + "/withdrawals/", + strlen ("/withdrawals/"))) + { + /* POST /accounts/$ACCOUNT/withdrawals/$WID/$OP */ + MHD_RESULT ret; + const char *pos = &end_acc[strlen ("/withdrawals/")]; + const char *op = strchr (pos, '/'); + + if (NULL != op) + { + char *wid = GNUNET_strndup (pos, + op - pos); + + ret = TALER_FAKEBANK_bank_withdrawals_id_op_ ( + h, + connection, + acc, + wid, + op, + upload_data, + upload_data_size, + con_cls); + GNUNET_free (wid); + GNUNET_free (acc); + return ret; + } + GNUNET_free (acc); + } } } diff --git a/src/bank-lib/fakebank_bank_accounts_withdrawals.c b/src/bank-lib/fakebank_bank_accounts_withdrawals.c index ffcff0e20..bb435d975 100644 --- a/src/bank-lib/fakebank_bank_accounts_withdrawals.c +++ b/src/bank-lib/fakebank_bank_accounts_withdrawals.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/src/bank-lib/fakebank_bank_post_withdrawals_id_op.c b/src/bank-lib/fakebank_bank_post_withdrawals_id_op.c new file mode 100644 index 000000000..fe5cc982d --- /dev/null +++ b/src/bank-lib/fakebank_bank_post_withdrawals_id_op.c @@ -0,0 +1,241 @@ +/* + This file is part of TALER + (C) 2016-2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ +/** + * @file bank-lib/fakebank_bank_post_withdrawals_id_op.c + * @brief implement bank API POST /accounts/$ACCOUNT/withdrawals/$WID/$OP endpoint(s) + * @author Christian Grothoff <christian@grothoff.org> + */ +#include "platform.h" +#include <pthread.h> +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_mhd_lib.h" +#include <gnunet/gnunet_mhd_compat.h> +#include "fakebank.h" +#include "fakebank_bank_post_withdrawals_id_op.h" +#include "fakebank_common_lookup.h" +#include "fakebank_common_lp.h" +#include "fakebank_common_make_admin_transfer.h" + + +/** + * Handle POST /accounts/$ACC/withdrawals/{withdrawal_id}/confirm request. + * + * @param h our fakebank handle + * @param connection the connection + * @param account name of the account + * @param withdrawal_id the withdrawal operation identifier + * @return MHD result code + */ +static MHD_RESULT +bank_withdrawals_confirm ( + struct TALER_FAKEBANK_Handle *h, + struct MHD_Connection *connection, + const char *account, + const char *withdrawal_id) +{ + const struct Account *acc; + struct WithdrawalOperation *wo; + + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + acc = TALER_FAKEBANK_lookup_account_ (h, + account, + NULL); + if (NULL == acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Account %s is unknown\n", + account); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h, + withdrawal_id); + if ( (NULL == wo) || + (acc != wo->debit_account) ) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_TRANSACTION_NOT_FOUND, + withdrawal_id); + } + if (NULL == wo->exchange_account) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_BANK_POST_WITHDRAWAL_OPERATION_REQUIRED, + NULL); + } + if (wo->aborted) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_BANK_CONFIRM_ABORT_CONFLICT, + withdrawal_id); + } + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + if (GNUNET_OK != + TALER_FAKEBANK_make_admin_transfer_ ( + h, + wo->debit_account->account_name, + wo->exchange_account->account_name, + &wo->amount, + &wo->reserve_pub, + &wo->row_id, + &wo->timestamp)) + { + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_BANK_DUPLICATE_RESERVE_PUB_SUBJECT, + NULL); + } + /* Re-acquiring the lock and continuing to operate on 'wo' + is currently (!) acceptable because we NEVER free 'wo' + until shutdown. We may want to revise this if keeping + all withdraw operations in RAM becomes an issue... */ + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + wo->confirmation_done = true; + TALER_FAKEBANK_notify_withdrawal_ (h, + wo); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +/** + * Handle POST /accounts/$ACC/withdrawals/{withdrawal_id}/abort request. + * + * @param h our fakebank handle + * @param connection the connection + * @param account name of the account + * @param withdrawal_id the withdrawal operation identifier + * @return MHD result code + */ +static MHD_RESULT +bank_withdrawals_abort ( + struct TALER_FAKEBANK_Handle *h, + struct MHD_Connection *connection, + const char *account, + const char *withdrawal_id) +{ + struct WithdrawalOperation *wo; + const struct Account *acc; + + GNUNET_assert (0 == + pthread_mutex_lock (&h->big_lock)); + acc = TALER_FAKEBANK_lookup_account_ (h, + account, + NULL); + if (NULL == acc) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Account %s is unknown\n", + account); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_UNKNOWN_ACCOUNT, + account); + } + wo = TALER_FAKEBANK_lookup_withdrawal_operation_ (h, + withdrawal_id); + if ( (NULL == wo) || + (acc != wo->debit_account) ) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_BANK_TRANSACTION_NOT_FOUND, + withdrawal_id); + } + if (wo->confirmation_done) + { + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_CONFLICT, + TALER_EC_BANK_ABORT_CONFIRM_CONFLICT, + withdrawal_id); + } + wo->aborted = true; + TALER_FAKEBANK_notify_withdrawal_ (h, + wo); + GNUNET_assert (0 == + pthread_mutex_unlock (&h->big_lock)); + return TALER_MHD_reply_static (connection, + MHD_HTTP_NO_CONTENT, + NULL, + NULL, + 0); +} + + +MHD_RESULT +TALER_FAKEBANK_bank_withdrawals_id_op_ ( + struct TALER_FAKEBANK_Handle *h, + struct MHD_Connection *connection, + const char *account, + const char *withdrawal_id, + const char *op, + const char *upload_data, + size_t *upload_data_size, + void **con_cls) +{ + if (0 == strcmp (op, + "/confirm")) + { + return bank_withdrawals_confirm (h, + connection, + account, + withdrawal_id); + } + if (0 == strcmp (op, + "/abort")) + { + return bank_withdrawals_abort (h, + connection, + account, + withdrawal_id); + } + GNUNET_break_op (0); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_NOT_FOUND, + TALER_EC_GENERIC_ENDPOINT_UNKNOWN, + op); +} diff --git a/src/bank-lib/fakebank_bank_post_withdrawals_id_op.h b/src/bank-lib/fakebank_bank_post_withdrawals_id_op.h new file mode 100644 index 000000000..a2d40e66f --- /dev/null +++ b/src/bank-lib/fakebank_bank_post_withdrawals_id_op.h @@ -0,0 +1,58 @@ +/* + This file is part of TALER + (C) 2016-2024 Taler Systems SA + + TALER is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 3, + or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public + License along with TALER; see the file COPYING. If not, + see <http://www.gnu.org/licenses/> +*/ +/** + * @file bank-lib/fakebank_bank_post_withdrawals_id_op.h + * @brief implement bank API POST /accounts/$ACCOUNT/withdrawals/$WID/$OP endpoint(s) + * @author Christian Grothoff <christian@grothoff.org> + */ +#ifndef FAKEBANK_BANK_POST_WITHDRAWALS_ID_OP_H +#define FAKEBANK_BANK_POST_WITHDRAWALS_ID_OP_H + +#include "taler_fakebank_lib.h" +#include "taler_bank_service.h" +#include "taler_mhd_lib.h" +#include <gnunet/gnunet_mhd_compat.h> +#include "fakebank.h" + + +/** + * Handle POST /accounts/{account_name}/withdrawals/{withdrawal_id}/${OP} request. + * + * @param h our fakebank handle + * @param connection the connection + * @param account name of the account + * @param withdrawal_id the withdrawal operation identifier + * @param op operation to be performed, includes leading "/" + * @param upload_data data uploaded + * @param[in,out] upload_data_size number of bytes in @a upload_data + * @param[in,out] con_cls application context that can be used + * @return MHD result code + */ +MHD_RESULT +TALER_FAKEBANK_bank_withdrawals_id_op_ ( + struct TALER_FAKEBANK_Handle *h, + struct MHD_Connection *connection, + const char *account, + const char *withdrawal_id, + const char *op, + const char *upload_data, + size_t *upload_data_size, + void **con_cls); + +#endif diff --git a/src/bank-lib/fakebank_tbi.c b/src/bank-lib/fakebank_tbi.c index d3d65afd6..463ec7d31 100644 --- a/src/bank-lib/fakebank_tbi.c +++ b/src/bank-lib/fakebank_tbi.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -61,6 +61,8 @@ TALER_FAKEBANK_tbi_main_ (struct TALER_FAKEBANK_Handle *h, "1:0:1"), GNUNET_JSON_pack_string ("currency", h->currency), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:bank:fakebank"), GNUNET_JSON_pack_bool ("allow_conversion", false), GNUNET_JSON_pack_bool ("allow_registrations", diff --git a/src/bank-lib/fakebank_tbr.c b/src/bank-lib/fakebank_tbr.c index de96394e0..0f0e5bdc1 100644 --- a/src/bank-lib/fakebank_tbr.c +++ b/src/bank-lib/fakebank_tbr.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -46,16 +46,36 @@ TALER_FAKEBANK_tbr_main_ ( "Fakebank - Anastasis API: serving URL `%s' for account `%s'\n", url, account); + + if ( (0 == strcmp (url, + "/config")) && + (0 == strcasecmp (method, + MHD_HTTP_METHOD_GET)) ) + { + /* GET /config */ + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("version", + "0:0:0"), + GNUNET_JSON_pack_string ("currency", + h->currency), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:bank:fakebank"), + GNUNET_JSON_pack_string ("name", + "taler-revenue")); + } + if (0 == strcasecmp (method, MHD_HTTP_METHOD_GET)) { if ( (0 == strcmp (url, - "/history/incoming")) && + "/history")) && (NULL != account) ) - return TALER_FAKEBANK_tbr_get_history_incoming (h, - connection, - account, - con_cls); + return TALER_FAKEBANK_tbr_get_history (h, + connection, + account, + con_cls); if (0 == strcmp (url, "/")) return TALER_FAKEBANK_tbr_get_root (h, diff --git a/src/bank-lib/fakebank_tbr_get_history.c b/src/bank-lib/fakebank_tbr_get_history.c index 79678636a..b7d447adc 100644 --- a/src/bank-lib/fakebank_tbr_get_history.c +++ b/src/bank-lib/fakebank_tbr_get_history.c @@ -50,7 +50,7 @@ history_cleanup (void *cls) MHD_RESULT -TALER_FAKEBANK_tbr_get_history_incoming ( +TALER_FAKEBANK_tbr_get_history ( struct TALER_FAKEBANK_Handle *h, struct MHD_Connection *connection, const char *account, @@ -72,8 +72,8 @@ TALER_FAKEBANK_tbr_get_history_incoming ( cc->ctx = hc; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handling /accounts/$USERNAME/taler-revenue/history/incoming request %p\n", - connection); + "Handling /accounts/%s/taler-revenue/history request\n", + account); if (GNUNET_OK != (ret = TALER_FAKEBANK_common_parse_history_args (h, connection, @@ -93,6 +93,9 @@ TALER_FAKEBANK_tbr_get_history_incoming ( { GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Account %s is unknown\n", + account); return TALER_MHD_reply_with_error (connection, MHD_HTTP_NOT_FOUND, TALER_EC_BANK_UNKNOWN_ACCOUNT, @@ -153,10 +156,14 @@ TALER_FAKEBANK_tbr_get_history_incoming ( GNUNET_assert (0 == pthread_mutex_unlock (&h->big_lock)); if (overflow) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Transactions lost due to RAM limits\n"); return TALER_MHD_reply_with_ec ( connection, TALER_EC_BANK_ANCIENT_TRANSACTION_GONE, NULL); + } goto finish; } if (h->in_shutdown) @@ -282,6 +289,8 @@ finish: { GNUNET_break (in_shutdown || (! GNUNET_TIME_absolute_is_future (hc->timeout))); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Zero transactions found\n"); return TALER_MHD_reply_static (connection, MHD_HTTP_NO_CONTENT, NULL, diff --git a/src/bank-lib/fakebank_tbr_get_history.h b/src/bank-lib/fakebank_tbr_get_history.h index 99170ab7b..997c9a86b 100644 --- a/src/bank-lib/fakebank_tbr_get_history.h +++ b/src/bank-lib/fakebank_tbr_get_history.h @@ -32,8 +32,8 @@ /** - * Handle incoming HTTP request for /history/incoming - * of the Anastasis API. This one can return transactions + * Handle incoming HTTP request for /history + * of the taler-revenue API. This one can return transactions * created by debits from the exchange! * * @param h the fakebank handle @@ -43,7 +43,7 @@ * @return MHD result code */ MHD_RESULT -TALER_FAKEBANK_tbr_get_history_incoming ( +TALER_FAKEBANK_tbr_get_history ( struct TALER_FAKEBANK_Handle *h, struct MHD_Connection *connection, const char *account, diff --git a/src/bank-lib/fakebank_twg.c b/src/bank-lib/fakebank_twg.c index 353821bd2..9356e69ba 100644 --- a/src/bank-lib/fakebank_twg.c +++ b/src/bank-lib/fakebank_twg.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2016-2023 Taler Systems SA + (C) 2016-2024 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -49,6 +49,24 @@ TALER_FAKEBANK_twg_main_ ( "Fakebank TWG, serving URL `%s' for account `%s'\n", url, account); + if ( (0 == strcmp (url, + "/config")) && + (0 == strcasecmp (method, + MHD_HTTP_METHOD_GET)) ) + { + /* GET /config */ + return TALER_MHD_REPLY_JSON_PACK ( + connection, + MHD_HTTP_OK, + GNUNET_JSON_pack_string ("version", + "0:0:0"), + GNUNET_JSON_pack_string ("currency", + h->currency), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:bank:fakebank"), + GNUNET_JSON_pack_string ("name", + "taler-wire-gateway")); + } if (0 == strcasecmp (method, MHD_HTTP_METHOD_GET)) { diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 7a579a9f5..1d0a0bb5d 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -382,6 +382,7 @@ release_shard (struct Shard *s) case GNUNET_DB_STATUS_SOFT_ERROR: GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR != qs); GNUNET_break (0); + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: @@ -934,6 +935,7 @@ run_aggregation (void *cls) switch (ret) { case GNUNET_SYSERR: + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); db_plugin->rollback (db_plugin->cls); release_shard (s); @@ -1197,6 +1199,7 @@ drain_kyc_alerts (void *cls) { case GNUNET_SYSERR: GNUNET_break (0); + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); db_plugin->rollback (db_plugin->cls); /* just in case */ return; diff --git a/src/exchange/taler-exchange-closer.c b/src/exchange/taler-exchange-closer.c index 63a98bd0d..779525c4e 100644 --- a/src/exchange/taler-exchange-closer.c +++ b/src/exchange/taler-exchange-closer.c @@ -469,13 +469,11 @@ run_reserve_closures (void *cls) if (GNUNET_YES == test_mode) { GNUNET_SCHEDULER_shutdown (); + return; } - else - { - task = GNUNET_SCHEDULER_add_delayed (closer_idle_sleep_interval, - &run_reserve_closures, - NULL); - } + task = GNUNET_SCHEDULER_add_delayed (closer_idle_sleep_interval, + &run_reserve_closures, + NULL); return; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: (void) commit_or_warn (); diff --git a/src/exchange/taler-exchange-expire.c b/src/exchange/taler-exchange-expire.c index c7132fcb2..b2d34ee1c 100644 --- a/src/exchange/taler-exchange-expire.c +++ b/src/exchange/taler-exchange-expire.c @@ -272,9 +272,9 @@ run_expire (void *cls) "expire-purse")) { GNUNET_break (0); - global_ret = EXIT_FAILURE; db_plugin->rollback (db_plugin->cls); abort_shard (s); + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; } @@ -285,9 +285,9 @@ run_expire (void *cls) { case GNUNET_DB_STATUS_HARD_ERROR: GNUNET_break (0); - global_ret = EXIT_FAILURE; db_plugin->rollback (db_plugin->cls); abort_shard (s); + global_ret = EXIT_FAILURE; GNUNET_SCHEDULER_shutdown (); return; case GNUNET_DB_STATUS_SOFT_ERROR: diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index de64003fd..21f2d080b 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -2434,7 +2434,9 @@ run_single_request (void) xfork = fork (); if (-1 == xfork) { - global_ret = EXIT_FAILURE; + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "fork"); + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } @@ -2603,35 +2605,38 @@ run (void *cls, if (GNUNET_OK != TALER_TEMPLATING_init ("exchange")) { - global_ret = EXIT_FAILURE; + global_ret = EXIT_NOTINSTALLED; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_SYSERR == TEH_plugin->preflight (TEH_plugin->cls)) { - global_ret = EXIT_FAILURE; + GNUNET_break (0); + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != TEH_extensions_init ()) { - global_ret = EXIT_FAILURE; + global_ret = EXIT_NOTINSTALLED; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != TEH_keys_init ()) { - global_ret = EXIT_FAILURE; + GNUNET_break (0); + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } if (GNUNET_OK != TEH_wire_init ()) { - global_ret = EXIT_FAILURE; + GNUNET_break (0); + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } @@ -2643,7 +2648,7 @@ run (void *cls, if (NULL == TEH_curl_ctx) { GNUNET_break (0); - global_ret = EXIT_FAILURE; + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } diff --git a/src/exchange/taler-exchange-httpd_config.c b/src/exchange/taler-exchange-httpd_config.c index fde1823fc..29cbf2b51 100644 --- a/src/exchange/taler-exchange-httpd_config.c +++ b/src/exchange/taler-exchange-httpd_config.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2021 Taler Systems SA + Copyright (C) 2015-2024 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 @@ -46,6 +46,8 @@ TEH_handler_config (struct TEH_RequestContext *rc, TEH_currency), GNUNET_JSON_pack_string ("name", "taler-exchange"), + GNUNET_JSON_pack_string ("implementation", + "urn:net:taler:specs:exchange:c-reference"), GNUNET_JSON_pack_string ("version", EXCHANGE_PROTOCOL_VERSION)); } diff --git a/src/exchange/taler-exchange-httpd_config.h b/src/exchange/taler-exchange-httpd_config.h index 362667aca..40293e89a 100644 --- a/src/exchange/taler-exchange-httpd_config.h +++ b/src/exchange/taler-exchange-httpd_config.h @@ -41,7 +41,7 @@ * * Returned via both /config and /keys endpoints. */ -#define EXCHANGE_PROTOCOL_VERSION "18:0:1" +#define EXCHANGE_PROTOCOL_VERSION "18:1:1" /** diff --git a/src/exchange/taler-exchange-transfer.c b/src/exchange/taler-exchange-transfer.c index ae2b4fe7f..b0fad660c 100644 --- a/src/exchange/taler-exchange-transfer.c +++ b/src/exchange/taler-exchange-transfer.c @@ -574,7 +574,7 @@ wire_prepare_cb (void *cls, GNUNET_break (0); cleanup_wpd (); db_plugin->rollback (db_plugin->cls); - global_ret = EXIT_NOTCONFIGURED; + global_ret = EXIT_NO_RESTART; GNUNET_SCHEDULER_shutdown (); return; } diff --git a/src/exchange/taler-exchange-wirewatch.c b/src/exchange/taler-exchange-wirewatch.c index 34235eb94..da5d9c098 100644 --- a/src/exchange/taler-exchange-wirewatch.c +++ b/src/exchange/taler-exchange-wirewatch.c @@ -362,7 +362,6 @@ exchange_serve_process_config (void) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No accounts enabled for credit!\n"); GNUNET_SCHEDULER_shutdown (); - global_ret = EXIT_INVALIDARGUMENT; return GNUNET_SYSERR; } return GNUNET_OK; @@ -951,6 +950,7 @@ run (void *cls, { GNUNET_break (0); GNUNET_SCHEDULER_shutdown (); + global_ret = EXIT_NO_RESTART; return; } rc = GNUNET_CURL_gnunet_rc_create (ctx); diff --git a/src/exchangedb/pg_get_age_withdraw.c b/src/exchangedb/pg_get_age_withdraw.c index 9a80f189b..ea4d3b909 100644 --- a/src/exchangedb/pg_get_age_withdraw.c +++ b/src/exchangedb/pg_get_age_withdraw.c @@ -33,7 +33,10 @@ TEH_PG_get_age_withdraw ( const struct TALER_AgeWithdrawCommitmentHashP *ach, struct TALER_EXCHANGEDB_AgeWithdraw *aw) { + enum GNUNET_DB_QueryStatus ret; struct PostgresClosure *pg = cls; + size_t num_sigs; + size_t num_hashes; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (reserve_pub), GNUNET_PQ_query_param_auto_from_type (ach), @@ -61,12 +64,12 @@ TEH_PG_get_age_withdraw ( TALER_PQ_result_spec_array_blinded_denom_sig ( pg->conn, "denom_sigs", - NULL, /* FIXME-Oec: this assumes that this is the same size as h_coin_evs, but we should check! */ + &num_sigs, &aw->denom_sigs), TALER_PQ_result_spec_array_denom_hash ( pg->conn, "denom_pub_hashes", - NULL, /* FIXME-Oec: this assumes that this is the same size as h_coin_evs, but we should check! */ + &num_hashes, &aw->denom_pub_hashes), GNUNET_PQ_result_spec_end }; @@ -92,8 +95,25 @@ TEH_PG_get_age_withdraw ( " FROM age_withdraw" " WHERE reserve_pub=$1 and h_commitment=$2;"); - return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, - "get_age_withdraw", - params, - rs); + ret = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, + "get_age_withdraw", + params, + rs); + if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != ret) + return ret; + + if ((aw->num_coins != num_sigs) || + (aw->num_coins != num_hashes)) + { + GNUNET_break (0); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "got inconsistent number of entries from DB: " + "num_coins=%ld, num_sigs=%ld, num_hashes=%ld\n", + aw->num_coins, + num_sigs, + num_hashes); + return GNUNET_DB_STATUS_HARD_ERROR; + } + + return ret; } diff --git a/src/include/platform.h b/src/include/platform.h index f27ee38b7..db04cb972 100644 --- a/src/include/platform.h +++ b/src/include/platform.h @@ -231,22 +231,42 @@ atoll (const char *nptr); /* LSB-style exit status codes */ #ifndef EXIT_INVALIDARGUMENT +/** + * Command-line arguments are invalid. + * Restarting useless. + */ #define EXIT_INVALIDARGUMENT 2 #endif #ifndef EXIT_NOTIMPLEMENTED +/** + * The requested operation is not implemented. + * Restarting useless. + */ #define EXIT_NOTIMPLEMENTED 3 #endif #ifndef EXIT_NOPERMISSION +/** + * Permissions needed to run are not available. + * Restarting useless. + */ #define EXIT_NOPERMISSION 4 #endif #ifndef EXIT_NOTINSTALLED +/** + * Key resources are not installed. + * Restarting useless. + */ #define EXIT_NOTINSTALLED 5 #endif #ifndef EXIT_NOTCONFIGURED +/** + * Key configuration settings are missing or invalid. + * Restarting useless. + */ #define EXIT_NOTCONFIGURED 6 #endif @@ -254,7 +274,12 @@ atoll (const char *nptr); #define EXIT_NOTRUNNING 7 #endif + #ifndef EXIT_NO_RESTART +/** + * Exit code from 'main' if we do not want to be restarted, + * except by manual intervention (hard failure). + */ #define EXIT_NO_RESTART 9 #endif diff --git a/src/include/taler_auditor_service.h b/src/include/taler_auditor_service.h index de32be9a4..36ea781b1 100644 --- a/src/include/taler_auditor_service.h +++ b/src/include/taler_auditor_service.h @@ -16,6 +16,8 @@ /** * @file include/taler_auditor_service.h * @brief C interface of libtalerauditor, a C library to use auditor's HTTP API + * This library is not thread-safe, all APIs must only be used from a single thread. + * This library calls abort() if it runs out of memory. Be aware of these limitations. * @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Christian Grothoff */ diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h index b872af08d..e3ae829fd 100644 --- a/src/include/taler_crypto_lib.h +++ b/src/include/taler_crypto_lib.h @@ -938,6 +938,22 @@ GNUNET_NETWORK_STRUCT_END /** + * Compute RFC 3548 base32 decoding of @a val and write + * result to @a udata. + * + * @param val value to decode + * @param val_size number of bytes in @a val + * @param key is the val in bits + * @param key_len is the size of @a key + */ +int +TALER_rfc3548_base32decode (const char *val, + size_t val_size, + void *key, + size_t key_len); + + +/** * @brief Builds POS confirmation token to verify payment. * * @param pos_key encoded key for verification payment diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 8a59f157f..465c54ae5 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -16,6 +16,8 @@ /** * @file include/taler_exchange_service.h * @brief C interface of libtalerexchange, a C library to use exchange's HTTP API + * This library is not thread-safe, all APIs must only be used from a single thread. + * This library calls abort() if it runs out of memory. Be aware of these limitations. * @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Christian Grothoff * @author Özgür Kesim @@ -30,6 +32,12 @@ #include <gnunet/gnunet_curl_lib.h> +/** + * Version of the Taler Exchange API, in hex. + * Thus 0.8.4-1 = 0x00080401. + */ +#define TALER_EXCHANGE_API_VERSION 0x00090400 + /* ********************* /keys *********************** */ @@ -2690,9 +2698,9 @@ struct TALER_EXCHANGE_Withdraw2Handle; * Withdraw a coin from the exchange using a /reserves/$RESERVE_PUB/withdraw * request. This API is typically used by a merchant to withdraw a tip * where the blinding factor is unknown to the merchant. Note that unlike - * the #TALER_EXCHANGE_withdraw() API, this API neither unblinds the signatures + * the #TALER_EXCHANGE_batch_withdraw() API, this API neither unblinds the signatures * nor can it verify that the exchange signatures are valid, so these tasks - * are left to the caller. Wallets probably should use #TALER_EXCHANGE_withdraw() + * are left to the caller. Wallets probably should use #TALER_EXCHANGE_batch_withdraw() * which integrates these steps. * * Note that to ensure that no money is lost in case of hardware diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h index 859ec8879..98e565f0c 100644 --- a/src/include/taler_json_lib.h +++ b/src/include/taler_json_lib.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016, 2021, 2022 Taler Systems SA + Copyright (C) 2014-2024 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 @@ -59,7 +59,6 @@ struct TALER_EncryptedContract */ size_t econtract_size; - }; @@ -287,6 +286,34 @@ TALER_JSON_spec_age_commitment (const char *name, /** + * Provide specification to parse an OTP key. + * An OTP key must be an RFC 3548 base32-encoded + * value (so NOT our usual Crockford-base32 encoding!). + * + * @param name name of the OTP key field in the JSON + * @param[out] otp_key where to store the OTP key + * @return spec for parsing an age commitment + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_key (const char *name, + const char **otp_key); + + +/** + * Provide specification to parse an OTP method type. + * The value could be provided as an integer or + * as a descriptive string. + * + * @param name name of the OTP method type in the JSON + * @param[out] mca where to store the method type + * @return spec for parsing an age commitment + */ +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_type (const char *name, + enum TALER_MerchantConfirmationAlgorithm *mca); + + +/** * Generate specification to parse all fees for * a denomination under a prefix @a pfx. * diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 43923fea7..f07d9be20 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -20,6 +20,8 @@ /** * @file include/taler_testing_lib.h * @brief API for writing an interpreter to test Taler components + * This library is not thread-safe, all APIs must only be used from a single thread. + * This library calls abort() if it runs out of memory. Be aware of these limitations. * @author Christian Grothoff <christian@grothoff.org> * @author Marcello Stanisci */ diff --git a/src/include/taler_util.h b/src/include/taler_util.h index e895c3445..fc2316705 100644 --- a/src/include/taler_util.h +++ b/src/include/taler_util.h @@ -16,6 +16,8 @@ /** * @file include/taler_util.h * @brief Interface for common utility functions + * This library is not thread-safe, all APIs must only be used from a single thread. + * This library calls abort() if it runs out of memory. Be aware of these limitations. * @author Sree Harsha Totakura <sreeharsha@totakura.in> * @author Christian Grothoff */ diff --git a/src/json/Makefile.am b/src/json/Makefile.am index 6886b285a..ce863cb7e 100644 --- a/src/json/Makefile.am +++ b/src/json/Makefile.am @@ -16,7 +16,7 @@ libtalerjson_la_SOURCES = \ json_pack.c \ json_wire.c libtalerjson_la_LDFLAGS = \ - -version-info 2:0:0 \ + -version-info 3:0:1 \ -no-undefined libtalerjson_la_LIBADD = \ $(top_builddir)/src/util/libtalerutil.la \ diff --git a/src/json/json_helper.c b/src/json/json_helper.c index 01ca45f2b..0a533610b 100644 --- a/src/json/json_helper.c +++ b/src/json/json_helper.c @@ -1666,4 +1666,154 @@ TALER_JSON_spec_version (const char *field, } +/** + * Parse given JSON object to an OTP key. + * + * @param cls closure, NULL + * @param root the json object representing data + * @param[out] spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static enum GNUNET_GenericReturnValue +parse_otp_key (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + const char *pos_key; + + (void) cls; + pos_key = json_string_value (root); + if (NULL == pos_key) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + { + size_t pos_key_length = strlen (pos_key); + void *key; /* pos_key in binary */ + size_t key_len; /* length of the key */ + int dret; + + key_len = pos_key_length * 5 / 8; + key = GNUNET_malloc (key_len); + dret = TALER_rfc3548_base32decode (pos_key, + pos_key_length, + key, + key_len); + if (-1 == dret) + { + GNUNET_free (key); + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_free (key); + } + *(const char **) spec->ptr = pos_key; + return GNUNET_OK; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_key (const char *name, + const char **otp_key) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_otp_key, + .field = name, + .ptr = otp_key + }; + + *otp_key = NULL; + return ret; +} + + +/** + * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm` + * + * @param cls closure, NULL + * @param root the json object representing data + * @param[out] spec where to write the data + * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error + */ +static enum GNUNET_GenericReturnValue +parse_otp_type (void *cls, + json_t *root, + struct GNUNET_JSON_Specification *spec) +{ + static const struct Entry + { + const char *name; + enum TALER_MerchantConfirmationAlgorithm val; + } lt [] = { + { .name = "NONE", + .val = TALER_MCA_NONE }, + { .name = "TOTP_WITHOUT_PRICE", + .val = TALER_MCA_WITHOUT_PRICE }, + { .name = "TOTP_WITH_PRICE", + .val = TALER_MCA_WITH_PRICE }, + { .name = NULL, + .val = TALER_MCA_NONE }, + }; + enum TALER_MerchantConfirmationAlgorithm *res + = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr; + + (void) cls; + if (json_is_string (root)) + { + const char *str; + + str = json_string_value (root); + if (NULL == str) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + for (unsigned int i = 0; NULL != lt[i].name; i++) + { + if (0 == strcasecmp (str, + lt[i].name)) + { + *res = lt[i].val; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + } + if (json_is_integer (root)) + { + json_int_t val; + + val = json_integer_value (root); + for (unsigned int i = 0; NULL != lt[i].name; i++) + { + if (val == lt[i].val) + { + *res = lt[i].val; + return GNUNET_OK; + } + } + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + GNUNET_break_op (0); + return GNUNET_SYSERR; +} + + +struct GNUNET_JSON_Specification +TALER_JSON_spec_otp_type (const char *name, + enum TALER_MerchantConfirmationAlgorithm *mca) +{ + struct GNUNET_JSON_Specification ret = { + .parser = &parse_otp_type, + .field = name, + .ptr = mca + }; + + *mca = TALER_MCA_NONE; + return ret; +} + + /* end of json/json_helper.c */ diff --git a/src/lib/exchange_api_common.c b/src/lib/exchange_api_common.c index 239632656..417fdf357 100644 --- a/src/lib/exchange_api_common.c +++ b/src/lib/exchange_api_common.c @@ -414,18 +414,22 @@ parse_restrictions (const json_t *jresta, unsigned int *resta_len, struct TALER_EXCHANGE_AccountRestriction **resta) { + size_t alen; + if (! json_is_array (jresta)) { GNUNET_break_op (0); return GNUNET_SYSERR; } - *resta_len = json_array_size (jresta); - if (0 == *resta_len) + alen = json_array_size (jresta); + if (0 == alen) { /* no restrictions, perfectly OK */ *resta = NULL; return GNUNET_OK; } + *resta_len = (unsigned int) alen; + GNUNET_assert (alen == *resta_len); *resta = GNUNET_new_array (*resta_len, struct TALER_EXCHANGE_AccountRestriction); for (unsigned int i = 0; i<*resta_len; i++) diff --git a/src/lib/exchange_api_csr_melt.c b/src/lib/exchange_api_csr_melt.c index 1644f00a9..bf6f4bfe1 100644 --- a/src/lib/exchange_api_csr_melt.c +++ b/src/lib/exchange_api_csr_melt.c @@ -86,7 +86,7 @@ csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh, const json_t *arr, struct TALER_EXCHANGE_HttpResponse *hr) { - unsigned int alen = json_array_size (arr); + size_t alen = json_array_size (arr); struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)]; struct TALER_EXCHANGE_CsRMeltResponse csrr = { .hr = *hr, @@ -94,7 +94,7 @@ csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh, .details.ok.alg_values = alg_values }; - for (unsigned int i = 0; i<alen; i++) + for (size_t i = 0; i<alen; i++) { json_t *av = json_array_get (arr, i); @@ -116,7 +116,7 @@ csr_ok (struct TALER_EXCHANGE_CsRMeltHandle *csrh, } csrh->cb (csrh->cb_cls, &csrr); - for (unsigned int i = 0; i<alen; i++) + for (size_t i = 0; i<alen; i++) TALER_denom_ewv_free (&alg_values[i]); return GNUNET_OK; } diff --git a/src/lib/exchange_api_handle.c b/src/lib/exchange_api_handle.c index 7db89933b..306d2f261 100644 --- a/src/lib/exchange_api_handle.c +++ b/src/lib/exchange_api_handle.c @@ -224,7 +224,7 @@ append_signature (struct SignatureContext *sig_ctx, if (0 == sig_ctx->elements_size) new_size = 1024; else - new_size = sig_ctx->elements_size; + new_size = sig_ctx->elements_size * 2; GNUNET_array_grow (sig_ctx->elements, sig_ctx->elements_size, new_size); @@ -280,17 +280,22 @@ parse_fees (const struct TALER_MasterPublicKeyP *master_pub, unsigned int *fees_len) { struct TALER_EXCHANGE_WireFeesByMethod *fbm; - unsigned int fbml = json_object_size (fees); + size_t fbml = json_object_size (fees); unsigned int i = 0; const char *key; const json_t *fee_array; + if (UINT_MAX < fbml) + { + GNUNET_break (0); + return NULL; + } fbm = GNUNET_new_array (fbml, struct TALER_EXCHANGE_WireFeesByMethod); - *fees_len = fbml; + *fees_len = (unsigned int) fbml; json_object_foreach ((json_t *) fees, key, fee_array) { struct TALER_EXCHANGE_WireFeesByMethod *fe = &fbm[i++]; - unsigned int idx; + size_t idx; json_t *fee; fe->method = GNUNET_strdup (key); @@ -517,11 +522,11 @@ parse_json_denomkey_partially ( &denom_key->master_sig)); return GNUNET_OK; EXITIF_exit: + GNUNET_JSON_parse_free (spec); /* invalidate denom_key, just to be sure */ memset (denom_key, 0, sizeof (*denom_key)); - GNUNET_JSON_parse_free (spec); return GNUNET_SYSERR; } @@ -544,8 +549,8 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, { const json_t *keys; json_t *key; - unsigned int off; - unsigned int pos; + size_t off; + size_t pos; const char *auditor_url; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_fixed_auto ("auditor_pub", @@ -637,7 +642,12 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, auditor->denom_keys[pos].auditor_sig = auditor_sig; pos++; } - auditor->num_denom_keys = pos; + if (pos > UINT_MAX) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + auditor->num_denom_keys = (unsigned int) pos; return GNUNET_OK; } @@ -718,7 +728,7 @@ parse_global_fee (struct TALER_EXCHANGE_GlobalFee *gf, * @param denom1 first denomination key * @param denom2 second denomination key * @return 0 if the two keys are equal (not necessarily - * the same object), 1 otherwise. + * the same object), non-zero otherwise. */ static unsigned int denoms_cmp (const struct TALER_EXCHANGE_DenomPublicKey *denom1, @@ -950,12 +960,13 @@ decode_keys_json (const json_t *resp_obj, } /* parse the global fees */ + EXITIF (json_array_size (global_fees) > UINT_MAX); key_data->num_global_fees - = json_array_size (global_fees); + = (unsigned int) json_array_size (global_fees); if (0 != key_data->num_global_fees) { json_t *global_fee; - unsigned int index; + size_t index; key_data->global_fees = GNUNET_new_array (key_data->num_global_fees, @@ -971,12 +982,13 @@ decode_keys_json (const json_t *resp_obj, } /* parse the signing keys */ + EXITIF (json_array_size (sign_keys_array) > UINT_MAX); key_data->num_sign_keys - = json_array_size (sign_keys_array); + = (unsigned int) json_array_size (sign_keys_array); if (0 != key_data->num_sign_keys) { json_t *sign_key_obj; - unsigned int index; + size_t index; key_data->sign_keys = GNUNET_new_array (key_data->num_sign_keys, @@ -993,7 +1005,9 @@ decode_keys_json (const json_t *resp_obj, /* Parse balance limits */ if (NULL != wblwk) { - key_data->wblwk_length = json_array_size (wblwk); + EXITIF (json_array_size (wblwk) > UINT_MAX); + key_data->wblwk_length + = (unsigned int) json_array_size (wblwk); key_data->wallet_balance_limit_without_kyc = GNUNET_new_array (key_data->wblwk_length, struct TALER_Amount); @@ -1023,6 +1037,7 @@ decode_keys_json (const json_t *resp_obj, &key_data->fees_len); EXITIF (NULL == key_data->fees); /* parse accounts */ + EXITIF (json_array_size (accounts) > UINT_MAX); GNUNET_array_grow (key_data->accounts, key_data->accounts_len, json_array_size (accounts)); @@ -1034,7 +1049,7 @@ decode_keys_json (const json_t *resp_obj, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Parsed %u wire accounts from JSON\n", - (unsigned int) json_array_size (accounts)); + key_data->accounts_len); /* Parse the supported extension(s): age-restriction. */ @@ -1150,6 +1165,9 @@ decode_keys_json (const json_t *resp_obj, GNUNET_array_grow (key_data->denom_keys, key_data->denom_keys_size, key_data->denom_keys_size * 2 + 2); + GNUNET_assert (key_data->denom_keys_size > + key_data->num_denom_keys); + GNUNET_assert (key_data->num_denom_keys < UINT_MAX); key_data->denom_keys[key_data->num_denom_keys++] = dk; /* Update "last_denom_issue_date" */ @@ -1228,7 +1246,10 @@ decode_keys_json (const json_t *resp_obj, GNUNET_array_grow (key_data->auditors, key_data->auditors_size, key_data->auditors_size * 2 + 2); + GNUNET_assert (key_data->auditors_size > + key_data->num_auditors); GNUNET_assert (NULL != ai.auditor_url); + GNUNET_assert (key_data->num_auditors < UINT_MAX); key_data->auditors[key_data->num_auditors++] = ai; }; } diff --git a/src/lib/exchange_api_management_revoke_denomination_key.c b/src/lib/exchange_api_management_revoke_denomination_key.c index aa4d527a7..a57704776 100644 --- a/src/lib/exchange_api_management_revoke_denomination_key.c +++ b/src/lib/exchange_api_management_revoke_denomination_key.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2020 Taler Systems SA + Copyright (C) 2015-2024 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 @@ -186,6 +186,7 @@ TALER_EXCHANGE_management_revoke_denomination_key ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (rh->url); + GNUNET_free (rh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_revoke_signing_key.c b/src/lib/exchange_api_management_revoke_signing_key.c index c4d634248..d2fa78264 100644 --- a/src/lib/exchange_api_management_revoke_signing_key.c +++ b/src/lib/exchange_api_management_revoke_signing_key.c @@ -176,6 +176,7 @@ TALER_EXCHANGE_management_revoke_signing_key ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (rh->url); + GNUNET_free (rh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_set_global_fee.c b/src/lib/exchange_api_management_set_global_fee.c index 54c37fd64..f6282a812 100644 --- a/src/lib/exchange_api_management_set_global_fee.c +++ b/src/lib/exchange_api_management_set_global_fee.c @@ -200,6 +200,7 @@ TALER_EXCHANGE_management_set_global_fees ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (sgfh->url); + GNUNET_free (sgfh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_set_wire_fee.c b/src/lib/exchange_api_management_set_wire_fee.c index 03cab8c99..aaeae21f4 100644 --- a/src/lib/exchange_api_management_set_wire_fee.c +++ b/src/lib/exchange_api_management_set_wire_fee.c @@ -192,6 +192,7 @@ TALER_EXCHANGE_management_set_wire_fees ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (swfh->url); + GNUNET_free (swfh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_update_aml_officer.c b/src/lib/exchange_api_management_update_aml_officer.c index 76cbc7e8d..af0169b02 100644 --- a/src/lib/exchange_api_management_update_aml_officer.c +++ b/src/lib/exchange_api_management_update_aml_officer.c @@ -194,6 +194,7 @@ TALER_EXCHANGE_management_update_aml_officer ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (wh->url); + GNUNET_free (wh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_wire_disable.c b/src/lib/exchange_api_management_wire_disable.c index 30749b0e4..23b10c58c 100644 --- a/src/lib/exchange_api_management_wire_disable.c +++ b/src/lib/exchange_api_management_wire_disable.c @@ -185,6 +185,7 @@ TALER_EXCHANGE_management_disable_wire ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (wh->url); + GNUNET_free (wh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_management_wire_enable.c b/src/lib/exchange_api_management_wire_enable.c index 5add3e0b0..1982a502e 100644 --- a/src/lib/exchange_api_management_wire_enable.c +++ b/src/lib/exchange_api_management_wire_enable.c @@ -210,6 +210,7 @@ TALER_EXCHANGE_management_enable_wire ( curl_easy_cleanup (eh); json_decref (body); GNUNET_free (wh->url); + GNUNET_free (wh); return NULL; } json_decref (body); diff --git a/src/lib/exchange_api_purse_create_with_deposit.c b/src/lib/exchange_api_purse_create_with_deposit.c index fc2499338..fff898e57 100644 --- a/src/lib/exchange_api_purse_create_with_deposit.c +++ b/src/lib/exchange_api_purse_create_with_deposit.c @@ -512,6 +512,10 @@ TALER_EXCHANGE_purse_create_with_deposit ( &attest)) { GNUNET_break (0); + GNUNET_array_grow (pch->deposits, + pch->num_deposits, + 0); + GNUNET_free (pch->url); json_decref (deposit_arr); GNUNET_free (pch); return NULL; @@ -606,7 +610,9 @@ TALER_EXCHANGE_purse_create_with_deposit ( curl_easy_cleanup (eh); json_decref (create_obj); GNUNET_free (pch->econtract.econtract); - GNUNET_free (pch->deposits); + GNUNET_array_grow (pch->deposits, + pch->num_deposits, + 0); GNUNET_free (pch->url); GNUNET_free (pch); return NULL; @@ -638,7 +644,9 @@ TALER_EXCHANGE_purse_create_with_deposit_cancel ( GNUNET_free (pch->econtract.econtract); GNUNET_free (pch->exchange_url); GNUNET_free (pch->url); - GNUNET_free (pch->deposits); + GNUNET_array_grow (pch->deposits, + pch->num_deposits, + 0); TALER_EXCHANGE_keys_decref (pch->keys); TALER_curl_easy_post_finished (&pch->ctx); GNUNET_free (pch); diff --git a/src/lib/exchange_api_purse_deposit.c b/src/lib/exchange_api_purse_deposit.c index 7db2f34c7..9c5fa4e78 100644 --- a/src/lib/exchange_api_purse_deposit.c +++ b/src/lib/exchange_api_purse_deposit.c @@ -425,6 +425,7 @@ TALER_EXCHANGE_purse_deposit ( json_decref (deposit_arr); GNUNET_free (pch->base_url); GNUNET_free (pch->coins); + GNUNET_free (pch->url); GNUNET_free (pch); return NULL; } diff --git a/src/lib/exchange_api_purse_merge.c b/src/lib/exchange_api_purse_merge.c index 8fd952515..c013b29d2 100644 --- a/src/lib/exchange_api_purse_merge.c +++ b/src/lib/exchange_api_purse_merge.c @@ -403,6 +403,7 @@ TALER_EXCHANGE_account_merge ( GNUNET_JSON_pack_timestamp ("merge_timestamp", merge_timestamp)); GNUNET_assert (NULL != merge_obj); + GNUNET_free (reserve_url); eh = TALER_EXCHANGE_curl_easy_get_ (pch->url); if ( (NULL == eh) || (GNUNET_OK != diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am index f1e7f1cce..f35c8b6d8 100644 --- a/src/testing/Makefile.am +++ b/src/testing/Makefile.am @@ -145,9 +145,6 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH= .NOTPARALLEL: check_PROGRAMS = \ - test_auditor_api_cs \ - test_auditor_api_rsa \ - test_auditor_api_version \ test_bank_api_with_fakebank \ test_bank_api_with_nexus \ test_exchange_api_cs \ @@ -176,6 +173,11 @@ if HAVE_TWISTER test_bank_api_with_fakebank_twisted endif +# Removed for now... +# test_auditor_api_cs +# test_auditor_api_rsa +# test_auditor_api_version + TESTS = \ @@ -601,6 +603,9 @@ EXTRA_DIST = \ test_exchange_api_age_restriction.conf \ test_exchange_api_age_restriction-cs.conf \ test_exchange_api_age_restriction-rsa.conf \ + test_exchange_api_conflicts.conf \ + test_exchange_api_conflicts-cs.conf \ + test_exchange_api_conflicts-rsa.conf \ test_exchange_api-twisted.conf \ test_exchange_api_twisted-cs.conf \ test_exchange_api_twisted-rsa.conf \ diff --git a/src/testing/taler-unified-setup.sh b/src/testing/taler-unified-setup.sh index b1c8402f5..e1fcc8015 100755 --- a/src/testing/taler-unified-setup.sh +++ b/src/testing/taler-unified-setup.sh @@ -77,6 +77,7 @@ START_TRANSFER=0 START_WIREWATCH=0 START_DEPOSITCHECK=0 START_MERCHANT_EXCHANGE=0 +START_MERCHANT_WIREWATCH=0 USE_ACCOUNT="exchange-account-1" USE_VALGRIND="" WIRE_DOMAIN="x-taler-bank" @@ -85,7 +86,7 @@ LOGLEVEL="DEBUG" DEFAULT_SLEEP="0.2" # Parse command-line options -while getopts ':abc:d:DeEfghkL:mMnr:stu:vwW' OPTION; do +while getopts ':abc:d:DeEfghkL:mMnr:stu:vwWz' OPTION; do case "$OPTION" in a) START_AUDITOR="1" @@ -125,6 +126,7 @@ while getopts ':abc:d:DeEfghkL:mMnr:stu:vwW' OPTION; do echo ' -f -- start fakebank' echo ' -g -- start taler-exchange-aggregator' echo ' -h -- print this help' + echo ' -k -- start challenger (KYC service)' # shellcheck disable=SC2016 echo ' -L $LOGLEVEL -- set log level' echo ' -m -- start taler-merchant' @@ -139,6 +141,7 @@ while getopts ':abc:d:DeEfghkL:mMnr:stu:vwW' OPTION; do echo ' -v -- use valgrind' echo ' -w -- start taler-exchange-wirewatch' echo ' -W -- wait for signal' + echo ' -z -- start taler-merchant-wirewatch' exit 0 ;; g) @@ -181,6 +184,9 @@ while getopts ':abc:d:DeEfghkL:mMnr:stu:vwW' OPTION; do W) WAIT_FOR_SIGNAL="1" ;; + z) + START_MERCHANT_WIREWATCH="1" + ;; ?) exit_fail "Unrecognized command line option" ;; @@ -265,7 +271,7 @@ register_bank_account() { ENAME=$(echo "$3" | sed -e "s/ /+/g") # Note: this assumes that $3 has no spaces. Should probably escape in the future.. PAYTO="payto://iban/SANDBOXX/${MAYBE_IBAN}?receiver-name=$ENAME" - BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'","internal_payto_uri":"'"$PAYTO"'"}' + BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'","payto_uri":"'"$PAYTO"'"}' else BODY='{"username":"'"$1"'","password":"'"$2"'","is_taler_exchange":'"$IS_EXCHANGE"',"name":"'"$3"'"}' fi @@ -568,19 +574,33 @@ then $USE_VALGRIND taler-merchant-webhook \ -c "$CONF" \ -L "$LOGLEVEL" 2> taler-merchant-webhook.log & + echo " DONE" + if [ "1" = "$START_MERCHANT_WIREWATCH" ] + then + echo -n "Starting taler-merchant-wirewatch ..." + $USE_VALGRIND taler-merchant-wirewatch \ + -c "$CONF" \ + -L "$LOGLEVEL" \ + --persist \ + 2> taler-merchant-wirewatch.log & + echo " DONE" + fi if [ "1" = "$START_MERCHANT_EXCHANGE" ] then + echo -n "Starting taler-merchant-exchange ..." $USE_VALGRIND taler-merchant-exchange \ -c "$CONF" \ -L "$LOGLEVEL" 2> taler-merchant-exchange.log & + echo " DONE" fi if [ "1" = "$START_DEPOSITCHECK" ] then + echo -n "Starting taler-merchant-depositcheck ..." $USE_VALGRIND taler-merchant-depositcheck \ -c "$CONF" \ -L "$LOGLEVEL" 2> taler-merchant-depositcheck.log & + echo " DONE" fi - echo " DONE" fi @@ -667,9 +687,9 @@ then $USE_VALGRIND taler-auditor-httpd \ -L "$LOGLEVEL" \ -c "$CONF" 2> taler-auditor-httpd.log & - $USE_VALGRIND taler-helper-auditor-deposits \ - -L "$LOGLEVEL" \ - -c "$CONF" 2> taler-helper-auditor.log & +# $USE_VALGRIND taler-helper-auditor-deposits \ +# -L "$LOGLEVEL" \ +# -c "$CONF" 2> taler-helper-auditor.log & echo " DONE" fi diff --git a/src/testing/test_bank_api.conf b/src/testing/test_bank_api.conf index 3618770bc..c262ae197 100644 --- a/src/testing/test_bank_api.conf +++ b/src/testing/test_bank_api.conf @@ -12,6 +12,8 @@ HTTP_PORT = 8082 [libeufin-bank] CURRENCY = EUR +WIRE_TYPE = iban +IBAN_PAYTO_BIC = SANDBOXX= DEFAULT_CUSTOMER_DEBT_LIMIT = EUR:200 DEFAULT_ADMIN_DEBT_LIMIT = EUR:2000 REGISTRATION_BONUS_ENABLED = yes diff --git a/src/testing/test_kyc_api.c b/src/testing/test_kyc_api.c index a0178db06..f7cf1ce97 100644 --- a/src/testing/test_kyc_api.c +++ b/src/testing/test_kyc_api.c @@ -201,8 +201,6 @@ run (void *cls, }; struct TALER_TESTING_Command wallet_kyc[] = { - TALER_TESTING_cmd_oauth ("start-oauth-service", - 6666), TALER_TESTING_cmd_wallet_kyc_get ("wallet-kyc-fail", NULL, "EUR:1000000", diff --git a/src/testing/testing_api_cmd_oauth.c b/src/testing/testing_api_cmd_oauth.c index 17f0eaa68..80d38e4c8 100644 --- a/src/testing/testing_api_cmd_oauth.c +++ b/src/testing/testing_api_cmd_oauth.c @@ -347,12 +347,18 @@ oauth_run (void *cls, struct OAuthState *oas = cls; (void) cmd; - oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD, + oas->mhd = MHD_start_daemon (MHD_USE_AUTO_INTERNAL_THREAD | MHD_USE_DEBUG, oas->port, NULL, NULL, &handler_cb, oas, MHD_OPTION_NOTIFY_COMPLETED, &cleanup, NULL, NULL); + if (NULL == oas->mhd) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } TALER_TESTING_interpreter_next (is); } diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 478f75cfe..914ddfdf1 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -120,7 +120,7 @@ libtalerutil_la_LIBADD = \ -lm libtalerutil_la_LDFLAGS = \ - -version-info 1:0:0 \ + -version-info 2:0:1 \ -no-undefined diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c index f19fc4a3c..204c373da 100644 --- a/src/util/crypto_confirmation.c +++ b/src/util/crypto_confirmation.c @@ -112,20 +112,11 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, } -/** - * Compute RFC 3548 base32 decoding of @a val and write - * result to @a udata. - * - * @param val value to decode - * @param val_size number of bytes in @a val - * @param key is the val in bits - * @param key_len is the size of @a key - */ -static int -base32decode (const char *val, - size_t val_size, - void *key, - size_t key_len) +int +TALER_rfc3548_base32decode (const char *val, + size_t val_size, + void *key, + size_t key_len) { /** * 32 characters for decoding, using RFC 3548. @@ -142,13 +133,21 @@ base32decode (const char *val, if ((rpos < val_size) && (vbit < 8)) { char c = val[rpos++]; - if (c == '=') // padding character + + if (c == '=') { - break; + /* padding character */ + if (rpos == val_size) + break; /* Ok, 1x '=' padding is allowed */ + if ( ('=' == val[rpos]) && + (rpos + 1 == val_size) ) + break; /* Ok, 2x '=' padding is allowed */ + return -1; /* invalid padding */ } const char *p = strchr (decTable__, toupper (c)); if (! p) - { // invalid character + { + /* invalid character */ return -1; } bits = (bits << 5) | (p - decTable__); @@ -226,10 +225,10 @@ TALER_build_pos_confirmation (const char *pos_key, return NULL; key_len = pos_key_length * 5 / 8; key = GNUNET_malloc (key_len); - dret = base32decode (pos_key, - pos_key_length, - key, - key_len); + dret = TALER_rfc3548_base32decode (pos_key, + pos_key_length, + key, + key_len); if (-1 == dret) { GNUNET_free (key); |