summaryrefslogtreecommitdiff
path: root/src/testing
diff options
context:
space:
mode:
Diffstat (limited to 'src/testing')
-rw-r--r--src/testing/.gitignore3
-rw-r--r--src/testing/Makefile.am91
-rwxr-xr-xsrc/testing/sms_authentication.sh10
-rw-r--r--src/testing/test_anastasis.c464
-rw-r--r--src/testing/test_anastasis_api.c421
-rw-r--r--src/testing/test_anastasis_api.conf264
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/exchange/account-2.json3
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/account-3.json1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/default.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/dtip.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/nulltip.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/dtip.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/nulltip.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/tip.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/tip.privbin0 -> 32 bytes
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/merchant/tor.privbin0 -> 32 bytes
-rw-r--r--src/testing/test_anastasis_api_home/.config/taler/test.json8
-rw-r--r--src/testing/test_anastasis_api_home/.local/share/taler/exchange/offline-keys/master.priv1
-rw-r--r--src/testing/test_anastasis_api_home/.local/share/taler/merchant/merchant.priv1
-rw-r--r--src/testing/testing_api_cmd_config.c206
-rw-r--r--src/testing/testing_api_cmd_keyshare_lookup.c465
-rw-r--r--src/testing/testing_api_cmd_policy_lookup.c267
-rw-r--r--src/testing/testing_api_cmd_policy_store.c397
-rw-r--r--src/testing/testing_api_cmd_truth_store.c436
-rw-r--r--src/testing/testing_api_helpers.c173
-rw-r--r--src/testing/testing_api_trait_account_priv.c72
-rw-r--r--src/testing/testing_api_trait_account_pub.c72
-rw-r--r--src/testing/testing_api_trait_code.c73
-rw-r--r--src/testing/testing_api_trait_eks.c58
-rw-r--r--src/testing/testing_api_trait_hash.c72
-rw-r--r--src/testing/testing_api_trait_payment_secret.c73
-rw-r--r--src/testing/testing_api_trait_salt.c74
-rw-r--r--src/testing/testing_api_trait_truth_key.c58
-rw-r--r--src/testing/testing_api_trait_truth_uuid.c74
-rw-r--r--src/testing/testing_cmd_challenge_answer.c584
-rw-r--r--src/testing/testing_cmd_policy_create.c208
-rw-r--r--src/testing/testing_cmd_recover_secret.c518
-rw-r--r--src/testing/testing_cmd_secret_share.c441
-rw-r--r--src/testing/testing_cmd_truth_upload.c383
-rw-r--r--src/testing/testing_trait_challenge.c72
-rw-r--r--src/testing/testing_trait_core_secret.c74
-rw-r--r--src/testing/testing_trait_policy.c73
-rw-r--r--src/testing/testing_trait_truth.c73
43 files changed, 6269 insertions, 0 deletions
diff --git a/src/testing/.gitignore b/src/testing/.gitignore
new file mode 100644
index 0000000..a6eb294
--- /dev/null
+++ b/src/testing/.gitignore
@@ -0,0 +1,3 @@
+test_anastasis
+test_anastasisrest_api
+test_anastasis_api_home/.local/share/taler/crypto-*
diff --git a/src/testing/Makefile.am b/src/testing/Makefile.am
new file mode 100644
index 0000000..8fc710b
--- /dev/null
+++ b/src/testing/Makefile.am
@@ -0,0 +1,91 @@
+# This Makefile.am is in the public domain
+AM_CPPFLAGS = -I$(top_srcdir)/src/include -I$(top_srcdir)/src/backend -I$(top_srcdir)/src/lib
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+ XLIB = -lgcov
+endif
+
+lib_LTLIBRARIES = \
+ libanastasistesting.la
+
+libanastasistesting_la_LDFLAGS = \
+ -version-info 0:0:0 \
+ -no-undefined
+libanastasistesting_la_SOURCES = \
+ testing_api_cmd_policy_store.c \
+ testing_api_cmd_truth_store.c \
+ testing_api_cmd_policy_lookup.c \
+ testing_api_cmd_keyshare_lookup.c \
+ testing_api_cmd_config.c \
+ testing_api_helpers.c \
+ testing_api_trait_account_pub.c \
+ testing_api_trait_account_priv.c \
+ testing_api_trait_eks.c \
+ testing_api_trait_payment_secret.c \
+ testing_api_trait_truth_key.c \
+ testing_api_trait_truth_uuid.c \
+ testing_api_trait_hash.c \
+ testing_api_trait_salt.c \
+ testing_api_trait_code.c \
+ testing_cmd_truth_upload.c \
+ testing_cmd_policy_create.c \
+ testing_cmd_secret_share.c \
+ testing_cmd_recover_secret.c \
+ testing_cmd_challenge_answer.c \
+ testing_trait_truth.c \
+ testing_trait_policy.c \
+ testing_trait_core_secret.c \
+ testing_trait_challenge.c
+libanastasistesting_la_LIBADD = \
+ $(top_builddir)/src/restclient/libanastasisrest.la \
+ $(top_builddir)/src/lib/libanastasis.la \
+ $(top_builddir)/src/util/libanastasisutil.la \
+ -ltalerexchange \
+ -ltalermerchant \
+ -ltalerjson \
+ -ltalerutil \
+ -lgnunetcurl \
+ -lgnunetjson \
+ -lgnunetutil \
+ -ljansson \
+ -luuid \
+ -ltalertesting \
+ $(XLIB)
+
+
+check_PROGRAMS = \
+ test_anastasisrest_api \
+ test_anastasis
+
+AM_TESTS_ENVIRONMENT=export ANASTASIS_PREFIX=$${ANASTASIS_PREFIX:-@libdir@};export PATH=$${ANASTASIS_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
+TESTS = \
+ $(check_PROGRAMS)
+
+test_anastasisrest_api_SOURCES = \
+ test_anastasis_api.c
+test_anastasisrest_api_LDADD = \
+ libanastasistesting.la \
+ -ltalermerchanttesting \
+ -ltalertesting \
+ -lgnunetutil \
+ $(XLIB)
+
+test_anastasis_SOURCES = \
+ test_anastasis.c
+test_anastasis_LDADD = \
+ libanastasistesting.la \
+ -ltalermerchanttesting \
+ -ltalertesting \
+ -ltalerexchange \
+ -lgnunetutil \
+ $(XLIB)
+
+EXTRA_DIST = \
+ test_anastasis_api.conf \
+ test_anastasis_api_home/.config/taler/exchange/account-2.json \
+ test_anastasis_api_home/.local/share/taler/exchange/offline-keys/master.priv \
+ sms_authentication.sh
+
+MOSTLYCLEANFILES = \
+ test_anastasis_api_home/.local/share/taler/exchange/offline-keys/secm_tofus.pub
diff --git a/src/testing/sms_authentication.sh b/src/testing/sms_authentication.sh
new file mode 100755
index 0000000..0c2c851
--- /dev/null
+++ b/src/testing/sms_authentication.sh
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+# Note: to use this script, you must set
+# ANASTASIS_SMS_API_KEY and
+# ANASTASIS_SMS_API_SECRET environment variables.
+curl -X "POST" "https://rest.nexmo.com/sms/json" \
+ -d "from=Vonage APIs" \
+ -d "text=$1" \
+ -d "to=$2" \
+ -d "api_key=$ANASTASIS_SMS_API_KEY" \
+ -d "api_secret=$ANASTASIS_SMS_API_SECRET"
diff --git a/src/testing/test_anastasis.c b/src/testing/test_anastasis.c
new file mode 100644
index 0000000..2ff7cb0
--- /dev/null
+++ b/src/testing/test_anastasis.c
@@ -0,0 +1,464 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020, 2021 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/test_anastasis.c
+ * @brief testcase to test anastasis
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_merchant_testing_lib.h>
+
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_anastasis_api.conf"
+
+/**
+ * Exchange base URL. Could also be taken from config.
+ */
+#define EXCHANGE_URL "http://localhost:8081/"
+
+/**
+ * Account number of the exchange at the bank.
+ */
+#define EXCHANGE_ACCOUNT_NAME "2"
+
+/**
+ * Account number of some user.
+ */
+#define USER_ACCOUNT_NAME "62"
+
+/**
+ * Account number used by the merchant
+ */
+#define MERCHANT_ACCOUNT_NAME "3"
+
+/**
+ * Configuration of the bank.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Configuration of the exchange.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Payto URI of the customer (payer).
+ */
+static char *payer_payto;
+
+/**
+ * Payto URI of the exchange (escrow account).
+ */
+static char *exchange_payto;
+
+/**
+ * Payto URI of the merchant (receiver).
+ */
+static char *merchant_payto;
+
+/**
+ * Merchant base URL.
+ */
+static char *merchant_url;
+
+/**
+ * Anastasis base URL.
+ */
+static char *anastasis_url;
+
+/**
+ * Name of the file for exchanging the secret.
+ */
+static char *file_secret;
+
+/**
+ * Merchant process.
+ */
+static struct GNUNET_OS_Process *merchantd;
+
+/**
+ * Anastasis process.
+ */
+static struct GNUNET_OS_Process *anastasisd;
+
+/**
+ * Identity to use for testing.
+ */
+static json_t *id_data;
+
+
+/**
+ * Execute the taler-exchange-wirewatch command with
+ * our configuration file.
+ *
+ * @param label label to use for the command.
+ */
+static struct TALER_TESTING_Command
+cmd_exec_wirewatch (char *label)
+{
+ return TALER_TESTING_cmd_exec_wirewatch (label,
+ CONFIG_FILE);
+}
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ * @param url exchange_url
+ */
+static struct TALER_TESTING_Command
+cmd_transfer_to_exchange (const char *label,
+ const char *amount)
+{
+ return TALER_TESTING_cmd_admin_add_incoming (label,
+ amount,
+ &bc.exchange_auth,
+ payer_payto);
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to
+ * run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command pay[] = {
+ /**
+ * Move money to the exchange's bank account.
+ */
+ cmd_transfer_to_exchange ("create-reserve-1",
+ "EUR:10.02"),
+ /**
+ * Make a reserve exist, according to the previous
+ * transfer.
+ */
+ cmd_exec_wirewatch ("wirewatch-1"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ /**
+ * Check the reserve is depleted.
+ */
+ TALER_TESTING_cmd_status ("withdraw-status-1",
+ "create-reserve-1",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command anastasis[] = {
+ ANASTASIS_TESTING_cmd_config ("salt-request-1",
+ anastasis_url,
+ MHD_HTTP_OK),
+ ANASTASIS_TESTING_cmd_truth_upload_question ("truth-create-1",
+ anastasis_url,
+ id_data,
+ "answer the question",
+ "text/plain",
+ "SomeTruth1",
+ MHD_HTTP_NO_CONTENT,
+ ANASTASIS_TESTING_TSO_NONE,
+ "salt-request-1"),
+ ANASTASIS_TESTING_cmd_truth_upload_question ("truth-create-2",
+ anastasis_url,
+ id_data,
+ "answer the question",
+ "text/plain",
+ "SomeTruth2",
+ MHD_HTTP_NO_CONTENT,
+ ANASTASIS_TESTING_TSO_NONE,
+ "salt-request-1"),
+ ANASTASIS_TESTING_cmd_truth_upload ("truth-create-3",
+ anastasis_url,
+ id_data,
+ "file",
+ "read the file",
+ "text/plain",
+ file_secret,
+ strlen (file_secret),
+ MHD_HTTP_NO_CONTENT,
+ ANASTASIS_TESTING_TSO_NONE,
+ "salt-request-1"),
+ ANASTASIS_TESTING_cmd_policy_create ("policy-create-1",
+ "truth-create-1",
+ "truth-create-2",
+ NULL),
+ ANASTASIS_TESTING_cmd_policy_create ("policy-create-2",
+ "truth-create-1",
+ "truth-create-3",
+ NULL),
+ ANASTASIS_TESTING_cmd_policy_create ("policy-create-3",
+ "truth-create-2",
+ "truth-create-3",
+ NULL),
+ ANASTASIS_TESTING_cmd_secret_share ("secret-share-1",
+ anastasis_url,
+ "salt-request-1",
+ NULL,
+ id_data,
+ "core secret",
+ strlen ("core secret"),
+ ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED,
+ ANASTASIS_TESTING_SSO_NONE,
+ "policy-create-1",
+ "policy-create-2",
+ "policy-create-3",
+ NULL),
+ /* what would we have to pay? */
+ TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal",
+ merchant_url,
+ MHD_HTTP_OK,
+ "secret-share-1",
+ NULL),
+ /* make the payment */
+ TALER_TESTING_cmd_merchant_pay_order ("pay-account",
+ merchant_url,
+ MHD_HTTP_OK,
+ "fetch-proposal",
+ "withdraw-coin-1",
+ "EUR:5",
+ "EUR:4.99", /* must match ANNUAL_FEE in config! */
+ NULL),
+ ANASTASIS_TESTING_cmd_secret_share ("secret-share-2",
+ anastasis_url,
+ "salt-request-1",
+ "secret-share-1",
+ id_data,
+ "core secret",
+ strlen ("core secret"),
+ ANASTASIS_SHARE_STATUS_SUCCESS,
+ ANASTASIS_TESTING_SSO_NONE,
+ "policy-create-1",
+ "policy-create-2",
+ "policy-create-3",
+ NULL),
+ ANASTASIS_TESTING_cmd_recover_secret ("recover-secret-1",
+ anastasis_url,
+ id_data,
+ 0, /* version */
+ ANASTASIS_TESTING_RSO_NONE,
+ "salt-request-1",
+ "secret-share-2"),
+ ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-1",
+ NULL, /* payment ref */
+ "recover-secret-1", /* challenge ref */
+ 0, /* challenge index */
+ "SomeTruth1",
+ 0, /* mode */
+ ANASTASIS_CHALLENGE_STATUS_SOLVED),
+#if 0
+ ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-2",
+ NULL, /* payment ref */
+ "recover-secret-1",
+ 1, /* challenge index */
+ "SomeTruth2",
+ 0, /* mode */
+ ANASTASIS_CHALLENGE_STATUS_SOLVED),
+#endif
+ ANASTASIS_TESTING_cmd_challenge_start ("challenge-start-3-pay",
+ NULL, /* payment ref */
+ "recover-secret-1",
+ 2, /* challenge index */
+ ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED),
+ TALER_TESTING_cmd_merchant_claim_order ("fetch-challenge-pay-proposal",
+ merchant_url,
+ MHD_HTTP_OK,
+ "challenge-start-3-pay",
+ NULL),
+ TALER_TESTING_cmd_merchant_pay_order ("pay-file-challenge",
+ merchant_url,
+ MHD_HTTP_OK,
+ "fetch-challenge-pay-proposal",
+ "withdraw-coin-2",
+ "EUR:1",
+ "EUR:1", /* must match COST in config! */
+ NULL),
+ ANASTASIS_TESTING_cmd_challenge_start ("challenge-start-3-paid",
+ "challenge-start-3-pay", /* payment ref */
+ "recover-secret-1",
+ 2, /* challenge index */
+ ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS),
+ ANASTASIS_TESTING_cmd_challenge_answer ("challenge-answer-3",
+ "challenge-start-3-pay", /* payment ref */
+ "recover-secret-1",
+ 2, /* challenge index */
+ "challenge-start-3-paid", /* answer */
+ 1, /* mode */
+ ANASTASIS_CHALLENGE_STATUS_SOLVED),
+ ANASTASIS_TESTING_cmd_recover_secret_finish ("recover-finish-1",
+ "recover-secret-1",
+ GNUNET_TIME_UNIT_SECONDS),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ /* general setup */
+ TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
+ MHD_HTTP_NO_CONTENT,
+ false),
+ TALER_TESTING_cmd_wire_add ("add-wire-account",
+ "payto://x-taler-bank/localhost/2",
+ MHD_HTTP_NO_CONTENT,
+ false),
+ TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
+ CONFIG_FILE,
+ "EUR:0.01",
+ "EUR:0.01"),
+ TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
+ 1),
+ TALER_TESTING_cmd_merchant_post_instances ("instance-create-default",
+ merchant_url,
+ "default",
+ merchant_payto,
+ "EUR",
+ MHD_HTTP_NO_CONTENT),
+ TALER_TESTING_cmd_batch ("pay",
+ pay),
+ TALER_TESTING_cmd_batch ("anastasis",
+ anastasis),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_url);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ unsigned int ret;
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+
+ GNUNET_log_setup ("test-anastasis",
+ "DEBUG",
+ NULL);
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "exchange-account-exchange",
+ &bc))
+ return 77;
+ {
+ char dir[] = "/tmp/test-anastasis-file-XXXXXX";
+
+ if (NULL == mkdtemp (dir))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "mkdtemp",
+ dir);
+ return 77;
+ }
+ GNUNET_asprintf (&file_secret,
+ "%s/.secret",
+ dir);
+ }
+ id_data = ANASTASIS_TESTING_make_id_data_example (
+ "MaxMuster123456789");
+ payer_payto = ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME);
+ exchange_payto = ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME);
+ merchant_payto = ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME);
+ if (NULL ==
+ (merchant_url = TALER_TESTING_prepare_merchant (CONFIG_FILE)))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+
+ if (NULL ==
+ (anastasis_url = ANASTASIS_TESTING_prepare_anastasis (CONFIG_FILE)))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ GNUNET_YES,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (NULL == (merchantd =
+ TALER_TESTING_run_merchant (CONFIG_FILE,
+ merchant_url)))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (NULL == (anastasisd =
+ ANASTASIS_TESTING_run_anastasis (CONFIG_FILE,
+ anastasis_url)))
+ {
+ GNUNET_break (0);
+ GNUNET_OS_process_kill (merchantd,
+ SIGTERM);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_destroy (merchantd);
+
+ return 1;
+ }
+ ret = TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE);
+
+ GNUNET_OS_process_kill (merchantd,
+ SIGTERM);
+ GNUNET_OS_process_kill (anastasisd,
+ SIGTERM);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_wait (anastasisd);
+ GNUNET_OS_process_destroy (merchantd);
+ GNUNET_OS_process_destroy (anastasisd);
+ GNUNET_free (merchant_url);
+ GNUNET_free (anastasis_url);
+
+ if (GNUNET_OK != ret)
+ return 1;
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_anastasis.c */
diff --git a/src/testing/test_anastasis_api.c b/src/testing/test_anastasis_api.c
new file mode 100644
index 0000000..db18b41
--- /dev/null
+++ b/src/testing/test_anastasis_api.c
@@ -0,0 +1,421 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020, 2021 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/test_anastasis_api.c
+ * @brief testcase to test anastasis' HTTP API interface
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_merchant_testing_lib.h>
+
+
+/**
+ * Configuration file we use. One (big) configuration is used
+ * for the various components for this test.
+ */
+#define CONFIG_FILE "test_anastasis_api.conf"
+
+/**
+ * Exchange base URL. Could also be taken from config.
+ */
+#define EXCHANGE_URL "http://localhost:8081/"
+
+/**
+ * Account number of the exchange at the bank.
+ */
+#define EXCHANGE_ACCOUNT_NAME "2"
+
+/**
+ * Account number of some user.
+ */
+#define USER_ACCOUNT_NAME "62"
+
+/**
+ * Account number used by the merchant
+ */
+#define MERCHANT_ACCOUNT_NAME "3"
+
+/**
+ * Configuration of the bank.
+ */
+static struct TALER_TESTING_BankConfiguration bc;
+
+/**
+ * Configuration of the exchange.
+ */
+static struct TALER_TESTING_ExchangeConfiguration ec;
+
+/**
+ * Payto URI of the customer (payer).
+ */
+static char *payer_payto;
+
+/**
+ * Payto URI of the exchange (escrow account).
+ */
+static char *exchange_payto;
+
+/**
+ * Payto URI of the merchant (receiver).
+ */
+static char *merchant_payto;
+
+/**
+ * Merchant base URL.
+ */
+static char *merchant_url;
+
+/**
+ * Anastasis base URL.
+ */
+static char *anastasis_url;
+
+/**
+ * Merchant process.
+ */
+static struct GNUNET_OS_Process *merchantd;
+
+/**
+ * Anastasis process.
+ */
+static struct GNUNET_OS_Process *anastasisd;
+
+/**
+ * Name of the file for exchanging the secret.
+ */
+static char *file_secret;
+
+/**
+ * Execute the taler-exchange-wirewatch command with our configuration
+ * file.
+ *
+ * @param label label to use for the command.
+ */
+static struct TALER_TESTING_Command
+cmd_exec_wirewatch (char *label)
+{
+ return TALER_TESTING_cmd_exec_wirewatch (label,
+ CONFIG_FILE);
+}
+
+
+/**
+ * Run wire transfer of funds from some user's account to the
+ * exchange.
+ *
+ * @param label label to use for the command.
+ * @param amount amount to transfer, i.e. "EUR:1"
+ * @param url exchange_url
+ */
+static struct TALER_TESTING_Command
+cmd_transfer_to_exchange (const char *label,
+ const char *amount)
+{
+ return TALER_TESTING_cmd_admin_add_incoming (label,
+ amount,
+ &bc.exchange_auth,
+ payer_payto);
+}
+
+
+/**
+ * Main function that will tell the interpreter what commands to run.
+ *
+ * @param cls closure
+ */
+static void
+run (void *cls,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TALER_TESTING_Command withdraw[] = {
+ cmd_transfer_to_exchange ("create-reserve-1",
+ "EUR:10.02"),
+ cmd_exec_wirewatch ("wirewatch-1"),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-1",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_withdraw_amount ("withdraw-coin-2",
+ "create-reserve-1",
+ "EUR:5",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_status ("withdraw-status-1",
+ "create-reserve-1",
+ "EUR:0",
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command policy[] = {
+ ANASTASIS_TESTING_cmd_policy_store ("policy-store-1",
+ anastasis_url,
+ NULL /* prev upload */,
+ MHD_HTTP_PAYMENT_REQUIRED,
+ ANASTASIS_TESTING_PSO_NONE,
+ "Test-1",
+ strlen ("Test-1")),
+ /* what would we have to pay? */
+ TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal",
+ merchant_url,
+ MHD_HTTP_OK,
+ "policy-store-1",
+ NULL),
+ /* make the payment */
+ TALER_TESTING_cmd_merchant_pay_order ("pay-account",
+ merchant_url,
+ MHD_HTTP_OK,
+ "fetch-proposal",
+ "withdraw-coin-1",
+ "EUR:5",
+ "EUR:4.99", /* must match ANNUAL_FEE in config! */
+ NULL),
+ ANASTASIS_TESTING_cmd_policy_store ("policy-store-2",
+ anastasis_url,
+ "policy-store-1",
+ MHD_HTTP_NO_CONTENT,
+ ANASTASIS_TESTING_PSO_NONE,
+ "Test-1",
+ strlen ("Test-1")),
+ ANASTASIS_TESTING_cmd_policy_lookup ("policy-lookup-1",
+ anastasis_url,
+ MHD_HTTP_OK,
+ "policy-store-2"),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command truth[] = {
+ ANASTASIS_TESTING_cmd_truth_question (
+ "truth-store-1",
+ anastasis_url,
+ NULL,
+ "The-Answer",
+ ANASTASIS_TESTING_TSO_NONE,
+ MHD_HTTP_NO_CONTENT),
+ ANASTASIS_TESTING_cmd_keyshare_lookup (
+ "keyshare-lookup-1",
+ anastasis_url,
+ "The-Answer",
+ NULL, /* payment ref */
+ "truth-store-1",
+ 0,
+ ANASTASIS_KSD_SUCCESS),
+ ANASTASIS_TESTING_cmd_truth_store (
+ "truth-store-2",
+ anastasis_url,
+ NULL,
+ "file",
+ "text/plain",
+ strlen (file_secret),
+ file_secret,
+ ANASTASIS_TESTING_TSO_NONE,
+ MHD_HTTP_NO_CONTENT),
+ ANASTASIS_TESTING_cmd_keyshare_lookup (
+ "challenge-fail-1",
+ anastasis_url,
+ "Wrong-Answer",
+ NULL,
+ "truth-store-1",
+ 0,
+ ANASTASIS_KSD_INVALID_ANSWER),
+ ANASTASIS_TESTING_cmd_keyshare_lookup (
+ "file-challenge-run-1",
+ anastasis_url,
+ NULL, /* no answer */
+ NULL, /* payment ref */
+ "truth-store-2", /* upload ref */
+ 0,
+ ANASTASIS_KSD_PAYMENT_REQUIRED),
+ /* what would we have to pay? */
+ TALER_TESTING_cmd_merchant_claim_order ("fetch-proposal-2",
+ merchant_url,
+ MHD_HTTP_OK,
+ "file-challenge-run-1",
+ NULL),
+ /* make the payment */
+ TALER_TESTING_cmd_merchant_pay_order ("pay-account-2",
+ merchant_url,
+ MHD_HTTP_OK,
+ "fetch-proposal-2",
+ "withdraw-coin-2",
+ "EUR:1.01",
+ "EUR:1",
+ NULL),
+
+ ANASTASIS_TESTING_cmd_keyshare_lookup (
+ "file-challenge-run-2",
+ anastasis_url,
+ NULL, /* no answer */
+ "file-challenge-run-1", /* payment ref */
+ "truth-store-2",
+ 0,
+ ANASTASIS_KSD_INVALID_ANSWER),
+ ANASTASIS_TESTING_cmd_keyshare_lookup (
+ "file-challenge-run-3",
+ anastasis_url,
+ "file-challenge-run-2", /* answer */
+ "file-challenge-run-1", /* payment ref */
+ "truth-store-2",
+ 1,
+ ANASTASIS_KSD_SUCCESS),
+ TALER_TESTING_cmd_end ()
+ };
+
+ struct TALER_TESTING_Command commands[] = {
+ /* general setup */
+ TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
+ MHD_HTTP_NO_CONTENT,
+ false),
+ TALER_TESTING_cmd_wire_add ("add-wire-account",
+ "payto://x-taler-bank/localhost/2",
+ MHD_HTTP_NO_CONTENT,
+ false),
+ TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
+ CONFIG_FILE),
+ TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
+ CONFIG_FILE,
+ "EUR:0.01",
+ "EUR:0.01"),
+ TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
+ 1),
+ TALER_TESTING_cmd_merchant_post_instances ("instance-create-default",
+ merchant_url,
+ "default",
+ merchant_payto,
+ "EUR",
+ MHD_HTTP_NO_CONTENT),
+ ANASTASIS_TESTING_cmd_config ("salt-request-1",
+ anastasis_url,
+ MHD_HTTP_OK),
+ TALER_TESTING_cmd_batch ("withdraw",
+ withdraw),
+ TALER_TESTING_cmd_batch ("policy",
+ policy),
+ TALER_TESTING_cmd_batch ("truth",
+ truth),
+ TALER_TESTING_cmd_end ()
+ };
+
+ TALER_TESTING_run_with_fakebank (is,
+ commands,
+ bc.exchange_auth.wire_gateway_url);
+}
+
+
+int
+main (int argc,
+ char *const *argv)
+{
+ int ret;
+
+ /* These environment variables get in the way... */
+ unsetenv ("XDG_DATA_HOME");
+ unsetenv ("XDG_CONFIG_HOME");
+ GNUNET_log_setup ("test-anastasis-api",
+ "DEBUG",
+ NULL);
+ if (GNUNET_OK !=
+ TALER_TESTING_prepare_fakebank (CONFIG_FILE,
+ "exchange-account-exchange",
+ &bc))
+ return 77;
+ {
+ char dir[] = "/tmp/test-anastasis-file-XXXXXX";
+
+ if (NULL == mkdtemp (dir))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "mkdtemp",
+ dir);
+ return 77;
+ }
+ GNUNET_asprintf (&file_secret,
+ "%s/.secret",
+ dir);
+ }
+ payer_payto = ("payto://x-taler-bank/localhost/" USER_ACCOUNT_NAME);
+ exchange_payto = ("payto://x-taler-bank/localhost/" EXCHANGE_ACCOUNT_NAME);
+ merchant_payto = ("payto://x-taler-bank/localhost/" MERCHANT_ACCOUNT_NAME);
+ if (NULL ==
+ (merchant_url = TALER_TESTING_prepare_merchant (CONFIG_FILE)))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+
+ if (NULL ==
+ (anastasis_url = ANASTASIS_TESTING_prepare_anastasis (CONFIG_FILE)))
+ return 77;
+ TALER_TESTING_cleanup_files (CONFIG_FILE);
+
+ switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
+ GNUNET_YES,
+ &ec))
+ {
+ case GNUNET_SYSERR:
+ GNUNET_break (0);
+ return 1;
+ case GNUNET_NO:
+ return 77;
+ case GNUNET_OK:
+ if (NULL == (merchantd =
+ TALER_TESTING_run_merchant (CONFIG_FILE,
+ merchant_url)))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ if (NULL == (anastasisd =
+ ANASTASIS_TESTING_run_anastasis (CONFIG_FILE,
+ anastasis_url)))
+ {
+ GNUNET_break (0);
+ GNUNET_OS_process_kill (merchantd,
+ SIGTERM);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_destroy (merchantd);
+ return 1;
+ }
+ ret = TALER_TESTING_setup_with_exchange (&run,
+ NULL,
+ CONFIG_FILE);
+ GNUNET_OS_process_kill (merchantd,
+ SIGTERM);
+ GNUNET_OS_process_kill (anastasisd,
+ SIGTERM);
+ GNUNET_OS_process_wait (merchantd);
+ GNUNET_OS_process_wait (anastasisd);
+ GNUNET_OS_process_destroy (merchantd);
+ GNUNET_OS_process_destroy (anastasisd);
+ GNUNET_free (merchant_url);
+ GNUNET_free (anastasis_url);
+
+ if (GNUNET_OK != ret)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Test failed in interpreter\n");
+ return 1;
+ }
+ break;
+ default:
+ GNUNET_break (0);
+ return 1;
+ }
+ return 0;
+}
+
+
+/* end of test_anastasis_api.c */
diff --git a/src/testing/test_anastasis_api.conf b/src/testing/test_anastasis_api.conf
new file mode 100644
index 0000000..bde7ee1
--- /dev/null
+++ b/src/testing/test_anastasis_api.conf
@@ -0,0 +1,264 @@
+# This file is in the public domain.
+#
+[PATHS]
+# Persistent data storage for the testcase
+TALER_TEST_HOME = test_anastasis_api_home/
+TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
+
+# Persistent data storage
+TALER_DATA_HOME = $TALER_TEST_HOME/.local/share/taler/
+
+# Configuration files
+TALER_CONFIG_HOME = $TALER_TEST_HOME/.config/taler/
+
+# Cached data, no big deal if lost
+TALER_CACHE_HOME = $TALER_TEST_HOME/.cache/taler/
+
+[taler]
+# What currency do we use?
+#currency = EUR
+currency = EUR
+#CURRENCY_ROUND_UNIT = EUR:0.01
+#CURRENCY_ROUND_UNIT = EUR:0.01
+
+[taler-helper-crypto-rsa]
+# Reduce from 1 year to speed up test
+LOOKAHEAD_SIGN = 12 days
+
+[taler-helper-crypto-eddsa]
+# Reduce from 1 year to speed up test
+LOOKAHEAD_SIGN = 12 days
+# Reduce from 12 weeks to ensure we have multiple
+DURATION = 7 days
+
+
+[bank]
+HTTP_PORT = 8082
+#BASE_URL = https://bank.test.taler.net/
+
+##########################################
+# Configuration for Anastasis #
+##########################################
+
+[anastasis]
+PORT = 8086
+
+DB = postgres
+
+BUSINESS_NAME = "Checker's Test Inc."
+
+# Upload limit
+UPLOAD_LIMIT_MB = 1
+
+ANNUAL_POLICY_UPLOAD_LIMIT = 64
+
+INSURANCE = EUR:0
+
+SERVER_SALT = salty
+
+# Base URL of anastasis.
+# BASE_URL = http://localhost:8086/
+
+# Where does our payment backend run? Must match PORT under [merchant]
+PAYMENT_BACKEND_URL = http://localhost:8080/
+
+# Annual fee we charge.
+#ANNUAL_FEE = EUR:4.99
+ANNUAL_FEE = EUR:4.99
+
+TRUTH_UPLOAD_FEE = EUR:0.0
+
+# Authentication costs
+[authorization-question]
+# Cost of authentication by question
+COST = EUR:0
+
+[authorization-file]
+# Cost of authentication by file (only for testing purposes)
+COST = EUR:1
+
+[authorization-email]
+# Cost of authentication by E-Mail
+COST = EUR:0
+
+[authorization-sms]
+# Cost of authentication by SMS
+COST = EUR:0
+
+# Command which is executed for the sms authentication
+COMMAND = ./sms_authentication.sh
+
+
+
+
+# This specifies which database the postgres backend uses.
+[stasis-postgres]
+CONFIG = postgres:///anastasischeck
+
+##########################################
+# Configuration for the merchant backend #
+##########################################
+
+[merchant]
+
+# Which port do we run the backend on? (HTTP server)
+PORT = 8080
+
+# How quickly do we want the exchange to send us our money?
+# Used only if the frontend does not specify a value.
+WIRE_TRANSFER_DELAY = 0 s
+
+# Which plugin (backend) do we use for the DB.
+DB = postgres
+
+# Default choice for maximum wire fee.
+DEFAULT_MAX_WIRE_FEE = EUR:0.10
+
+# Default choice for maximum deposit fee.
+DEFAULT_MAX_DEPOSIT_FEE = EUR:0.10
+
+
+# This specifies which database the postgres backend uses.
+[merchantdb-postgres]
+CONFIG = postgres:///talercheck
+
+# Sections starting with "exchange-" specify trusted exchanges
+# (by the merchant)
+[merchant-exchange-default]
+MASTER_KEY = T1VVFQZZARQ1CMF4BN58EE7SKTW5AV2BS18S87ZEGYS4S29J6DNG
+EXCHANGE_BASE_URL = http://localhost:8081/
+#MASTER_KEY = DY95EXAHQ2BKM2WK9YHZHYG1R7PPMMJPY14FNGP662DAKE35AKQG
+#EXCHANGE_BASE_URL = https://exchange.test.taler.net/
+#CURRENCY = EUR
+CURRENCY = EUR
+
+# only fixes skips.
+[auditor]
+BASE_URL = http://the.auditor/
+#BASE_URL = https://auditor.test.taler.net/
+#AUDITOR_KEY = DSDASDXAMDAARMNAD53ZA4AFAHA2QADAMAHHASWDAWXN84SDAA11
+# If currency does not match [TALER] section, the auditor
+# will be ignored!
+CURRENCY = EUR
+
+# Where do we store the auditor's private key?
+AUDITOR_PRIV_FILE = ${TALER_DATA_HOME}/auditor/offline-keys/auditor.priv
+
+# Auditors must be in sections "auditor-", the rest of the section
+# name could be anything.
+[auditor-ezb]
+# Informal name of the auditor. Just for the user.
+NAME = European Central Bank
+
+# URL of the auditor (especially for in the future, when the
+# auditor offers an automated issue reporting system).
+# Not really used today.
+URL = http://taler.ezb.eu/
+
+# This is the important bit: the signing key of the auditor.
+PUBLIC_KEY = 9QXF7XY7E9VPV47B5Z806NDFSX2VJ79SVHHD29QEQ3BG31ANHZ60
+
+# Which currency is this auditor trusted for?
+CURRENCY = EUR
+
+
+###################################################
+# Configuration for the exchange for the testcase #
+###################################################
+
+[exchange]
+# How to access our database
+DB = postgres
+
+# HTTP port the exchange listens to
+PORT = 8081
+
+# how long are the signatures with the signkey valid?
+SIGNKEY_LEGAL_DURATION = 2 years
+
+# Our public key
+MASTER_PUBLIC_KEY = T1VVFQZZARQ1CMF4BN58EE7SKTW5AV2BS18S87ZEGYS4S29J6DNG
+
+# Base URL of the exchange.
+BASE_URL = "http://localhost:8081/"
+#BASE_URL = https://exchange.test.taler.net/
+
+KEYDIR = ${TALER_DATA_HOME}/exchange/live-keys/
+
+REVOCATION_DIR = ${TALER_DATA_HOME}/exchange/revocations/
+
+
+# Network configuration for the normal API/service HTTP server
+# serve via tcp socket (on PORT)
+SERVE = tcp
+
+[exchange-offline]
+
+# Where do we store the offline master private key of the exchange?
+MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
+
+# Where do we store the TOFU key material?
+SECM_TOFU_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/secm_tofus.pub
+
+
+[exchangedb-postgres]
+CONFIG = "postgres:///talercheck"
+
+[auditordb-postgres]
+CONFIG = "postgres:///talercheck"
+
+# Account of the EXCHANGE
+[exchange-account-exchange]
+# What is the exchange's bank account (with the "Taler Bank" demo system)?
+PAYTO_URI = "payto://x-taler-bank/localhost:8082/2"
+
+WIRE_GATEWAY_URL = "http://localhost:8082/2/"
+WIRE_GATEWAY_AUTH_METHOD = NONE
+
+ENABLE_DEBIT = YES
+ENABLE_CREDIT = YES
+
+
+[coin_eur_ct_1]
+value = EUR:0.01
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.00
+fee_deposit = EUR:0.00
+fee_refresh = EUR:0.01
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+
+[coin_eur_ct_10]
+value = EUR:0.10
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+
+[coin_eur_1]
+value = EUR:1
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
+
+[coin_eur_5]
+value = EUR:5
+duration_withdraw = 7 days
+duration_spend = 2 years
+duration_legal = 3 years
+fee_withdraw = EUR:0.01
+fee_deposit = EUR:0.01
+fee_refresh = EUR:0.03
+fee_refund = EUR:0.01
+rsa_keysize = 1024
diff --git a/src/testing/test_anastasis_api_home/.config/taler/exchange/account-2.json b/src/testing/test_anastasis_api_home/.config/taler/exchange/account-2.json
new file mode 100644
index 0000000..f798275
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/exchange/account-2.json
@@ -0,0 +1,3 @@
+{
+ "payto_uri": "payto://x-taler-bank/localhost:8082/2",
+ "master_sig": "AM32QB4RYMWK548PE63PJXJMWSA001TFFWTZZPSSD8HQ8JE4D5V5X8WTSYSX59ANF4YRTRMF5Q4Q12CE2KTA8KQ03CM11YDTK75SJ20"}
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/account-3.json b/src/testing/test_anastasis_api_home/.config/taler/merchant/account-3.json
new file mode 100644
index 0000000..016e133
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/account-3.json
@@ -0,0 +1 @@
+{"salt":"ZSHKZ4DRFMFRFBMB10BX8M1GD16AZNG639AY8QMW26XBGECQRS1H7H8CQ4WETHT66PG99CYBVGFRKJ7ZENEDJJ4E0X0JHRY1QKPQ3W0","payto_uri":"payto://x-taler-bank/localhost:8082/3"}
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/default.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/default.priv
new file mode 100644
index 0000000..3ed8c04
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/default.priv
@@ -0,0 +1 @@
+<!ÔÇ»³¶l¶Ú&…|ÇÆËSb¿¹0)hó8ö \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/dtip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/dtip.priv
new file mode 100644
index 0000000..a72136d
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/dtip.priv
@@ -0,0 +1 @@
+æÍëÕð*¾šiWªLØ(ß:ZOtG…s41æ \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/nulltip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/nulltip.priv
new file mode 100644
index 0000000..fe56b97
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/nulltip.priv
@@ -0,0 +1 @@
+ç§l9h‡[èYÌÊ›‘ô"h1Àø—–žsÿÊB;¤Ð \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/dtip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/dtip.priv
new file mode 100644
index 0000000..a5f982f
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/dtip.priv
@@ -0,0 +1 @@
+ò^Sz™êƒ5?éÌ<e?Ì[ÔY•ãs¨Âœ¿ûC$ \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/nulltip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/nulltip.priv
new file mode 100644
index 0000000..8b9f09c
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/nulltip.priv
@@ -0,0 +1 @@
+I4Z‹‹JxžuRFSþEJßãÙÚÍf7?0W \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/tip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/tip.priv
new file mode 100644
index 0000000..16fecd6
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/reserve/tip.priv
@@ -0,0 +1 @@
+òœÓËÌ­Œò?SwfJ¯")Dù²¶whšiôxK \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/tip.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/tip.priv
new file mode 100644
index 0000000..951d893
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/tip.priv
Binary files differ
diff --git a/src/testing/test_anastasis_api_home/.config/taler/merchant/tor.priv b/src/testing/test_anastasis_api_home/.config/taler/merchant/tor.priv
new file mode 100644
index 0000000..007b02c
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/merchant/tor.priv
Binary files differ
diff --git a/src/testing/test_anastasis_api_home/.config/taler/test.json b/src/testing/test_anastasis_api_home/.config/taler/test.json
new file mode 100644
index 0000000..74cdc92
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.config/taler/test.json
@@ -0,0 +1,8 @@
+{
+ "name": "The exchange",
+ "account_number": 3,
+ "bank_url": "http://localhost:8083/",
+ "salt": "6259MV4W9V8D2A75RSGGPKYHQRXRPQZ33EBG263JZRJ6SA5HK0RRKHV70TNA1RVRG77M57CCFVSK2B0EJN3SR8S21F0ZX2MR9DNVG50",
+ "type": "test",
+ "sig": "8C3D3J816S29AA2AJ7P9TS6W13KFNFS2RCVYJEWRBNHRRMTTRAWKY7WA1N3G54E4K3XAC2HN6JDHS42TWR5315J34JHHCKV618K221G"
+}
diff --git a/src/testing/test_anastasis_api_home/.local/share/taler/exchange/offline-keys/master.priv b/src/testing/test_anastasis_api_home/.local/share/taler/exchange/offline-keys/master.priv
new file mode 100644
index 0000000..c20942d
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.local/share/taler/exchange/offline-keys/master.priv
@@ -0,0 +1 @@
+åÊk;d³_Uû}£A.wÔ"!Gûçv_m "_ò \ No newline at end of file
diff --git a/src/testing/test_anastasis_api_home/.local/share/taler/merchant/merchant.priv b/src/testing/test_anastasis_api_home/.local/share/taler/merchant/merchant.priv
new file mode 100644
index 0000000..fd6e5f7
--- /dev/null
+++ b/src/testing/test_anastasis_api_home/.local/share/taler/merchant/merchant.priv
@@ -0,0 +1 @@
+¶ù,åY%–FF<ßþR˜‰9ϳ5„¬v\þš×k4«6 \ No newline at end of file
diff --git a/src/testing/testing_api_cmd_config.c b/src/testing/testing_api_cmd_config.c
new file mode 100644
index 0000000..8906261
--- /dev/null
+++ b/src/testing/testing_api_cmd_config.c
@@ -0,0 +1,206 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019, 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 lib/testing_api_cmd_config.c
+ * @brief command to obtain the configuration of an anastasis backend service.
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "config" CMD.
+ */
+struct ConfigState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * Expected status code.
+ */
+ unsigned int http_status;
+
+ /**
+ * The /config GET operation handle.
+ */
+ struct ANASTASIS_ConfigOperation *so;
+
+ /**
+ * The salt value from server.
+ */
+ struct ANASTASIS_CRYPTO_ProviderSaltP salt;
+};
+
+
+/**
+ * Function called with the results of a #ANASTASIS_config().
+ *
+ * @param cls closure
+ * @param http_status HTTP status of the request
+ * @param config config from the server
+ */
+static void
+config_cb (void *cls,
+ unsigned int http_status,
+ const struct ANASTASIS_Config *config)
+{
+ struct ConfigState *ss = cls;
+
+ ss->so = NULL;
+ if (http_status != ss->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ ss->is->commands[ss->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ if (NULL == config)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Config is NULL, command %s in %s:%u\n",
+ ss->is->commands[ss->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+ ss->salt = config->salt;
+ TALER_TESTING_interpreter_next (ss->is);
+}
+
+
+/**
+ * Run a "config" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+config_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ConfigState *ss = cls;
+
+ ss->is = is;
+ ss->so = ANASTASIS_get_config (is->ctx,
+ ss->anastasis_url,
+ &config_cb,
+ ss);
+ if (NULL == ss->so)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ss->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "config" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+config_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ConfigState *ss = cls;
+
+ if (NULL != ss->so)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (config)\n",
+ cmd->label);
+ ANASTASIS_config_cancel (ss->so);
+ ss->so = NULL;
+ }
+ GNUNET_free (ss);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+config_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ConfigState *ss = cls;
+
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_salt (0,
+ &ss->salt),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_config (const char *label,
+ const char *anastasis_url,
+ unsigned int http_status)
+{
+ struct ConfigState *ss;
+
+ ss = GNUNET_new (struct ConfigState);
+ ss->http_status = http_status;
+ ss->anastasis_url = anastasis_url;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ss,
+ .label = label,
+ .run = &config_run,
+ .cleanup = &config_cleanup,
+ .traits = &config_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_keyshare_lookup.c b/src/testing/testing_api_cmd_keyshare_lookup.c
new file mode 100644
index 0000000..895d321
--- /dev/null
+++ b/src/testing/testing_api_cmd_keyshare_lookup.c
@@ -0,0 +1,465 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/anastasis_api_keyshare_lookup.c
+ * @brief Testing of Implementation of the /truth GET
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_merchant_service.h>
+
+
+/**
+ * State for a "keyshare lookup" CMD.
+ */
+struct KeyShareLookupState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * Expected status code.
+ */
+ enum ANASTASIS_KeyShareDownloadStatus expected_ksdd;
+
+ /**
+ * The /truth GET operation handle.
+ */
+ struct ANASTASIS_KeyShareLookupOperation *kslo;
+
+ /**
+ * answer to a challenge
+ */
+ const char *answer;
+
+ /**
+ * Reference to upload command we expect to lookup.
+ */
+ const char *upload_reference;
+
+ /**
+ * Reference to upload command we expect to lookup.
+ */
+ const char *payment_reference;
+
+ /**
+ * Payment secret requested by the service, if any.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret_response;
+
+ /**
+ * Taler-URI with payment request, if any.
+ */
+ char *pay_uri;
+
+ /**
+ * Order ID for payment request, if any.
+ */
+ char *order_id;
+
+ /**
+ * Redirect-URI for challenge, if any.
+ */
+ char *redirect_uri;
+
+ /**
+ * "code" returned by service, if any.
+ */
+ char *code;
+
+ /**
+ * "instructions" for how to solve the challenge as returned by service, if any.
+ */
+ char *instructions;
+
+ /**
+ * Name of the file where the service will write the challenge, if method is "file".
+ * Otherwise NULL.
+ */
+ char *filename;
+
+ /**
+ * Mode for the lookup(0 = question, 1 = code based)
+ */
+ int lookup_mode;
+
+};
+
+
+static void
+keyshare_lookup_cb (void *cls,
+ const struct ANASTASIS_KeyShareDownloadDetails *dd)
+{
+ struct KeyShareLookupState *ksls = cls;
+
+ ksls->kslo = NULL;
+ if (dd->status != ksls->expected_ksdd)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ dd->status,
+ ksls->is->commands[ksls->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ switch (dd->status)
+ {
+ case ANASTASIS_KSD_SUCCESS:
+ break;
+ case ANASTASIS_KSD_PAYMENT_REQUIRED:
+ ksls->pay_uri = GNUNET_strdup (dd->details.payment_required.taler_pay_uri);
+ ksls->payment_secret_response = dd->details.payment_required.payment_secret;
+ {
+ struct TALER_MERCHANT_PayUriData pd;
+
+ if (GNUNET_OK !=
+ TALER_MERCHANT_parse_pay_uri (ksls->pay_uri,
+ &pd))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ ksls->order_id = GNUNET_strdup (pd.order_id);
+ TALER_MERCHANT_parse_pay_uri_free (&pd);
+ }
+
+ break;
+ case ANASTASIS_KSD_INVALID_ANSWER:
+ if (ksls->filename)
+ {
+ FILE *file;
+ char code[22];
+
+ file = fopen (ksls->filename,
+ "r");
+ if (NULL == file)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "open",
+ ksls->filename);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (0 == fscanf (file,
+ "%21s",
+ code))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "fscanf",
+ ksls->filename);
+ GNUNET_break (0 == fclose (file));
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ GNUNET_break (0 == fclose (file));
+ ksls->code = GNUNET_strdup (code);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Read code `%s'\n",
+ code);
+ }
+ else
+ {
+ ksls->instructions = GNUNET_strndup (
+ dd->details.open_challenge.body,
+ dd->details.open_challenge.body_size);
+ }
+ break;
+ case ANASTASIS_KSD_REDIRECT_FOR_AUTHENTICATION:
+ ksls->redirect_uri = GNUNET_strdup (dd->details.redirect_url);
+ break;
+ case ANASTASIS_KSD_SERVER_ERROR:
+ break;
+ case ANASTASIS_KSD_CLIENT_FAILURE:
+ break;
+ case ANASTASIS_KSD_TRUTH_UNKNOWN:
+ break;
+ case ANASTASIS_KSD_RATE_LIMIT_EXCEEDED:
+ break;
+ }
+ TALER_TESTING_interpreter_next (ksls->is);
+}
+
+
+static void
+keyshare_lookup_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct KeyShareLookupState *ksls = cls;
+ const struct ANASTASIS_CRYPTO_TruthKeyP *truth_key;
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid;
+ const struct ANASTASIS_PaymentSecretP *payment_secret;
+ const char *answer;
+
+ ksls->is = is;
+ if (NULL == ksls->upload_reference)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ {
+ const struct TALER_TESTING_Command *upload_cmd;
+
+ upload_cmd = TALER_TESTING_interpreter_lookup_command (
+ is,
+ ksls->upload_reference);
+ if (NULL == upload_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ {
+ const char *fn;
+
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_string (upload_cmd,
+ 0,
+ &fn))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (NULL != fn)
+ ksls->filename = GNUNET_strdup (fn);
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_truth_uuid (upload_cmd,
+ 0,
+ &truth_uuid))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (NULL == truth_uuid)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_truth_key (upload_cmd,
+ 0,
+ &truth_key))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (NULL == truth_key)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ }
+
+ if (ksls->lookup_mode == 1)
+ {
+ const struct TALER_TESTING_Command *download_cmd;
+
+ download_cmd = TALER_TESTING_interpreter_lookup_command (is,
+ ksls->answer);
+ if (NULL == download_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_code (download_cmd,
+ 0,
+ &answer))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ if (NULL == answer)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ }
+ else
+ {
+ /* answer is the answer */
+ answer = ksls->answer;
+ }
+
+ if (NULL != ksls->payment_reference)
+ {
+ const struct TALER_TESTING_Command *payment_cmd;
+
+ payment_cmd = TALER_TESTING_interpreter_lookup_command
+ (is,
+ ksls->payment_reference);
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_payment_secret (payment_cmd,
+ 0,
+ &payment_secret))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+ }
+ else
+ {
+ payment_secret = NULL;
+ }
+
+ {
+ struct GNUNET_HashCode h_answer;
+
+ if (NULL != answer)
+ GNUNET_CRYPTO_hash (answer,
+ strlen (answer),
+ &h_answer);
+ ksls->kslo = ANASTASIS_keyshare_lookup (is->ctx,
+ ksls->anastasis_url,
+ truth_uuid,
+ truth_key,
+ payment_secret,
+ GNUNET_TIME_UNIT_ZERO,
+ (NULL != answer)
+ ? &h_answer
+ : NULL,
+ &keyshare_lookup_cb,
+ ksls);
+ }
+ if (NULL == ksls->kslo)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (ksls->is);
+ return;
+ }
+}
+
+
+static void
+keyshare_lookup_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct KeyShareLookupState *ksls = cls;
+
+ if (NULL != ksls->kslo)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (keyshare lookup)\n",
+ cmd->label);
+ ANASTASIS_keyshare_lookup_cancel (ksls->kslo);
+ ksls->kslo = NULL;
+ }
+ GNUNET_free (ksls->pay_uri);
+ GNUNET_free (ksls->order_id);
+ GNUNET_free (ksls->code);
+ GNUNET_free (ksls->instructions);
+ GNUNET_free (ksls->redirect_uri);
+ GNUNET_free (ksls);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param[out] trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+keyshare_lookup_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct KeyShareLookupState *ksls = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_payment_secret (0,
+ &ksls->payment_secret_response),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_TALER_URL,
+ ksls->pay_uri),
+ TALER_TESTING_make_trait_order_id (0,
+ ksls->order_id),
+ ANASTASIS_TESTING_make_trait_code (0,
+ ksls->code),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_keyshare_lookup (
+ const char *label,
+ const char *anastasis_url,
+ const char *answer,
+ const char *payment_ref,
+ const char *upload_ref,
+ int lookup_mode,
+ enum ANASTASIS_KeyShareDownloadStatus ksdd)
+{
+ struct KeyShareLookupState *ksls;
+
+ GNUNET_assert (NULL != upload_ref);
+ ksls = GNUNET_new (struct KeyShareLookupState);
+ ksls->expected_ksdd = ksdd;
+ ksls->anastasis_url = anastasis_url;
+ ksls->upload_reference = upload_ref;
+ ksls->payment_reference = payment_ref;
+ ksls->answer = answer;
+ ksls->lookup_mode = lookup_mode;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = ksls,
+ .label = label,
+ .run = &keyshare_lookup_run,
+ .cleanup = &keyshare_lookup_cleanup,
+ .traits = &keyshare_lookup_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_api_cmd_keyshare_lookup.c */
diff --git a/src/testing/testing_api_cmd_policy_lookup.c b/src/testing/testing_api_cmd_policy_lookup.c
new file mode 100644
index 0000000..e97f746
--- /dev/null
+++ b/src/testing/testing_api_cmd_policy_lookup.c
@@ -0,0 +1,267 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_policy_lookup.c
+ * @brief command to execute the anastasis backend service.
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "policy lookup" CMD.
+ */
+struct PolicyLookupState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Eddsa Publickey.
+ */
+ struct ANASTASIS_CRYPTO_AccountPublicKeyP anastasis_pub;
+
+ /**
+ * Hash of the upload (all zeros if there was no upload).
+ */
+ const struct GNUNET_HashCode *upload_hash;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * Expected status code.
+ */
+ unsigned int http_status;
+
+ /**
+ * Reference to upload command we expect to lookup.
+ */
+ const char *upload_reference;
+
+ /**
+ * The /policy GET operation handle.
+ */
+ struct ANASTASIS_PolicyLookupOperation *plo;
+};
+
+
+/**
+ * Function called with the results of a #ANASTASIS_lookup().
+ *
+ * @param cls closure
+ * @param http_status HTTP status of the request
+ * @param ud details about the lookup operation
+ */
+static void
+policy_lookup_cb (void *cls,
+ unsigned int http_status,
+ const struct ANASTASIS_DownloadDetails *dd)
+{
+ struct PolicyLookupState *pls = cls;
+
+ pls->plo = NULL;
+ if (http_status != pls->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ http_status,
+ pls->is->commands[pls->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+ if (NULL != pls->upload_reference)
+ {
+ if ( (MHD_HTTP_OK == http_status) &&
+ (0 != GNUNET_memcmp (&dd->curr_policy_hash,
+ pls->upload_hash)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+ }
+ TALER_TESTING_interpreter_next (pls->is);
+}
+
+
+/**
+ * Run a "policy lookup" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+policy_lookup_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PolicyLookupState *pls = cls;
+
+ pls->is = is;
+ if (NULL != pls->upload_reference)
+ {
+ const struct TALER_TESTING_Command *upload_cmd;
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *anastasis_pub;
+
+ upload_cmd = TALER_TESTING_interpreter_lookup_command
+ (is,
+ pls->upload_reference);
+ if (NULL == upload_cmd)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_hash (upload_cmd,
+ ANASTASIS_TESTING_TRAIT_HASH_CURRENT,
+ &pls->upload_hash))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_account_pub (upload_cmd,
+ 0,
+ &anastasis_pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+ pls->anastasis_pub = *anastasis_pub;
+ }
+ pls->plo = ANASTASIS_policy_lookup (is->ctx,
+ pls->anastasis_url,
+ &pls->anastasis_pub,
+ &policy_lookup_cb,
+ pls);
+ if (NULL == pls->plo)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pls->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "policy lookup" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+policy_lookup_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PolicyLookupState *pls = cls;
+
+ if (NULL != pls->plo)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (policy lookup)\n",
+ cmd->label);
+ ANASTASIS_policy_lookup_cancel (pls->plo);
+ pls->plo = NULL;
+ }
+ GNUNET_free (pls);
+}
+
+
+/**
+ * Make the "policy lookup" command.
+ *
+ * @param label command label
+ * @param anastasis_url base URL of the ANASTASIS serving
+ * the policy store request.
+ * @param http_status expected HTTP status.
+ * @param upload_ref reference to upload command
+ * @return the command
+ */
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_policy_lookup (const char *label,
+ const char *anastasis_url,
+ unsigned int http_status,
+ const char *upload_ref)
+{
+ struct PolicyLookupState *pls;
+
+ GNUNET_assert (NULL != upload_ref);
+ pls = GNUNET_new (struct PolicyLookupState);
+ pls->http_status = http_status;
+ pls->anastasis_url = anastasis_url;
+ pls->upload_reference = upload_ref;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = pls,
+ .label = label,
+ .run = &policy_lookup_run,
+ .cleanup = &policy_lookup_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * Make the "policy lookup" command for a non-existent upload.
+ *
+ * @param label command label
+ * @param anastasis_url base URL of the ANASTASIS serving
+ * the policy lookup request.
+ * @return the command
+ */
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_policy_nx (const char *label,
+ const char *anastasis_url)
+{
+ struct PolicyLookupState *pls;
+ struct GNUNET_CRYPTO_EddsaPrivateKey priv;
+
+ pls = GNUNET_new (struct PolicyLookupState);
+ pls->http_status = MHD_HTTP_NOT_FOUND;
+ pls->anastasis_url = anastasis_url;
+ GNUNET_CRYPTO_eddsa_key_create (&priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&priv,
+ &pls->anastasis_pub.pub);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = pls,
+ .label = label,
+ .run = &policy_lookup_run,
+ .cleanup = &policy_lookup_cleanup
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_policy_store.c b/src/testing/testing_api_cmd_policy_store.c
new file mode 100644
index 0000000..a8f0a70
--- /dev/null
+++ b/src/testing/testing_api_cmd_policy_store.c
@@ -0,0 +1,397 @@
+/*
+ This file is part of ANASTASIS
+ Copyright (C) 2014-2019 Taler Systems SA
+
+ ANASTASIS 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.
+
+ ANASTASIS 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 ANASTASIS; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/testing_api_cmd_policy_store.c
+ * @brief command to execute the anastasis backend service.
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_merchant_service.h>
+
+
+/**
+ * State for a "policy store" CMD.
+ */
+struct PolicyStoreState
+{
+ /**
+ * Claim token we got back, if any. Otherwise all zeros.
+ */
+ struct TALER_ClaimTokenP claim_token;
+
+ /**
+ * The policy data.
+ */
+ const void *recovery_data;
+
+ /**
+ * Number of bytes in @e recovery_data
+ */
+ size_t recovery_data_size;
+
+ /**
+ * Expected status code.
+ */
+ unsigned int http_status;
+
+ /**
+ * Eddsa Publickey.
+ */
+ struct ANASTASIS_CRYPTO_AccountPublicKeyP anastasis_pub;
+
+ /**
+ * Eddsa Privatekey.
+ */
+ struct ANASTASIS_CRYPTO_AccountPrivateKeyP anastasis_priv;
+
+ /**
+ * Hash of uploaded data, used to verify the response.
+ */
+ struct GNUNET_HashCode curr_hash;
+
+ /**
+ * The /policy POST operation handle.
+ */
+ struct ANASTASIS_PolicyStoreOperation *pso;
+
+ /**
+ * The nonce.
+ */
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Previous upload, or NULL for none. Used to calculate what THIS
+ * upload is based on.
+ */
+ const char *prev_upload;
+
+ /**
+ * Payment order ID we are to provide in the request, or zero.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret_request;
+
+ /**
+ * The order ID, for making the payment.
+ */
+ char *order_id;
+
+ /**
+ * Payment order ID we are to provide in the response, or zero.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret_response;
+
+ /**
+ * Options for how we are supposed to do the upload.
+ */
+ enum ANASTASIS_TESTING_PolicyStoreOption psopt;
+
+ /**
+ * True if @e payment_secret_request is initialized.
+ */
+ bool payment_secret_set;
+};
+
+/**
+ * Function called with the results of a #policy_store().
+ *
+ * @param cls closure
+ * @param http_status HTTP status of the request
+ * @param ud details about the upload operation
+ */
+static void
+policy_store_cb (void *cls,
+ const struct ANASTASIS_UploadDetails *ud)
+{
+ struct PolicyStoreState *pss = cls;
+
+ pss->pso = NULL;
+ if (ud->http_status != pss->http_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ ud->http_status,
+ pss->is->commands[pss->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ switch (ud->us)
+ {
+ case ANASTASIS_US_SUCCESS:
+ if (0 != GNUNET_memcmp (&pss->curr_hash,
+ ud->details.success.curr_backup_hash))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ break;
+ case ANASTASIS_US_PAYMENT_REQUIRED:
+ pss->payment_secret_response = ud->details.payment.ps;
+ {
+ struct TALER_MERCHANT_PayUriData pd;
+
+ if (GNUNET_OK !=
+ TALER_MERCHANT_parse_pay_uri (ud->details.payment.payment_request,
+ &pd))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ pss->order_id = GNUNET_strdup (pd.order_id);
+ if (NULL != pd.claim_token)
+ pss->claim_token = *pd.claim_token;
+ TALER_MERCHANT_parse_pay_uri_free (&pd);
+ }
+ break;
+ case ANASTASIS_US_HTTP_ERROR:
+ break;
+ case ANASTASIS_US_CLIENT_ERROR:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ case ANASTASIS_US_SERVER_ERROR:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ default:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (pss->is);
+}
+
+
+/**
+ * Run a "policy store" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+policy_store_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PolicyStoreState *pss = cls;
+
+ pss->is = is;
+ if (NULL != pss->prev_upload)
+ {
+ const struct TALER_TESTING_Command *ref;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ pss->prev_upload);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ {
+ const struct ANASTASIS_CRYPTO_AccountPrivateKeyP *priv;
+
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_account_priv (ref,
+ 0,
+ &priv))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ pss->anastasis_priv = *priv;
+ }
+ {
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *pub;
+
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_account_pub (ref,
+ 0,
+ &pub))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ pss->anastasis_pub = *pub;
+ }
+ {
+ const struct ANASTASIS_PaymentSecretP *ps;
+
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_payment_secret (ref,
+ 0,
+ &ps))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+ pss->payment_secret_request = *ps;
+ pss->payment_secret_set = true;
+ }
+ }
+ else
+ {
+ GNUNET_CRYPTO_eddsa_key_create (&pss->anastasis_priv.priv);
+ GNUNET_CRYPTO_eddsa_key_get_public (&pss->anastasis_priv.priv,
+ &pss->anastasis_pub.pub);
+ }
+
+ GNUNET_CRYPTO_hash (pss->recovery_data,
+ pss->recovery_data_size,
+ &pss->curr_hash);
+ pss->pso = ANASTASIS_policy_store (
+ is->ctx,
+ pss->anastasis_url,
+ &pss->anastasis_priv,
+ pss->recovery_data,
+ pss->recovery_data_size,
+ (0 != (ANASTASIS_TESTING_PSO_REQUEST_PAYMENT & pss->psopt)),
+ pss->payment_secret_set ? &pss->payment_secret_request : NULL,
+ GNUNET_TIME_UNIT_ZERO,
+ &policy_store_cb,
+ pss);
+ if (NULL == pss->pso)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pss->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "policy store" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+policy_store_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PolicyStoreState *pss = cls;
+
+ if (NULL != pss->pso)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (policy post)\n",
+ cmd->label);
+ ANASTASIS_policy_store_cancel (pss->pso);
+ pss->pso = NULL;
+ }
+ GNUNET_free (pss->order_id);
+ GNUNET_free (pss);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+policy_store_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PolicyStoreState *pss = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_claim_token (0,
+ &pss->claim_token),
+ TALER_TESTING_make_trait_order_id (0,
+ pss->order_id),
+ ANASTASIS_TESTING_make_trait_hash (0,
+ &pss->curr_hash),
+ ANASTASIS_TESTING_make_trait_account_pub (0,
+ &pss->anastasis_pub),
+ ANASTASIS_TESTING_make_trait_account_priv (0,
+ &pss->anastasis_priv),
+ ANASTASIS_TESTING_make_trait_payment_secret (0,
+ &pss->payment_secret_response),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_policy_store (
+ const char *label,
+ const char *anastasis_url,
+ const char *prev_upload,
+ unsigned int http_status,
+ enum ANASTASIS_TESTING_PolicyStoreOption pso,
+ const void *recovery_data,
+ size_t recovery_data_size)
+{
+ struct PolicyStoreState *pss;
+
+ pss = GNUNET_new (struct PolicyStoreState);
+ pss->recovery_data = recovery_data;
+ pss->recovery_data_size = recovery_data_size;
+ pss->http_status = http_status;
+ pss->psopt = pso;
+ pss->anastasis_url = anastasis_url;
+ pss->prev_upload = prev_upload;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = pss,
+ .label = label,
+ .run = &policy_store_run,
+ .cleanup = &policy_store_cleanup,
+ .traits = &policy_store_traits
+ };
+
+ return cmd;
+ }
+}
diff --git a/src/testing/testing_api_cmd_truth_store.c b/src/testing/testing_api_cmd_truth_store.c
new file mode 100644
index 0000000..0883406
--- /dev/null
+++ b/src/testing/testing_api_cmd_truth_store.c
@@ -0,0 +1,436 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_cmd_truth_store.c
+ * @brief command to execute the anastasis backend service.
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_merchant_service.h>
+
+/**
+ * State for a "truth store" CMD.
+ */
+struct TruthStoreState
+{
+ /**
+ * UUID of the uploaded truth
+ */
+ struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
+
+ /**
+ * Key used to encrypt the @e truth_data on the server.
+ */
+ struct ANASTASIS_CRYPTO_TruthKeyP key;
+
+ /**
+ * "Encrypted" key share data we store at the server.
+ */
+ struct ANASTASIS_CRYPTO_EncryptedKeyShareP encrypted_keyshare;
+
+ /**
+ * The /truth POST operation handle.
+ */
+ struct ANASTASIS_TruthStoreOperation *tso;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Previous upload, or NULL for none. Used to calculate what THIS
+ * upload is based on.
+ */
+ const char *prev_upload;
+
+ /**
+ * Authorization method / plugin name.
+ */
+ const char *method;
+
+ /**
+ * Mimetype of @e truth_data.
+ */
+ const char *mime_type;
+
+ /**
+ * Number of bytes in @e truth_data
+ */
+ size_t truth_data_size;
+
+ /**
+ * Data used by the authorization process.
+ */
+ void *truth_data;
+
+ /**
+ * Name of the file where the service will write the challenge, or NULL.
+ */
+ char *filename;
+
+ /**
+ * Expected status code.
+ */
+ unsigned int http_status;
+
+ /**
+ * Payment request we got back, or NULL.
+ */
+ char *pay_uri;
+
+ /**
+ * Payment order ID we got back, or all zeros.
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret_response;
+
+ /**
+ * Options for how we are supposed to do the upload.
+ */
+ enum ANASTASIS_TESTING_TruthStoreOption tsopt;
+};
+
+/**
+ * Function called with the results of a #truth_store().
+ *
+ * @param cls closure
+ * @param ec ANASTASIS error code
+ * @param http_status HTTP status of the request
+ * @param ud details about the upload operation
+ */
+static void
+truth_store_cb (void *cls,
+ const struct ANASTASIS_UploadDetails *ud)
+{
+ struct TruthStoreState *tss = cls;
+
+ tss->tso = NULL;
+ if ( (NULL == ud) ||
+ (ud->http_status != tss->http_status) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ (NULL != ud) ? ud->http_status : 0,
+ tss->is->commands[tss->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+ switch (ud->us)
+ {
+ case ANASTASIS_US_SUCCESS:
+ break;
+ case ANASTASIS_US_PAYMENT_REQUIRED:
+ tss->pay_uri = GNUNET_strdup (ud->details.payment.payment_request);
+ tss->payment_secret_response = ud->details.payment.ps;
+ break;
+ case ANASTASIS_US_CONFLICTING_TRUTH:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ case ANASTASIS_US_HTTP_ERROR:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ case ANASTASIS_US_CLIENT_ERROR:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ case ANASTASIS_US_SERVER_ERROR:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ default:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (tss->is);
+}
+
+
+/**
+ * Run a "truth store" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+truth_store_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TruthStoreState *tss = cls;
+
+ tss->is = is;
+ if (NULL != tss->prev_upload)
+ {
+ const struct TALER_TESTING_Command *ref;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ tss->prev_upload);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+
+ if (0 != (ANASTASIS_TESTING_TSO_REFERENCE_UUID & tss->tsopt))
+ {
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid;
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *eks;
+
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_truth_uuid (ref,
+ 0,
+ &uuid))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+ tss->uuid = *uuid;
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_eks (ref,
+ 0,
+ &eks))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+ tss->encrypted_keyshare = *eks;
+ }
+ }
+ else
+ {
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &tss->uuid,
+ sizeof (struct ANASTASIS_CRYPTO_TruthUUIDP));
+ GNUNET_CRYPTO_random_block (
+ GNUNET_CRYPTO_QUALITY_WEAK,
+ &tss->encrypted_keyshare,
+ sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
+ }
+ GNUNET_CRYPTO_random_block (
+ GNUNET_CRYPTO_QUALITY_WEAK,
+ &tss->key,
+ sizeof (struct ANASTASIS_CRYPTO_TruthKeyP));
+
+ {
+ void *encrypted_truth;
+ size_t size_encrypted_truth;
+ struct ANASTASIS_CRYPTO_NonceP nonce;
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
+ &nonce,
+ sizeof (nonce));
+ ANASTASIS_CRYPTO_truth_encrypt (&nonce,
+ &tss->key,
+ tss->truth_data,
+ tss->truth_data_size,
+ &encrypted_truth,
+ &size_encrypted_truth);
+ {
+ void *t;
+ size_t t_size;
+
+ ANASTASIS_CRYPTO_truth_decrypt (&tss->key,
+ encrypted_truth,
+ size_encrypted_truth,
+ &t,
+ &t_size);
+ if ( (t_size != tss->truth_data_size) ||
+ (0 != memcmp (tss->truth_data,
+ t,
+ t_size)) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+ GNUNET_free (t);
+ }
+ tss->tso = ANASTASIS_truth_store (
+ is->ctx,
+ tss->anastasis_url,
+ &tss->uuid,
+ tss->method,
+ &tss->encrypted_keyshare,
+ tss->mime_type,
+ size_encrypted_truth,
+ encrypted_truth,
+ (0 != (ANASTASIS_TESTING_TSO_REQUEST_PAYMENT & tss->tsopt)),
+ GNUNET_TIME_UNIT_ZERO,
+ &truth_store_cb,
+ tss);
+ GNUNET_free (encrypted_truth);
+ }
+ if (NULL == tss->tso)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tss->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "truth store" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+truth_store_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct TruthStoreState *tss = cls;
+
+ if (NULL != tss->tso)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (truth post)\n",
+ cmd->label);
+ ANASTASIS_truth_store_cancel (tss->tso);
+ tss->tso = NULL;
+ }
+ GNUNET_free (tss->truth_data);
+ GNUNET_free (tss->pay_uri);
+ GNUNET_free (tss->filename);
+ GNUNET_free (tss);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param[out] ret result (could be anything)
+ * @param[out] trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+truth_store_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct TruthStoreState *tss = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_truth_uuid (0,
+ &tss->uuid),
+ ANASTASIS_TESTING_make_trait_truth_key (0,
+ &tss->key),
+ ANASTASIS_TESTING_make_trait_eks (0,
+ &tss->encrypted_keyshare),
+ ANASTASIS_TESTING_make_trait_payment_secret (0,
+ &tss->payment_secret_response),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_TALER_URL,
+ tss->pay_uri),
+ TALER_TESTING_make_trait_string (0,
+ tss->filename),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_truth_store (const char *label,
+ const char *anastasis_url,
+ const char *prev_upload,
+ const char *method,
+ const char *mime_type,
+ size_t truth_data_size,
+ const void *truth_data,
+ enum ANASTASIS_TESTING_TruthStoreOption tso,
+ unsigned int http_status)
+{
+ struct TruthStoreState *tss;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Storing %u bytes of truth\n",
+ (unsigned int) truth_data_size);
+ tss = GNUNET_new (struct TruthStoreState);
+ tss->http_status = http_status;
+ tss->tsopt = tso;
+ tss->anastasis_url = anastasis_url;
+ tss->prev_upload = prev_upload;
+ tss->method = method;
+ tss->mime_type = mime_type;
+ tss->truth_data = GNUNET_memdup (truth_data,
+ truth_data_size);
+ tss->truth_data_size = truth_data_size;
+ if (0 == strcasecmp (method,
+ "file"))
+ tss->filename = GNUNET_strndup (truth_data,
+ truth_data_size);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tss,
+ .label = label,
+ .run = &truth_store_run,
+ .cleanup = &truth_store_cleanup,
+ .traits = &truth_store_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_truth_question (
+ const char *label,
+ const char *anastasis_url,
+ const char *prev_upload,
+ const char *answer,
+ enum ANASTASIS_TESTING_TruthStoreOption tso,
+ unsigned int http_status)
+{
+ struct GNUNET_HashCode h;
+
+ GNUNET_CRYPTO_hash (answer,
+ strlen (answer),
+ &h);
+ return ANASTASIS_TESTING_cmd_truth_store (label,
+ anastasis_url,
+ prev_upload,
+ "question",
+ "binary/sha512",
+ sizeof (h),
+ &h,
+ tso,
+ http_status);
+}
diff --git a/src/testing/testing_api_helpers.c b/src/testing/testing_api_helpers.c
new file mode 100644
index 0000000..66e7032
--- /dev/null
+++ b/src/testing/testing_api_helpers.c
@@ -0,0 +1,173 @@
+/*
+ This file is part of ANASTASIS
+ Copyright (C) 2014-2021 Taler Systems SA
+
+ ANASTASIS 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.
+
+ ANASTASIS is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ ANASTASISABILITY 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 ANASTASIS; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+
+/**
+ * @file lib/testing_api_helpers.c
+ * @brief helper functions for test library.
+ * @author Christian Grothoff
+ * @author Marcello Stanisci
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <gnunet/gnunet_curl_lib.h>
+
+
+struct GNUNET_OS_Process *
+ANASTASIS_TESTING_run_anastasis (const char *config_filename,
+ const char *anastasis_url)
+{
+ struct GNUNET_OS_Process *anastasis_proc;
+ unsigned int iter;
+ char *wget_cmd;
+
+ anastasis_proc
+ = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "anastasis-httpd",
+ "anastasis-httpd",
+ "--log=INFO",
+ "-c", config_filename,
+ NULL);
+ if (NULL == anastasis_proc)
+ ANASTASIS_FAIL ();
+
+ GNUNET_asprintf (&wget_cmd,
+ "wget -q -t 1 -T 1"
+ " %s"
+ " -o /dev/null -O /dev/null",
+ anastasis_url);
+
+ /* give child time to start and bind against the socket */
+ fprintf (stderr,
+ "Waiting for `anastasis-httpd' to be ready\n");
+ iter = 0;
+ do
+ {
+ if (100 == iter)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to launch `anastasis-httpd' (or `wget')\n");
+ GNUNET_OS_process_kill (anastasis_proc,
+ SIGTERM);
+ GNUNET_OS_process_wait (anastasis_proc);
+ GNUNET_OS_process_destroy (anastasis_proc);
+ ANASTASIS_FAIL ();
+ }
+ {
+ struct timespec req = {
+ .tv_nsec = 10000
+ };
+
+ nanosleep (&req,
+ NULL);
+ }
+ iter++;
+ }
+ while (0 != system (wget_cmd));
+ GNUNET_free (wget_cmd);
+ fprintf (stderr,
+ "\n");
+ return anastasis_proc;
+}
+
+
+char *
+ANASTASIS_TESTING_prepare_anastasis (const char *config_filename)
+{
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+ unsigned long long port;
+ struct GNUNET_OS_Process *dbinit_proc;
+ enum GNUNET_OS_ProcessStatusType type;
+ unsigned long code;
+ char *base_url;
+
+ cfg = GNUNET_CONFIGURATION_create ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_load (cfg,
+ config_filename))
+ ANASTASIS_FAIL ();
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg,
+ "anastasis",
+ "PORT",
+ &port))
+ {
+ GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
+ "anastasis",
+ "PORT");
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return NULL;
+ }
+
+ GNUNET_CONFIGURATION_destroy (cfg);
+
+ if (GNUNET_OK !=
+ GNUNET_NETWORK_test_port_free (IPPROTO_TCP,
+ (uint16_t) port))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Required port %llu not available, skipping.\n",
+ port);
+ return NULL;
+ }
+
+ /* DB preparation */
+ if (NULL == (dbinit_proc = GNUNET_OS_start_process
+ (GNUNET_OS_INHERIT_STD_ALL,
+ NULL, NULL, NULL,
+ "anastasis-dbinit",
+ "anastasis-dbinit",
+ "-c", config_filename,
+ "-r",
+ NULL)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to run anastasis-dbinit. Check your PATH.\n");
+ return NULL;
+ }
+
+ if (GNUNET_SYSERR ==
+ GNUNET_OS_process_wait_status (dbinit_proc,
+ &type,
+ &code))
+ {
+ GNUNET_OS_process_destroy (dbinit_proc);
+ ANASTASIS_FAIL ();
+ }
+ if ( (type == GNUNET_OS_PROCESS_EXITED) &&
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Failed to setup database\n");
+ return NULL;
+ }
+ if ( (type != GNUNET_OS_PROCESS_EXITED) ||
+ (0 != code) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error running `anastasis-dbinit'!\n");
+ return NULL;
+ }
+ GNUNET_OS_process_destroy (dbinit_proc);
+ GNUNET_asprintf (&base_url,
+ "http://localhost:%llu/",
+ port);
+ return base_url;
+}
diff --git a/src/testing/testing_api_trait_account_priv.c b/src/testing/testing_api_trait_account_priv.c
new file mode 100644
index 0000000..4860e82
--- /dev/null
+++ b/src/testing/testing_api_trait_account_priv.c
@@ -0,0 +1,72 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 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 Privlic License for more details.
+
+ You should have received a copy of the GNU General Privlic
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_trait_account_priv.c
+ * @brief traits to offer a account_priv
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_ACCOUNT_PRIV "anastasis-account_priv"
+
+
+/**
+ * Obtain an account private key from @a cmd.
+ *
+ * @param cmd command to extract the private key from.
+ * @param index the private key's index number.
+ * @param n[out] set to the private key coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_account_priv
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_AccountPrivateKeyP **priv)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) priv,
+ ANASTASIS_TESTING_TRAIT_ACCOUNT_PRIV,
+ index);
+}
+
+
+/**
+ * Offer an account private key.
+ *
+ * @param index usually zero
+ * @param priv the account_priv to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_account_priv
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_AccountPrivateKeyP *priv)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_ACCOUNT_PRIV,
+ .ptr = (const void *) priv
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_account_priv.c */
diff --git a/src/testing/testing_api_trait_account_pub.c b/src/testing/testing_api_trait_account_pub.c
new file mode 100644
index 0000000..5a3632e
--- /dev/null
+++ b/src/testing/testing_api_trait_account_pub.c
@@ -0,0 +1,72 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 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/testing_api_trait_account_pub.c
+ * @brief traits to offer a account_pub
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_ACCOUNT_PUB "anastasis-account_pub"
+
+
+/**
+ * Obtain an account public key from @a cmd.
+ *
+ * @param cmd command to extract the public key from.
+ * @param index the public key's index number.
+ * @param n[out] set to the public key coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_account_pub
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP **pub)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) pub,
+ ANASTASIS_TESTING_TRAIT_ACCOUNT_PUB,
+ index);
+}
+
+
+/**
+ * Offer an account public key.
+ *
+ * @param index usually zero
+ * @param h the account_pub to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_account_pub
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_AccountPublicKeyP *h)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_ACCOUNT_PUB,
+ .ptr = (const void *) h
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_account_pub.c */
diff --git a/src/testing/testing_api_trait_code.c b/src/testing/testing_api_trait_code.c
new file mode 100644
index 0000000..1a43cf8
--- /dev/null
+++ b/src/testing/testing_api_trait_code.c
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 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/testing_api_trait_string.c
+ * @brief traits to offers a code for a challenge
+ * @author Dominik Meister
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_CODE "anastasis-code"
+
+
+/**
+ * Obtain a code from @a cmd.
+ *
+ * @param cmd command to extract the number from.
+ * @param index the number's index number.
+ * @param n[out] set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_code
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const char **code)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) code,
+ ANASTASIS_TESTING_TRAIT_CODE,
+ index);
+}
+
+
+/**
+ * Offer a code.
+ *
+ * @param index the number's index number.
+ * @param code the code to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_code
+ (unsigned int index,
+ const char *code)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_CODE,
+ .ptr = (const void *) code
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_string.c */
diff --git a/src/testing/testing_api_trait_eks.c b/src/testing/testing_api_trait_eks.c
new file mode 100644
index 0000000..dc3f923
--- /dev/null
+++ b/src/testing/testing_api_trait_eks.c
@@ -0,0 +1,58 @@
+/*
+ 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/testing_api_trait_eks.c
+ * @brief traits to offer a payment identifier
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_EKS \
+ "anastasis-eks"
+
+
+int
+ANASTASIS_TESTING_get_trait_eks
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP **eks)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) eks,
+ ANASTASIS_TESTING_TRAIT_EKS,
+ index);
+}
+
+
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_eks
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *eks)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_EKS,
+ .ptr = (const void *) eks
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_eks.c */
diff --git a/src/testing/testing_api_trait_hash.c b/src/testing/testing_api_trait_hash.c
new file mode 100644
index 0000000..18be1ea
--- /dev/null
+++ b/src/testing/testing_api_trait_hash.c
@@ -0,0 +1,72 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 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/testing_api_trait_hash.c
+ * @brief traits to offer a hash
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_HASH "anastasis-hash"
+
+
+/**
+ * Obtain a hash from @a cmd.
+ *
+ * @param cmd command to extract the number from.
+ * @param index the number's index number.
+ * @param n[out] set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_hash
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct GNUNET_HashCode **h)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) h,
+ ANASTASIS_TESTING_TRAIT_HASH,
+ index);
+}
+
+
+/**
+ * Offer a hash.
+ *
+ * @param index the number's index number.
+ * @param h the hash to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_hash
+ (unsigned int index,
+ const struct GNUNET_HashCode *h)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_HASH,
+ .ptr = (const void *) h
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_hash.c */
diff --git a/src/testing/testing_api_trait_payment_secret.c b/src/testing/testing_api_trait_payment_secret.c
new file mode 100644
index 0000000..6238879
--- /dev/null
+++ b/src/testing/testing_api_trait_payment_secret.c
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019 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/testing_api_trait_payment_secret.c
+ * @brief traits to offer a payment identifier
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_PAYMENT_SECRET \
+ "anastasis-payment_secret"
+
+
+/**
+ * Obtain an account public key from @a cmd.
+ *
+ * @param cmd command to extract the payment identifier from.
+ * @param index the payment identifier's index number.
+ * @param n[out] set to the payment identifier coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_payment_secret
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_PaymentSecretP **payment_secret)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) payment_secret,
+ ANASTASIS_TESTING_TRAIT_PAYMENT_SECRET,
+ index);
+}
+
+
+/**
+ * Offer a payment identifier.
+ *
+ * @param index usually zero
+ * @param h the payment identifier to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_payment_secret
+ (unsigned int index,
+ const struct ANASTASIS_PaymentSecretP *h)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_PAYMENT_SECRET,
+ .ptr = (const void *) h
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_payment_secret.c */
diff --git a/src/testing/testing_api_trait_salt.c b/src/testing/testing_api_trait_salt.c
new file mode 100644
index 0000000..116742f
--- /dev/null
+++ b/src/testing/testing_api_trait_salt.c
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_trait_salt.c
+ * @brief traits to offer a hash
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_SALT "anastasis-provider-salt"
+
+
+/**
+ * Obtain a salt from @a cmd.
+ *
+ * @param cmd command to extract the salt from.
+ * @param index the salt's index number.
+ * @param s[out] set to the salt coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_salt
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_ProviderSaltP **s)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) s,
+ ANASTASIS_TESTING_TRAIT_SALT,
+ index);
+}
+
+
+/**
+ * Offer an salt.
+ *
+ * @param index the salt's index number.
+ * @param u the salt to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_salt
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *s)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_SALT,
+ .ptr = (const void *) s
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_salt.c */
diff --git a/src/testing/testing_api_trait_truth_key.c b/src/testing/testing_api_trait_truth_key.c
new file mode 100644
index 0000000..55094c1
--- /dev/null
+++ b/src/testing/testing_api_trait_truth_key.c
@@ -0,0 +1,58 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2019, 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/testing_api_trait_truth_key.c
+ * @brief traits to offer a payment identifier
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_TRUTH_KEY \
+ "anastasis-truth_key"
+
+
+int
+ANASTASIS_TESTING_get_trait_truth_key
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_TruthKeyP **truth_key)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) truth_key,
+ ANASTASIS_TESTING_TRAIT_TRUTH_KEY,
+ index);
+}
+
+
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_truth_key
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_TruthKeyP *h)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_TRUTH_KEY,
+ .ptr = (const void *) h
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_truth_key.c */
diff --git a/src/testing/testing_api_trait_truth_uuid.c b/src/testing/testing_api_trait_truth_uuid.c
new file mode 100644
index 0000000..38a7336
--- /dev/null
+++ b/src/testing/testing_api_trait_truth_uuid.c
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_api_trait_truth_pub.c
+ * @brief traits to offer a UUID for some truth
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_TRUTH_UUID "anastasis-truth-uuid"
+
+
+/**
+ * Obtain an public key from @a cmd.
+ *
+ * @param cmd command to extract the number from.
+ * @param index the number's index number.
+ * @param u[out] set to the number coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_truth_uuid
+ (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP **tpk)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) tpk,
+ ANASTASIS_TESTING_TRAIT_TRUTH_UUID,
+ index);
+}
+
+
+/**
+ * Offer a truth public key.
+ *
+ * @param index the number's index number.
+ * @param tpk the public key to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_truth_uuid
+ (unsigned int index,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *tpk)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_TRUTH_UUID,
+ .ptr = (const void *) tpk
+ };
+ return ret;
+}
+
+
+/* end of testing_api_trait_truth_pub.c */
diff --git a/src/testing/testing_cmd_challenge_answer.c b/src/testing/testing_cmd_challenge_answer.c
new file mode 100644
index 0000000..b243d61
--- /dev/null
+++ b/src/testing/testing_cmd_challenge_answer.c
@@ -0,0 +1,584 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_cmd_challenge_answer.c
+ * @brief command to execute the anastasis recovery service
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_merchant_service.h>
+
+
+/**
+ * State for a "challenge answer" CMD.
+ */
+struct ChallengeState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Reference to the challenge we are solving
+ */
+ struct ANASTASIS_Challenge *c;
+
+ /**
+ * Answer to the challenge we are solving
+ */
+ const char *answer;
+
+ /**
+ * Reference to the recovery process
+ */
+ const char *challenge_ref;
+
+ /**
+ * Reference to the payment
+ */
+ const char *payment_ref;
+
+ /**
+ * "taler://pay/" URL we got back, if any. Otherwise NULL.
+ */
+ char *payment_uri;
+
+ /**
+ * Order ID extracted from @e payment_uri, or NULL.
+ */
+ char *order_id;
+
+ /**
+ * Payment order ID we are to provide in the request.
+ */
+ struct ANASTASIS_PaymentSecretP payment_order_req;
+
+ /**
+ * Expected status code.
+ */
+ enum ANASTASIS_ChallengeStatus expected_cs;
+
+ /**
+ * Index of the challenge we are solving
+ */
+ unsigned int challenge_index;
+
+ /**
+ * 0 for no plugin needed 1 for plugin needed to authenticate
+ */
+ unsigned int mode;
+
+ /**
+ * code we read in the file generated by the plugin
+ */
+ char code[22];
+
+};
+
+
+static void
+challenge_answer_cb (void *af_cls,
+ const struct ANASTASIS_ChallengeStartResponse *csr)
+{
+ struct ChallengeState *cs = af_cls;
+
+ cs->c = NULL;
+ if (csr->cs != cs->expected_cs)
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected status %u, got %u\n",
+ cs->expected_cs,
+ csr->cs);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ switch (csr->cs)
+ {
+ case ANASTASIS_CHALLENGE_STATUS_SOLVED:
+ break;
+ case ANASTASIS_CHALLENGE_STATUS_INSTRUCTIONS:
+ {
+ FILE *file;
+ char *fn;
+
+ if (0 == strcasecmp (csr->details.open_challenge.content_type,
+ "application/json"))
+ {
+ const char *filename;
+ json_t *in;
+
+ in = json_loadb (csr->details.open_challenge.body,
+ csr->details.open_challenge.body_size,
+ JSON_REJECT_DUPLICATES,
+ NULL);
+ if (NULL == in)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ filename = json_string_value (json_object_get (in,
+ "filename"));
+ if (NULL == filename)
+ {
+ GNUNET_break (0);
+ json_decref (in);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ fn = GNUNET_strdup (filename);
+ json_decref (in);
+ }
+ else
+ {
+ fn = GNUNET_strndup (csr->details.open_challenge.body,
+ csr->details.open_challenge.body_size);
+ }
+ file = fopen (fn,
+ "r");
+ if (NULL == file)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "open",
+ fn);
+ GNUNET_free (fn);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (0 == fscanf (file,
+ "%21s",
+ cs->code))
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
+ "fscanf",
+ fn);
+ TALER_TESTING_interpreter_fail (cs->is);
+ fclose (file);
+ GNUNET_free (fn);
+ return;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Read challenge answer `%s' from file `%s'\n",
+ cs->code,
+ fn);
+ TALER_TESTING_interpreter_next (cs->is);
+ GNUNET_break (0 == fclose (file));
+ GNUNET_free (fn);
+ return;
+ }
+ case ANASTASIS_CHALLENGE_STATUS_PAYMENT_REQUIRED:
+ if (0 != strncmp (csr->details.payment_required.taler_pay_uri,
+ "taler+http://pay/",
+ strlen ("taler+http://pay/")))
+ {
+ GNUNET_break (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid payment URI `%s'\n",
+ csr->details.payment_required.taler_pay_uri);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ cs->payment_uri = GNUNET_strdup (
+ csr->details.payment_required.taler_pay_uri);
+ {
+ struct TALER_MERCHANT_PayUriData pud;
+
+ if (GNUNET_OK !=
+ TALER_MERCHANT_parse_pay_uri (cs->payment_uri,
+ &pud))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ cs->order_id = GNUNET_strdup (pud.order_id);
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (cs->order_id,
+ strlen (cs->order_id),
+ &cs->payment_order_req,
+ sizeof (cs->payment_order_req)))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ TALER_MERCHANT_parse_pay_uri_free (&pud);
+ }
+ TALER_TESTING_interpreter_next (cs->is);
+ return;
+ case ANASTASIS_CHALLENGE_STATUS_TRUTH_UNKNOWN:
+ break;
+ case ANASTASIS_CHALLENGE_STATUS_REDIRECT_FOR_AUTHENTICATION:
+ break;
+ case ANASTASIS_CHALLENGE_STATUS_SERVER_FAILURE:
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ case ANASTASIS_CHALLENGE_STATUS_RATE_LIMIT_EXCEEDED:
+ break;
+ }
+ TALER_TESTING_interpreter_next (cs->is);
+}
+
+
+/**
+ * Run a "recover secret" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+challenge_answer_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ChallengeState *cs = cls;
+ const struct ANASTASIS_Challenge *c;
+ const struct ANASTASIS_PaymentSecretP *ps;
+
+ cs->is = is;
+ if (NULL != cs->challenge_ref)
+ {
+ const struct TALER_TESTING_Command *ref;
+
+ ref = TALER_TESTING_interpreter_lookup_command (
+ is,
+ cs->challenge_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_challenge (ref,
+ cs->challenge_index,
+ &c))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ }
+
+ if (NULL != cs->payment_ref)
+ {
+ const struct TALER_TESTING_Command *ref;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ cs->payment_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_payment_secret (ref,
+ 0,
+ &ps))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ }
+ else
+ {
+ ps = NULL;
+ }
+
+ cs->c = (struct ANASTASIS_Challenge *) c;
+
+ if (1 == cs->mode)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const char *answer;
+ unsigned long long code;
+ char dummy;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ cs->answer);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_code (ref,
+ 0,
+ &answer))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (1 !=
+ sscanf (answer,
+ "%llu%c",
+ &code,
+ &dummy))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_challenge_answer2 (cs->c,
+ ps,
+ GNUNET_TIME_UNIT_ZERO,
+ code,
+ &challenge_answer_cb,
+ cs))
+ {
+ GNUNET_break (0);
+ cs->c = NULL;
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ ANASTASIS_challenge_answer (cs->c,
+ ps,
+ GNUNET_TIME_UNIT_ZERO,
+ cs->answer,
+ &challenge_answer_cb,
+ cs))
+ {
+ GNUNET_break (0);
+ cs->c = NULL;
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ }
+}
+
+
+/**
+ * Run a "recover secret" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+challenge_start_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct ChallengeState *cs = cls;
+ const struct ANASTASIS_Challenge *c;
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_PaymentSecretP *ps;
+
+ cs->is = is;
+ ref = TALER_TESTING_interpreter_lookup_command (
+ is,
+ cs->challenge_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_challenge (ref,
+ cs->challenge_index,
+ &c))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (NULL != cs->payment_ref)
+ {
+ const struct TALER_TESTING_Command *ref;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ cs->payment_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_payment_secret (ref,
+ 0,
+ &ps))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+ }
+ else
+ {
+ ps = NULL;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_challenge_start ((struct ANASTASIS_Challenge *) c,
+ ps,
+ GNUNET_TIME_UNIT_ZERO,
+ NULL,
+ &challenge_answer_cb,
+ cs))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (cs->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "recover secret" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+challenge_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct ChallengeState *cs = cls;
+
+ if (NULL != cs->c)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete (challenge answer)\n",
+ cmd->label);
+ ANASTASIS_challenge_abort (cs->c);
+ cs->c = NULL;
+ }
+ GNUNET_free (cs->payment_uri);
+ GNUNET_free (cs->order_id);
+ GNUNET_free (cs);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+challenge_create_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct ChallengeState *cs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_code (0,
+ cs->code),
+ ANASTASIS_TESTING_make_trait_payment_secret (0,
+ &cs->payment_order_req),
+ TALER_TESTING_make_trait_url (TALER_TESTING_UT_TALER_URL,
+ cs->payment_uri),
+ TALER_TESTING_make_trait_order_id (0,
+ cs->order_id),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_challenge_start (
+ const char *label,
+ const char *payment_ref,
+ const char *challenge_ref,
+ unsigned int challenge_index,
+ enum ANASTASIS_ChallengeStatus expected_cs)
+{
+ struct ChallengeState *cs;
+
+ cs = GNUNET_new (struct ChallengeState);
+ cs->expected_cs = expected_cs;
+ cs->challenge_ref = challenge_ref;
+ cs->payment_ref = payment_ref;
+ cs->challenge_index = challenge_index;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cs,
+ .label = label,
+ .run = &challenge_start_run,
+ .cleanup = &challenge_cleanup,
+ .traits = &challenge_create_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_challenge_answer (
+ const char *label,
+ const char *payment_ref,
+ const char *challenge_ref,
+ unsigned int challenge_index,
+ const char *answer,
+ unsigned int mode,
+ enum ANASTASIS_ChallengeStatus expected_cs)
+{
+ struct ChallengeState *cs;
+
+ cs = GNUNET_new (struct ChallengeState);
+ cs->expected_cs = expected_cs;
+ cs->challenge_ref = challenge_ref;
+ cs->payment_ref = payment_ref;
+ cs->answer = answer;
+ cs->challenge_index = challenge_index;
+ cs->mode = mode;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = cs,
+ .label = label,
+ .run = &challenge_answer_run,
+ .cleanup = &challenge_cleanup,
+ .traits = &challenge_create_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_cmd_challenge_answer.c */
diff --git a/src/testing/testing_cmd_policy_create.c b/src/testing/testing_cmd_policy_create.c
new file mode 100644
index 0000000..fc9ed44
--- /dev/null
+++ b/src/testing/testing_cmd_policy_create.c
@@ -0,0 +1,208 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_cmd_policy_create.c
+ * @brief command to execute the anastasis secret share service
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "policy create" CMD.
+ */
+struct PolicyCreateState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Label of this command.
+ */
+ const char *label;
+
+ /**
+ * References to upload commands of previous truth uploads.
+ */
+ const char **cmd_label_array;
+
+ /**
+ * Length of array of command labels (cmd_label_array).
+ */
+ unsigned int cmd_label_array_length;
+
+ /**
+ * Policy object
+ */
+ struct ANASTASIS_Policy *policy;
+};
+
+
+/**
+ * Run a "policy create" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+policy_create_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct PolicyCreateState *pcs = cls;
+ const struct ANASTASIS_Truth *truths[pcs->cmd_label_array_length];
+
+ GNUNET_assert (pcs->cmd_label_array_length > 0);
+ GNUNET_assert (NULL != pcs->cmd_label_array);
+ pcs->is = is;
+ if (NULL != pcs->cmd_label_array)
+ {
+ for (unsigned int i = 0; i < pcs->cmd_label_array_length; i++)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_Truth *truth;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ pcs->cmd_label_array[i]);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pcs->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_truth (ref,
+ 0,
+ &truth))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pcs->is);
+ return;
+ }
+ GNUNET_assert (NULL != truth);
+ truths[i] = truth;
+ }
+ }
+
+ pcs->policy = ANASTASIS_policy_create (truths,
+ pcs->cmd_label_array_length);
+
+ if (NULL == pcs->policy)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (pcs->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (pcs->is);
+}
+
+
+/**
+ * Free the state of a "policy create" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+policy_create_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct PolicyCreateState *pcs = cls;
+
+ GNUNET_free (pcs->cmd_label_array);
+ if (NULL != pcs->policy)
+ {
+ ANASTASIS_policy_destroy (pcs->policy);
+ pcs->policy = NULL;
+ }
+ GNUNET_free (pcs);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+policy_create_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct PolicyCreateState *pcs = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_policy (0,
+ pcs->policy),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_policy_create (const char *label,
+ ...)
+{
+ struct PolicyCreateState *pcs;
+ va_list ap;
+ const char *truth_upload_cmd;
+
+ pcs = GNUNET_new (struct PolicyCreateState);
+ pcs->label = label;
+
+ va_start (ap,
+ label);
+ while (NULL != (truth_upload_cmd = va_arg (ap, const char *)))
+ {
+ GNUNET_array_append (pcs->cmd_label_array,
+ pcs->cmd_label_array_length,
+ truth_upload_cmd);
+ }
+ va_end (ap);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = pcs,
+ .label = label,
+ .run = &policy_create_run,
+ .cleanup = &policy_create_cleanup,
+ .traits = &policy_create_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_cmd_policy_create.c */
diff --git a/src/testing/testing_cmd_recover_secret.c b/src/testing/testing_cmd_recover_secret.c
new file mode 100644
index 0000000..a95bdd2
--- /dev/null
+++ b/src/testing/testing_cmd_recover_secret.c
@@ -0,0 +1,518 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020, 2021 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_cmd_recover_secret.c
+ * @brief command to execute the anastasis recovery service
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "recover secret" CMD.
+ */
+struct RecoverSecretState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * The /policy GET operation handle.
+ */
+ struct ANASTASIS_Recovery *recovery;
+
+ /**
+ * Reference to download command we expect to lookup.
+ */
+ const char *download_reference;
+
+ /**
+ * Reference to download command we expect to lookup.
+ */
+ const char *core_secret_reference;
+
+ /**
+ * Options for how we are supposed to do the download.
+ */
+ enum ANASTASIS_TESTING_RecoverSecretOption rsopt;
+
+ /**
+ * Identification data from the user
+ */
+ json_t *id_data;
+
+ /**
+ * Salt to be used to derive the id
+ */
+ struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
+
+ /**
+ * Recovery information from the lookup
+ */
+ struct ANASTASIS_RecoveryInformation *ri;
+
+ /**
+ * Coresecret to check if decryption worked
+ */
+ const void *core_secret;
+
+ /**
+ * Task scheduled to wait for recovery to complete.
+ */
+ struct GNUNET_SCHEDULER_Task *recovery_task;
+
+ /**
+ * version of the recovery document
+ */
+ unsigned int version;
+
+ /**
+ * #GNUNET_OK if the secret was recovered, #GNUNET_SYSERR if
+ * recovery failed (yielded wrong secret).
+ */
+ int recovered;
+};
+
+
+/**
+ * Callback which passes back the recovery document and its possible
+ * policies. Also passes back the version of the document for the user
+ * to check.
+ *
+ * @param cls closure for the callback
+ * @param ri recovery information struct which contains the policies
+ */
+static void
+policy_lookup_cb (void *cls,
+ const struct ANASTASIS_RecoveryInformation *ri)
+{
+ struct RecoverSecretState *rss = cls;
+
+ rss->ri = (struct ANASTASIS_RecoveryInformation *) ri;
+ if (NULL == ri)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ TALER_TESTING_interpreter_next (rss->is);
+}
+
+
+/**
+ * This function is called whenever the recovery process ends.
+ * On success, the secret is returned in @a secret.
+ *
+ * @param cls closure
+ * @param ec error code
+ * @param secret contains the core secret which is passed to the user
+ * @param secret_size defines the size of the core secret
+ */
+static void
+core_secret_cb (void *cls,
+ enum ANASTASIS_RecoveryStatus rc,
+ const void *secret,
+ size_t secret_size)
+{
+ struct RecoverSecretState *rss = cls;
+
+ rss->recovery = NULL;
+ if (ANASTASIS_RS_SUCCESS != rc)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Recovery failed with status %d\n",
+ rc);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ if (0 != memcmp (secret,
+ rss->core_secret,
+ secret_size))
+ {
+ GNUNET_break (0);
+ rss->recovered = GNUNET_SYSERR;
+ if (NULL != rss->recovery_task)
+ {
+ GNUNET_SCHEDULER_cancel (rss->recovery_task);
+ rss->recovery_task = NULL;
+ TALER_TESTING_interpreter_fail (rss->is);
+ }
+ return;
+ }
+ rss->recovered = GNUNET_OK;
+ if (NULL != rss->recovery_task)
+ {
+ GNUNET_SCHEDULER_cancel (rss->recovery_task);
+ rss->recovery_task = NULL;
+ TALER_TESTING_interpreter_next (rss->is);
+ }
+}
+
+
+/**
+ * Run a "recover secret" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+recover_secret_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RecoverSecretState *rss = cls;
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
+ rss->is = is;
+
+ if (NULL != rss->download_reference)
+ {
+ ref = TALER_TESTING_interpreter_lookup_command
+ (is,
+ rss->download_reference);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_salt (ref,
+ 0,
+ &salt))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ }
+ if (NULL != rss->core_secret_reference)
+ {
+ ref = TALER_TESTING_interpreter_lookup_command
+ (is,
+ rss->core_secret_reference);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_core_secret (ref,
+ 0,
+ &rss->core_secret))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+ }
+ rss->recovery = ANASTASIS_recovery_begin (is->ctx,
+ rss->id_data,
+ rss->version,
+ rss->anastasis_url,
+ salt,
+ &policy_lookup_cb,
+ rss,
+ &core_secret_cb,
+ rss);
+ if (NULL == rss->recovery)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rss->is);
+ return;
+ }
+}
+
+
+/**
+ * Task to run the abort routine on the given @a cls object
+ * after the stack has fully unwound.
+ *
+ * @param cls a `struct ANASTASIS_Recovery *`
+ */
+static void
+delayed_abort (void *cls)
+{
+ struct ANASTASIS_Recovery *recovery = cls;
+
+ ANASTASIS_recovery_abort (recovery);
+}
+
+
+/**
+ * Free the state of a "recover secret" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure
+ * @param cmd command being freed.
+ */
+static void
+recover_secret_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RecoverSecretState *rss = cls;
+
+ if (NULL != rss->recovery)
+ {
+ /* must run first, or at least before #core_secret_cb */
+ (void) GNUNET_SCHEDULER_add_with_priority (
+ GNUNET_SCHEDULER_PRIORITY_SHUTDOWN,
+ &delayed_abort,
+ rss->recovery);
+ rss->recovery = NULL;
+ }
+ if (NULL != rss->recovery_task)
+ {
+ GNUNET_SCHEDULER_cancel (rss->recovery_task);
+ rss->recovery_task = NULL;
+ }
+ json_decref (rss->id_data);
+ GNUNET_free (rss);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+recover_secret_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct RecoverSecretState *rss = cls;
+
+ if (NULL == rss->ri)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (index >= rss->ri->cs_len)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_challenge (index,
+ rss->ri->cs[index]),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+ }
+}
+
+
+/**
+ * Function called on timeout of the secret finishing operation.
+ *
+ * @param cls a `struct RecoverSecretState *`
+ */
+static void
+recovery_fail (void *cls)
+{
+ struct RecoverSecretState *rss = cls;
+
+ rss->recovery_task = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout during secret recovery\n");
+ TALER_TESTING_interpreter_fail (rss->is);
+}
+
+
+/**
+ * Wait @a delay for @a cmd to finish secret recovery.
+ *
+ * @param cmd command to wait on
+ * @param delay how long to wait at most
+ */
+static void
+recover_secret_finish (struct TALER_TESTING_Command *cmd,
+ struct GNUNET_TIME_Relative delay)
+{
+ struct RecoverSecretState *rss = cmd->cls;
+
+ GNUNET_assert (&recover_secret_run == cmd->run);
+ GNUNET_assert (NULL == rss->recovery_task);
+ switch (rss->recovered)
+ {
+ case GNUNET_OK:
+ TALER_TESTING_interpreter_next (rss->is);
+ break;
+ case GNUNET_NO:
+ rss->recovery_task = GNUNET_SCHEDULER_add_delayed (delay,
+ &recovery_fail,
+ rss);
+ break;
+ case GNUNET_SYSERR:
+ TALER_TESTING_interpreter_fail (rss->is);
+ break;
+ }
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_recover_secret (
+ const char *label,
+ const char *anastasis_url,
+ const json_t *id_data,
+ unsigned int version,
+ enum ANASTASIS_TESTING_RecoverSecretOption rso,
+ const char *download_ref,
+ const char *core_secret_ref)
+{
+ struct RecoverSecretState *rss;
+
+ rss = GNUNET_new (struct RecoverSecretState);
+ rss->version = version;
+ rss->id_data = json_incref ((json_t *) id_data);
+ rss->rsopt = rso;
+ rss->anastasis_url = anastasis_url;
+ rss->download_reference = download_ref;
+ rss->core_secret_reference = core_secret_ref;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rss,
+ .label = label,
+ .run = &recover_secret_run,
+ .cleanup = &recover_secret_cleanup,
+ .traits = &recover_secret_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/**
+ * State for a "recover secret finish" CMD.
+ */
+struct RecoverSecretFinishState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *recover_label;
+
+ /**
+ * Timeout.
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+};
+
+
+/**
+ * Run a "recover secret finish" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+recover_secret_finish_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct RecoverSecretFinishState *rsfs = cls;
+ struct TALER_TESTING_Command *ref;
+
+ rsfs->is = is;
+ ref = (struct TALER_TESTING_Command *)
+ TALER_TESTING_interpreter_lookup_command (is,
+ rsfs->recover_label);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (rsfs->is);
+ return;
+ }
+ recover_secret_finish (ref,
+ rsfs->timeout);
+}
+
+
+/**
+ * Free the state of a "recover secret finish" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure
+ * @param cmd command being freed.
+ */
+static void
+recover_secret_finish_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct RecoverSecretFinishState *rsfs = cls;
+
+ GNUNET_free (rsfs);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_recover_secret_finish (
+ const char *label,
+ const char *recover_label,
+ struct GNUNET_TIME_Relative timeout)
+{
+ struct RecoverSecretFinishState *rsfs;
+
+ rsfs = GNUNET_new (struct RecoverSecretFinishState);
+ rsfs->recover_label = recover_label;
+ rsfs->timeout = timeout;
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = rsfs,
+ .label = label,
+ .run = &recover_secret_finish_run,
+ .cleanup = &recover_secret_finish_cleanup
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_cmd_recover_secret.c */
diff --git a/src/testing/testing_cmd_secret_share.c b/src/testing/testing_cmd_secret_share.c
new file mode 100644
index 0000000..b80006e
--- /dev/null
+++ b/src/testing/testing_cmd_secret_share.c
@@ -0,0 +1,441 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_cmd_secret_share.c
+ * @brief command to execute the anastasis secret share service
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+#include <taler/taler_merchant_service.h>
+
+
+/**
+ * State for a "secret share" CMD.
+ */
+struct SecretShareState
+{
+ /**
+ * Claim token we got back, if any. Otherwise all zeros.
+ */
+ struct TALER_ClaimTokenP token;
+
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * Label of this command.
+ */
+ const char *label;
+
+ /**
+ * References to commands of previous policy creations.
+ */
+ const char **cmd_label_array;
+
+ /**
+ * Data to derive user identifier from.
+ */
+ json_t *id_data;
+
+ /**
+ * The core secret to backup/recover.
+ */
+ const void *core_secret;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * URL of a /config command for the @e anastasis_url.
+ */
+ const char *config_ref;
+
+ /**
+ * The /truth GET operation handle.
+ */
+ struct ANASTASIS_SecretShare *sso;
+
+ /**
+ * Reference to previous secret share command we expect to lookup.
+ */
+ const char *prev_secret_share;
+
+ /**
+ * closure for the payment callback
+ */
+ void *spc_cls;
+
+ /**
+ * closure for the result callback
+ */
+ void *src_cls;
+
+ /**
+ * Payment order ID we got back, if any. Otherwise NULL.
+ */
+ char *payment_order_id;
+
+ /**
+ * Size of core_secret.
+ */
+ size_t core_secret_size;
+
+ /**
+ * Length of array of command labels (cmd_label_array).
+ */
+ unsigned int cmd_label_array_length;
+
+ /**
+ * Expected status code.
+ */
+ enum ANASTASIS_ShareStatus want_status;
+
+ /**
+ * Options for how we are supposed to do the upload.
+ */
+ enum ANASTASIS_TESTING_SecretShareOption ssopt;
+};
+
+
+/**
+ * Function called with the results of a #ANASTASIS_secret_share().
+ *
+ * @param cls closure
+ * @param sr result from the operation
+ */
+static void
+secret_share_result_cb (void *cls,
+ const struct ANASTASIS_ShareResult *sr)
+{
+ struct SecretShareState *sss = cls;
+
+ sss->sso = NULL;
+ if (sr->ss != sss->want_status)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u to command %s in %s:%u\n",
+ sr->ss,
+ sss->is->commands[sss->is->ip].label,
+ __FILE__,
+ __LINE__);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ switch (sr->ss)
+ {
+ case ANASTASIS_SHARE_STATUS_SUCCESS:
+ break;
+ case ANASTASIS_SHARE_STATUS_PAYMENT_REQUIRED:
+ {
+ struct TALER_MERCHANT_PayUriData pd;
+
+ GNUNET_assert (0 < sr->details.payment_required.payment_requests_length);
+ if (GNUNET_OK !=
+ TALER_MERCHANT_parse_pay_uri (
+ sr->details.payment_required.payment_requests[0].payment_request_url,
+ &pd))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ sss->payment_order_id = GNUNET_strdup (pd.order_id);
+ TALER_MERCHANT_parse_pay_uri_free (&pd);
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Order ID from Anastasis service is `%s'\n",
+ sss->payment_order_id);
+ }
+ case ANASTASIS_SHARE_STATUS_PROVIDER_FAILED:
+ break;
+ }
+ TALER_TESTING_interpreter_next (sss->is);
+}
+
+
+/**
+ * Run a "secret share" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+secret_share_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct SecretShareState *sss = cls;
+ const struct ANASTASIS_Policy *policies[sss->cmd_label_array_length];
+ struct ANASTASIS_ProviderDetails pds;
+
+ GNUNET_assert (sss->cmd_label_array_length > 0);
+ GNUNET_assert (NULL != sss->cmd_label_array);
+ sss->is = is;
+ if (NULL != sss->cmd_label_array)
+ {
+ for (unsigned int i = 0; i < sss->cmd_label_array_length; i++)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_Policy *policy;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ sss->cmd_label_array[i]);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_policy (ref,
+ 0,
+ &policy))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ GNUNET_assert (NULL != policy);
+ policies[i] = policy;
+ }
+ }
+
+ if (NULL != sss->prev_secret_share)
+ {
+ const struct TALER_TESTING_Command *ref;
+ const char *order_id;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ sss->prev_secret_share);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ TALER_TESTING_get_trait_order_id (ref,
+ 0,
+ &order_id))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ sss->payment_order_id = (char *) order_id;
+
+ if (NULL == sss->payment_order_id)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ }
+
+ memset (&pds,
+ 0,
+ sizeof (pds));
+ if (NULL != sss->payment_order_id)
+ {
+ if (GNUNET_OK !=
+ GNUNET_STRINGS_string_to_data (
+ sss->payment_order_id,
+ strlen (sss->payment_order_id),
+ &pds.payment_secret,
+ sizeof (struct ANASTASIS_PaymentSecretP)))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ GNUNET_free (sss->payment_order_id);
+ return;
+ }
+ GNUNET_free (sss->payment_order_id);
+ }
+ pds.provider_url = sss->anastasis_url;
+ {
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
+
+ ref = TALER_TESTING_interpreter_lookup_command (is,
+ sss->config_ref);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_salt (ref,
+ 0,
+ &salt))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+ pds.provider_salt = *salt;
+ }
+
+ sss->sso = ANASTASIS_secret_share (is->ctx,
+ sss->id_data,
+ &pds,
+ 1,
+ policies,
+ sss->cmd_label_array_length,
+ false,
+ GNUNET_TIME_UNIT_ZERO,
+ &secret_share_result_cb,
+ sss,
+ "test-case",
+ sss->core_secret,
+ sss->core_secret_size);
+ if (NULL == sss->sso)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (sss->is);
+ return;
+ }
+}
+
+
+/**
+ * Free the state of a "secret share" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+secret_share_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct SecretShareState *sss = cls;
+
+ if (NULL != sss->cmd_label_array)
+ {
+ GNUNET_free (sss->cmd_label_array);
+ }
+ if (NULL != sss->sso)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete\n",
+ cmd->label);
+ ANASTASIS_secret_share_cancel (sss->sso);
+ sss->sso = NULL;
+ }
+ json_decref (sss->id_data);
+ GNUNET_free (sss);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+secret_share_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct SecretShareState *sss = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ TALER_TESTING_make_trait_claim_token (0,
+ &sss->token),
+ ANASTASIS_TESTING_make_trait_core_secret (0,
+ sss->core_secret),
+ TALER_TESTING_make_trait_order_id (0,
+ sss->payment_order_id),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_secret_share (
+ const char *label,
+ const char *anastasis_url,
+ const char *config_ref,
+ const char *prev_secret_share,
+ const json_t *id_data,
+ const void *core_secret,
+ size_t core_secret_size,
+ enum ANASTASIS_ShareStatus want_status,
+ enum ANASTASIS_TESTING_SecretShareOption sso,
+ ...)
+{
+ struct SecretShareState *sss;
+
+ sss = GNUNET_new (struct SecretShareState);
+ sss->want_status = want_status;
+ sss->ssopt = sso;
+ sss->anastasis_url = anastasis_url;
+ sss->config_ref = config_ref;
+ sss->label = label;
+ sss->id_data = json_incref ((json_t *) id_data);
+ sss->core_secret = core_secret;
+ sss->core_secret_size = core_secret_size;
+ sss->prev_secret_share = prev_secret_share;
+
+ {
+ const char *policy_create_cmd;
+ va_list ap;
+
+ va_start (ap,
+ sso);
+ while (NULL != (policy_create_cmd = va_arg (ap, const char *)))
+ {
+ GNUNET_array_append (sss->cmd_label_array,
+ sss->cmd_label_array_length,
+ policy_create_cmd);
+ }
+ va_end (ap);
+ }
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = sss,
+ .label = label,
+ .run = &secret_share_run,
+ .cleanup = &secret_share_cleanup,
+ .traits = &secret_share_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+/* end of testing_cmd_secret_share.c */
diff --git a/src/testing/testing_cmd_truth_upload.c b/src/testing/testing_cmd_truth_upload.c
new file mode 100644
index 0000000..f9149d5
--- /dev/null
+++ b/src/testing/testing_cmd_truth_upload.c
@@ -0,0 +1,383 @@
+/*
+ This file is part of Anastasis
+ Copyright (C) 2020 Taler Systems SA
+
+ Anastasis is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 3, or (at your option) any later version.
+
+ Anastasis 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
+ Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_cmd_truth_upload.c
+ * @brief command to execute the anastasis secret share service
+ * @author Christian Grothoff
+ * @author Dennis Neufeld
+ * @author Dominik Meister
+ */
+
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+#include <taler/taler_util.h>
+#include <taler/taler_testing_lib.h>
+
+
+/**
+ * State for a "truth upload" CMD.
+ */
+struct TruthUploadState
+{
+ /**
+ * The interpreter state.
+ */
+ struct TALER_TESTING_Interpreter *is;
+
+ /**
+ * URL of the anastasis backend.
+ */
+ const char *anastasis_url;
+
+ /**
+ * Label of this command.
+ */
+ const char *label;
+
+ /**
+ * The ID data to generate user identifier
+ */
+ json_t *id_data;
+
+ /**
+ * The escrow method
+ */
+ const char *method;
+
+ /**
+ * Instructions to be returned to client/user
+ * (e.g. "Look at your smartphone. SMS was sent to you")
+ */
+ const char *instructions;
+
+ /**
+ * Mime type of truth_data (eg. jpeg, string etc.)
+ */
+ const char *mime_type;
+
+ /**
+ * The truth_data (e.g. hash of answer to a secure question)
+ */
+ void *truth_data;
+
+ /**
+ * Requested order ID for this upload (if unpaid).
+ */
+ struct ANASTASIS_PaymentSecretP payment_secret_response;
+
+ /**
+ * Size of truth_data
+ */
+ size_t truth_data_size;
+
+ /**
+ * Expected status code.
+ */
+ unsigned int http_status;
+
+ /**
+ * The /truth POST operation handle.
+ */
+ struct ANASTASIS_TruthUpload *tuo;
+
+ /**
+ * closure for the payment callback
+ */
+ void *tpc_cls;
+
+ /**
+ * Reference to salt download.
+ */
+ const char *salt_reference;
+
+ /**
+ * Options for how we are supposed to do the upload.
+ */
+ enum ANASTASIS_TESTING_TruthStoreOption tsopt;
+
+ /**
+ * Truth object
+ */
+ struct ANASTASIS_Truth *truth;
+};
+
+
+/**
+ * Upload information
+ * caller MUST free 't' using ANASTASIS_truth_free()
+ *
+ * @param cls closure for callback
+ * @param t Truth object (contains provider url and truth public key)
+ * @param ud upload details, useful to continue in case of errors, NULL on success
+ */
+static void
+truth_upload_cb (void *cls,
+ struct ANASTASIS_Truth *t,
+ const struct ANASTASIS_UploadDetails *ud)
+{
+ struct TruthUploadState *tus = cls;
+
+ tus->tuo = NULL;
+ if (NULL == ud)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ return;
+ }
+ if (ud->http_status != tus->http_status)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ return;
+ }
+ if (MHD_HTTP_PAYMENT_REQUIRED == ud->http_status)
+ {
+ if (ANASTASIS_US_PAYMENT_REQUIRED != ud->us)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ return;
+ }
+ tus->payment_secret_response = ud->details.payment.ps;
+ TALER_TESTING_interpreter_next (tus->is);
+ return;
+ }
+ if ( (ANASTASIS_US_SUCCESS == ud->us) &&
+ (NULL == t) )
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_next (tus->is);
+ return;
+ }
+ tus->truth = t;
+ TALER_TESTING_interpreter_next (tus->is);
+}
+
+
+/**
+ * Run a "truth upload" CMD.
+ *
+ * @param cls closure.
+ * @param cmd command currently being run.
+ * @param is interpreter state.
+ */
+static void
+truth_upload_run (void *cls,
+ const struct TALER_TESTING_Command *cmd,
+ struct TALER_TESTING_Interpreter *is)
+{
+ struct TruthUploadState *tus = cls;
+ const struct TALER_TESTING_Command *ref;
+ const struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
+ struct ANASTASIS_CRYPTO_UserIdentifierP user_id;
+
+ tus->is = is;
+ if (NULL != tus->salt_reference)
+ {
+ ref = TALER_TESTING_interpreter_lookup_command
+ (is,
+ tus->salt_reference);
+ if (NULL == ref)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ return;
+ }
+ if (GNUNET_OK !=
+ ANASTASIS_TESTING_get_trait_salt (ref,
+ 0,
+ &salt))
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ return;
+ }
+ }
+
+ ANASTASIS_CRYPTO_user_identifier_derive (tus->id_data,
+ salt,
+ &user_id);
+
+ tus->tuo = ANASTASIS_truth_upload (is->ctx,
+ &user_id,
+ tus->anastasis_url,
+ tus->method,
+ tus->instructions,
+ tus->mime_type,
+ salt,
+ tus->truth_data,
+ tus->truth_data_size,
+ false, /* force payment */
+ GNUNET_TIME_UNIT_ZERO,
+ &truth_upload_cb,
+ tus);
+ if (NULL == tus->tuo)
+ {
+ GNUNET_break (0);
+ TALER_TESTING_interpreter_fail (tus->is);
+ }
+}
+
+
+/**
+ * Free the state of a "truth upload" CMD, and possibly
+ * cancel it if it did not complete.
+ *
+ * @param cls closure.
+ * @param cmd command being freed.
+ */
+static void
+truth_upload_cleanup (void *cls,
+ const struct TALER_TESTING_Command *cmd)
+{
+ struct TruthUploadState *tus = cls;
+
+ if (NULL != tus->tuo)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Command '%s' did not complete\n",
+ cmd->label);
+ ANASTASIS_truth_upload_cancel (tus->tuo);
+ tus->tuo = NULL;
+ }
+ if (NULL != tus->id_data)
+ {
+ json_decref (tus->id_data);
+ tus->id_data = NULL;
+ }
+ if (NULL != tus->truth)
+ {
+ ANASTASIS_truth_free (tus->truth);
+ tus->truth = NULL;
+ }
+ GNUNET_free (tus->truth_data);
+ GNUNET_free (tus);
+}
+
+
+/**
+ * Offer internal data to other commands.
+ *
+ * @param cls closure
+ * @param ret[out] result (could be anything)
+ * @param trait name of the trait
+ * @param index index number of the object to extract.
+ * @return #GNUNET_OK on success
+ */
+static int
+truth_upload_traits (void *cls,
+ const void **ret,
+ const char *trait,
+ unsigned int index)
+{
+ struct TruthUploadState *tus = cls;
+ struct TALER_TESTING_Trait traits[] = {
+ ANASTASIS_TESTING_make_trait_truth (0,
+ tus->truth),
+ ANASTASIS_TESTING_make_trait_payment_secret (0,
+ &tus->payment_secret_response),
+ TALER_TESTING_trait_end ()
+ };
+
+ return TALER_TESTING_get_trait (traits,
+ ret,
+ trait,
+ index);
+}
+
+
+json_t *
+ANASTASIS_TESTING_make_id_data_example (const char *id_data)
+{
+ json_t *id;
+
+ id = json_pack ("{s:s}",
+ "id_data", id_data);
+ GNUNET_assert (NULL != id);
+ return id;
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_truth_upload (
+ const char *label,
+ const char *anastasis_url,
+ const json_t *id_data,
+ const char *method,
+ const char *instructions,
+ const char *mime_type,
+ const void *truth_data,
+ size_t truth_data_size,
+ unsigned int http_status,
+ enum ANASTASIS_TESTING_TruthStoreOption tso,
+ const char *salt_ref)
+{
+ struct TruthUploadState *tus;
+
+ tus = GNUNET_new (struct TruthUploadState);
+ tus->label = label;
+ tus->http_status = http_status;
+ tus->tsopt = tso;
+ tus->anastasis_url = anastasis_url;
+ tus->salt_reference = salt_ref;
+ tus->id_data = json_incref ((json_t *) id_data);
+ tus->method = method;
+ tus->instructions = instructions;
+ tus->mime_type = mime_type;
+ tus->truth_data_size = truth_data_size;
+ tus->truth_data = GNUNET_memdup (truth_data,
+ truth_data_size);
+ {
+ struct TALER_TESTING_Command cmd = {
+ .cls = tus,
+ .label = label,
+ .run = &truth_upload_run,
+ .cleanup = &truth_upload_cleanup,
+ .traits = &truth_upload_traits
+ };
+
+ return cmd;
+ }
+}
+
+
+struct TALER_TESTING_Command
+ANASTASIS_TESTING_cmd_truth_upload_question (
+ const char *label,
+ const char *anastasis_url,
+ const json_t *id_data,
+ const char *instructions,
+ const char *mime_type,
+ const void *answer,
+ unsigned int http_status,
+ enum ANASTASIS_TESTING_TruthStoreOption tso,
+ const char *salt_ref)
+{
+ return ANASTASIS_TESTING_cmd_truth_upload (label,
+ anastasis_url,
+ id_data,
+ "question",
+ instructions,
+ mime_type,
+ answer,
+ strlen (answer),
+ http_status,
+ tso,
+ salt_ref);
+}
+
+
+/* end of testing_cmd_truth_upload.c */
diff --git a/src/testing/testing_trait_challenge.c b/src/testing/testing_trait_challenge.c
new file mode 100644
index 0000000..5c40d8e
--- /dev/null
+++ b/src/testing/testing_trait_challenge.c
@@ -0,0 +1,72 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_trait_challenge.c
+ * @brief traits to offer a challenge
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_CHALLENGE "anastasis-challenge"
+
+/**
+ * Obtain a challenge from @a cmd.
+ *
+ * @param cmd command to extract the challenge from.
+ * @param index the index of the challenge
+ * @param c[out] set to the challenge coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_challenge (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_Challenge **c)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) c,
+ ANASTASIS_TESTING_TRAIT_CHALLENGE,
+ index);
+}
+
+
+/**
+ * Offer a challenge.
+ *
+ * @param index the challenge index number.
+ * @param c the challenge to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_challenge
+ (unsigned int index,
+ const struct ANASTASIS_Challenge *c)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_CHALLENGE,
+ .ptr = (const void *) c
+ };
+ return ret;
+}
+
+
+/* end of testing_trait_challenge.c */
diff --git a/src/testing/testing_trait_core_secret.c b/src/testing/testing_trait_core_secret.c
new file mode 100644
index 0000000..100a249
--- /dev/null
+++ b/src/testing/testing_trait_core_secret.c
@@ -0,0 +1,74 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_trait_core_secret.c
+ * @brief traits to offer the core secret
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_CORE_SECRET "anastasis-core-secret"
+
+
+/**
+ * Obtain the core secret from @a cmd.
+ *
+ * @param cmd command to extract the core secret from.
+ * @param index the index of the core secret (usually 0)
+ * @param s[out] set to the core secret coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_core_secret (const struct
+ TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const void **s)
+{
+ return cmd->traits (cmd->cls,
+ s,
+ ANASTASIS_TESTING_TRAIT_CORE_SECRET,
+ index);
+}
+
+
+/**
+ * Offer the core secret.
+ *
+ * @param index the core secret's index number (usually 0).
+ * @param s the core secret to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_core_secret
+ (unsigned int index,
+ const void *s)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_CORE_SECRET,
+ .ptr = s
+ };
+ return ret;
+}
+
+
+/* end of testing_trait_core_secret.c */
diff --git a/src/testing/testing_trait_policy.c b/src/testing/testing_trait_policy.c
new file mode 100644
index 0000000..45e773c
--- /dev/null
+++ b/src/testing/testing_trait_policy.c
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_trait_policy.c
+ * @brief traits to offer a policy
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_POLICY "anastasis-policy"
+
+
+/**
+ * Obtain a policy from @a cmd.
+ *
+ * @param cmd command to extract the policy from.
+ * @param index the index of the policy
+ * @param t[out] set to the policy coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_policy (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_Policy **p)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) p,
+ ANASTASIS_TESTING_TRAIT_POLICY,
+ index);
+}
+
+
+/**
+ * Offer a policy.
+ *
+ * @param index the policy's index number.
+ * @param t the policy to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_policy
+ (unsigned int index,
+ const struct ANASTASIS_Policy *p)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_POLICY,
+ .ptr = (const void *) p
+ };
+ return ret;
+}
+
+
+/* end of testing_trait_policy.c */
diff --git a/src/testing/testing_trait_truth.c b/src/testing/testing_trait_truth.c
new file mode 100644
index 0000000..51696e1
--- /dev/null
+++ b/src/testing/testing_trait_truth.c
@@ -0,0 +1,73 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with TALER; see the file COPYING. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/testing_trait_truth.c
+ * @brief traits to offer a truth
+ * @author Christian Grothoff
+ * @author Dominik Meister
+ * @author Dennis Neufeld
+ */
+#include "platform.h"
+#include "anastasis_testing_lib.h"
+
+#define ANASTASIS_TESTING_TRAIT_TRUTH "anastasis-truth"
+
+
+/**
+ * Obtain a truth from @a cmd.
+ *
+ * @param cmd command to extract the truth from.
+ * @param index the index of the truth
+ * @param t[out] set to the truth coming from @a cmd.
+ * @return #GNUNET_OK on success.
+ */
+int
+ANASTASIS_TESTING_get_trait_truth (const struct TALER_TESTING_Command *cmd,
+ unsigned int index,
+ const struct ANASTASIS_Truth **t)
+{
+ return cmd->traits (cmd->cls,
+ (const void **) t,
+ ANASTASIS_TESTING_TRAIT_TRUTH,
+ index);
+}
+
+
+/**
+ * Offer a truth.
+ *
+ * @param index the truth's index number.
+ * @param t the truth to offer.
+ * @return #GNUNET_OK on success.
+ */
+struct TALER_TESTING_Trait
+ANASTASIS_TESTING_make_trait_truth
+ (unsigned int index,
+ const struct ANASTASIS_Truth *t)
+{
+ struct TALER_TESTING_Trait ret = {
+ .index = index,
+ .trait_name = ANASTASIS_TESTING_TRAIT_TRUTH,
+ .ptr = (const void *) t
+ };
+ return ret;
+}
+
+
+/* end of testing_trait_truth.c */