diff --git a/src/exchange/Makefile.am b/src/exchange/Makefile.am index 9d9c454d0..2fc601e77 100644 --- a/src/exchange/Makefile.am +++ b/src/exchange/Makefile.am @@ -89,8 +89,7 @@ taler_exchange_httpd_SOURCES = \ taler-exchange-httpd_terms.c taler-exchange-httpd_terms.h \ taler-exchange-httpd_transfers_get.c taler-exchange-httpd_transfers_get.h \ taler-exchange-httpd_wire.c taler-exchange-httpd_wire.h \ - taler-exchange-httpd_withdraw.c taler-exchange-httpd_withdraw.h \ - taler-exchange-httpd_validation.c taler-exchange-httpd_validation.h + taler-exchange-httpd_withdraw.c taler-exchange-httpd_withdraw.h taler_exchange_httpd_LDADD = \ $(LIBGCRYPT_LIBS) \ $(top_builddir)/src/bank-lib/libtalerbank.la \ diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index eba6e42a1..4095d00fa 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -42,7 +42,6 @@ #include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_wire.h" #include "taler_exchangedb_plugin.h" -#include "taler-exchange-httpd_validation.h" /** @@ -777,10 +776,8 @@ exchange_serve_process_config (void) "Launching exchange with public key `%s'...\n", GNUNET_p2s (&TEH_master_public_key.eddsa_pub)); - if ( (GNUNET_OK != - TEH_VALIDATION_init (TEH_cfg)) || - (GNUNET_OK != - TEH_WIRE_init ()) ) + if (GNUNET_OK != + TEH_WIRE_init (TEH_cfg)) return GNUNET_SYSERR; @@ -789,7 +786,7 @@ exchange_serve_process_config (void) { fprintf (stderr, "Failed to initialize DB subsystem\n"); - TEH_VALIDATION_done (); + TEH_WIRE_done (); return GNUNET_SYSERR; } @@ -800,7 +797,7 @@ exchange_serve_process_config (void) &serve_unixpath, &unixpath_mode)) { - TEH_VALIDATION_done (); + TEH_WIRE_done (); return GNUNET_SYSERR; } return GNUNET_OK; @@ -1311,7 +1308,7 @@ main (int argc, TEH_KS_free (); } TALER_EXCHANGEDB_plugin_unload (TEH_plugin); - TEH_VALIDATION_done (); + TEH_WIRE_done (); return (GNUNET_SYSERR == ret) ? 1 : 0; } diff --git a/src/exchange/taler-exchange-httpd_deposit.c b/src/exchange/taler-exchange-httpd_deposit.c index 02f41bf93..a5fad2647 100644 --- a/src/exchange/taler-exchange-httpd_deposit.c +++ b/src/exchange/taler-exchange-httpd_deposit.c @@ -33,7 +33,6 @@ #include "taler-exchange-httpd_deposit.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" -#include "taler-exchange-httpd_validation.h" /** diff --git a/src/exchange/taler-exchange-httpd_recoup.c b/src/exchange/taler-exchange-httpd_recoup.c index 32bc81986..485e5b411 100644 --- a/src/exchange/taler-exchange-httpd_recoup.c +++ b/src/exchange/taler-exchange-httpd_recoup.c @@ -31,7 +31,6 @@ #include "taler-exchange-httpd_recoup.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" -#include "taler-exchange-httpd_validation.h" /** diff --git a/src/exchange/taler-exchange-httpd_refund.c b/src/exchange/taler-exchange-httpd_refund.c index f8b265c58..d564a3619 100644 --- a/src/exchange/taler-exchange-httpd_refund.c +++ b/src/exchange/taler-exchange-httpd_refund.c @@ -33,7 +33,6 @@ #include "taler-exchange-httpd_refund.h" #include "taler-exchange-httpd_responses.h" #include "taler-exchange-httpd_keystate.h" -#include "taler-exchange-httpd_validation.h" /** diff --git a/src/exchange/taler-exchange-httpd_validation.c b/src/exchange/taler-exchange-httpd_validation.c deleted file mode 100644 index f114607cf..000000000 --- a/src/exchange/taler-exchange-httpd_validation.c +++ /dev/null @@ -1,250 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016-2020 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see -*/ - -/** - * @file taler-exchange-httpd_validation.c - * @brief helpers for getting our wire account information - * @author Christian Grothoff - */ -#include "platform.h" -#include -#include "taler-exchange-httpd.h" -#include "taler-exchange-httpd_validation.h" -#include "taler-exchange-httpd_wire.h" -#include "taler_exchangedb_lib.h" - - -/** - * Array of wire methods supported by this exchange. - */ -static json_t *wire_accounts_array; - -/** - * Object mapping wire methods to the respective fee structure. - */ -static json_t *wire_fee_object; - - -/** - * Load wire fees for @a method. - * - * @param method wire method to load fee structure for - * @return #GNUNET_OK on success - */ -static int -load_fee (const char *method) -{ - json_t *fees; - - if (NULL != json_object_get (wire_fee_object, - method)) - return GNUNET_OK; /* already have them */ - fees = TEH_WIRE_get_fees (method); - if (NULL == fees) - return GNUNET_SYSERR; - /* Add fees to #wire_fee_object */ - if (0 != - json_object_set_new (wire_fee_object, - method, - fees)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Initialize account; checks if @a ai has /wire information, and if so, - * adds the /wire information (if included) to our responses. - * - * @param cls pointer to `int` to set to #GNUNET_SYSERR on errors - * @param ai details about the account we should load the wire details for - */ -static void -load_account (void *cls, - const struct TALER_EXCHANGEDB_AccountInfo *ai) -{ - int *ret = cls; - - if ( (NULL != ai->wire_response_filename) && - (GNUNET_YES == ai->credit_enabled) ) - { - json_t *wire_s; - json_error_t error; - char *url; - char *method; - - if (NULL == (wire_s = json_load_file (ai->wire_response_filename, - JSON_REJECT_DUPLICATES, - &error))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Failed to parse `%s': %s at %d:%d (%d)\n", - ai->wire_response_filename, - error.text, - error.line, - error.column, - error.position); - *ret = GNUNET_SYSERR; - return; - } - if (NULL == (url = TALER_JSON_wire_to_payto (wire_s))) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire response file `%s' lacks `url' entry\n", - ai->wire_response_filename); - json_decref (wire_s); - *ret = GNUNET_SYSERR; - return; - } - if (0 != strcasecmp (url, - ai->payto_uri)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "URL in Wire response file `%s' does not match URL in configuration (%s vs %s)!\n", - ai->wire_response_filename, - url, - ai->payto_uri); - json_decref (wire_s); - GNUNET_free (url); - *ret = GNUNET_SYSERR; - return; - } - GNUNET_free (url); - /* Provide friendly error message if user forgot to sign wire response. */ - if (NULL == json_object_get (wire_s, "master_sig")) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire response file `%s' has not been signed." - " Use taler-exchange-wire to sign it.\n", - ai->wire_response_filename); - json_decref (wire_s); - *ret = GNUNET_SYSERR; - return; - } - if (GNUNET_OK != - TALER_JSON_exchange_wire_signature_check (wire_s, - &TEH_master_public_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid signature in `%s' for public key `%s'\n", - ai->wire_response_filename, - GNUNET_p2s (&TEH_master_public_key.eddsa_pub)); - json_decref (wire_s); - *ret = GNUNET_SYSERR; - return; - } - method = TALER_payto_get_method (ai->payto_uri); - if (GNUNET_OK == - load_fee (method)) - { - GNUNET_assert (-1 != - json_array_append_new (wire_accounts_array, - wire_s)); - } - else - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire fees not specified for `%s'\n", - method); - *ret = GNUNET_SYSERR; - } - GNUNET_free (method); - } - - if (GNUNET_YES == ai->debit_enabled) - { - if (GNUNET_OK != - load_fee (ai->method)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Wire transfer fees for `%s' are not given correctly\n", - ai->method); - *ret = GNUNET_SYSERR; - return; - } - } -} - - -/** - * Initialize validation subsystem. - * - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -int -TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg) -{ - int ret; - - ret = GNUNET_OK; - wire_accounts_array = json_array (); - if (NULL == wire_accounts_array) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - wire_fee_object = json_object (); - if (NULL == wire_fee_object) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - TALER_EXCHANGEDB_find_accounts (cfg, - &load_account, - &ret); - if (GNUNET_OK != ret) - TEH_VALIDATION_done (); - return ret; -} - - -/** - * Shutdown validation subsystem. - */ -void -TEH_VALIDATION_done () -{ - json_decref (wire_fee_object); - wire_fee_object = NULL; - json_decref (wire_accounts_array); - wire_accounts_array = NULL; -} - - -/** - * Obtain JSON response for /wire - * - * @return JSON array with the supported validation methods, NULL on error - */ -json_t * -TEH_VALIDATION_get_wire_response () -{ - if ( (0 == json_array_size (wire_accounts_array)) || - (0 == json_object_size (wire_fee_object)) ) - return NULL; - return json_pack ("{s:O, s:O, s:o}", - "accounts", wire_accounts_array, - "fees", wire_fee_object, - "master_public_key", GNUNET_JSON_from_data_auto ( - &TEH_master_public_key)); -} - - -/* end of taler-exchange-httpd_validation.c */ diff --git a/src/exchange/taler-exchange-httpd_validation.h b/src/exchange/taler-exchange-httpd_validation.h deleted file mode 100644 index 30bc43b77..000000000 --- a/src/exchange/taler-exchange-httpd_validation.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2016 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU Affero General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER 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 Affero General Public License for more details. - - You should have received a copy of the GNU Affero General Public License along with - TALER; see the file COPYING. If not, see -*/ - -/** - * @file taler-exchange-httpd_validation.h - * @brief helpers for calling the wire plugins to validate addresses - * @author Christian Grothoff - */ -#ifndef TALER_EXCHANGE_HTTPD_VALIDATION_H -#define TALER_EXCHANGE_HTTPD_VALIDATION_H -#include -#include - - -/** - * Initialize validation subsystem. - * - * @param cfg configuration to use - * @return #GNUNET_OK on success - */ -int -TEH_VALIDATION_init (const struct GNUNET_CONFIGURATION_Handle *cfg); - - -/** - * Shutdown validation subsystem. - */ -void -TEH_VALIDATION_done (void); - - -/** - * Check if the given wire format JSON object is correctly formatted as - * a wire address. - * - * @param wire the JSON wire format object - * @param[out] emsg set to error message if we return an error code - * @return #TALER_EC_NONE if correctly formatted; otherwise error code - */ -enum TALER_ErrorCode -TEH_json_validate_wireformat (const json_t *wire, - char **emsg); - - -/** - * Obtain JSON response for /wire - * - * @return JSON object with the supported wire transfer options, NULL on error - */ -json_t * -TEH_VALIDATION_get_wire_response (void); - - -#endif diff --git a/src/exchange/taler-exchange-httpd_wire.c b/src/exchange/taler-exchange-httpd_wire.c index 7534e835a..6bd3f2903 100644 --- a/src/exchange/taler-exchange-httpd_wire.c +++ b/src/exchange/taler-exchange-httpd_wire.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2015-2017 Taler Systems SA + Copyright (C) 2015-2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -22,7 +22,6 @@ #include #include "taler-exchange-httpd_keystate.h" #include "taler-exchange-httpd_responses.h" -#include "taler-exchange-httpd_validation.h" #include "taler-exchange-httpd_wire.h" #include "taler_json_lib.h" #include "taler_mhd_lib.h" @@ -33,6 +32,160 @@ */ static json_t *wire_methods; +/** + * Array of wire methods supported by this exchange. + */ +static json_t *wire_accounts_array; + +/** + * Object mapping wire methods to the respective fee structure. + */ +static json_t *wire_fee_object; + + +/** + * Load wire fees for @a method. + * + * @param method wire method to load fee structure for + * @return #GNUNET_OK on success + */ +static int +load_fee (const char *method) +{ + json_t *fees; + + if (NULL != json_object_get (wire_fee_object, + method)) + return GNUNET_OK; /* already have them */ + fees = TEH_WIRE_get_fees (method); + if (NULL == fees) + return GNUNET_SYSERR; + /* Add fees to #wire_fee_object */ + if (0 != + json_object_set_new (wire_fee_object, + method, + fees)) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * Initialize account; checks if @a ai has /wire information, and if so, + * adds the /wire information (if included) to our responses. + * + * @param cls pointer to `int` to set to #GNUNET_SYSERR on errors + * @param ai details about the account we should load the wire details for + */ +static void +load_account (void *cls, + const struct TALER_EXCHANGEDB_AccountInfo *ai) +{ + int *ret = cls; + + if ( (NULL != ai->wire_response_filename) && + (GNUNET_YES == ai->credit_enabled) ) + { + json_t *wire_s; + json_error_t error; + char *url; + char *method; + + if (NULL == (wire_s = json_load_file (ai->wire_response_filename, + JSON_REJECT_DUPLICATES, + &error))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed to parse `%s': %s at %d:%d (%d)\n", + ai->wire_response_filename, + error.text, + error.line, + error.column, + error.position); + *ret = GNUNET_SYSERR; + return; + } + if (NULL == (url = TALER_JSON_wire_to_payto (wire_s))) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire response file `%s' lacks `url' entry\n", + ai->wire_response_filename); + json_decref (wire_s); + *ret = GNUNET_SYSERR; + return; + } + if (0 != strcasecmp (url, + ai->payto_uri)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "URL in Wire response file `%s' does not match URL in configuration (%s vs %s)!\n", + ai->wire_response_filename, + url, + ai->payto_uri); + json_decref (wire_s); + GNUNET_free (url); + *ret = GNUNET_SYSERR; + return; + } + GNUNET_free (url); + /* Provide friendly error message if user forgot to sign wire response. */ + if (NULL == json_object_get (wire_s, "master_sig")) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire response file `%s' has not been signed." + " Use taler-exchange-wire to sign it.\n", + ai->wire_response_filename); + json_decref (wire_s); + *ret = GNUNET_SYSERR; + return; + } + if (GNUNET_OK != + TALER_JSON_exchange_wire_signature_check (wire_s, + &TEH_master_public_key)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Invalid signature in `%s' for public key `%s'\n", + ai->wire_response_filename, + GNUNET_p2s (&TEH_master_public_key.eddsa_pub)); + json_decref (wire_s); + *ret = GNUNET_SYSERR; + return; + } + method = TALER_payto_get_method (ai->payto_uri); + if (GNUNET_OK == + load_fee (method)) + { + GNUNET_assert (-1 != + json_array_append_new (wire_accounts_array, + wire_s)); + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire fees not specified for `%s'\n", + method); + *ret = GNUNET_SYSERR; + } + GNUNET_free (method); + } + + if (GNUNET_YES == ai->debit_enabled) + { + if (GNUNET_OK != + load_fee (ai->method)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Wire transfer fees for `%s' are not given correctly\n", + ai->method); + *ret = GNUNET_SYSERR; + return; + } + } +} + /** * Convert fee structure to JSON result to be returned @@ -151,17 +304,56 @@ TEH_handler_wire (const struct TEH_RequestHandler *rh, /** * Initialize wire subsystem. * + * @param cfg configuration to use * @return #GNUNET_OK on success, #GNUNET_SYSERR if we found no valid * wire methods */ int -TEH_WIRE_init () +TEH_WIRE_init (const struct GNUNET_CONFIGURATION_Handle *cfg) { - wire_methods = TEH_VALIDATION_get_wire_response (); + wire_accounts_array = json_array (); + if (NULL == wire_accounts_array) + { + GNUNET_break (0); + return GNUNET_SYSERR; + } + wire_fee_object = json_object (); + if (NULL == wire_fee_object) + { + GNUNET_break (0); + TEH_WIRE_done (); + return GNUNET_SYSERR; + } + { + int ret; + + ret = GNUNET_OK; + TALER_EXCHANGEDB_find_accounts (cfg, + &load_account, + &ret); + if (GNUNET_OK != ret) + { + TEH_WIRE_done (); + return GNUNET_SYSERR; + } + } + if ( (0 == json_array_size (wire_accounts_array)) || + (0 == json_object_size (wire_fee_object)) ) + { + TEH_WIRE_done (); + return GNUNET_SYSERR; + } + wire_methods = json_pack ("{s:O, s:O, s:o}", + "accounts", wire_accounts_array, + "fees", wire_fee_object, + "master_public_key", + GNUNET_JSON_from_data_auto ( + &TEH_master_public_key)); if (NULL == wire_methods) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to find properly configured wire transfer method\n"); + TEH_WIRE_done (); return GNUNET_SYSERR; } return GNUNET_OK; @@ -171,14 +363,24 @@ TEH_WIRE_init () /** * Clean up wire subsystem. */ -void __attribute__ ((destructor)) -TEH_wire_cleanup () +void +TEH_WIRE_done () { if (NULL != wire_methods) { json_decref (wire_methods); wire_methods = NULL; } + if (NULL != wire_fee_object) + { + json_decref (wire_fee_object); + wire_fee_object = NULL; + } + if (NULL != wire_accounts_array) + { + json_decref (wire_accounts_array); + wire_accounts_array = NULL; + } } diff --git a/src/exchange/taler-exchange-httpd_wire.h b/src/exchange/taler-exchange-httpd_wire.h index b51bfd781..09e6dd53c 100644 --- a/src/exchange/taler-exchange-httpd_wire.h +++ b/src/exchange/taler-exchange-httpd_wire.h @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014, 2015, 2016 Taler Systems SA + Copyright (C) 2014--2020 Taler Systems SA TALER is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software @@ -29,11 +29,19 @@ /** * Initialize wire subsystem. * + * @param cfg configuration to use * @return #GNUNET_OK on success, #GNUNET_SYSERR if we found no valid * wire methods */ int -TEH_WIRE_init (void); +TEH_WIRE_init (const struct GNUNET_CONFIGURATION_Handle *cfg); + + +/** + * Clean up wire subsystem. + */ +void +TEH_WIRE_done (void); /**