anastasis_authorization_plugin_iban.c (24945B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero 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 Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file anastasis_authorization_plugin_iban.c 18 * @brief authorization plugin wire transfer based 19 * @author Christian Grothoff 20 */ 21 #include "platform.h" 22 #include "anastasis_authorization_plugin.h" 23 #include <taler/taler_mhd_lib.h> 24 #include <taler/taler_json_lib.h> 25 #include <gnunet/gnunet_db_lib.h> 26 #include "anastasis_authorization_lib.h" 27 #include "anastasis_database_lib.h" 28 #include "anastasis_util_lib.h" 29 #include "iban.h" 30 31 /** 32 * How long is a code valid once generated? Very long 33 * here as we do not want to refuse authentication 34 * just because the user took a while to execute the 35 * wire transfer (and then get back to their recovery 36 * operation). 37 */ 38 #define CODE_VALIDITY_PERIOD GNUNET_TIME_UNIT_MONTHS 39 40 41 /** 42 * Saves the State of a authorization plugin. 43 */ 44 struct IBAN_Context 45 { 46 47 /** 48 * Messages of the plugin, read from a resource file. 49 */ 50 json_t *messages; 51 52 /** 53 * IBAN of our business, must be credited in the SEPA 54 * wire transfer. 55 */ 56 char *business_iban; 57 58 /** 59 * Name of our business, for the SEPA wire transfer. 60 */ 61 char *business_name; 62 63 /** 64 * Handle to interact with a authorization backend. 65 */ 66 const struct ANASTASIS_AuthorizationContext *ac; 67 68 /** 69 * Amount we expect to be transferred. 70 */ 71 struct TALER_Amount expected_amount; 72 73 }; 74 75 76 /** 77 * Saves the State of a authorization process 78 */ 79 struct ANASTASIS_AUTHORIZATION_State 80 { 81 /** 82 * Public key of the challenge which is authorised 83 */ 84 struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid; 85 86 /** 87 * Code which is sent to the user (here sent via IBAN) 88 */ 89 uint64_t code; 90 91 /** 92 * Our plugin context. 93 */ 94 struct IBAN_Context *ctx; 95 96 /** 97 * Function to call when we made progress. 98 */ 99 GNUNET_SCHEDULER_TaskCallback trigger; 100 101 /** 102 * Closure for @e trigger. 103 */ 104 void *trigger_cls; 105 106 /** 107 * holds the truth information 108 */ 109 char *iban_number; 110 111 /** 112 * Our client connection, set if suspended. 113 */ 114 struct MHD_Connection *connection; 115 116 /** 117 * Handler for database event we are waiting for. 118 */ 119 struct GNUNET_DB_EventHandler *eh; 120 121 }; 122 123 124 /** 125 * Returned by #get_message() when the configured messages file has no entry 126 * for the requested ID. This is an installation error, but it must not be 127 * allowed to reach GNUNET_asprintf() as a NULL format string. The text 128 * deliberately contains no printf conversions, so substituting it for any 129 * template is safe whatever argument list the caller passes. 130 */ 131 #define MISSING_MESSAGE \ 132 "The provider is misconfigured: a message template is missing." 133 134 135 /** 136 * Obtain internationalized message @a msg_id from @a ctx using 137 * language preferences of @a conn. 138 * 139 * @param messages JSON object to lookup message from 140 * @param conn connection to lookup message for 141 * @param msg_id unique message ID 142 * @return the requested message, or #MISSING_MESSAGE if it was not 143 * configured; never NULL 144 */ 145 static const char * 146 get_message (const json_t *messages, 147 struct MHD_Connection *conn, 148 const char *msg_id) 149 { 150 const char *accept_lang; 151 152 accept_lang = MHD_lookup_connection_value (conn, 153 MHD_HEADER_KIND, 154 MHD_HTTP_HEADER_ACCEPT_LANGUAGE); 155 if (NULL == accept_lang) 156 accept_lang = "en_US"; 157 { 158 const char *ret; 159 struct GNUNET_JSON_Specification spec[] = { 160 TALER_JSON_spec_i18n_string (msg_id, 161 accept_lang, 162 &ret), 163 GNUNET_JSON_spec_end () 164 }; 165 166 if (GNUNET_OK != 167 GNUNET_JSON_parse (messages, 168 spec, 169 NULL, NULL)) 170 { 171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 172 "Message `%s' is missing from the configured messages file\n", 173 msg_id); 174 GNUNET_JSON_parse_free (spec); 175 return MISSING_MESSAGE; 176 } 177 GNUNET_JSON_parse_free (spec); 178 if (NULL == ret) 179 { 180 /* The parser of TALER_JSON_spec_i18n_string returns #GNUNET_OK even 181 when the field is absent or is not a string, in which case it stores 182 NULL; the check above therefore never fires for a missing message and 183 this one is what keeps NULL out of the format argument of the 184 GNUNET_asprintf() calls below. */ 185 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 186 "Message `%s' is missing or not a string in the configured messages file\n", 187 msg_id); 188 return MISSING_MESSAGE; 189 } 190 return ret; 191 } 192 } 193 194 195 /** 196 * Validate @a data is a well-formed input into the challenge method, 197 * i.e. @a data is a well-formed iban number for sending an IBAN, or 198 * a well-formed e-mail address for sending an e-mail. Not expected to 199 * check that the iban number or e-mail account actually exists. 200 * 201 * To be possibly used before issuing a 402 payment required to the client. 202 * 203 * @param cls closure with a `struct IBAN_Context` 204 * @param connection HTTP client request (for queuing response) 205 * @param truth_mime mime type of @e data 206 * @param data input to validate (i.e. is it a valid iban number, etc.) 207 * @param data_length number of bytes in @a data 208 * @return #GNUNET_OK if @a data is valid, 209 * #GNUNET_NO if @a data is invalid and a reply was successfully queued on @a connection 210 * #GNUNET_SYSERR if @a data invalid but we failed to queue a reply on @a connection 211 */ 212 static enum GNUNET_GenericReturnValue 213 iban_validate (void *cls, 214 struct MHD_Connection *connection, 215 const char *truth_mime, 216 const char *data, 217 size_t data_length) 218 { 219 char *iban_number; 220 char *emsg; 221 222 iban_number = GNUNET_strndup (data, 223 data_length); 224 emsg = TALER_iban_validate (iban_number); 225 if (NULL != emsg) 226 { 227 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 228 "Invalid IBAN `%s' provided: %s\n", 229 iban_number, 230 emsg); 231 GNUNET_free (iban_number); 232 if (MHD_NO == 233 TALER_MHD_reply_with_error (connection, 234 MHD_HTTP_CONFLICT, 235 TALER_EC_ANASTASIS_IBAN_INVALID, 236 emsg)) 237 { 238 GNUNET_free (emsg); 239 return GNUNET_SYSERR; 240 } 241 GNUNET_free (emsg); 242 return GNUNET_NO; 243 } 244 GNUNET_free (iban_number); 245 return GNUNET_OK; 246 } 247 248 249 /** 250 * Begin issuing authentication challenge to user based on @a data. 251 * Sends IBAN. 252 * 253 * @param cls closure with a `struct IBAN_Context` 254 * @param trigger function to call when we made progress 255 * @param trigger_cls closure for @a trigger 256 * @param truth_uuid Identifier of the challenge, to be (if possible) included in the 257 * interaction with the user 258 * @param code secret code that the user has to provide back to satisfy the challenge in 259 * the main anastasis protocol 260 * @param data input to validate (i.e. is it a valid iban number, etc.) 261 * @param data_length number of bytes in @a data 262 * @return state to track progress on the authorization operation, NULL on failure 263 */ 264 static struct ANASTASIS_AUTHORIZATION_State * 265 iban_start (void *cls, 266 GNUNET_SCHEDULER_TaskCallback trigger, 267 void *trigger_cls, 268 const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, 269 uint64_t code, 270 const void *data, 271 size_t data_length) 272 { 273 struct IBAN_Context *ctx = cls; 274 struct ANASTASIS_AUTHORIZATION_State *as; 275 276 as = GNUNET_new (struct ANASTASIS_AUTHORIZATION_State); 277 as->trigger = trigger; 278 as->trigger_cls = trigger_cls; 279 as->ctx = ctx; 280 as->truth_uuid = *truth_uuid; 281 as->code = code; 282 as->iban_number = GNUNET_strndup (data, 283 data_length); 284 return as; 285 } 286 287 288 /** 289 * Function called when we received a wire transfer 290 * with the respective code from the specified IBAN. 291 * 292 * @param cls our `struct ANASTASIS_AUHTORIZATION_State` 293 * @param extra string describing amount transferred 294 * @param extra_size number of byes in @a extra 295 */ 296 static void 297 bank_event_cb (void *cls, 298 const void *extra, 299 size_t extra_size) 300 { 301 struct ANASTASIS_AUTHORIZATION_State *as = cls; 302 char *amount_s; 303 304 if (NULL != extra) 305 { 306 struct TALER_Amount amount; 307 308 /* The amount is only carried for diagnostics: the authoritative value is 309 re-read from the database by #check_payment_ok(), so we must not keep 310 (or act on) whatever the notification claims. */ 311 amount_s = GNUNET_strndup (extra, 312 extra_size); 313 if (GNUNET_OK != 314 TALER_string_to_amount (amount_s, 315 &amount)) 316 { 317 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 318 "Expected amount in event notification, got `%s'\n", 319 amount_s); 320 } 321 GNUNET_free (amount_s); 322 } 323 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 324 "IBAN event triggers resumption of request handling\n"); 325 MHD_resume_connection (as->connection); 326 as->trigger (as->trigger_cls); 327 } 328 329 330 #include "iban.c" 331 332 333 /** 334 * Check if the @a wire_subject matches the challenge in the context 335 * and if the @a amount is sufficient. If so, return true. 336 * 337 * @param cls a `const struct ANASTASIS_AUTHORIZATION_State *` 338 * @param amount the amount that was transferred 339 * @param wire_subject a wire subject we received 340 * @return true if the wire transfer satisfied the check 341 */ 342 static bool 343 check_payment_ok (void *cls, 344 const struct TALER_Amount *amount, 345 const char *wire_subject) 346 { 347 const struct ANASTASIS_AUTHORIZATION_State *as = cls; 348 struct IBAN_Context *ctx = as->ctx; 349 uint64_t code; 350 351 if (GNUNET_OK != 352 extract_code (wire_subject, 353 &code)) 354 return false; 355 /* The database stamps every row with the currency configured for this 356 provider, so a mismatch here means the plugin was configured for a 357 different currency than the rest of the service. Refusing is the only 358 safe answer: comparing the magnitudes across currencies would let a 359 transfer of "5 XYZ" authorize a challenge that costs 5 EUR. */ 360 if (GNUNET_YES != 361 TALER_amount_cmp_currency (amount, 362 &ctx->expected_amount)) 363 { 364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 365 "Received `%s', but [authorization-iban]/COST is denominated in `%s'\n", 366 amount->currency, 367 ctx->expected_amount.currency); 368 return false; 369 } 370 if (1 == 371 TALER_amount_cmp (&ctx->expected_amount, 372 amount)) 373 { 374 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 375 "Amount `%s' insufficient for authorization\n", 376 TALER_amount2s (amount)); 377 return false; 378 } 379 return (code == as->code); 380 } 381 382 383 /** 384 * Check if we have received a wire transfer with a subject 385 * authorizing the disclosure of the credential in the meantime. 386 * 387 * @param as state to check for 388 * @return WTS_SUCCESS if a transfer was received, 389 * WTS_NOT_READY if no transfer was received, 390 * WTS_FAILED_WITH_REPLY if we had an internal error and queued a reply 391 * WTS_FAILED_WITHOUT_REPLY if we had an internal error and failed to queue a reply 392 */ 393 static enum 394 { 395 WTS_SUCCESS, 396 WTS_NOT_READY, 397 WTS_FAILED_WITH_REPLY, 398 WTS_FAILED_WITHOUT_REPLY 399 } 400 test_wire_transfers (struct ANASTASIS_AUTHORIZATION_State *as) 401 { 402 enum GNUNET_DB_QueryStatus qs; 403 struct GNUNET_TIME_Absolute now; 404 struct GNUNET_TIME_Timestamp limit; 405 406 now = GNUNET_TIME_absolute_get (); 407 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 408 "Testing for wire transfers\n"); 409 limit = GNUNET_TIME_absolute_to_timestamp ( 410 GNUNET_TIME_absolute_subtract (now, 411 CODE_VALIDITY_PERIOD)); 412 qs = ANASTASIS_DB_iterate_auth_iban_transfers ( 413 as->iban_number, 414 limit, 415 &check_payment_ok, 416 as); 417 switch (qs) 418 { 419 case GNUNET_DB_STATUS_HARD_ERROR: 420 case GNUNET_DB_STATUS_SOFT_ERROR: 421 return (MHD_YES == 422 TALER_MHD_reply_with_error (as->connection, 423 MHD_HTTP_INTERNAL_SERVER_ERROR, 424 TALER_EC_GENERIC_DB_FETCH_FAILED, 425 NULL)) 426 ? WTS_FAILED_WITH_REPLY 427 : WTS_FAILED_WITHOUT_REPLY; 428 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 429 return WTS_NOT_READY; 430 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 431 break; 432 } 433 qs = ANASTASIS_DB_update_to_challenge_code_satisfied ( 434 &as->truth_uuid, 435 as->code); 436 GNUNET_break (qs > 0); 437 return WTS_SUCCESS; 438 } 439 440 441 /** 442 * Respond with instructions to the user how to 443 * satisfy the challenge. 444 * 445 * @param as authorization state 446 * @param connection HTTP client request (for queuing response, such as redirection to video portal) 447 * @return state of the request 448 */ 449 static enum ANASTASIS_AUTHORIZATION_ChallengeResult 450 iban_challenge (struct ANASTASIS_AUTHORIZATION_State *as, 451 struct MHD_Connection *connection) 452 { 453 struct IBAN_Context *ctx = as->ctx; 454 const char *mime; 455 const char *lang; 456 enum MHD_Result mres; 457 458 mime = MHD_lookup_connection_value (connection, 459 MHD_HEADER_KIND, 460 MHD_HTTP_HEADER_ACCEPT); 461 if (NULL == mime) 462 mime = "text/plain"; 463 lang = MHD_lookup_connection_value (connection, 464 MHD_HEADER_KIND, 465 MHD_HTTP_HEADER_ACCEPT_LANGUAGE); 466 if (NULL == lang) 467 lang = "en"; 468 469 /* Build HTTP response */ 470 { 471 struct MHD_Response *resp; 472 473 if (0.0 < TALER_pattern_matches (mime, 474 "application/json")) 475 { 476 char subject[64]; 477 478 GNUNET_snprintf (subject, 479 sizeof (subject), 480 "Anastasis %llu", 481 (unsigned long long) as->code); 482 resp = TALER_MHD_MAKE_JSON_PACK ( 483 GNUNET_JSON_pack_string ("challenge_type", 484 "IBAN_WIRE"), 485 GNUNET_JSON_pack_object_steal ( 486 "wire_details", 487 GNUNET_JSON_PACK ( 488 GNUNET_JSON_pack_uint64 ( 489 "answer_code", 490 as->code), 491 TALER_JSON_pack_amount ( 492 "challenge_amount", 493 &ctx->expected_amount), 494 GNUNET_JSON_pack_string ( 495 "credit_iban", 496 ctx->business_iban), 497 GNUNET_JSON_pack_string ( 498 "business_name", 499 ctx->business_name), 500 GNUNET_JSON_pack_string ( 501 "wire_transfer_subject", 502 subject)))); 503 } 504 else 505 { 506 size_t reply_len; 507 char *reply; 508 509 reply_len = GNUNET_asprintf (&reply, 510 get_message (ctx->messages, 511 connection, 512 "instructions"), 513 TALER_amount2s (&ctx->expected_amount), 514 ctx->business_name, 515 ctx->business_iban, 516 (unsigned long long) as->code); 517 resp = MHD_create_response_from_buffer (reply_len, 518 reply, 519 MHD_RESPMEM_MUST_COPY); 520 GNUNET_free (reply); 521 TALER_MHD_add_global_headers (resp, 522 false); 523 GNUNET_break (MHD_YES == 524 MHD_add_response_header (resp, 525 MHD_HTTP_HEADER_CONTENT_TYPE, 526 "text/plain")); 527 } 528 mres = MHD_queue_response (connection, 529 MHD_HTTP_OK, 530 resp); 531 MHD_destroy_response (resp); 532 if (MHD_YES != mres) 533 return ANASTASIS_AUTHORIZATION_CRES_SUCCESS_REPLY_FAILED; 534 return ANASTASIS_AUTHORIZATION_CRES_SUCCESS; 535 } 536 } 537 538 539 /** 540 * Begin issuing authentication challenge to user based on @a data. 541 * I.e. start to send IBAN or e-mail or launch video identification. 542 * 543 * @param as authorization state 544 * @param timeout how long do we have to produce a reply 545 * @param challenge_response hash of the challenge response, or NULL 546 * @param connection HTTP client request (for queuing response, such as redirection to video portal) 547 * @return state of the request 548 */ 549 static enum ANASTASIS_AUTHORIZATION_SolveResult 550 iban_solve (struct ANASTASIS_AUTHORIZATION_State *as, 551 struct GNUNET_TIME_Absolute timeout, 552 const struct GNUNET_HashCode *challenge_response, 553 struct MHD_Connection *connection) 554 { 555 enum MHD_Result mres; 556 enum GNUNET_DB_QueryStatus qs; 557 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); 558 struct GNUNET_TIME_Timestamp after; 559 560 if (NULL == as->eh) 561 { 562 struct IbanEventP espec = { 563 .header.size = htons (sizeof (espec)), 564 .header.type = htons (TALER_DBEVENT_ANASTASIS_AUTH_IBAN_TRANSFER), 565 .code = GNUNET_htonll (as->code) 566 }; 567 568 GNUNET_CRYPTO_hash (as->iban_number, 569 strlen (as->iban_number), 570 &espec.debit_iban_hash); 571 as->eh = ANASTASIS_DB_event_listen ( 572 &espec.header, 573 GNUNET_TIME_absolute_get_remaining ( 574 timeout), 575 &bank_event_cb, 576 as); 577 } 578 after = GNUNET_TIME_absolute_to_timestamp ( 579 GNUNET_TIME_absolute_subtract (now, 580 CODE_VALIDITY_PERIOD)); 581 qs = ANASTASIS_DB_get_exists_challenge_code_satisfied ( 582 &as->truth_uuid, 583 as->code, 584 after); 585 switch (qs) 586 { 587 case GNUNET_DB_STATUS_HARD_ERROR: 588 case GNUNET_DB_STATUS_SOFT_ERROR: 589 mres = TALER_MHD_reply_with_error (connection, 590 MHD_HTTP_INTERNAL_SERVER_ERROR, 591 TALER_EC_GENERIC_DB_FETCH_FAILED, 592 "get exists challenge code satisfied"); 593 if (MHD_YES != mres) 594 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 595 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 596 case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: 597 switch (test_wire_transfers (as)) 598 { 599 case WTS_SUCCESS: 600 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 601 "IBAN authorization finished!\n"); 602 return ANASTASIS_AUTHORIZATION_SRES_FINISHED; 603 case WTS_NOT_READY: 604 break; /* continue below */ 605 case WTS_FAILED_WITH_REPLY: 606 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 607 case WTS_FAILED_WITHOUT_REPLY: 608 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 609 } 610 if (GNUNET_TIME_absolute_is_future (timeout)) 611 { 612 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 613 "Suspending IBAN check until %s\n", 614 GNUNET_TIME_absolute2s (timeout)); 615 as->connection = connection; 616 MHD_suspend_connection (connection); 617 return ANASTASIS_AUTHORIZATION_SRES_SUSPENDED; 618 } 619 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 620 "Timeout reached at %s, failing request\n", 621 GNUNET_TIME_absolute2s (timeout)); 622 mres = TALER_MHD_reply_with_error (connection, 623 MHD_HTTP_FORBIDDEN, 624 TALER_EC_ANASTASIS_IBAN_MISSING_TRANSFER, 625 NULL); 626 if (MHD_YES != mres) 627 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 628 return ANASTASIS_AUTHORIZATION_SRES_FAILED; 629 case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: 630 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 631 "IBAN authorization finished!\n"); 632 return ANASTASIS_AUTHORIZATION_SRES_FINISHED; 633 } 634 /* should be impossible */ 635 GNUNET_break (0); 636 return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; 637 } 638 639 640 /** 641 * Free internal state associated with @a as. 642 * 643 * @param as state to clean up 644 */ 645 static void 646 iban_cleanup (struct ANASTASIS_AUTHORIZATION_State *as) 647 { 648 if (NULL != as->eh) 649 { 650 ANASTASIS_DB_event_listen_cancel (as->eh); 651 as->eh = NULL; 652 } 653 GNUNET_free (as->iban_number); 654 GNUNET_free (as); 655 } 656 657 658 /** 659 * Initialize email based authorization plugin 660 * 661 * @param cls a `struct ANASTASIS_AuthorizationContext` 662 * @return NULL on error, otherwise a `struct ANASTASIS_AuthorizationPlugin` 663 */ 664 void * 665 libanastasis_plugin_authorization_iban_init (void *cls); 666 667 /* declaration to fix compiler warning */ 668 void * 669 libanastasis_plugin_authorization_iban_init (void *cls) 670 { 671 struct ANASTASIS_AuthorizationContext *ac = cls; 672 struct ANASTASIS_AuthorizationPlugin *plugin; 673 const struct GNUNET_CONFIGURATION_Handle *cfg = ac->cfg; 674 struct IBAN_Context *ctx; 675 676 ctx = GNUNET_new (struct IBAN_Context); 677 if (GNUNET_OK != 678 GNUNET_CONFIGURATION_get_value_string (cfg, 679 "authorization-iban", 680 "CREDIT_IBAN", 681 &ctx->business_iban)) 682 { 683 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 684 "authorization-iban", 685 "CREDIT_IBAN"); 686 GNUNET_free (ctx); 687 return NULL; 688 } 689 if (GNUNET_OK != 690 TALER_config_get_amount (cfg, 691 "authorization-iban", 692 "COST", 693 &ctx->expected_amount)) 694 { 695 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 696 "authorization-iban", 697 "COST"); 698 GNUNET_free (ctx); 699 return NULL; 700 } 701 if (GNUNET_OK != 702 GNUNET_CONFIGURATION_get_value_string (cfg, 703 "authorization-iban", 704 "BUSINESS_NAME", 705 &ctx->business_name)) 706 { 707 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 708 "authorization-iban", 709 "BUSINESS_NAME"); 710 GNUNET_free (ctx->business_iban); 711 GNUNET_free (ctx); 712 return NULL; 713 } 714 { 715 char *fn; 716 json_error_t err; 717 char *tmp; 718 719 tmp = GNUNET_OS_installation_get_path (ANASTASIS_project_data (), 720 GNUNET_OS_IPK_DATADIR); 721 GNUNET_asprintf (&fn, 722 "%sauthorization-iban-messages.json", 723 tmp); 724 GNUNET_free (tmp); 725 ctx->messages = json_load_file (fn, 726 JSON_REJECT_DUPLICATES, 727 &err); 728 if (NULL == ctx->messages) 729 { 730 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 731 "Failed to load messages from `%s': %s at %d:%d\n", 732 fn, 733 err.text, 734 err.line, 735 err.column); 736 GNUNET_free (ctx->business_iban); 737 GNUNET_free (ctx->business_name); 738 GNUNET_free (fn); 739 GNUNET_free (ctx); 740 return NULL; 741 } 742 GNUNET_free (fn); 743 } 744 ctx->ac = ac; 745 plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); 746 plugin->payment_plugin_managed = true; 747 plugin->retry_counter = UINT32_MAX; /* long polling */ 748 plugin->code_validity_period = CODE_VALIDITY_PERIOD; 749 plugin->code_rotation_period = GNUNET_TIME_UNIT_ZERO; 750 plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_ZERO; /* not applicable */ 751 plugin->cls = ctx; 752 plugin->validate = &iban_validate; 753 plugin->start = &iban_start; 754 plugin->challenge = &iban_challenge; 755 plugin->solve = &iban_solve; 756 plugin->cleanup = &iban_cleanup; 757 return plugin; 758 } 759 760 761 /** 762 * Unload authorization plugin 763 * 764 * @param cls a `struct ANASTASIS_AuthorizationPlugin` 765 * @return NULL (always) 766 */ 767 void * 768 libanastasis_plugin_authorization_iban_done (void *cls); 769 770 /* declaration to fix compiler warning */ 771 void * 772 libanastasis_plugin_authorization_iban_done (void *cls) 773 { 774 struct ANASTASIS_AuthorizationPlugin *plugin = cls; 775 struct IBAN_Context *ctx = plugin->cls; 776 777 json_decref (ctx->messages); 778 GNUNET_free (ctx->business_iban); 779 GNUNET_free (ctx->business_name); 780 GNUNET_free (ctx); 781 GNUNET_free (plugin); 782 return NULL; 783 }