/* This file is part of Anastasis Copyright (C) 2020, 2022 Anastasis SARL 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.GPL. If not, see */ /** * @file testing/testing_api_cmd_truth_challenge.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 #include #include /** * State for a "keyshare lookup" CMD. */ struct TruthChallengeState { /** * The interpreter state. */ struct TALER_TESTING_Interpreter *is; /** * URL of the anastasis backend. */ const char *anastasis_url; /** * Expected HTTP status code. */ unsigned int expected_http_status; /** * The /truth GET operation handle. */ struct ANASTASIS_TruthChallengeOperation *tco; /** * 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; /** * "code" returned by service, if any. */ char *code; /** * "instructions" for how to solve the challenge as returned by service, if any. */ char *instructions; }; static void truth_challenge_cb (void *cls, const struct ANASTASIS_TruthChallengeDetails *tcd) { struct TruthChallengeState *ksls = cls; ksls->tco = NULL; if (tcd->http_status != ksls->expected_http_status) { TALER_TESTING_unexpected_status (ksls->is, tcd->http_status, ksls->expected_http_status); return; } switch (tcd->http_status) { case MHD_HTTP_OK: switch (tcd->details.success.cs) { case ANASTASIS_CS_FILE_WRITTEN: { FILE *file; char code[22]; file = fopen (tcd->details.success.details.challenge_filename, "r"); if (NULL == file) { GNUNET_log_strerror_file ( GNUNET_ERROR_TYPE_ERROR, "open", tcd->details.success.details.challenge_filename); TALER_TESTING_interpreter_fail (ksls->is); return; } if (0 == fscanf (file, "%21s", code)) { GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "fscanf", tcd->details.success.details. challenge_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); } break; case ANASTASIS_CS_TAN_SENT: ksls->instructions = GNUNET_strdup ( tcd->details.success.details.tan_address_hint); break; case ANASTASIS_CS_TAN_ALREADY_SENT: break; case ANASTASIS_CS_WIRE_FUNDS: /* FIXME: not implemented */ GNUNET_break (0); return; } break; case MHD_HTTP_PAYMENT_REQUIRED: ksls->pay_uri = GNUNET_strdup ( tcd->details.payment_required.payment_request); ksls->payment_secret_response = tcd->details.payment_required.ps; { 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; default: break; } TALER_TESTING_interpreter_next (ksls->is); } static void truth_challenge_run (void *cls, const struct TALER_TESTING_Command *cmd, struct TALER_TESTING_Interpreter *is) { struct TruthChallengeState *ksls = cls; const struct ANASTASIS_CRYPTO_TruthKeyP *truth_key; const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid; const struct ANASTASIS_PaymentSecretP *payment_secret; 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; } if (GNUNET_OK != ANASTASIS_TESTING_get_trait_truth_uuid (upload_cmd, &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, &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 (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, &payment_secret)) { GNUNET_break (0); TALER_TESTING_interpreter_fail (ksls->is); return; } } else { payment_secret = NULL; } ksls->tco = ANASTASIS_truth_challenge ( TALER_TESTING_interpreter_get_context (is), ksls->anastasis_url, truth_uuid, truth_key, payment_secret, &truth_challenge_cb, ksls); if (NULL == ksls->tco) { GNUNET_break (0); TALER_TESTING_interpreter_fail (ksls->is); return; } } static void truth_challenge_cleanup (void *cls, const struct TALER_TESTING_Command *cmd) { struct TruthChallengeState *ksls = cls; if (NULL != ksls->tco) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Command '%s' did not complete (keyshare lookup)\n", cmd->label); ANASTASIS_truth_challenge_cancel (ksls->tco); ksls->tco = NULL; } GNUNET_free (ksls->pay_uri); GNUNET_free (ksls->order_id); GNUNET_free (ksls->code); GNUNET_free (ksls->instructions); 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 enum GNUNET_GenericReturnValue truth_challenge_traits (void *cls, const void **ret, const char *trait, unsigned int index) { struct TruthChallengeState *ksls = cls; struct TALER_TESTING_Trait traits[] = { ANASTASIS_TESTING_make_trait_payment_secret ( &ksls->payment_secret_response), TALER_TESTING_make_trait_payto_uri (ksls->pay_uri), TALER_TESTING_make_trait_order_id (ksls->order_id), ANASTASIS_TESTING_make_trait_code (ksls->code), TALER_TESTING_trait_end () }; return TALER_TESTING_get_trait (traits, ret, trait, index); } struct TALER_TESTING_Command ANASTASIS_TESTING_cmd_truth_challenge ( const char *label, const char *anastasis_url, const char *payment_ref, const char *upload_ref, unsigned int http_status) { struct TruthChallengeState *ksls; GNUNET_assert (NULL != upload_ref); ksls = GNUNET_new (struct TruthChallengeState); ksls->expected_http_status = http_status; ksls->anastasis_url = anastasis_url; ksls->upload_reference = upload_ref; ksls->payment_reference = payment_ref; { struct TALER_TESTING_Command cmd = { .cls = ksls, .label = label, .run = &truth_challenge_run, .cleanup = &truth_challenge_cleanup, .traits = &truth_challenge_traits }; return cmd; } } /* end of testing_api_cmd_truth_challenge.c */