From 150917694a4dc3709319fc9586e502eb4b05151f Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 30 Jul 2022 22:54:21 +0200 Subject: finish taler-exchange-drain implementation --- src/exchange/taler-exchange-aggregator.c | 6 +- src/exchange/taler-exchange-drain.c | 180 ++++++++++++++++++++++++++++--- src/exchange/taler-exchange-httpd.c | 6 +- src/include/taler_exchangedb_plugin.h | 38 +++++++ 4 files changed, 213 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/exchange/taler-exchange-aggregator.c b/src/exchange/taler-exchange-aggregator.c index 9568f011e..3d30ccd08 100644 --- a/src/exchange/taler-exchange-aggregator.c +++ b/src/exchange/taler-exchange-aggregator.c @@ -234,12 +234,12 @@ shutdown_task (void *cls) /** - * Parse the configuration for wirewatch. + * Parse the configuration for aggregator. * * @return #GNUNET_OK on success */ static enum GNUNET_GenericReturnValue -parse_wirewatch_config (void) +parse_aggregator_config (void) { if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, @@ -811,7 +811,7 @@ run (void *cls, (void) cfgfile; cfg = c; - if (GNUNET_OK != parse_wirewatch_config ()) + if (GNUNET_OK != parse_aggregator_config ()) { cfg = NULL; global_ret = EXIT_NOTCONFIGURED; diff --git a/src/exchange/taler-exchange-drain.c b/src/exchange/taler-exchange-drain.c index 71656412e..d409487c1 100644 --- a/src/exchange/taler-exchange-drain.c +++ b/src/exchange/taler-exchange-drain.c @@ -39,11 +39,21 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; */ static struct TALER_EXCHANGEDB_Plugin *db_plugin; +/** + * Our master public key. + */ +static struct TALER_MasterPublicKeyP master_pub; + /** * Next task to run, if any. */ static struct GNUNET_SCHEDULER_Task *task; +/** + * Base URL of this exchange. + */ +static char *exchange_base_url; + /** * Value to return from main(). 0 on success, non-zero on errors. */ @@ -82,6 +92,47 @@ shutdown_task (void *cls) static enum GNUNET_GenericReturnValue parse_drain_config (void) { + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "BASE_URL", + &exchange_base_url)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "BASE_URL"); + return GNUNET_SYSERR; + } + + { + char *master_public_key_str; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cfg, + "exchange", + "MASTER_PUBLIC_KEY", + &master_public_key_str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "MASTER_PUBLIC_KEY"); + return GNUNET_SYSERR; + } + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_public_key_from_string (master_public_key_str, + strlen ( + master_public_key_str), + &master_pub.eddsa_pub)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "MASTER_PUBLIC_KEY", + "invalid base32 encoding for a master public key"); + GNUNET_free (master_public_key_str); + return GNUNET_SYSERR; + } + GNUNET_free (master_public_key_str); + } if (NULL == (db_plugin = TALER_EXCHANGEDB_plugin_load (cfg))) { @@ -134,6 +185,13 @@ static void run_drain (void *cls) { enum GNUNET_DB_QueryStatus qs; + uint64_t serial; + struct TALER_WireTransferIdentifierRawP wtid; + char *account_section; + char *payto_uri; + struct GNUNET_TIME_Timestamp request_timestamp; + struct TALER_Amount amount; + struct TALER_MasterSignatureP master_sig; (void) cls; task = NULL; @@ -147,11 +205,14 @@ run_drain (void *cls) GNUNET_SCHEDULER_shutdown (); return; } -#if 0 - qs = db_plugin->profit_drains_get_pending (db_plugin->cls); -#else - qs = -1; -#endif + qs = db_plugin->profit_drains_get_pending (db_plugin->cls, + &serial, + &wtid, + &account_section, + &payto_uri, + &request_timestamp, + &amount, + &master_sig); switch (qs) { case GNUNET_DB_STATUS_HARD_ERROR: @@ -161,7 +222,6 @@ run_drain (void *cls) GNUNET_SCHEDULER_shutdown (); return; case GNUNET_DB_STATUS_SOFT_ERROR: - /* try again */ db_plugin->rollback (db_plugin->cls); GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Serialization failure on simple SELECT!?\n"); @@ -169,7 +229,7 @@ run_drain (void *cls) GNUNET_SCHEDULER_shutdown (); return; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - /* no more profit drains, go sleep a bit! */ + /* no profit drains, finished */ db_plugin->rollback (db_plugin->cls); GNUNET_assert (NULL == task); GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, @@ -180,11 +240,107 @@ run_drain (void *cls) /* continued below */ break; } - // FIXME: check signature (again!) - // FIMXE: display for human check - // FIXME: insert into pre-wire - // FIXME: mark as done - // FIXME: commit transaction + report success + exit + /* Check signature (again, this is a critical operation!) */ + if (GNUNET_OK != + TALER_exchange_offline_profit_drain_verify ( + &wtid, + request_timestamp, + &amount, + account_section, + payto_uri, + &master_pub, + &master_sig)) + { + GNUNET_break (0); + global_ret = EXIT_FAILURE; + db_plugin->rollback (db_plugin->cls); + GNUNET_assert (NULL == task); + GNUNET_SCHEDULER_shutdown (); + return; + } + + /* Display data for manual human check */ + fprintf (stdout, + "Critical operation. MANUAL CHECK REQUIRED.\n"); + fprintf (stdout, + "We will wire %s to `%s'\n based on instructions from %s.\n", + TALER_amount2s (&amount), + payto_uri, + GNUNET_TIME_timestamp2s (request_timestamp)); + fprintf (stdout, + "Press ENTER to confirm, CTRL-D to abort.\n"); + while (1) + { + int key; + + key = getchar (); + if (EOF == key) + { + fprintf (stdout, + "Transfer aborted.\n" + "Re-run 'taler-exchange-drain' to try it again.\n" + "Contact Taler Systems SA to cancel it for good.\n" + "Exiting.\n"); + db_plugin->rollback (db_plugin->cls); + GNUNET_assert (NULL == task); + GNUNET_SCHEDULER_shutdown (); + global_ret = EXIT_FAILURE; + return; + } + if ('\n' == key) + break; + } + + /* Note: account_section ignored for now, we + might want to use it here in the future... */ + (void) account_section; + { + char *method; + void *buf; + size_t buf_size; + + TALER_BANK_prepare_transfer (payto_uri, + &amount, + exchange_base_url, + &wtid, + &buf, + &buf_size); + method = TALER_payto_get_method (payto_uri); + qs = db_plugin->wire_prepare_data_insert (db_plugin->cls, + method, + buf, + buf_size); + GNUNET_free (method); + GNUNET_free (buf); + } + qs = db_plugin->profit_drains_set_finished (db_plugin->cls, + serial); + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + db_plugin->rollback (db_plugin->cls); + GNUNET_break (0); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + case GNUNET_DB_STATUS_SOFT_ERROR: + db_plugin->rollback (db_plugin->cls); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Failed: database serialization issue\n"); + global_ret = EXIT_FAILURE; + GNUNET_SCHEDULER_shutdown (); + return; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + db_plugin->rollback (db_plugin->cls); + GNUNET_assert (NULL == task); + GNUNET_break (0); + GNUNET_SCHEDULER_shutdown (); + return; + default: + /* continued below */ + break; + } + /* commit transaction + report success + exit */ if (0 >= commit_or_warn ()) GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Profit drain triggered. Exiting.\n"); diff --git a/src/exchange/taler-exchange-httpd.c b/src/exchange/taler-exchange-httpd.c index 2d659058a..14cc8c1c5 100644 --- a/src/exchange/taler-exchange-httpd.c +++ b/src/exchange/taler-exchange-httpd.c @@ -1836,8 +1836,10 @@ exchange_serve_process_config (void) &TEH_master_public_key. eddsa_pub)) { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Invalid master public key given in exchange configuration."); + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "exchange", + "MASTER_PUBLIC_KEY", + "invalid base32 encoding for a master public key"); GNUNET_free (master_public_key_str); return GNUNET_SYSERR; } diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h index 7f31752df..2ffa84866 100644 --- a/src/include/taler_exchangedb_plugin.h +++ b/src/include/taler_exchangedb_plugin.h @@ -5545,6 +5545,44 @@ struct TALER_EXCHANGEDB_Plugin const struct TALER_MasterSignatureP *master_sig); + /** + * Get profit drain operation ready to execute. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param[out] serial set to serial ID of the entry + * @param[out] wtid set set to wire transfer ID to use + * @param[out] account_section set to account to drain + * @param[out] payto_uri set to account to wire funds to + * @param[out] request_timestamp set to time of the signature + * @param[out] amount set to amount to wire + * @param[out] master_sig set to signature affirming the operation + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*profit_drains_get_pending)( + void *cls, + uint64_t *serial, + struct TALER_WireTransferIdentifierRawP *wtid, + char **account_section, + char **payto_uri, + struct GNUNET_TIME_Timestamp *request_timestamp, + struct TALER_Amount *amount, + struct TALER_MasterSignatureP *master_sig); + + + /** + * Set profit drain operation to finished. + * + * @param cls the @e cls of this struct with the plugin-specific state + * @param serial serial ID of the entry to mark finished + * @return transaction status code + */ + enum GNUNET_DB_QueryStatus + (*profit_drains_set_finished)( + void *cls, + uint64_t serial); + + }; #endif /* _TALER_EXCHANGE_DB_H */ -- cgit v1.2.3