testing_cmd_challenge_answer.c (16762B)
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 /* fscanf returns EOF (-1), not 0, on an empty/short file; checking 351 `0 ==` misses that and would use the uninitialized `code` buffer. */ 352 if (1 != fscanf (file, 353 "%21s", 354 code)) 355 { 356 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 357 "fscanf", 358 csr->details.tan_filename); 359 GNUNET_break (0 == fclose (file)); 360 TALER_TESTING_interpreter_fail (cs->is); 361 return; 362 } 363 GNUNET_break (0 == fclose (file)); 364 cs->code = GNUNET_strdup (code); 365 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 366 "Read code `%s'\n", 367 code); 368 } 369 break; 370 case ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED: 371 GNUNET_break (0); /* FIXME: not implemented */ 372 break; 373 case ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT: 374 GNUNET_break (0); /* FIXME: not implemented */ 375 break; 376 case ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED: 377 GNUNET_break (0); /* FIXME: not implemented */ 378 break; 379 case ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED: 380 if (0 != strncmp (csr->details.payment_required.taler_pay_uri, 381 "taler+http://pay/", 382 strlen ("taler+http://pay/"))) 383 { 384 GNUNET_break (0); 385 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 386 "Invalid payment URI `%s'\n", 387 csr->details.payment_required.taler_pay_uri); 388 TALER_TESTING_interpreter_fail (cs->is); 389 return; 390 } 391 cs->payment_uri = GNUNET_strdup ( 392 csr->details.payment_required.taler_pay_uri); 393 { 394 struct TALER_MERCHANT_PayUriData pud; 395 396 if (GNUNET_OK != 397 TALER_MERCHANT_parse_pay_uri (cs->payment_uri, 398 &pud)) 399 { 400 GNUNET_break (0); 401 TALER_TESTING_interpreter_fail (cs->is); 402 return; 403 } 404 cs->order_id = GNUNET_strdup (pud.order_id); 405 if (GNUNET_OK != 406 GNUNET_STRINGS_string_to_data (cs->order_id, 407 strlen (cs->order_id), 408 &cs->payment_order_req, 409 sizeof (cs->payment_order_req))) 410 { 411 GNUNET_break (0); 412 TALER_TESTING_interpreter_fail (cs->is); 413 return; 414 } 415 TALER_MERCHANT_parse_pay_uri_free (&pud); 416 } 417 TALER_TESTING_interpreter_next (cs->is); 418 return; 419 case ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN: 420 break; 421 case ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE: 422 GNUNET_break (0); 423 TALER_TESTING_interpreter_fail (cs->is); 424 return; 425 } 426 TALER_TESTING_interpreter_next (cs->is); 427 } 428 429 430 /** 431 * Run a "recover secret" CMD. 432 * 433 * @param cls closure. 434 * @param cmd command currently being run. 435 * @param is interpreter state. 436 */ 437 static void 438 challenge_start_run (void *cls, 439 const struct TALER_TESTING_Command *cmd, 440 struct TALER_TESTING_Interpreter *is) 441 { 442 struct ChallengeState *cs = cls; 443 const struct ANASTASIS_Challenge **c; 444 const struct ANASTASIS_PaymentSecretP *ps; 445 446 cs->is = is; 447 { 448 const struct TALER_TESTING_Command *ref; 449 450 ref = TALER_TESTING_interpreter_lookup_command ( 451 is, 452 cs->challenge_ref); 453 if (NULL == ref) 454 { 455 GNUNET_break (0); 456 TALER_TESTING_interpreter_fail (cs->is); 457 return; 458 } 459 if (GNUNET_OK != 460 ANASTASIS_TESTING_get_trait_challenges (ref, 461 cs->challenge_index, 462 &c)) 463 { 464 GNUNET_break (0); 465 TALER_TESTING_interpreter_fail (cs->is); 466 return; 467 } 468 } 469 470 if (NULL != cs->payment_ref) 471 { 472 const struct TALER_TESTING_Command *pref; 473 474 pref = TALER_TESTING_interpreter_lookup_command (is, 475 cs->payment_ref); 476 if (NULL == pref) 477 { 478 GNUNET_break (0); 479 TALER_TESTING_interpreter_fail (cs->is); 480 return; 481 } 482 if (GNUNET_OK != 483 ANASTASIS_TESTING_get_trait_payment_secret (pref, 484 &ps)) 485 { 486 GNUNET_break (0); 487 TALER_TESTING_interpreter_fail (cs->is); 488 return; 489 } 490 } 491 else 492 { 493 ps = NULL; 494 } 495 if (GNUNET_OK != 496 ANASTASIS_challenge_start ((struct ANASTASIS_Challenge *) *c, 497 ps, 498 &challenge_start_cb, 499 cs)) 500 { 501 GNUNET_break (0); 502 TALER_TESTING_interpreter_fail (cs->is); 503 return; 504 } 505 } 506 507 508 /** 509 * Free the state of a "recover secret" CMD, and possibly 510 * cancel it if it did not complete. 511 * 512 * @param cls closure. 513 * @param cmd command being freed. 514 */ 515 static void 516 challenge_cleanup (void *cls, 517 const struct TALER_TESTING_Command *cmd) 518 { 519 struct ChallengeState *cs = cls; 520 521 if (NULL != cs->c) 522 { 523 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 524 "Command '%s' did not complete (challenge answer)\n", 525 cmd->label); 526 ANASTASIS_challenge_abort (cs->c); 527 cs->c = NULL; 528 } 529 GNUNET_free (cs->payment_uri); 530 GNUNET_free (cs->order_id); 531 GNUNET_free (cs->code); 532 GNUNET_free (cs); 533 } 534 535 536 /** 537 * Offer internal data to other commands. 538 * 539 * @param cls closure 540 * @param[out] ret result (could be anything) 541 * @param trait name of the trait 542 * @param index index number of the object to extract. 543 * @return #GNUNET_OK on success 544 */ 545 static enum GNUNET_GenericReturnValue 546 challenge_create_traits (void *cls, 547 const void **ret, 548 const char *trait, 549 unsigned int index) 550 { 551 struct ChallengeState *cs = cls; 552 struct TALER_TESTING_Trait traits[] = { 553 ANASTASIS_TESTING_make_trait_code (cs->code), 554 ANASTASIS_TESTING_make_trait_payment_secret ( 555 &cs->payment_order_req), 556 TALER_TESTING_make_trait_taler_uri (cs->payment_uri), 557 TALER_TESTING_make_trait_order_id (cs->order_id), 558 TALER_TESTING_trait_end () 559 }; 560 561 return TALER_TESTING_get_trait (traits, 562 ret, 563 trait, 564 index); 565 } 566 567 568 struct TALER_TESTING_Command 569 ANASTASIS_TESTING_cmd_challenge_start ( 570 const char *label, 571 const char *payment_ref, 572 const char *challenge_ref, 573 unsigned int challenge_index, 574 enum ANASTASIS_ChallengeStartStatus expected_cs) 575 { 576 struct ChallengeState *cs; 577 578 cs = GNUNET_new (struct ChallengeState); 579 cs->expected_scs = expected_cs; 580 cs->challenge_ref = challenge_ref; 581 cs->payment_ref = payment_ref; 582 cs->challenge_index = challenge_index; 583 { 584 struct TALER_TESTING_Command cmd = { 585 .cls = cs, 586 .label = label, 587 .run = &challenge_start_run, 588 .cleanup = &challenge_cleanup, 589 .traits = &challenge_create_traits 590 }; 591 592 return cmd; 593 } 594 } 595 596 597 struct TALER_TESTING_Command 598 ANASTASIS_TESTING_cmd_challenge_answer ( 599 const char *label, 600 const char *payment_ref, 601 const char *challenge_ref, 602 unsigned int challenge_index, 603 const char *answer, 604 unsigned int mode, 605 enum ANASTASIS_ChallengeAnswerStatus expected_cs) 606 { 607 struct ChallengeState *cs; 608 609 cs = GNUNET_new (struct ChallengeState); 610 cs->expected_acs = expected_cs; 611 cs->challenge_ref = challenge_ref; 612 cs->payment_ref = payment_ref; 613 cs->answer = answer; 614 cs->challenge_index = challenge_index; 615 cs->mode = mode; 616 { 617 struct TALER_TESTING_Command cmd = { 618 .cls = cs, 619 .label = label, 620 .run = &challenge_answer_run, 621 .cleanup = &challenge_cleanup, 622 .traits = &challenge_create_traits 623 }; 624 625 return cmd; 626 } 627 } 628 629 630 /* end of testing_cmd_challenge_answer.c */