From 7e669bcf6b6336ec429da949bcb4aa456971dba2 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Fri, 30 Jul 2021 10:38:27 +0200 Subject: folding history in preparation of GNU Anastasis v0.0.0 release --- src/testing/testing_cmd_challenge_answer.c | 584 +++++++++++++++++++++++++++++ 1 file changed, 584 insertions(+) create mode 100644 src/testing/testing_cmd_challenge_answer.c (limited to 'src/testing/testing_cmd_challenge_answer.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 +*/ +/** + * @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 +#include +#include + + +/** + * 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 */ -- cgit v1.2.3