testing_cmd_challenge_answer.c (16610B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021, 2022 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU General Public License for more details. 12 13 You should have received a copy of the GNU General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file testing/testing_cmd_challenge_answer.c 18 * @brief command to execute the anastasis recovery service 19 * @author Christian Grothoff 20 * @author Dennis Neufeld 21 * @author Dominik Meister 22 */ 23 #include "platform.h" 24 #include "anastasis_testing_lib.h" 25 #include <taler/taler_util.h> 26 #include <taler/taler_testing_lib.h> 27 #include <taler/taler_merchant_service.h> 28 29 30 // FIXME: break up into two files, one for start, one for answer! 31 32 /** 33 * State for a "challenge answer" CMD. 34 */ 35 struct ChallengeState 36 { 37 /** 38 * The interpreter state. 39 */ 40 struct TALER_TESTING_Interpreter *is; 41 42 /** 43 * Reference to the challenge we are solving 44 */ 45 struct ANASTASIS_Challenge *c; 46 47 /** 48 * Answer to the challenge we are solving 49 */ 50 const char *answer; 51 52 /** 53 * Reference to the recovery process 54 */ 55 const char *challenge_ref; 56 57 /** 58 * Reference to the payment 59 */ 60 const char *payment_ref; 61 62 /** 63 * "taler://pay/" URL we got back, if any. Otherwise NULL. 64 */ 65 char *payment_uri; 66 67 /** 68 * Order ID extracted from @e payment_uri, or NULL. 69 */ 70 char *order_id; 71 72 /** 73 * Payment order ID we are to provide in the request. 74 */ 75 struct ANASTASIS_PaymentSecretP payment_order_req; 76 77 /** 78 * Expected answer status code. 79 */ 80 enum ANASTASIS_ChallengeAnswerStatus expected_acs; 81 82 /** 83 * Expected start status code. 84 */ 85 enum ANASTASIS_ChallengeStartStatus expected_scs; 86 87 /** 88 * Index of the challenge we are solving 89 */ 90 unsigned int challenge_index; 91 92 /** 93 * 0 for no plugin needed 1 for plugin needed to authenticate 94 */ 95 unsigned int mode; 96 97 /** 98 * code we read in the file generated by the plugin 99 */ 100 char *code; 101 102 }; 103 104 105 static void 106 challenge_answer_cb (void *af_cls, 107 const struct ANASTASIS_ChallengeAnswerResponse *csr) 108 { 109 struct ChallengeState *cs = af_cls; 110 111 cs->c = NULL; 112 if (csr->cs != cs->expected_acs) 113 { 114 GNUNET_break (0); 115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 116 "Expected status %u, got %u\n", 117 cs->expected_acs, 118 csr->cs); 119 TALER_TESTING_interpreter_fail (cs->is); 120 return; 121 } 122 switch (csr->cs) 123 { 124 case ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED: 125 break; 126 case ANASTASIS_CHALLENGE_ANSWER_STATUS_INVALID_ANSWER: 127 break; 128 case ANASTASIS_CHALLENGE_ANSWER_STATUS_PAYMENT_REQUIRED: 129 if (0 != strncmp (csr->details.payment_required.taler_pay_uri, 130 "taler+http://pay/", 131 strlen ("taler+http://pay/"))) 132 { 133 GNUNET_break (0); 134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 135 "Invalid payment URI `%s'\n", 136 csr->details.payment_required.taler_pay_uri); 137 TALER_TESTING_interpreter_fail (cs->is); 138 return; 139 } 140 cs->payment_uri = GNUNET_strdup ( 141 csr->details.payment_required.taler_pay_uri); 142 { 143 struct TALER_MERCHANT_PayUriData pud; 144 145 if (GNUNET_OK != 146 TALER_MERCHANT_parse_pay_uri (cs->payment_uri, 147 &pud)) 148 { 149 GNUNET_break (0); 150 TALER_TESTING_interpreter_fail (cs->is); 151 return; 152 } 153 cs->order_id = GNUNET_strdup (pud.order_id); 154 if (GNUNET_OK != 155 GNUNET_STRINGS_string_to_data (cs->order_id, 156 strlen (cs->order_id), 157 &cs->payment_order_req, 158 sizeof (cs->payment_order_req))) 159 { 160 GNUNET_break (0); 161 TALER_TESTING_interpreter_fail (cs->is); 162 return; 163 } 164 TALER_MERCHANT_parse_pay_uri_free (&pud); 165 } 166 TALER_TESTING_interpreter_next (cs->is); 167 return; 168 case ANASTASIS_CHALLENGE_ANSWER_STATUS_TRUTH_UNKNOWN: 169 break; 170 case ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE: 171 GNUNET_break (0); 172 TALER_TESTING_interpreter_fail (cs->is); 173 return; 174 case ANASTASIS_CHALLENGE_ANSWER_STATUS_RATE_LIMIT_EXCEEDED: 175 break; 176 } 177 TALER_TESTING_interpreter_next (cs->is); 178 } 179 180 181 /** 182 * Run a "recover secret" CMD. 183 * 184 * @param cls closure. 185 * @param cmd command currently being run. 186 * @param is interpreter state. 187 */ 188 static void 189 challenge_answer_run (void *cls, 190 const struct TALER_TESTING_Command *cmd, 191 struct TALER_TESTING_Interpreter *is) 192 { 193 struct ChallengeState *cs = cls; 194 const struct ANASTASIS_Challenge **c; 195 const struct ANASTASIS_PaymentSecretP *ps; 196 197 cs->is = is; 198 if (NULL != cs->challenge_ref) 199 { 200 const struct TALER_TESTING_Command *ref; 201 202 ref = TALER_TESTING_interpreter_lookup_command ( 203 is, 204 cs->challenge_ref); 205 if (NULL == ref) 206 { 207 GNUNET_break (0); 208 TALER_TESTING_interpreter_fail (cs->is); 209 return; 210 } 211 if (GNUNET_OK != 212 ANASTASIS_TESTING_get_trait_challenges (ref, 213 cs->challenge_index, 214 &c)) 215 { 216 GNUNET_break (0); 217 TALER_TESTING_interpreter_fail (cs->is); 218 return; 219 } 220 cs->c = (struct ANASTASIS_Challenge *) *c; 221 } 222 223 if (NULL != cs->payment_ref) 224 { 225 const struct TALER_TESTING_Command *ref; 226 227 ref = TALER_TESTING_interpreter_lookup_command (is, 228 cs->payment_ref); 229 if (NULL == ref) 230 { 231 GNUNET_break (0); 232 TALER_TESTING_interpreter_fail (cs->is); 233 return; 234 } 235 if (GNUNET_OK != 236 ANASTASIS_TESTING_get_trait_payment_secret (ref, 237 &ps)) 238 { 239 GNUNET_break (0); 240 TALER_TESTING_interpreter_fail (cs->is); 241 return; 242 } 243 } 244 else 245 { 246 ps = NULL; 247 } 248 249 if (1 == cs->mode) 250 { 251 const struct TALER_TESTING_Command *ref; 252 const char *answer; 253 unsigned long long code; 254 char dummy; 255 256 ref = TALER_TESTING_interpreter_lookup_command (is, 257 cs->answer); 258 if (NULL == ref) 259 { 260 GNUNET_break (0); 261 TALER_TESTING_interpreter_fail (cs->is); 262 return; 263 } 264 if (GNUNET_OK != 265 ANASTASIS_TESTING_get_trait_code (ref, 266 &answer)) 267 { 268 GNUNET_break (0); 269 TALER_TESTING_interpreter_fail (cs->is); 270 return; 271 } 272 if (1 != 273 sscanf (answer, 274 "%llu%c", 275 &code, 276 &dummy)) 277 { 278 GNUNET_break (0); 279 TALER_TESTING_interpreter_fail (cs->is); 280 return; 281 } 282 if (GNUNET_OK != 283 ANASTASIS_challenge_answer2 (cs->c, 284 ps, 285 GNUNET_TIME_UNIT_ZERO, 286 code, 287 &challenge_answer_cb, 288 cs)) 289 { 290 GNUNET_break (0); 291 cs->c = NULL; 292 TALER_TESTING_interpreter_fail (cs->is); 293 return; 294 } 295 296 } 297 else 298 { 299 if (GNUNET_OK != 300 ANASTASIS_challenge_answer (cs->c, 301 ps, 302 GNUNET_TIME_UNIT_ZERO, 303 cs->answer, 304 &challenge_answer_cb, 305 cs)) 306 { 307 GNUNET_break (0); 308 cs->c = NULL; 309 TALER_TESTING_interpreter_fail (cs->is); 310 return; 311 } 312 } 313 } 314 315 316 static void 317 challenge_start_cb (void *af_cls, 318 const struct ANASTASIS_ChallengeStartResponse *csr) 319 { 320 struct ChallengeState *cs = af_cls; 321 322 cs->c = NULL; 323 if (csr->cs != cs->expected_scs) 324 { 325 GNUNET_break (0); 326 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 327 "Expected status %u, got %u\n", 328 cs->expected_scs, 329 csr->cs); 330 TALER_TESTING_interpreter_fail (cs->is); 331 return; 332 } 333 switch (csr->cs) 334 { 335 case ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED: 336 { 337 FILE *file; 338 char code[22]; 339 340 file = fopen (csr->details.tan_filename, 341 "r"); 342 if (NULL == file) 343 { 344 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 345 "open", 346 csr->details.tan_filename); 347 TALER_TESTING_interpreter_fail (cs->is); 348 return; 349 } 350 if (0 == fscanf (file, 351 "%21s", 352 code)) 353 { 354 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 355 "fscanf", 356 csr->details.tan_filename); 357 GNUNET_break (0 == fclose (file)); 358 TALER_TESTING_interpreter_fail (cs->is); 359 return; 360 } 361 GNUNET_break (0 == fclose (file)); 362 cs->code = GNUNET_strdup (code); 363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 364 "Read code `%s'\n", 365 code); 366 } 367 break; 368 case ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED: 369 GNUNET_break (0); /* FIXME: not implemented */ 370 break; 371 case ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT: 372 GNUNET_break (0); /* FIXME: not implemented */ 373 break; 374 case ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED: 375 GNUNET_break (0); /* FIXME: not implemented */ 376 break; 377 case ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED: 378 if (0 != strncmp (csr->details.payment_required.taler_pay_uri, 379 "taler+http://pay/", 380 strlen ("taler+http://pay/"))) 381 { 382 GNUNET_break (0); 383 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 384 "Invalid payment URI `%s'\n", 385 csr->details.payment_required.taler_pay_uri); 386 TALER_TESTING_interpreter_fail (cs->is); 387 return; 388 } 389 cs->payment_uri = GNUNET_strdup ( 390 csr->details.payment_required.taler_pay_uri); 391 { 392 struct TALER_MERCHANT_PayUriData pud; 393 394 if (GNUNET_OK != 395 TALER_MERCHANT_parse_pay_uri (cs->payment_uri, 396 &pud)) 397 { 398 GNUNET_break (0); 399 TALER_TESTING_interpreter_fail (cs->is); 400 return; 401 } 402 cs->order_id = GNUNET_strdup (pud.order_id); 403 if (GNUNET_OK != 404 GNUNET_STRINGS_string_to_data (cs->order_id, 405 strlen (cs->order_id), 406 &cs->payment_order_req, 407 sizeof (cs->payment_order_req))) 408 { 409 GNUNET_break (0); 410 TALER_TESTING_interpreter_fail (cs->is); 411 return; 412 } 413 TALER_MERCHANT_parse_pay_uri_free (&pud); 414 } 415 TALER_TESTING_interpreter_next (cs->is); 416 return; 417 case ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN: 418 break; 419 case ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE: 420 GNUNET_break (0); 421 TALER_TESTING_interpreter_fail (cs->is); 422 return; 423 } 424 TALER_TESTING_interpreter_next (cs->is); 425 } 426 427 428 /** 429 * Run a "recover secret" CMD. 430 * 431 * @param cls closure. 432 * @param cmd command currently being run. 433 * @param is interpreter state. 434 */ 435 static void 436 challenge_start_run (void *cls, 437 const struct TALER_TESTING_Command *cmd, 438 struct TALER_TESTING_Interpreter *is) 439 { 440 struct ChallengeState *cs = cls; 441 const struct ANASTASIS_Challenge **c; 442 const struct ANASTASIS_PaymentSecretP *ps; 443 444 cs->is = is; 445 { 446 const struct TALER_TESTING_Command *ref; 447 448 ref = TALER_TESTING_interpreter_lookup_command ( 449 is, 450 cs->challenge_ref); 451 if (NULL == ref) 452 { 453 GNUNET_break (0); 454 TALER_TESTING_interpreter_fail (cs->is); 455 return; 456 } 457 if (GNUNET_OK != 458 ANASTASIS_TESTING_get_trait_challenges (ref, 459 cs->challenge_index, 460 &c)) 461 { 462 GNUNET_break (0); 463 TALER_TESTING_interpreter_fail (cs->is); 464 return; 465 } 466 } 467 468 if (NULL != cs->payment_ref) 469 { 470 const struct TALER_TESTING_Command *pref; 471 472 pref = TALER_TESTING_interpreter_lookup_command (is, 473 cs->payment_ref); 474 if (NULL == pref) 475 { 476 GNUNET_break (0); 477 TALER_TESTING_interpreter_fail (cs->is); 478 return; 479 } 480 if (GNUNET_OK != 481 ANASTASIS_TESTING_get_trait_payment_secret (pref, 482 &ps)) 483 { 484 GNUNET_break (0); 485 TALER_TESTING_interpreter_fail (cs->is); 486 return; 487 } 488 } 489 else 490 { 491 ps = NULL; 492 } 493 if (GNUNET_OK != 494 ANASTASIS_challenge_start ((struct ANASTASIS_Challenge *) *c, 495 ps, 496 &challenge_start_cb, 497 cs)) 498 { 499 GNUNET_break (0); 500 TALER_TESTING_interpreter_fail (cs->is); 501 return; 502 } 503 } 504 505 506 /** 507 * Free the state of a "recover secret" CMD, and possibly 508 * cancel it if it did not complete. 509 * 510 * @param cls closure. 511 * @param cmd command being freed. 512 */ 513 static void 514 challenge_cleanup (void *cls, 515 const struct TALER_TESTING_Command *cmd) 516 { 517 struct ChallengeState *cs = cls; 518 519 if (NULL != cs->c) 520 { 521 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 522 "Command '%s' did not complete (challenge answer)\n", 523 cmd->label); 524 ANASTASIS_challenge_abort (cs->c); 525 cs->c = NULL; 526 } 527 GNUNET_free (cs->payment_uri); 528 GNUNET_free (cs->order_id); 529 GNUNET_free (cs->code); 530 GNUNET_free (cs); 531 } 532 533 534 /** 535 * Offer internal data to other commands. 536 * 537 * @param cls closure 538 * @param[out] ret result (could be anything) 539 * @param trait name of the trait 540 * @param index index number of the object to extract. 541 * @return #GNUNET_OK on success 542 */ 543 static enum GNUNET_GenericReturnValue 544 challenge_create_traits (void *cls, 545 const void **ret, 546 const char *trait, 547 unsigned int index) 548 { 549 struct ChallengeState *cs = cls; 550 struct TALER_TESTING_Trait traits[] = { 551 ANASTASIS_TESTING_make_trait_code (cs->code), 552 ANASTASIS_TESTING_make_trait_payment_secret ( 553 &cs->payment_order_req), 554 TALER_TESTING_make_trait_taler_uri (cs->payment_uri), 555 TALER_TESTING_make_trait_order_id (cs->order_id), 556 TALER_TESTING_trait_end () 557 }; 558 559 return TALER_TESTING_get_trait (traits, 560 ret, 561 trait, 562 index); 563 } 564 565 566 struct TALER_TESTING_Command 567 ANASTASIS_TESTING_cmd_challenge_start ( 568 const char *label, 569 const char *payment_ref, 570 const char *challenge_ref, 571 unsigned int challenge_index, 572 enum ANASTASIS_ChallengeStartStatus expected_cs) 573 { 574 struct ChallengeState *cs; 575 576 cs = GNUNET_new (struct ChallengeState); 577 cs->expected_scs = expected_cs; 578 cs->challenge_ref = challenge_ref; 579 cs->payment_ref = payment_ref; 580 cs->challenge_index = challenge_index; 581 { 582 struct TALER_TESTING_Command cmd = { 583 .cls = cs, 584 .label = label, 585 .run = &challenge_start_run, 586 .cleanup = &challenge_cleanup, 587 .traits = &challenge_create_traits 588 }; 589 590 return cmd; 591 } 592 } 593 594 595 struct TALER_TESTING_Command 596 ANASTASIS_TESTING_cmd_challenge_answer ( 597 const char *label, 598 const char *payment_ref, 599 const char *challenge_ref, 600 unsigned int challenge_index, 601 const char *answer, 602 unsigned int mode, 603 enum ANASTASIS_ChallengeAnswerStatus expected_cs) 604 { 605 struct ChallengeState *cs; 606 607 cs = GNUNET_new (struct ChallengeState); 608 cs->expected_acs = expected_cs; 609 cs->challenge_ref = challenge_ref; 610 cs->payment_ref = payment_ref; 611 cs->answer = answer; 612 cs->challenge_index = challenge_index; 613 cs->mode = mode; 614 { 615 struct TALER_TESTING_Command cmd = { 616 .cls = cs, 617 .label = label, 618 .run = &challenge_answer_run, 619 .cleanup = &challenge_cleanup, 620 .traits = &challenge_create_traits 621 }; 622 623 return cmd; 624 } 625 } 626 627 628 /* end of testing_cmd_challenge_answer.c */