donau

Donation authority for GNU Taler (experimental)
Log | Files | Refs | Submodules | README | LICENSE

commit b5b231dca72b8d6768025b05dae1a455f6f559f0
parent 3ae949a93460b2df1b9809874b210161075675b0
Author: Casaburi Johannes <johannes.casaburi@students.bfh.ch>
Date:   Tue,  2 Jan 2024 16:22:23 +0100

cleanup

Diffstat:
Msrc/donau/donau-httpd.c | 30------------------------------
Msrc/donau/donau-httpd.h | 23-----------------------
Dsrc/donau/donau-httpd_batch-submit_receipts.c | 716-------------------------------------------------------------------------------
Dsrc/donau/donau-httpd_batch-submit_receipts.h | 49-------------------------------------------------
Dsrc/donau/donau-httpd_charities_get.c | 274-------------------------------------------------------------------------------
Dsrc/donau/donau-httpd_charities_get.h | 53-----------------------------------------------------
Dsrc/donau/donau-httpd_charities_history.c | 295-------------------------------------------------------------------------------
Dsrc/donau/donau-httpd_charities_history.h | 42------------------------------------------
Dsrc/donau/donau-httpd_charities_open.c | 468-------------------------------------------------------------------------------
Dsrc/donau/donau-httpd_charities_open.h | 41-----------------------------------------
Dsrc/donau/donau-httpd_charities_status.c | 243-------------------------------------------------------------------------------
Dsrc/donau/donau-httpd_charities_status.h | 43-------------------------------------------
Msrc/donau/donau-httpd_csr.c | 14+++++++-------
Msrc/donau/donau-httpd_csr.h | 4++--
Msrc/donau/donau-httpd_db.c | 3---
Msrc/donau/donau-httpd_keys.c | 1382-------------------------------------------------------------------------------
Msrc/donau/donau-httpd_keys.h | 194-------------------------------------------------------------------------------
Msrc/lib/Makefile.am | 37+++++++++++++++++--------------------
Dsrc/lib/donau_api_charities_close.c | 84-------------------------------------------------------------------------------
Dsrc/lib/donau_api_charities_get.c | 266-------------------------------------------------------------------------------
Dsrc/lib/donau_api_charities_history.c | 363-------------------------------------------------------------------------------
Dsrc/lib/donau_api_charities_open.c | 61-------------------------------------------------------------
Dsrc/lib/donau_api_charities_status.c | 336-------------------------------------------------------------------------------
Dsrc/lib/donau_api_csr_issue_receipts.c | 279-------------------------------------------------------------------------------
Dsrc/lib/donau_api_issue_receipts.c | 265-------------------------------------------------------------------------------
Dsrc/lib/donau_api_issue_receipts2.c | 498-------------------------------------------------------------------------------
26 files changed, 26 insertions(+), 6037 deletions(-)

diff --git a/src/donau/donau-httpd.c b/src/donau/donau-httpd.c @@ -80,22 +80,12 @@ static struct MHD_Daemon *mhd; struct GNUNET_TIME_Relative DH_max_keys_caching; /** - * How long is the delay before we close reserves? - */ -struct GNUNET_TIME_Relative DH_reserve_closing_delay; - -/** * Master public key (according to the * configuration in the donau directory). (global) */ struct TALER_MasterPublicKeyP DH_master_public_key; /** - * Key used to encrypt KYC attribute data in our database. - */ -// struct TALER_AttributeEncryptionKeyP DH_attribute_key; - -/** * Our DB plugin. (global) */ struct DONAUDB_Plugin *DH_plugin; @@ -127,16 +117,6 @@ unsigned int DH_currency_fraction_digits; char *DH_currency; /** - * Name of the KYC-AML-trigger evaluation binary. - */ -char *DH_kyc_aml_trigger; - -/** - * Option set to #GNUNET_YES if rewards are enabled. - */ -// int DH_enable_rewards; - -/** * What is the largest amount we allow a peer to * merge into a reserve before always triggering * an AML check? @@ -159,11 +139,6 @@ static unsigned int connection_timeout = 30; static int connection_close; /** - * -I command-line flag given? - */ -int DH_check_invariants_flag; - -/** * True if we should commit suicide once all active * connections are finished. */ @@ -248,11 +223,8 @@ handle_mhd_completion_callback (void *cls, return; GNUNET_async_scope_enter (&rc->async_scope_id, &old_scope); - // check_suicide (); - // DH_check_invariants (); if (NULL != rc->rh_cleaner) rc->rh_cleaner (rc); - // DH_check_invariants (); { #if MHD_VERSION >= 0x00097304 const union MHD_ConnectionInfo *ci; @@ -475,7 +447,6 @@ handle_mhd_request (void *cls, rc = *con_cls = GNUNET_new (struct DH_RequestContext); rc->start_time = GNUNET_TIME_absolute_get (); GNUNET_async_scope_fresh (&rc->async_scope_id); - // DH_check_invariants (); rc->url = url; rc->connection = connection; /* We only read the correlation ID on the first callback for every client */ @@ -502,7 +473,6 @@ handle_mhd_request (void *cls, GNUNET_async_scope_enter (&rc->async_scope_id, &old_scope); - // DH_check_invariants (); if (NULL != correlation_id) GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Handling request (%s) for URL '%s', correlation_id=%s\n", diff --git a/src/donau/donau-httpd.h b/src/donau/donau-httpd.h @@ -45,24 +45,6 @@ extern const struct GNUNET_CONFIGURATION_Handle *DH_cfg; extern char *DH_donau_directory; /** - * -I command-line flag given? - */ -extern int DH_check_invariants_flag; - -/** - * Are clients allowed to request /keys for times other than the - * current time? Allowing this could be abused in a DoS-attack - * as building new /keys responses is expensive. Should only be - * enabled for testcases, development and test systems. - */ -// extern int DH_allow_keys_timetravel; - -/** - * Main directory with data. - */ -// extern char *DH_revocation_directory; - -/** * True if we should commit suicide once all active * connections are finished. Also forces /keys requests * to terminate if they are long-polling. @@ -70,11 +52,6 @@ extern int DH_check_invariants_flag; extern bool DH_suicide; /** - * Key used to encrypt KYC attribute data in our database. - */ -extern struct TALER_AttributeEncryptionKeyP DH_attribute_key; - -/** * Our DB plugin. */ extern struct DONAUDB_Plugin *DH_plugin; diff --git a/src/donau/donau-httpd_batch-submit_receipts.c b/src/donau/donau-httpd_batch-submit_receipts.c @@ -1,716 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file donau-httpd_batch-submit_receipts.c - * @brief Handle /batch-deposit requests; parses the POST and JSON and - * verifies the coin signatures before handing things off - * to the database. - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <jansson.h> -#include <microhttpd.h> -#include <pthread.h> -#include "taler/taler_json_lib.h" -#include "taler/taler_mhd_lib.h" -#include "taler-donau-httpd_batch-deposit.h" -#include "taler-donau-httpd_responses.h" -#include "taler_donaudb_lib.h" -#include "taler-donau-httpd_keys.h" - - -/** - * Closure for #batch_deposit_transaction. - */ -struct BatchDepositContext -{ - - /** - * Array with the individual coin deposit fees. - */ - struct TALER_Amount *deposit_fees; - - /** - * Our timestamp (when we received the request). - * Possibly updated by the transaction if the - * request is idempotent (was repeated). - */ - struct GNUNET_TIME_Timestamp donau_timestamp; - - /** - * Details about the batch deposit operation. - */ - struct DONAUDB_BatchDeposit bd; - - /** - * Additional details for policy extension relevant for this - * deposit operation, possibly NULL! - */ - json_t *policy_json; - - /** - * Hash over the charity's payto://-URI with the wire salt. - */ - struct TALER_CharityWireHashP h_wire; - - /** - * If @e policy_json was present, the corresponding policy extension - * calculates these details. These will be persisted in the policy_details - * table. - */ - struct TALER_PolicyDetails policy_details; - - /** - * Hash over @e policy_details, might be all zero - */ - struct TALER_ExtensionPolicyHashP h_policy; - - /** - * When @e policy_details are persisted, this contains the id of the record - * in the policy_details table. - */ - uint64_t policy_details_serial_id; - -}; - - -/** - * Send confirmation of batch deposit success to client. This function will - * create a signed message affirming the given information and return it to - * the client. By this, the donau affirms that the coins had sufficient - * (residual) value for the specified transaction and that it will execute the - * requested batch deposit operation with the given wiring details. - * - * @param connection connection to the client - * @param dc information about the batch deposit - * @return MHD result code - */ -static MHD_RESULT -reply_batch_deposit_success ( - struct MHD_Connection *connection, - const struct BatchDepositContext *dc) -{ - const struct DONAUDB_BatchDeposit *bd = &dc->bd; - json_t *arr; - struct DONAU_DonauPublicKeyP pub; - -again: - arr = json_array (); - GNUNET_assert (NULL != arr); - for (unsigned int i = 0; i<bd->num_cdis; i++) - { - const struct DONAUDB_CoinDepositInformation *cdi - = &bd->cdis[i]; - struct DONAU_DonauPublicKeyP pubi; - struct TALER_DonauSignatureP sig; - enum TALER_ErrorCode ec; - struct TALER_Amount amount_without_fee; - - GNUNET_assert (0 <= - TALER_amount_subtract (&amount_without_fee, - &cdi->amount_with_fee, - &dc->deposit_fees[i])); - if (TALER_EC_NONE != - (ec = TALER_donau_online_deposit_confirmation_sign ( - &DH_keys_donau_sign_, - &bd->h_contract_terms, - &dc->h_wire, - NULL != dc->policy_json ? &dc->h_policy : NULL, - dc->donau_timestamp, - bd->wire_deadline, - bd->refund_deadline, - &amount_without_fee, - &cdi->coin.coin_pub, - &dc->bd.charity_pub, - &pubi, - &sig))) - { - GNUNET_break (0); - return TALER_MHD_reply_with_ec (connection, - ec, - NULL); - } - if (0 == i) - pub = pubi; - if (0 != - GNUNET_memcmp (&pub, - &pubi)) - { - /* note: in the future, maybe have batch sign API to avoid having to - handle key rollover... */ - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Donau public key changed during batch deposit, trying again\n"); - json_decref (arr); - goto again; - } - GNUNET_assert ( - 0 == - json_array_append_new (arr, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ( - "donau_sig", - &sig)))); - } - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - GNUNET_JSON_pack_timestamp ("donau_timestamp", - dc->donau_timestamp), - GNUNET_JSON_pack_data_auto ("donau_pub", - &pub), - GNUNET_JSON_pack_array_steal ("donau_sigs", - arr)); -} - - -/** - * Execute database transaction for /batch-deposit. Runs the transaction - * logic; IF it returns a non-error code, the transaction logic MUST - * NOT queue a MHD response. IF it returns an hard error, the - * transaction logic MUST queue a MHD response and set @a mhd_ret. IF - * it returns the soft error code, the function MAY be called again to - * retry and MUST not queue a MHD response. - * - * @param cls a `struct BatchDepositContext` - * @param connection MHD request context - * @param[out] mhd_ret set to MHD status on error - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -batch_deposit_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct BatchDepositContext *dc = cls; - const struct DONAUDB_BatchDeposit *bd = &dc->bd; - enum GNUNET_DB_QueryStatus qs = GNUNET_SYSERR; - uint32_t bad_balance_coin_index = UINT32_MAX; - bool balance_ok; - bool in_conflict; - - /* If the deposit has a policy associated to it, persist it. This will - * insert or update the record. */ - if (NULL != dc->policy_json) - { - qs = DH_plugin->persist_policy_details ( - DH_plugin->cls, - &dc->policy_details, - &dc->bd.policy_details_serial_id, - &dc->policy_details.accumulated_total, - &dc->policy_details.fulfillment_state); - if (qs < 0) - return qs; - /* FIXME-Oec: dc->bd.policy_blocked not initialized, - likely should be set based on fulfillment_state!?*/ - } - - /* FIXME: replace by batch insert! */ - for (unsigned int i = 0; i<bd->num_cdis; i++) - { - const struct DONAUDB_CoinDepositInformation *cdi - = &bd->cdis[i]; - uint64_t known_coin_id; - - qs = DH_make_coin_known (&cdi->coin, - connection, - &known_coin_id, - mhd_ret); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "make coin known (%s) returned %d\n", - TALER_B2S (&cdi->coin.coin_pub), - qs); - if (qs < 0) - return qs; - } - - qs = DH_plugin->do_deposit ( - DH_plugin->cls, - bd, - &dc->donau_timestamp, - &balance_ok, - &bad_balance_coin_index, - &in_conflict); - if (qs < 0) - { - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - return qs; - TALER_LOG_WARNING ( - "Failed to store /batch-deposit information in database\n"); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "batch-deposit"); - return qs; - } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "do_deposit returned: %d / %s[%u] / %s\n", - qs, - balance_ok ? "balance ok" : "balance insufficient", - (unsigned int) bad_balance_coin_index, - in_conflict ? "in conflict" : "no conflict"); - if (in_conflict) - { - /* FIXME: #7267 conflicting contract != insufficient funds */ - *mhd_ret - = DH_RESPONSE_reply_coin_insufficient_funds ( - connection, - TALER_EC_DONAU_DEPOSIT_CONFLICTING_CONTRACT, - &bd->cdis[0 /* SEE FIXME above! */].coin.denom_pub_hash, - &bd->cdis[0 /* SEE FIXME above! */].coin.coin_pub); - return GNUNET_DB_STATUS_HARD_ERROR; - } - if (! balance_ok) - { - GNUNET_assert (bad_balance_coin_index < bd->num_cdis); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "returning history of conflicting coin (%s)\n", - TALER_B2S (&bd->cdis[bad_balance_coin_index].coin.coin_pub)); - *mhd_ret - = DH_RESPONSE_reply_coin_insufficient_funds ( - connection, - TALER_EC_DONAU_GENERIC_INSUFFICIENT_FUNDS, - &bd->cdis[bad_balance_coin_index].coin.denom_pub_hash, - &bd->cdis[bad_balance_coin_index].coin.coin_pub); - return GNUNET_DB_STATUS_HARD_ERROR; - } - DH_METRICS_num_success[DH_MT_SUCCESS_DEPOSIT]++; - return qs; -} - - -/** - * Parse per-coin deposit information from @a jcoin - * into @a deposit. Fill in generic information from - * @a ctx. - * - * @param connection connection we are handling - * @param dc information about the overall batch - * @param jcoin coin data to parse - * @param[out] cdi where to store the result - * @param[out] deposit_fee where to write the deposit fee - * @return #GNUNET_OK on success, #GNUNET_NO if an error was returned, - * #GNUNET_SYSERR on failure and no error could be returned - */ -static enum GNUNET_GenericReturnValue -parse_coin (struct MHD_Connection *connection, - const struct BatchDepositContext *dc, - json_t *jcoin, - struct DONAUDB_CoinDepositInformation *cdi, - struct TALER_Amount *deposit_fee) -{ - const struct DONAUDB_BatchDeposit *bd = &dc->bd; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount ("contribution", - DH_currency, - &cdi->amount_with_fee), - GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", - &cdi->coin.denom_pub_hash), - TALER_JSON_spec_denom_sig ("ub_sig", - &cdi->coin.denom_sig), - GNUNET_JSON_spec_fixed_auto ("coin_pub", - &cdi->coin.coin_pub), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("h_age_commitment", - &cdi->coin.h_age_commitment), - &cdi->coin.no_age_commitment), - GNUNET_JSON_spec_fixed_auto ("coin_sig", - &cdi->csig), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - if (GNUNET_OK != - (res = TALER_MHD_parse_json_data (connection, - jcoin, - spec))) - return res; - /* check denomination exists and is valid */ - { - struct DH_DenominationKey *dk; - MHD_RESULT mret; - - dk = DH_keys_denomination_by_hash (&cdi->coin.denom_pub_hash, - connection, - &mret); - if (NULL == dk) - { - GNUNET_JSON_parse_free (spec); - return mret; - } - if (0 > TALER_amount_cmp (&dk->meta.value, - &cdi->amount_with_fee)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_GENERIC_AMOUNT_EXCEEDS_DENOMINATION_VALUE, - NULL)) - ? GNUNET_NO - : GNUNET_SYSERR; - } - if (GNUNET_TIME_absolute_is_past (dk->meta.expire_deposit.abs_time)) - { - /* This denomination is past the expiration time for deposits */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - DH_RESPONSE_reply_expired_denom_pub_hash ( - connection, - &cdi->coin.denom_pub_hash, - TALER_EC_DONAU_GENERIC_DENOMINATION_EXPIRED, - "DEPOSIT")) - ? GNUNET_NO - : GNUNET_SYSERR; - } - if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time)) - { - /* This denomination is not yet valid */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - DH_RESPONSE_reply_expired_denom_pub_hash ( - connection, - &cdi->coin.denom_pub_hash, - TALER_EC_DONAU_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE, - "DEPOSIT")) - ? GNUNET_NO - : GNUNET_SYSERR; - } - if (dk->denom_pub.cipher != cdi->coin.denom_sig.cipher) - { - /* denomination cipher and denomination signature cipher not the same */ - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_GENERIC_CIPHER_MISMATCH, - NULL)) - ? GNUNET_NO - : GNUNET_SYSERR; - } - - *deposit_fee = dk->meta.fees.deposit; - /* check coin signature */ - switch (dk->denom_pub.cipher) - { - case TALER_DENOMINATION_RSA: - DH_METRICS_num_verifications[DH_MT_SIGNATURE_RSA]++; - break; - case TALER_DENOMINATION_CS: - DH_METRICS_num_verifications[DH_MT_SIGNATURE_CS]++; - break; - default: - break; - } - if (GNUNET_YES != - TALER_test_coin_valid (&cdi->coin, - &dk->denom_pub)) - { - TALER_LOG_WARNING ("Invalid coin passed for /batch-deposit\n"); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_DENOMINATION_SIGNATURE_INVALID, - NULL)) - ? GNUNET_NO - : GNUNET_SYSERR; - } - } - if (0 < TALER_amount_cmp (deposit_fee, - &cdi->amount_with_fee)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_DEPOSIT_NEGATIVE_VALUE_AFTER_FEE, - NULL)) - ? GNUNET_NO - : GNUNET_SYSERR; - } - - DH_METRICS_num_verifications[DH_MT_SIGNATURE_EDDSA]++; - if (GNUNET_OK != - TALER_wallet_deposit_verify ( - &cdi->amount_with_fee, - deposit_fee, - &dc->h_wire, - &bd->h_contract_terms, - &bd->wallet_data_hash, - NULL != cdi->coin.no_age_commitment - ? NULL - : &cdi->coin.h_age_commitment, - NULL != dc->policy_json ? &dc->h_policy : NULL, - &cdi->coin.denom_pub_hash, - bd->wallet_timestamp, - &bd->charity_pub, - bd->refund_deadline, - &cdi->coin.coin_pub, - &cdi->csig)) - { - TALER_LOG_WARNING ("Invalid signature on /batch-deposit request\n"); - GNUNET_JSON_parse_free (spec); - return (MHD_YES == - TALER_MHD_reply_with_error (connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_DEPOSIT_COIN_SIGNATURE_INVALID, - TALER_B2S (&cdi->coin.coin_pub))) - ? GNUNET_NO - : GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -MHD_RESULT -DH_handler_batch_deposit (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]) -{ - struct MHD_Connection *connection = rc->connection; - struct BatchDepositContext dc = { 0 }; - struct DONAUDB_BatchDeposit *bd = &dc.bd; - const json_t *coins; - bool no_refund_deadline = true; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_string ("charity_payto_uri", - &bd->receiver_wire_account), - GNUNET_JSON_spec_fixed_auto ("wire_salt", - &bd->wire_salt), - GNUNET_JSON_spec_fixed_auto ("charity_pub", - &bd->charity_pub), - GNUNET_JSON_spec_fixed_auto ("h_contract_terms", - &bd->h_contract_terms), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_fixed_auto ("wallet_data_hash", - &bd->wallet_data_hash), - &bd->no_wallet_data_hash), - GNUNET_JSON_spec_array_const ("coins", - &coins), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_json ("policy", - &dc.policy_json), - NULL), - GNUNET_JSON_spec_timestamp ("timestamp", - &bd->wallet_timestamp), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_timestamp ("refund_deadline", - &bd->refund_deadline), - &no_refund_deadline), - GNUNET_JSON_spec_timestamp ("wire_transfer_deadline", - &bd->wire_deadline), - GNUNET_JSON_spec_end () - }; - enum GNUNET_GenericReturnValue res; - - (void) args; - res = TALER_MHD_parse_json_data (connection, - root, - spec); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - - /* validate charity's wire details (as far as we can) */ - { - char *emsg; - - emsg = TALER_payto_validate (bd->receiver_wire_account); - if (NULL != emsg) - { - MHD_RESULT ret; - - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - emsg); - GNUNET_free (emsg); - return ret; - } - } - if (GNUNET_TIME_timestamp_cmp (bd->refund_deadline, - >, - bd->wire_deadline)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_DEPOSIT_REFUND_DEADLINE_AFTER_WIRE_DEADLINE, - NULL); - } - if (GNUNET_TIME_absolute_is_never (bd->wire_deadline.abs_time)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_DEPOSIT_WIRE_DEADLINE_IS_NEVER, - NULL); - } - TALER_payto_hash (bd->receiver_wire_account, - &bd->wire_target_h_payto); - TALER_charity_wire_signature_hash (bd->receiver_wire_account, - &bd->wire_salt, - &dc.h_wire); - - /* handle policy, if present */ - if (NULL != dc.policy_json) - { - const char *error_hint = NULL; - - if (GNUNET_OK != - TALER_extensions_create_policy_details ( - dc.policy_json, - &dc.policy_details, - &error_hint)) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_DEPOSITS_POLICY_NOT_ACCEPTED, - error_hint); - - TALER_deposit_policy_hash (dc.policy_json, - &dc.h_policy); - } - - bd->num_cdis = json_array_size (coins); - if (0 == bd->num_cdis) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "coins"); - } - if (TALER_MAX_FRESH_COINS < bd->num_cdis) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "coins"); - } - - { - struct DONAUDB_CoinDepositInformation cdis[ - GNUNET_NZL (bd->num_cdis)]; - struct TALER_Amount deposit_fees[GNUNET_NZL (bd->num_cdis)]; - - bd->cdis = cdis; - dc.deposit_fees = deposit_fees; - for (unsigned int i = 0; i<bd->num_cdis; i++) - { - do { - res = parse_coin (connection, - &dc, - json_array_get (coins, - i), - &cdis[i], - &deposit_fees[i]); - if (GNUNET_OK != res) - break; - - /* If applicable, accumulate all contributions into the policy_details */ - if (NULL != dc.policy_json) - { - /* FIXME: how do deposit-fee and policy-fee interact? */ - struct TALER_Amount amount_without_fee; - - // FIXME-Oec: wrong enum type for 'res' here! - res = TALER_amount_subtract (&amount_without_fee, - &cdis[i].amount_with_fee, - &deposit_fees[i]); - // FIXME-Oec: rval of res not checked - res = TALER_amount_add ( - &dc.policy_details.accumulated_total, - &dc.policy_details.accumulated_total, - &amount_without_fee); - } - } while(0); - - if (GNUNET_OK != res) - { - for (unsigned int j = 0; j<i; j++) - TALER_denom_sig_free (&cdis[j].coin.denom_sig); - GNUNET_JSON_parse_free (spec); - return (GNUNET_NO == res) ? MHD_YES : MHD_NO; - } - } - - dc.donau_timestamp = GNUNET_TIME_timestamp_get (); - if (GNUNET_SYSERR == - DH_plugin->preflight (DH_plugin->cls)) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_START_FAILED, - "preflight failure"); - } - - /* execute transaction */ - { - MHD_RESULT mhd_ret; - - if (GNUNET_OK != - DH_DB_run_transaction (connection, - "execute batch deposit", - DH_MT_REQUEST_BATCH_DEPOSIT, - &mhd_ret, - &batch_deposit_transaction, - &dc)) - { - for (unsigned int j = 0; j<bd->num_cdis; j++) - TALER_denom_sig_free (&cdis[j].coin.denom_sig); - GNUNET_JSON_parse_free (spec); - return mhd_ret; - } - } - - /* generate regular response */ - { - MHD_RESULT res; - - res = reply_batch_deposit_success (connection, - &dc); - for (unsigned int j = 0; j<bd->num_cdis; j++) - TALER_denom_sig_free (&cdis[j].coin.denom_sig); - GNUNET_JSON_parse_free (spec); - return res; - } - } -} - - -/* end of donau-httpd_batch-submit_receipts.c */ diff --git a/src/donau/donau-httpd_batch-submit_receipts.h b/src/donau/donau-httpd_batch-submit_receipts.h @@ -1,49 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_batch-deposit.h - * @brief Handle /batch-deposit requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef DONAU_HTTPD_BATCH_DEPOSIT_H -#define DONAU_HTTPD_BATCH_DEPOSIT_H - -#include <gnunet/gnunet_util_lib.h> -#include <microhttpd.h> -#include "taler-donau-httpd.h" - - -/** - * Handle a "/batch-deposit" request. Parses the JSON, and, if - * successful, passes the JSON data to #deposit_transaction() to - * further check the details of the operation specified. If everything checks - * out, this will ultimately lead to the "/batch-deposit" being executed, or - * rejected. - * - * @param rc request context - * @param root uploaded JSON data - * @param args arguments, empty in this case - * @return MHD result code - */ -MHD_RESULT -DH_handler_batch_deposit (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]); - - -#endif diff --git a/src/donau/donau-httpd_charities_get.c b/src/donau/donau-httpd_charities_get.c @@ -1,274 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_get.c - * @brief Handle /reserves/$RESERVE_PUB GET requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler/taler_mhd_lib.h" -#include "taler/taler_json_lib.h" -#include "taler_dbevents.h" -#include "taler-donau-httpd_keys.h" -#include "taler-donau-httpd_reserves_get.h" -#include "taler-donau-httpd_responses.h" - - -/** - * Reserve GET request that is long-polling. - */ -struct ReservePoller -{ - /** - * Kept in a DLL. - */ - struct ReservePoller *next; - - /** - * Kept in a DLL. - */ - struct ReservePoller *prev; - - /** - * Connection we are handling. - */ - struct MHD_Connection *connection; - - /** - * Our request context. - */ - struct DH_RequestContext *rc; - - /** - * Subscription for the database event we are waiting for. - */ - struct GNUNET_DB_EventHandler *eh; - - /** - * When will this request time out? - */ - struct GNUNET_TIME_Absolute timeout; - - /** - * Public key of the reserve the inquiry is about. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Balance of the reserve, set in the callback. - */ - struct TALER_Amount balance; - - /** - * True if we are still suspended. - */ - bool suspended; - -}; - - -/** - * Head of list of requests in long polling. - */ -static struct ReservePoller *rp_head; - -/** - * Tail of list of requests in long polling. - */ -static struct ReservePoller *rp_tail; - - -void -DH_reserves_get_cleanup () -{ - for (struct ReservePoller *rp = rp_head; - NULL != rp; - rp = rp->next) - { - if (rp->suspended) - { - rp->suspended = false; - MHD_resume_connection (rp->connection); - } - } -} - - -/** - * Function called once a connection is done to - * clean up the `struct ReservePoller` state. - * - * @param rc context to clean up for - */ -static void -rp_cleanup (struct DH_RequestContext *rc) -{ - struct ReservePoller *rp = rc->rh_ctx; - - GNUNET_assert (! rp->suspended); - if (NULL != rp->eh) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Cancelling DB event listening on cleanup (odd unless during shutdown)\n"); - DH_plugin->event_listen_cancel (DH_plugin->cls, - rp->eh); - rp->eh = NULL; - } - GNUNET_CONTAINER_DLL_remove (rp_head, - rp_tail, - rp); - GNUNET_free (rp); -} - - -/** - * Function called on events received from Postgres. - * Wakes up long pollers. - * - * @param cls the `struct DH_RequestContext *` - * @param extra additional event data provided - * @param extra_size number of bytes in @a extra - */ -static void -db_event_cb (void *cls, - const void *extra, - size_t extra_size) -{ - struct ReservePoller *rp = cls; - struct GNUNET_AsyncScopeSave old_scope; - - (void) extra; - (void) extra_size; - if (! rp->suspended) - return; /* might get multiple wake-up events */ - GNUNET_async_scope_enter (&rp->rc->async_scope_id, - &old_scope); - DH_check_invariants (); - rp->suspended = false; - MHD_resume_connection (rp->connection); - TALER_MHD_daemon_trigger (); - DH_check_invariants (); - GNUNET_async_scope_restore (&old_scope); -} - - -MHD_RESULT -DH_handler_reserves_get (struct DH_RequestContext *rc, - const char *const args[1]) -{ - struct ReservePoller *rp = rc->rh_ctx; - - if (NULL == rp) - { - rp = GNUNET_new (struct ReservePoller); - rp->connection = rc->connection; - rp->rc = rc; - rc->rh_ctx = rp; - rc->rh_cleaner = &rp_cleanup; - GNUNET_CONTAINER_DLL_insert (rp_head, - rp_tail, - rp); - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (args[0], - strlen (args[0]), - &rp->reserve_pub, - sizeof (rp->reserve_pub))) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_RESERVE_PUB_MALFORMED, - args[0]); - } - TALER_MHD_parse_request_timeout (rc->connection, - &rp->timeout); - } - - if ( (GNUNET_TIME_absolute_is_future (rp->timeout)) && - (NULL == rp->eh) ) - { - struct TALER_ReserveEventP rep = { - .header.size = htons (sizeof (rep)), - .header.type = htons (TALER_DBEVENT_DONAU_RESERVE_INCOMING), - .reserve_pub = rp->reserve_pub - }; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Starting DB event listening until %s\n", - GNUNET_TIME_absolute2s (rp->timeout)); - rp->eh = DH_plugin->event_listen ( - DH_plugin->cls, - GNUNET_TIME_absolute_get_remaining (rp->timeout), - &rep.header, - &db_event_cb, - rp); - } - { - enum GNUNET_DB_QueryStatus qs; - - qs = DH_plugin->get_reserve_balance (DH_plugin->cls, - &rp->reserve_pub, - &rp->balance); - switch (qs) - { - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); /* single-shot query should never have soft-errors */ - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_SOFT_FAILURE, - "get_reserve_balance"); - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Got reserve balance of %s\n", - TALER_amount2s (&rp->balance)); - return TALER_MHD_REPLY_JSON_PACK (rc->connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rp->balance)); - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - if (! GNUNET_TIME_absolute_is_future (rp->timeout)) - { - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_RESERVES_STATUS_UNKNOWN, - args[0]); - } - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Long-polling on reserve for %s\n", - GNUNET_STRINGS_relative_time_to_string ( - GNUNET_TIME_absolute_get_remaining (rp->timeout), - true)); - rp->suspended = true; - MHD_suspend_connection (rc->connection); - return MHD_YES; - } - } - GNUNET_break (0); - return MHD_NO; -} - - -/* end of taler-donau-httpd_reserves_get.c */ diff --git a/src/donau/donau-httpd_charities_get.h b/src/donau/donau-httpd_charities_get.h @@ -1,53 +0,0 @@ -/* - This file is part of TALER - 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 - 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_get.h - * @brief Handle /reserves/$RESERVE_PUB GET requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef DONAU_HTTPD_RESERVES_GET_H -#define DONAU_HTTPD_RESERVES_GET_H - -#include <microhttpd.h> -#include "taler-donau-httpd.h" - - -/** - * Shutdown reserves-get subsystem. Resumes all - * suspended long-polling clients and cleans up - * data structures. - */ -void -DH_reserves_get_cleanup (void); - - -/** - * Handle a GET "/reserves/" request. Parses the - * given "reserve_pub" in @a args (which should contain the - * EdDSA public key of a reserve) and then respond with the - * status of the reserve. - * - * @param rc request context - * @param args array of additional options (length: 1, just the reserve_pub) - * @return MHD result code - */ -MHD_RESULT -DH_handler_reserves_get (struct DH_RequestContext *rc, - const char *const args[1]); - -#endif diff --git a/src/donau/donau-httpd_charities_history.c b/src/donau/donau-httpd_charities_history.c @@ -1,295 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_history.c - * @brief Handle /reserves/$RESERVE_PUB/history requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler/taler_mhd_lib.h" -#include "taler/taler_json_lib.h" -#include "taler_dbevents.h" -#include "taler-donau-httpd_keys.h" -#include "taler-donau-httpd_reserves_history.h" -#include "taler-donau-httpd_responses.h" - - -/** - * How far do we allow a client's time to be off when - * checking the request timestamp? - */ -#define TIMESTAMP_TOLERANCE \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) - - -/** - * Closure for #reserve_history_transaction. - */ -struct ReserveHistoryContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - const struct TALER_ReservePublicKeyP *reserve_pub; - - /** - * Timestamp of the request. - */ - struct GNUNET_TIME_Timestamp timestamp; - - /** - * Client signature approving the request. - */ - struct TALER_ReserveSignatureP reserve_sig; - - /** - * History of the reserve, set in the callback. - */ - struct DONAUDB_ReserveHistory *rh; - - /** - * Global fees applying to the request. - */ - const struct DH_GlobalFee *gf; - - /** - * Current reserve balance. - */ - struct TALER_Amount balance; -}; - - -/** - * Send reserve history to client. - * - * @param connection connection to the client - * @param rhc reserve history to return - * @return MHD result code - */ -static MHD_RESULT -reply_reserve_history_success (struct MHD_Connection *connection, - const struct ReserveHistoryContext *rhc) -{ - const struct DONAUDB_ReserveHistory *rh = rhc->rh; - json_t *json_history; - - json_history = DH_RESPONSE_compile_reserve_history (rh); - if (NULL == json_history) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, - NULL); - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rhc->balance), - GNUNET_JSON_pack_array_steal ("history", - json_history)); -} - - -/** - * Function implementing /reserves/$RID/history transaction. Given the public - * key of a reserve, return the associated transaction history. Runs the - * transaction logic; IF it returns a non-error code, the transaction logic - * MUST NOT queue a MHD response. IF it returns an hard error, the - * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it - * returns the soft error code, the function MAY be called again to retry and - * MUST not queue a MHD response. - * - * @param cls a `struct ReserveHistoryContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!); unused - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_history_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveHistoryContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - if (! TALER_amount_is_zero (&rsc->gf->fees.history)) - { - bool balance_ok = false; - bool idempotent = true; - - qs = DH_plugin->insert_history_request (DH_plugin->cls, - rsc->reserve_pub, - &rsc->reserve_sig, - rsc->timestamp, - &rsc->gf->fees.history, - &balance_ok, - &idempotent); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_history"); - } - if (qs <= 0) - { - GNUNET_break (GNUNET_DB_STATUS_SOFT_ERROR == qs); - return qs; - } - if (! balance_ok) - { - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_CONFLICT, - TALER_EC_DONAU_GET_RESERVE_HISTORY_ERROR_INSUFFICIENT_BALANCE, - NULL); - } - if (idempotent) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Idempotent /reserves/history request observed. Is caching working?\n"); - } - } - qs = DH_plugin->get_reserve_history (DH_plugin->cls, - rsc->reserve_pub, - &rsc->balance, - &rsc->rh); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_history"); - } - return qs; -} - - -MHD_RESULT -DH_handler_reserves_history (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root) -{ - struct ReserveHistoryContext rsc; - MHD_RESULT mhd_ret; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("request_timestamp", - &rsc.timestamp), - GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &rsc.reserve_sig), - GNUNET_JSON_spec_end () - }; - struct GNUNET_TIME_Timestamp now; - - rsc.reserve_pub = reserve_pub; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - now = GNUNET_TIME_timestamp_get (); - if (! GNUNET_TIME_absolute_approx_eq (now.abs_time, - rsc.timestamp.abs_time, - TIMESTAMP_TOLERANCE)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_GENERIC_CLOCK_SKEW, - NULL); - } - { - struct DH_KeyStateHandle *keys; - - keys = DH_keys_get_state (); - if (NULL == keys) - { - GNUNET_break (0); - GNUNET_JSON_parse_free (spec); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_DONAU_GENERIC_KEYS_MISSING, - NULL); - } - rsc.gf = DH_keys_global_fee_by_time (keys, - rsc.timestamp); - } - if (NULL == rsc.gf) - { - GNUNET_break (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_DONAU_GENERIC_BAD_CONFIGURATION, - NULL); - } - if (GNUNET_OK != - TALER_wallet_reserve_history_verify (rsc.timestamp, - &rsc.gf->fees.history, - reserve_pub, - &rsc.reserve_sig)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_RESERVES_HISTORY_BAD_SIGNATURE, - NULL); - } - rsc.rh = NULL; - if (GNUNET_OK != - DH_DB_run_transaction (rc->connection, - "get reserve history", - DH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_history_transaction, - &rsc)) - { - return mhd_ret; - } - if (NULL == rsc.rh) - { - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_RESERVES_STATUS_UNKNOWN, - NULL); - } - mhd_ret = reply_reserve_history_success (rc->connection, - &rsc); - DH_plugin->free_reserve_history (DH_plugin->cls, - rsc.rh); - return mhd_ret; -} - - -/* end of taler-donau-httpd_reserves_history.c */ diff --git a/src/donau/donau-httpd_charities_history.h b/src/donau/donau-httpd_charities_history.h @@ -1,42 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_history.h - * @brief Handle /reserves/$RESERVE_PUB/history requests - * @author Florian Dold - * @author Christian Grothoff - */ -#ifndef DONAU_HTTPD_RESERVES_HISTORY_H -#define DONAU_HTTPD_RESERVES_HISTORY_H - -#include <microhttpd.h> -#include "taler-donau-httpd.h" - - -/** - * Handle a POST "/reserves/$RID/history" request. - * - * @param rc request context - * @param reserve_pub public key of the reserve - * @param root uploaded body from the client - * @return MHD result code - */ -MHD_RESULT -DH_handler_reserves_history (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root); - -#endif diff --git a/src/donau/donau-httpd_charities_open.c b/src/donau/donau-httpd_charities_open.c @@ -1,468 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_open.c - * @brief Handle /reserves/$RESERVE_PUB/open requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler/taler_mhd_lib.h" -#include "taler/taler_json_lib.h" -#include "taler_dbevents.h" -#include "taler-donau-httpd_common_deposit.h" -#include "taler-donau-httpd_keys.h" -#include "taler-donau-httpd_reserves_open.h" -#include "taler-donau-httpd_responses.h" - - -/** - * How far do we allow a client's time to be off when - * checking the request timestamp? - */ -#define TIMESTAMP_TOLERANCE \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) - - -/** - * Closure for #reserve_open_transaction. - */ -struct ReserveOpenContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - const struct TALER_ReservePublicKeyP *reserve_pub; - - /** - * Desired (minimum) expiration time for the reserve. - */ - struct GNUNET_TIME_Timestamp desired_expiration; - - /** - * Actual expiration time for the reserve. - */ - struct GNUNET_TIME_Timestamp reserve_expiration; - - /** - * Timestamp of the request. - */ - struct GNUNET_TIME_Timestamp timestamp; - - /** - * Client signature approving the request. - */ - struct TALER_ReserveSignatureP reserve_sig; - - /** - * Global fees applying to the request. - */ - const struct DH_GlobalFee *gf; - - /** - * Amount to be paid from the reserve. - */ - struct TALER_Amount reserve_payment; - - /** - * Actual cost to open the reserve. - */ - struct TALER_Amount open_cost; - - /** - * Total amount that was deposited. - */ - struct TALER_Amount total; - - /** - * Information about payments by coin. - */ - struct DH_PurseDepositedCoin *payments; - - /** - * Length of the @e payments array. - */ - unsigned int payments_len; - - /** - * Desired minimum purse limit. - */ - uint32_t purse_limit; - - /** - * Set to true if the reserve balance is too low - * for the operation. - */ - bool no_funds; - -}; - - -/** - * Send reserve open to client. - * - * @param connection connection to the client - * @param rsc reserve open data to return - * @return MHD result code - */ -static MHD_RESULT -reply_reserve_open_success (struct MHD_Connection *connection, - const struct ReserveOpenContext *rsc) -{ - struct GNUNET_TIME_Timestamp now; - struct GNUNET_TIME_Timestamp re; - unsigned int status; - - status = MHD_HTTP_OK; - if (GNUNET_TIME_timestamp_cmp (rsc->reserve_expiration, - <, - rsc->desired_expiration)) - status = MHD_HTTP_PAYMENT_REQUIRED; - now = GNUNET_TIME_timestamp_get (); - if (GNUNET_TIME_timestamp_cmp (rsc->reserve_expiration, - <, - now)) - re = now; - else - re = rsc->reserve_expiration; - return TALER_MHD_REPLY_JSON_PACK ( - connection, - status, - GNUNET_JSON_pack_timestamp ("reserve_expiration", - re), - TALER_JSON_pack_amount ("open_cost", - &rsc->open_cost)); -} - - -/** - * Cleans up information in @a rsc, but does not - * free @a rsc itself (allocated on the stack!). - * - * @param[in] rsc struct with information to clean up - */ -static void -cleanup_rsc (struct ReserveOpenContext *rsc) -{ - for (unsigned int i = 0; i<rsc->payments_len; i++) - { - DH_common_purse_deposit_free_coin (&rsc->payments[i]); - } - GNUNET_free (rsc->payments); -} - - -/** - * Function implementing /reserves/$RID/open transaction. Given the public - * key of a reserve, return the associated transaction open. Runs the - * transaction logic; IF it returns a non-error code, the transaction logic - * MUST NOT queue a MHD response. IF it returns an hard error, the - * transaction logic MUST queue a MHD response and set @a mhd_ret. IF it - * returns the soft error code, the function MAY be called again to retry and - * MUST not queue a MHD response. - * - * @param cls a `struct ReserveOpenContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!) - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_open_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveOpenContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - for (unsigned int i = 0; i<rsc->payments_len; i++) - { - struct DH_PurseDepositedCoin *coin = &rsc->payments[i]; - bool insufficient_funds = true; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Make coin %u known\n", - i); - qs = DH_make_coin_known (&coin->cpi, - connection, - &coin->known_coin_id, - mhd_ret); - if (qs < 0) - return qs; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Insert open deposit %u known\n", - i); - qs = DH_plugin->insert_reserve_open_deposit ( - DH_plugin->cls, - &coin->cpi, - &coin->coin_sig, - coin->known_coin_id, - &coin->amount, - &rsc->reserve_sig, - rsc->reserve_pub, - &insufficient_funds); - /* 0 == qs is fine, then the coin was already - spent for this very operation as identified - by reserve_sig! */ - if (qs < 0) - { - if (GNUNET_DB_STATUS_SOFT_ERROR == qs) - return qs; - GNUNET_break (0); - *mhd_ret = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_STORE_FAILED, - "insert_reserve_open_deposit"); - return qs; - } - if (insufficient_funds) - { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Handle insufficient funds\n"); - *mhd_ret - = DH_RESPONSE_reply_coin_insufficient_funds ( - connection, - TALER_EC_DONAU_GENERIC_INSUFFICIENT_FUNDS, - &coin->cpi.denom_pub_hash, - &coin->cpi.coin_pub); - return GNUNET_DB_STATUS_HARD_ERROR; - } - } - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Do reserve open with reserve payment of %s\n", - TALER_amount2s (&rsc->total)); - qs = DH_plugin->do_reserve_open (DH_plugin->cls, - /* inputs */ - rsc->reserve_pub, - &rsc->total, - &rsc->reserve_payment, - rsc->purse_limit, - &rsc->reserve_sig, - rsc->desired_expiration, - rsc->timestamp, - &rsc->gf->fees.account, - /* outputs */ - &rsc->no_funds, - &rsc->open_cost, - &rsc->reserve_expiration); - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "do_reserve_open"); - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SOFT_ERROR: - return qs; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_GENERIC_RESERVE_UNKNOWN, - NULL); - return GNUNET_DB_STATUS_HARD_ERROR; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - break; - } - if (rsc->no_funds) - { - DH_plugin->rollback (DH_plugin->cls); - *mhd_ret - = DH_RESPONSE_reply_reserve_insufficient_balance ( - connection, - TALER_EC_DONAU_RESERVES_OPEN_INSUFFICIENT_FUNDS, - &rsc->reserve_payment, - rsc->reserve_pub); - return GNUNET_DB_STATUS_HARD_ERROR; - } - return qs; -} - - -MHD_RESULT -DH_handler_reserves_open (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root) -{ - struct ReserveOpenContext rsc; - const json_t *payments; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("request_timestamp", - &rsc.timestamp), - GNUNET_JSON_spec_timestamp ("reserve_expiration", - &rsc.desired_expiration), - GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &rsc.reserve_sig), - GNUNET_JSON_spec_uint32 ("purse_limit", - &rsc.purse_limit), - GNUNET_JSON_spec_array_const ("payments", - &payments), - TALER_JSON_spec_amount ("reserve_payment", - DH_currency, - &rsc.reserve_payment), - GNUNET_JSON_spec_end () - }; - - rsc.reserve_pub = reserve_pub; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - - { - struct GNUNET_TIME_Timestamp now; - - now = GNUNET_TIME_timestamp_get (); - if (! GNUNET_TIME_absolute_approx_eq (now.abs_time, - rsc.timestamp.abs_time, - TIMESTAMP_TOLERANCE)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_GENERIC_CLOCK_SKEW, - NULL); - } - } - - rsc.payments_len = json_array_size (payments); - rsc.payments = GNUNET_new_array (rsc.payments_len, - struct DH_PurseDepositedCoin); - rsc.total = rsc.reserve_payment; - for (unsigned int i = 0; i<rsc.payments_len; i++) - { - struct DH_PurseDepositedCoin *coin = &rsc.payments[i]; - enum GNUNET_GenericReturnValue res; - - res = DH_common_purse_deposit_parse_coin ( - rc->connection, - coin, - json_array_get (payments, - i)); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - cleanup_rsc (&rsc); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - cleanup_rsc (&rsc); - return MHD_YES; /* failure */ - } - if (0 > - TALER_amount_add (&rsc.total, - &rsc.total, - &coin->amount_minus_fee)) - { - GNUNET_break (0); - cleanup_rsc (&rsc); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_FAILED_COMPUTE_AMOUNT, - NULL); - } - } - - { - struct DH_KeyStateHandle *keys; - - keys = DH_keys_get_state (); - if (NULL == keys) - { - GNUNET_break (0); - cleanup_rsc (&rsc); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_DONAU_GENERIC_KEYS_MISSING, - NULL); - } - rsc.gf = DH_keys_global_fee_by_time (keys, - rsc.timestamp); - } - if (NULL == rsc.gf) - { - GNUNET_break (0); - cleanup_rsc (&rsc); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_DONAU_GENERIC_BAD_CONFIGURATION, - NULL); - } - - if (GNUNET_OK != - TALER_wallet_reserve_open_verify (&rsc.reserve_payment, - rsc.timestamp, - rsc.desired_expiration, - rsc.purse_limit, - reserve_pub, - &rsc.reserve_sig)) - { - GNUNET_break_op (0); - cleanup_rsc (&rsc); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_RESERVES_OPEN_BAD_SIGNATURE, - NULL); - } - - { - MHD_RESULT mhd_ret; - - if (GNUNET_OK != - DH_DB_run_transaction (rc->connection, - "reserve open", - DH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_open_transaction, - &rsc)) - { - cleanup_rsc (&rsc); - return mhd_ret; - } - } - - { - MHD_RESULT mhd_ret; - - mhd_ret = reply_reserve_open_success (rc->connection, - &rsc); - cleanup_rsc (&rsc); - return mhd_ret; - } -} - - -/* end of taler-donau-httpd_reserves_open.c */ diff --git a/src/donau/donau-httpd_charities_open.h b/src/donau/donau-httpd_charities_open.h @@ -1,41 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2022 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_open.h - * @brief Handle /reserves/$RESERVE_PUB/open requests - * @author Christian Grothoff - */ -#ifndef DONAU_HTTPD_RESERVES_OPEN_H -#define DONAU_HTTPD_RESERVES_OPEN_H - -#include <microhttpd.h> -#include "taler-donau-httpd.h" - - -/** - * Handle a POST "/reserves/$RID/open" request. - * - * @param rc request context - * @param reserve_pub public key of the reserve - * @param root uploaded body from the client - * @return MHD result code - */ -MHD_RESULT -DH_handler_reserves_open (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root); - -#endif diff --git a/src/donau/donau-httpd_charities_status.c b/src/donau/donau-httpd_charities_status.c @@ -1,243 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_status.c - * @brief Handle /reserves/$RESERVE_PUB STATUS requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <gnunet/gnunet_util_lib.h> -#include <jansson.h> -#include "taler/taler_mhd_lib.h" -#include "taler/taler_json_lib.h" -#include "taler_dbevents.h" -#include "taler-donau-httpd_keys.h" -#include "taler-donau-httpd_reserves_status.h" -#include "taler-donau-httpd_responses.h" - -/** - * How far do we allow a client's time to be off when - * checking the request timestamp? - */ -#define TIMESTAMP_TOLERANCE \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15) - - -/** - * Closure for #reserve_status_transaction. - */ -struct ReserveStatusContext -{ - /** - * Public key of the reserve the inquiry is about. - */ - const struct TALER_ReservePublicKeyP *reserve_pub; - - /** - * History of the reserve, set in the callback. - */ - struct DONAUDB_ReserveHistory *rh; - - /** - * Sum of incoming transactions within the returned history. - * (currently not used). - */ - struct TALER_Amount balance_in; - - /** - * Sum of outgoing transactions within the returned history. - * (currently not used). - */ - struct TALER_Amount balance_out; - - /** - * Current reserve balance. - */ - struct TALER_Amount balance; -}; - - -/** - * Send reserve status to client. - * - * @param connection connection to the client - * @param rhc reserve history to return - * @return MHD result code - */ -static MHD_RESULT -reply_reserve_status_success (struct MHD_Connection *connection, - const struct ReserveStatusContext *rhc) -{ - const struct DONAUDB_ReserveHistory *rh = rhc->rh; - json_t *json_history; - - json_history = DH_RESPONSE_compile_reserve_history (rh); - if (NULL == json_history) - return TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE, - NULL); - return TALER_MHD_REPLY_JSON_PACK ( - connection, - MHD_HTTP_OK, - TALER_JSON_pack_amount ("balance", - &rhc->balance), - GNUNET_JSON_pack_array_steal ("history", - json_history)); -} - - -/** - * Function implementing /reserves/ STATUS transaction. - * Execute a /reserves/ STATUS. Given the public key of a reserve, - * return the associated transaction history. Runs the - * transaction logic; IF it returns a non-error code, the transaction - * logic MUST NOT queue a MHD response. IF it returns an hard error, - * the transaction logic MUST queue a MHD response and set @a mhd_ret. - * IF it returns the soft error code, the function MAY be called again - * to retry and MUST not queue a MHD response. - * - * @param cls a `struct ReserveStatusContext *` - * @param connection MHD request which triggered the transaction - * @param[out] mhd_ret set to MHD response status for @a connection, - * if transaction failed (!); unused - * @return transaction status - */ -static enum GNUNET_DB_QueryStatus -reserve_status_transaction (void *cls, - struct MHD_Connection *connection, - MHD_RESULT *mhd_ret) -{ - struct ReserveStatusContext *rsc = cls; - enum GNUNET_DB_QueryStatus qs; - - qs = DH_plugin->get_reserve_status (DH_plugin->cls, - rsc->reserve_pub, - &rsc->balance_in, - &rsc->balance_out, - &rsc->rh); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_status"); - } - qs = DH_plugin->get_reserve_balance (DH_plugin->cls, - rsc->reserve_pub, - &rsc->balance); - if (GNUNET_DB_STATUS_HARD_ERROR == qs) - { - GNUNET_break (0); - *mhd_ret - = TALER_MHD_reply_with_error (connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "get_reserve_balance"); - } - return qs; -} - - -MHD_RESULT -DH_handler_reserves_status (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root) -{ - struct ReserveStatusContext rsc; - MHD_RESULT mhd_ret; - struct GNUNET_TIME_Timestamp timestamp; - struct TALER_ReserveSignatureP reserve_sig; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_timestamp ("request_timestamp", - &timestamp), - GNUNET_JSON_spec_fixed_auto ("reserve_sig", - &reserve_sig), - GNUNET_JSON_spec_end () - }; - struct GNUNET_TIME_Timestamp now; - - rsc.reserve_pub = reserve_pub; - { - enum GNUNET_GenericReturnValue res; - - res = TALER_MHD_parse_json_data (rc->connection, - root, - spec); - if (GNUNET_SYSERR == res) - { - GNUNET_break (0); - return MHD_NO; /* hard failure */ - } - if (GNUNET_NO == res) - { - GNUNET_break_op (0); - return MHD_YES; /* failure */ - } - } - now = GNUNET_TIME_timestamp_get (); - if (! GNUNET_TIME_absolute_approx_eq (now.abs_time, - timestamp.abs_time, - TIMESTAMP_TOLERANCE)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_DONAU_GENERIC_CLOCK_SKEW, - NULL); - } - if (GNUNET_OK != - TALER_wallet_reserve_status_verify (timestamp, - reserve_pub, - &reserve_sig)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_FORBIDDEN, - TALER_EC_DONAU_RESERVES_STATUS_BAD_SIGNATURE, - NULL); - } - rsc.rh = NULL; - if (GNUNET_OK != - DH_DB_run_transaction (rc->connection, - "get reserve status", - DH_MT_REQUEST_OTHER, - &mhd_ret, - &reserve_status_transaction, - &rsc)) - { - return mhd_ret; - } - if (NULL == rsc.rh) - { - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_NOT_FOUND, - TALER_EC_DONAU_RESERVES_STATUS_UNKNOWN, - NULL); - } - mhd_ret = reply_reserve_status_success (rc->connection, - &rsc); - DH_plugin->free_reserve_history (DH_plugin->cls, - rsc.rh); - return mhd_ret; -} - - -/* end of taler-donau-httpd_reserves_status.c */ diff --git a/src/donau/donau-httpd_charities_status.h b/src/donau/donau-httpd_charities_status.h @@ -1,43 +0,0 @@ -/* - This file is part of TALER - 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 - 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 CHARITYABILITY 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 <http://www.gnu.org/licenses/> -*/ -/** - * @file taler-donau-httpd_reserves_status.h - * @brief Handle /reserves/$RESERVE_PUB STATUS requests - * @author Florian Dold - * @author Benedikt Mueller - * @author Christian Grothoff - */ -#ifndef DONAU_HTTPD_RESERVES_STATUS_H -#define DONAU_HTTPD_RESERVES_STATUS_H - -#include <microhttpd.h> -#include "taler-donau-httpd.h" - - -/** - * Handle a POST "/reserves/$RID/status" request. - * - * @param rc request context - * @param reserve_pub public key of the reserve - * @param root uploaded body from the client - * @return MHD result code - */ -MHD_RESULT -DH_handler_reserves_status (struct DH_RequestContext *rc, - const struct TALER_ReservePublicKeyP *reserve_pub, - const json_t *root); - -#endif diff --git a/src/donau/donau-httpd_csr.c b/src/donau/donau-httpd_csr.c @@ -34,8 +34,8 @@ MHD_RESULT DH_handler_csr_withdraw (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]) + const json_t *root, + const char *const args[]) { struct TALER_CsNonce nonce; struct TALER_DenominationHashP denom_pub_hash; @@ -74,9 +74,9 @@ DH_handler_csr_withdraw (struct DH_RequestContext *rc, NULL); } dk = DH_keys_denomination_by_hash_from_state (ksh, - &denom_pub_hash, - NULL, - NULL); + &denom_pub_hash, + NULL, + NULL); if (NULL == dk) { return DH_RESPONSE_reply_unknown_denom_pub_hash ( @@ -120,8 +120,8 @@ DH_handler_csr_withdraw (struct DH_RequestContext *rc, }; ec = DH_keys_denomination_cs_r_pub (&cdd, - false, - &ewv.details.cs_values); + false, + &ewv.details.cs_values); if (TALER_EC_NONE != ec) { GNUNET_break (0); diff --git a/src/donau/donau-httpd_csr.h b/src/donau/donau-httpd_csr.h @@ -36,7 +36,7 @@ */ MHD_RESULT DH_handler_csr_withdraw (struct DH_RequestContext *rc, - const json_t *root, - const char *const args[]); + const json_t *root, + const char *const args[]); #endif diff --git a/src/donau/donau-httpd_db.c b/src/donau/donau-httpd_db.c @@ -95,9 +95,6 @@ DH_DB_run_transaction (struct MHD_Connection *connection, if (0 > qs) DH_plugin->rollback (DH_plugin->cls); } - /* make sure callback did not violate invariants! */ - GNUNET_assert ( (NULL == mhd_ret) || - (-1 == (int) *mhd_ret) ); if (0 <= qs) return GNUNET_OK; DH_METRICS_num_conflict[mt]++; diff --git a/src/donau/donau-httpd_keys.c b/src/donau/donau-httpd_keys.c @@ -42,164 +42,6 @@ /** - * Information about a denomination on offer by the denomination helper. - */ -struct HelperDonationUnit -{ - - // maybe change to year unsigned int later -> many associated changes - /** - * When will the helper start to use this key for signing? - */ - struct GNUNET_TIME_Timestamp start_time; - - - /** - * For how long will the helper allow signing? 0 if - * the key was revoked or purged. - */ - struct GNUNET_TIME_Relative validity_duration; - - - /** - * Hash of the full denomination key. - */ - struct TALER_DenominationHashP h_denom_pub; - - /** - * The (full) public key. - */ - struct TALER_DenominationPublicKey denom_pub; - - /** - * Details depend on the @e denom_pub.cipher type. - */ - union - { - - /** - * Hash of the RSA key. - */ - struct TALER_RsaPubHashP h_rsa; - - /** - * Hash of the CS key. - */ - struct TALER_CsPubHashP h_cs; - - } h_details; - - /** - * Name in configuration section for this denomination type. - */ - char *section_name; - - -}; - - -/** - * Information about a signing key on offer by the esign helper. - */ -struct HelperSignkey -{ - - /** - * The public key. - */ - struct DONAU_DonauPublicKeyP donau_pub; - - /** - * Signature over this key from the security module's key. - */ - struct TALER_SecurityModuleSignatureP sm_sig; - -}; - - -/** - * State associated with the crypto helpers / security modules. NOT updated - * when the #key_generation is updated (instead constantly kept in sync - * whenever #DH_keys_get_state() is called). - */ -struct HelperState -{ - - /** - * Handle for the esign/EdDSA helper. - */ - struct TALER_CRYPTO_DonauSignHelper *esh; - - /** - * Handle for the denom/RSA helper. - */ - struct TALER_CRYPTO_RsaDenominationHelper *rsadh; - - /** - * Handle for the denom/CS helper. - */ - struct TALER_CRYPTO_CsDenominationHelper *csdh; - - /** - * Map from H(denom_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *denom_keys; - - /** - * Map from H(rsa_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *rsa_keys; - - /** - * Map from H(cs_pub) to `struct HelperDonationUnit` entries. - */ - struct GNUNET_CONTAINER_MultiHashMap *cs_keys; - - /** - * Map from `struct TALER_DonauPublicKey` to `struct HelperSignkey` - * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also - * an EdDSA public key. - */ - struct GNUNET_CONTAINER_MultiPeerMap *esign_keys; - -}; - - -/** - * Entry in (sorted) array with possible pre-build responses for /keys. - * We keep pre-build responses for the various (valid) cherry-picking - * values around. - */ -struct KeysResponseData -{ - - /** - * Response to return if the client supports (deflate) compression. - */ - struct MHD_Response *response_compressed; - - /** - * Response to return if the client does not support compression. - */ - struct MHD_Response *response_uncompressed; - - /** - * ETag for these responses. - */ - char *etag; - - /** - * Cherry-picking timestamp the client must have set for this - * response to be valid. 0 if this is the "full" response. - * The client's request must include this date or a higher one - * for this response to be applicable. - */ - struct GNUNET_TIME_Timestamp cherry_pick_date; - -}; - - -/** * @brief All information about an donau online signing key (which is used to * sign messages from the donau). */ @@ -218,1233 +60,9 @@ struct SigningKey }; -struct DH_KeyStateHandle -{ - - /** - * Mapping from denomination keys to denomination key issue struct. - * Used to lookup the key by hash. - */ - struct GNUNET_CONTAINER_MultiHashMap *denomkey_map; - - /** - * Map from `struct TALER_DonauPublicKey` to `struct SigningKey` - * entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also - * an EdDSA public key. - */ - struct GNUNET_CONTAINER_MultiPeerMap *signkey_map; - - /** - * Sorted array of responses to /keys (MUST be sorted by cherry-picking date) of - * length @e krd_array_length; - */ - struct KeysResponseData *krd_array; - - /** - * Length of the @e krd_array. - */ - unsigned int krd_array_length; - - /** - * Information we track for thecrypto helpers. Preserved - * when the @e key_generation changes, thus kept separate. - */ - struct HelperState *helpers; - - /** - * Cached reply for a GET /management/keys request. Used so we do not - * re-create the reply every time. - */ - json_t *management_keys_reply; - - /** - * For which (global) key_generation was this data structure created? - * Used to check when we are outdated and need to be re-generated. - */ - uint64_t key_generation; - - /** - * True if #finish_keys_response() was not yet run and this key state - * is only suitable for the /management/keys API. - */ - bool management_only; - -}; - -/** - * Stores the latest generation of our key state. - */ -static struct DH_KeyStateHandle *key_state; - -/** - * Counter incremented whenever we have a reason to re-build the keys because - * something external changed. See #DH_keys_get_state() and - * #DH_keys_update_states() for uses of this variable. - */ -static uint64_t key_generation; - -/** - * Task to force timeouts on /keys requests. - */ -static struct GNUNET_SCHEDULER_Task *keys_tt; - -/** - * For how long should a signing key be legally retained? - * Configuration value. - */ -static struct GNUNET_TIME_Relative signkey_legal_duration; - -/** - * What type of asset are we dealing with here? - */ -static char *asset_type; - -/** - * RSA security module public key, all zero if not known. - */ -static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub; - -/** - * CS security module public key, all zero if not known. - */ -static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub; - -/** - * EdDSA security module public key, all zero if not known. - */ -static struct TALER_SecurityModulePublicKeyP esign_sm_pub; - /** * Are we shutting down? */ static bool terminating; - -/** - * Called on each denomination key. Checks that the key still works. - * - * @param cls NULL - * @param hc denomination hash (unused) - * @param value a `struct DH_DonationUnitKey` - * @return #GNUNET_OK - */ -static enum GNUNET_GenericReturnValue -check_dk (void *cls, - const struct GNUNET_HashCode *hc, - void *value) -{ - struct DH_DonationUnitKey *dk = value; - - (void) cls; - (void) hc; - GNUNET_assert (TALER_DENOMINATION_INVALID != dk->denom_pub.cipher); - if (TALER_DENOMINATION_RSA == dk->denom_pub.cipher) - GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check ( - dk->denom_pub.details.rsa_public_key)); - // nothing to do for TALER_DENOMINATION_CS - return GNUNET_OK; -} - - -void -DH_check_invariants () -{ - struct DH_KeyStateHandle *ksh; - - if (0 == DH_check_invariants_flag) - return; - ksh = DH_keys_get_state (); - if (NULL == ksh) - return; - GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, - &check_dk, - NULL); -} - - -/** - * Clear memory for responses to "/keys" in @a ksh. - * - * @param[in,out] ksh key state to update - */ -static void -clear_response_cache (struct DH_KeyStateHandle *ksh) -{ - for (unsigned int i = 0; i<ksh->krd_array_length; i++) - { - struct KeysResponseData *krd = &ksh->krd_array[i]; - - MHD_destroy_response (krd->response_compressed); - MHD_destroy_response (krd->response_uncompressed); - GNUNET_free (krd->etag); - } - GNUNET_array_grow (ksh->krd_array, - ksh->krd_array_length, - 0); -} - - -/** - * Check that the given RSA security module's public key is the one - * we have pinned. If it does not match, we die hard. - * - * @param sm_pub RSA security module public key to check - */ -static void -check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) -{ - if (0 != - GNUNET_memcmp (sm_pub, - &denom_rsa_sm_pub)) - { - if (! GNUNET_is_zero (&denom_rsa_sm_pub)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Our RSA security module changed its key. This must not happen.\n"); - GNUNET_assert (0); - } - denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) Trust on first use?*/ - } -} - - -/** - * Check that the given CS security module's public key is the one - * we have pinned. If it does not match, we die hard. - * - * @param sm_pub RSA security module public key to check - */ -static void -check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) -{ - if (0 != - GNUNET_memcmp (sm_pub, - &denom_cs_sm_pub)) - { - if (! GNUNET_is_zero (&denom_cs_sm_pub)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Our CS security module changed its key. This must not happen.\n"); - GNUNET_assert (0); - } - denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */ - } -} - - -/** - * Check that the given EdDSA security module's public key is the one - * we have pinned. If it does not match, we die hard. - * - * @param sm_pub EdDSA security module public key to check - */ -static void -check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub) -{ - if (0 != - GNUNET_memcmp (sm_pub, - &esign_sm_pub)) - { - if (! GNUNET_is_zero (&esign_sm_pub)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Our EdDSA security module changed its key. This must not happen.\n"); - GNUNET_assert (0); - } - esign_sm_pub = *sm_pub; /* TOFU ;-) */ - } -} - - -/** - * Helper function for #destroy_key_helpers to free all entries - * in the `denom_keys` map. - * - * @param cls the `struct HelperDonationUnit` - * @param h_denom_pub hash of the denomination public key - * @param value the `struct HelperDonationUnit` to release - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -free_denom_cb (void *cls, - const struct GNUNET_HashCode *h_denom_pub, - void *value) -{ - struct HelperDonationUnit *hd = value; - - (void) cls; - (void) h_denom_pub; - TALER_denom_pub_free (&hd->denom_pub); - GNUNET_free (hd->section_name); - GNUNET_free (hd); - return GNUNET_OK; -} - - -/** - * Helper function for #destroy_key_helpers to free all entries - * in the `esign_keys` map. - * - * @param cls the `struct HelperSignkey` - * @param pid unused, matches the donau public key - * @param value the `struct HelperSignkey` to release - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -free_esign_cb (void *cls, - const struct GNUNET_PeerIdentity *pid, - void *value) -{ - struct HelperSignkey *hsk = value; - - (void) cls; - (void) pid; - GNUNET_free (hsk); - return GNUNET_OK; -} - - -/** - * Destroy helper state. Does NOT call free() on @a hs, as that - * state is not separately allocated! Dual to #setup_key_helpers(). - * - * @param[in] hs helper state to free, but NOT the @a hs pointer itself! - */ -static void -destroy_key_helpers (struct HelperState *hs) -{ - GNUNET_CONTAINER_multihashmap_iterate (hs->denom_keys, - &free_denom_cb, - hs); - GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys); - hs->rsa_keys = NULL; - GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys); - hs->cs_keys = NULL; - GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys); - hs->denom_keys = NULL; - GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys, - &free_esign_cb, - hs); - GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys); - hs->esign_keys = NULL; - if (NULL != hs->rsadh) - { - TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh); - hs->rsadh = NULL; - } - if (NULL != hs->csdh) - { - TALER_CRYPTO_helper_cs_disconnect (hs->csdh); - hs->csdh = NULL; - } - if (NULL != hs->esh) - { - TALER_CRYPTO_helper_esign_disconnect (hs->esh); - hs->esh = NULL; - } -} - - -/** - * Function called with information about available keys for signing. Usually - * only called once per key upon connect. Also called again in case a key is - * being revoked, in that case with an @a end_time of zero. - * - * @param cls closure with the `struct HelperState *` - * @param start_time when does the key become available for signing; - * zero if the key has been revoked or purged - * @param validity_duration how long does the key remain available for signing; - * zero if the key has been revoked or purged - * @param donau_pub the public key itself, NULL if the key was revoked or purged - * @param sm_pub public key of the security module, NULL if the key was revoked or purged - * @param sm_sig signature from the security module, NULL if the key was revoked or purged - * The signature was already verified against @a sm_pub. - */ -static void -helper_esign_cb ( - void *cls, - struct GNUNET_TIME_Timestamp start_time, - struct GNUNET_TIME_Relative validity_duration, - const struct DONAU_DonauPublicKeyP *donau_pub, - const struct TALER_SecurityModulePublicKeyP *sm_pub, - const struct TALER_SecurityModuleSignatureP *sm_sig) -{ - struct HelperState *hs = cls; - struct HelperSignkey *hsk; - struct GNUNET_PeerIdentity pid; - - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "EdDSA helper announces signing key %s with validity %s\n", - TALER_B2S (donau_pub), - GNUNET_STRINGS_relative_time_to_string (validity_duration, - GNUNET_NO)); - key_generation++; - DH_resume_keys_requests (false); - pid.public_key = donau_pub->eddsa_pub; - hsk = GNUNET_CONTAINER_multipeermap_get (hs->esign_keys, - &pid); - if (NULL != hsk) - { - /* should be just an update (revocation!), so update existing entry */ - hsk->validity_duration = validity_duration; - return; - } - GNUNET_assert (NULL != sm_pub); - check_esign_sm_pub (sm_pub); - hsk = GNUNET_new (struct HelperSignkey); - hsk->start_time = start_time; - hsk->validity_duration = validity_duration; - hsk->donau_pub = *donau_pub; - hsk->sm_sig = *sm_sig; - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put ( - hs->esign_keys, - &pid, - hsk, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} - - -/** - * Setup helper state. - * - * @param[out] hs helper state to initialize - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -setup_key_helpers (struct HelperState *hs) -{ - hs->denom_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->rsa_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->cs_keys - = GNUNET_CONTAINER_multihashmap_create (1024, - GNUNET_YES); - hs->esign_keys - = GNUNET_CONTAINER_multipeermap_create (32, - GNUNET_NO /* MUST BE NO! */); - hs->rsadh = TALER_CRYPTO_helper_rsa_connect (DH_cfg, - &helper_rsa_cb, - hs); - if (NULL == hs->rsadh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - hs->csdh = TALER_CRYPTO_helper_cs_connect (DH_cfg, - &helper_cs_cb, - hs); - if (NULL == hs->csdh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - hs->esh = TALER_CRYPTO_helper_esign_connect (DH_cfg, - &helper_esign_cb, - hs); - if (NULL == hs->esh) - { - destroy_key_helpers (hs); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Synchronize helper state. Polls the key helper for updates. - * - * @param[in,out] hs helper state to synchronize - */ -static void -sync_key_helpers (struct HelperState *hs) -{ - TALER_CRYPTO_helper_rsa_poll (hs->rsadh); - TALER_CRYPTO_helper_cs_poll (hs->csdh); - TALER_CRYPTO_helper_esign_poll (hs->esh); -} - - -/** - * Free denomination key data. - * - * @param cls a `struct DH_KeyStateHandle`, unused - * @param h_denom_pub hash of the denomination public key, unused - * @param value a `struct DH_DonationUnitKey` to free - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -clear_donation_unit_cb (void *cls, - const struct GNUNET_HashCode *h_denom_pub, - void *value) -{ - struct DH_DonationUnitKey *dk = value; - struct DH_AuditorSignature *as; - - (void) cls; - (void) h_denom_pub; - TALER_denom_pub_free (&dk->denom_pub); - while (NULL != (as = dk->as_head)) - { - GNUNET_CONTAINER_DLL_remove (dk->as_head, - dk->as_tail, - as); - GNUNET_free (as); - } - GNUNET_free (dk); - return GNUNET_OK; -} - - -/** - * Free denomination key data. - * - * @param cls a `struct DH_KeyStateHandle`, unused - * @param pid the online signing key (type-disguised), unused - * @param value a `struct SigningKey` to free - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -clear_signkey_cb (void *cls, - const struct GNUNET_PeerIdentity *pid, - void *value) -{ - struct SigningKey *sk = value; - - (void) cls; - (void) pid; - GNUNET_free (sk); - return GNUNET_OK; -} - - -/** - * Free resources associated with @a cls, possibly excluding - * the helper data. - * - * @param[in] ksh key state to release - * @param free_helper true to also release the helper state - */ -static void -destroy_key_state (struct DH_KeyStateHandle *ksh, - bool free_helper) -{ - clear_response_cache (ksh); - - GNUNET_CONTAINER_multihashmap_iterate (ksh->denomkey_map, - &clear_denomination_cb, - ksh); - GNUNET_CONTAINER_multihashmap_destroy (ksh->denomkey_map); - GNUNET_CONTAINER_multipeermap_iterate (ksh->signkey_map, - &clear_signkey_cb, - ksh); - GNUNET_CONTAINER_multipeermap_destroy (ksh->signkey_map); - if (free_helper) - { - destroy_key_helpers (ksh->helpers); - GNUNET_free (ksh->helpers); - } - if (NULL != ksh->management_keys_reply) - { - json_decref (ksh->management_keys_reply); - ksh->management_keys_reply = NULL; - } - GNUNET_free (ksh); -} - - -/** - * Function called whenever another donau process has updated - * the keys data in the database. - * - * @param cls NULL - * @param extra unused - * @param extra_size number of bytes in @a extra unused - */ -static void -keys_update_event_cb (void *cls, - const void *extra, - size_t extra_size) -{ - (void) cls; - (void) extra; - (void) extra_size; - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Received /keys update event\n"); - DH_check_invariants (); - key_generation++; - DH_resume_keys_requests (false); - DH_check_invariants (); -} - - -enum GNUNET_GenericReturnValue -DH_keys_init () -{ - struct GNUNET_DB_EventHeaderP es = { - .size = htons (sizeof (es)), - .type = htons (TALER_DBEVENT_DONAU_KEYS_UPDATED), - }; - - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_time (DH_cfg, - "donau", - "SIGNKEY_LEGAL_DURATION", - &signkey_legal_duration)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "donau", - "SIGNKEY_LEGAL_DURATION"); - return GNUNET_SYSERR; - } - if (GNUNET_OK != - GNUNET_CONFIGURATION_get_value_string (DH_cfg, - "donau", - "ASSET_TYPE", - &asset_type)) - { - GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, - "donau", - "ASSET_TYPE"); - asset_type = GNUNET_strdup ("fiat"); - } - keys_eh = DH_plugin->event_listen (DH_plugin->cls, - GNUNET_TIME_UNIT_FOREVER_REL, - &es, - &keys_update_event_cb, - NULL); - if (NULL == keys_eh) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Fully clean up our state. - */ -void -DH_keys_finished () -{ - if (NULL != keys_tt) - { - GNUNET_SCHEDULER_cancel (keys_tt); - keys_tt = NULL; - } - if (NULL != key_state) - destroy_key_state (key_state, - true); - if (NULL != keys_eh) - { - DH_plugin->event_listen_cancel (DH_plugin->cls, - keys_eh); - keys_eh = NULL; - } -} - - -/** - * Function called with information about the donau's denomination keys. - * - * @param cls closure with a `struct DH_KeyStateHandle *` - * @param denom_pub public key of the denomination - * @param h_denom_pub hash of @a denom_pub - * @param meta meta data information about the denomination type (value, year) - */ -static void -denomination_info_cb ( - void *cls, - const struct TALER_DenominationPublicKey *denom_pub, - const struct TALER_DenominationHashP *h_denom_pub, - const struct DONAUDB_DonationUnitKeyMetaData *meta) -{ - struct DH_KeyStateHandle *ksh = cls; - struct DH_DonationUnitKey *dk; - - GNUNET_assert (TALER_DENOMINATION_INVALID != denom_pub->cipher); - if (GNUNET_TIME_absolute_is_zero (meta->start.abs_time) || - GNUNET_TIME_absolute_is_zero (meta->expire_withdraw.abs_time) || - GNUNET_TIME_absolute_is_zero (meta->expire_deposit.abs_time) || - GNUNET_TIME_absolute_is_zero (meta->expire_legal.abs_time) ) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Database contains invalid denomination key %s\n", - GNUNET_h2s (&h_denom_pub->hash)); - return; - } - dk = GNUNET_new (struct DH_DonationUnitKey); - TALER_denom_pub_deep_copy (&dk->denom_pub, - denom_pub); - dk->h_denom_pub = *h_denom_pub; - dk->meta = *meta; - dk->denom_pub.age_mask = meta->age_mask; - - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multihashmap_put (ksh->denomkey_map, - &dk->h_denom_pub.hash, - dk, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} - - -/** - * Function called with information about the donau's online signing keys. - * - * @param cls closure with a `struct DH_KeyStateHandle *` - * @param donau_pub the public key - * @param meta meta data information about the denomination type (expirations) - */ -static void -signkey_info_cb ( - void *cls, - const struct DONAU_DonauPublicKeyP *donau_pub, - const struct DONAUDB_SignkeyMetaData *meta) -{ - struct DH_KeyStateHandle *ksh = cls; - struct SigningKey *sk; - struct GNUNET_PeerIdentity pid; - - sk = GNUNET_new (struct SigningKey); - sk->donau_pub = *donau_pub; - sk->meta = *meta; - pid.public_key = donau_pub->eddsa_pub; - GNUNET_assert ( - GNUNET_OK == - GNUNET_CONTAINER_multipeermap_put (ksh->signkey_map, - &pid, - sk, - GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); -} - - -/** - * Closure for #add_sign_key_cb. - */ -struct SignKeyCtx -{ - /** - * What is the current rotation frequency for signing keys. Updated. - */ - struct GNUNET_TIME_Relative min_sk_frequency; - - /** - * JSON array of signing keys (being created). - */ - json_t *signkeys; -}; - - -/** - * Function called for all signing keys, used to build up the - * respective JSON response. - * - * @param cls a `struct SignKeyCtx *` with the array to append keys to - * @param pid the donau public key (in type disguise) - * @param value a `struct SigningKey` - * @return #GNUNET_OK (continue to iterate) - */ -static enum GNUNET_GenericReturnValue -add_sign_key_cb (void *cls, - const struct GNUNET_PeerIdentity *pid, - void *value) -{ - struct SignKeyCtx *ctx = cls; - struct SigningKey *sk = value; - - (void) pid; - if (GNUNET_TIME_absolute_is_future (sk->meta.expire_sign.abs_time)) - { - ctx->min_sk_frequency = - GNUNET_TIME_relative_min (ctx->min_sk_frequency, - GNUNET_TIME_absolute_get_difference ( - sk->meta.start.abs_time, - sk->meta.expire_sign.abs_time)); - } - GNUNET_assert ( - 0 == - json_array_append_new ( - ctx->signkeys, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_timestamp ("stamp_start", - sk->meta.start), - GNUNET_JSON_pack_timestamp ("stamp_expire", - sk->meta.expire_sign), - GNUNET_JSON_pack_timestamp ("stamp_end", - sk->meta.expire_legal), - GNUNET_JSON_pack_data_auto ("key", - &sk->donau_pub)))); - return GNUNET_OK; -} - - -/** - * Closure for #add_denom_key_cb. - */ -struct DenomKeyCtx -{ - /** - * Heap for sorting active denomination keys by start time. - */ - struct GNUNET_CONTAINER_Heap *heap; - - /** - * What is the minimum key rotation frequency of - * valid denomination keys? - */ - struct GNUNET_TIME_Relative min_dk_frequency; -}; - -struct DH_DonationUnitKey * -DH_keys_denomination_by_hash ( - const struct TALER_DenominationHashP *h_denom_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret) -{ - struct DH_KeyStateHandle *ksh; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - *mret = TALER_MHD_reply_with_error (conn, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_DONAU_GENERIC_KEYS_MISSING, - NULL); - return NULL; - } - - return DH_keys_denomination_by_hash_from_state (ksh, - h_denom_pub, - conn, - mret); -} - - -struct DH_DonationUnitKey * -DH_keys_denomination_by_hash_from_state ( - const struct DH_KeyStateHandle *ksh, - const struct TALER_DenominationHashP *h_denom_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret) -{ - struct DH_DonationUnitKey *dk; - - dk = GNUNET_CONTAINER_multihashmap_get (ksh->denomkey_map, - &h_denom_pub->hash); - if (NULL == dk) - { - if (NULL == conn) - return NULL; - *mret = DH_RESPONSE_reply_unknown_denom_pub_hash (conn, - h_denom_pub); - return NULL; - } - return dk; -} - - -enum TALER_ErrorCode -DH_keys_denomination_sign ( - const struct DONAU_BlindedUniqueDonationIdentifierKeyPair *budi_key, - bool for_melt, - struct TALER_BlindedDenominationSignature *bs) -{ - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - const struct TALER_DenominationHashP *h_denom_pub = csd->h_denom_pub; - const struct TALER_BlindedPlanchet *bp = csd->bp; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - return TALER_EC_DONAU_GENERIC_KEYS_MISSING; - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys, - &h_denom_pub->hash); - if (NULL == hd) - return TALER_EC_DONAU_GENERIC_DENOMINATION_KEY_UNKNOWN; - if (bp->cipher != hd->denom_pub.cipher) - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - switch (hd->denom_pub.cipher) - { - case TALER_DENOMINATION_RSA: - DH_METRICS_num_signatures[DH_MT_SIGNATURE_RSA]++; - { - struct TALER_CRYPTO_RsaSignRequest rsr = { - .h_rsa = &hd->h_details.h_rsa, - .msg = bp->details.rsa_blinded_planchet.blinded_msg, - .msg_size = bp->details.rsa_blinded_planchet.blinded_msg_size - }; - - return TALER_CRYPTO_helper_rsa_sign ( - ksh->helpers->rsadh, - &rsr, - bs); - } - case TALER_DENOMINATION_CS: - DH_METRICS_num_signatures[DH_MT_SIGNATURE_CS]++; - { - struct TALER_CRYPTO_CsSignRequest csr; - - csr.h_cs = &hd->h_details.h_cs; - csr.blinded_planchet = &bp->details.cs_blinded_planchet; - return TALER_CRYPTO_helper_cs_sign ( - ksh->helpers->csdh, - &csr, - for_melt, - bs); - } - default: - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - } -} - - -enum TALER_ErrorCode -DH_keys_donation_unit_batch_sign ( - const struct DONAU_BlindedUniqueDonationIdentifierKeyPair *budi_key, - unsigned int csds_length, - bool for_melt, - struct TALER_BlindedDenominationSignature *bss) -{ - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - struct TALER_CRYPTO_RsaSignRequest rsrs[csds_length]; - struct TALER_CRYPTO_CsSignRequest csrs[csds_length]; - struct TALER_BlindedDenominationSignature rs[csds_length]; - struct TALER_BlindedDenominationSignature cs[csds_length]; - unsigned int rsrs_pos = 0; - unsigned int csrs_pos = 0; - enum TALER_ErrorCode ec; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - return TALER_EC_DONAU_GENERIC_KEYS_MISSING; - for (unsigned int i = 0; i<csds_length; i++) - { - const struct TALER_DenominationHashP *h_denom_pub = csds[i].h_denom_pub; - const struct TALER_BlindedPlanchet *bp = csds[i].bp; - - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys, - &h_denom_pub->hash); - if (NULL == hd) - return TALER_EC_DONAU_GENERIC_DENOMINATION_KEY_UNKNOWN; - if (bp->cipher != hd->denom_pub.cipher) - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - switch (hd->denom_pub.cipher) - { - case TALER_DENOMINATION_RSA: - rsrs[rsrs_pos].h_rsa = &hd->h_details.h_rsa; - rsrs[rsrs_pos].msg - = bp->details.rsa_blinded_planchet.blinded_msg; - rsrs[rsrs_pos].msg_size - = bp->details.rsa_blinded_planchet.blinded_msg_size; - rsrs_pos++; - break; - case TALER_DENOMINATION_CS: - csrs[csrs_pos].h_cs = &hd->h_details.h_cs; - csrs[csrs_pos].blinded_planchet = &bp->details.cs_blinded_planchet; - csrs_pos++; - break; - default: - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - } - } - - if ( (0 != csrs_pos) && - (0 != rsrs_pos) ) - { - memset (rs, - 0, - sizeof (rs)); - memset (cs, - 0, - sizeof (cs)); - } - ec = TALER_EC_NONE; - if (0 != csrs_pos) - { - ec = TALER_CRYPTO_helper_cs_batch_sign ( - ksh->helpers->csdh, - csrs, - csrs_pos, - for_melt, - (0 == rsrs_pos) ? bss : cs); - if (TALER_EC_NONE != ec) - { - for (unsigned int i = 0; i<csrs_pos; i++) - TALER_blinded_denom_sig_free (&cs[i]); - return ec; - } - DH_METRICS_num_signatures[DH_MT_SIGNATURE_CS] += csrs_pos; - } - if (0 != rsrs_pos) - { - ec = TALER_CRYPTO_helper_rsa_batch_sign ( - ksh->helpers->rsadh, - rsrs, - rsrs_pos, - (0 == csrs_pos) ? bss : rs); - if (TALER_EC_NONE != ec) - { - for (unsigned int i = 0; i<csrs_pos; i++) - TALER_blinded_denom_sig_free (&cs[i]); - for (unsigned int i = 0; i<rsrs_pos; i++) - TALER_blinded_denom_sig_free (&rs[i]); - return ec; - } - DH_METRICS_num_signatures[DH_MT_SIGNATURE_RSA] += rsrs_pos; - } - - if ( (0 != csrs_pos) && - (0 != rsrs_pos) ) - { - rsrs_pos = 0; - csrs_pos = 0; - for (unsigned int i = 0; i<csds_length; i++) - { - const struct TALER_BlindedPlanchet *bp = csds[i].bp; - - switch (bp->cipher) - { - case TALER_DENOMINATION_RSA: - bss[i] = rs[rsrs_pos++]; - break; - case TALER_DENOMINATION_CS: - bss[i] = cs[csrs_pos++]; - break; - default: - GNUNET_assert (0); - } - } - } - return TALER_EC_NONE; -} - - -enum TALER_ErrorCode -DH_keys_denomination_cs_r_pub ( - const struct DH_CsDeriveData *cdd, - bool for_melt, - struct TALER_DenominationCSPublicRPairP *r_pub) -{ - const struct TALER_DenominationHashP *h_denom_pub = cdd->h_denom_pub; - const struct TALER_CsNonce *nonce = cdd->nonce; - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - return TALER_EC_DONAU_GENERIC_KEYS_MISSING; - } - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys, - &h_denom_pub->hash); - if (NULL == hd) - { - return TALER_EC_DONAU_GENERIC_DENOMINATION_KEY_UNKNOWN; - } - if (TALER_DENOMINATION_CS != hd->denom_pub.cipher) - { - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - } - - { - struct TALER_CRYPTO_CsDeriveRequest cdr = { - .h_cs = &hd->h_details.h_cs, - .nonce = nonce - }; - return TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh, - &cdr, - for_melt, - r_pub); - } -} - - -enum TALER_ErrorCode -DH_keys_denomination_cs_batch_r_pub ( - const struct DH_CsDeriveData *cdds, - unsigned int cdds_length, - bool for_melt, - struct TALER_DenominationCSPublicRPairP *r_pubs) -{ - struct DH_KeyStateHandle *ksh; - struct HelperDonationUnit *hd; - struct TALER_CRYPTO_CsDeriveRequest cdrs[cdds_length]; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - return TALER_EC_DONAU_GENERIC_KEYS_MISSING; - } - for (unsigned int i = 0; i<cdds_length; i++) - { - const struct TALER_DenominationHashP *h_denom_pub = cdds[i].h_denom_pub; - const struct TALER_CsNonce *nonce = cdds[i].nonce; - - hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys, - &h_denom_pub->hash); - if (NULL == hd) - { - return TALER_EC_DONAU_GENERIC_DENOMINATION_KEY_UNKNOWN; - } - if (TALER_DENOMINATION_CS != hd->denom_pub.cipher) - { - return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - } - cdrs[i].h_cs = &hd->h_details.h_cs; - cdrs[i].nonce = nonce; - } - - return TALER_CRYPTO_helper_cs_r_batch_derive (ksh->helpers->csdh, - cdrs, - cdds_length, - for_melt, - r_pubs); -} - - -enum TALER_ErrorCode -DH_keys_donau_sign_ ( - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct DONAU_DonauPublicKeyP *pub, - struct TALER_DonauSignatureP *sig) -{ - struct DH_KeyStateHandle *ksh; - - ksh = DH_keys_get_state (); - if (NULL == ksh) - { - /* This *can* happen if the donau's crypto helper is not running - or had some bad error. */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Cannot sign request, no valid signing keys available.\n"); - return TALER_EC_DONAU_GENERIC_KEYS_MISSING; - } - return DH_keys_donau_sign2_ (ksh, - purpose, - pub, - sig); -} - - -MHD_RESULT -DH_keys_get_handler (struct DH_RequestContext *rc, - const char *const args[]) -{ - struct GNUNET_TIME_Timestamp last_issue_date; - const char *etag; - struct WireStateHandle *wsh; - - wsh = get_wire_state (); - etag = MHD_lookup_connection_value (rc->connection, - MHD_HEADER_KIND, - MHD_HTTP_HEADER_IF_NONE_MATCH); - (void) args; - { - const char *have_cherrypick; - - have_cherrypick = MHD_lookup_connection_value (rc->connection, - MHD_GET_ARGUMENT_KIND, - "last_issue_date"); - if (NULL != have_cherrypick) - { - unsigned long long cherrypickn; - - if (1 != - sscanf (have_cherrypick, - "%llu", - &cherrypickn)) - { - GNUNET_break_op (0); - return TALER_MHD_reply_with_error (rc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - have_cherrypick); - } - /* The following multiplication may overflow; but this should not really - be a problem, as giving back 'older' data than what the client asks for - (given that the client asks for data in the distant future) is not - problematic */ - last_issue_date = GNUNET_TIME_timestamp_from_s (cherrypickn); - } - else - { - last_issue_date = GNUNET_TIME_UNIT_ZERO_TS; - } - } - - { - struct DH_KeyStateHandle *ksh; - const struct KeysResponseData *krd; - - ksh = DH_keys_get_state (); - if ( (NULL == ksh) || - (0 == ksh->krd_array_length) ) - krd = bsearch (&last_issue_date, - ksh->krd_array, - ksh->krd_array_length, - sizeof (struct KeysResponseData), - &krd_search_comparator); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Filtering /keys by cherry pick date %s found entry %u/%u\n", - GNUNET_TIME_timestamp2s (last_issue_date), - (unsigned int) (krd - ksh->krd_array), - ksh->krd_array_length); - if ( (NULL == krd) && - (ksh->krd_array_length > 0) ) - { - if (! GNUNET_TIME_absolute_is_zero (last_issue_date.abs_time)) - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Client provided invalid cherry picking timestamp %s, returning full response\n", - GNUNET_TIME_timestamp2s (last_issue_date)); - krd = &ksh->krd_array[ksh->krd_array_length - 1]; - } - if (NULL == krd) - { - /* Likely keys not ready *yet*. - Wait until they are. */ - return suspend_request (rc->connection); - } - if ( (NULL != etag) && - (0 == strcmp (etag, - krd->etag)) ) - { - MHD_RESULT ret; - struct MHD_Response *resp; - - resp = MHD_create_response_from_buffer (0, - NULL, - MHD_RESPMEM_PERSISTENT); - TALER_MHD_add_global_headers (resp); - GNUNET_break (GNUNET_OK == - setup_general_response_headers (ksh, - wsh, - resp)); - GNUNET_break (MHD_YES == - MHD_add_response_header (resp, - MHD_HTTP_HEADER_ETAG, - krd->etag)); - ret = MHD_queue_response (rc->connection, - MHD_HTTP_NOT_MODIFIED, - resp); - GNUNET_break (MHD_YES == ret); - MHD_destroy_response (resp); - return ret; - } - return MHD_queue_response (rc->connection, - MHD_HTTP_OK, - (MHD_YES == - TALER_MHD_can_compress (rc->connection)) - ? krd->response_compressed - : krd->response_uncompressed); - } -} - - /* end of donau-httpd_keys.c */ diff --git a/src/donau/donau-httpd_keys.h b/src/donau/donau-httpd_keys.h @@ -53,199 +53,5 @@ struct DH_DonationUnitKey */ struct DONAUDB_DonationUnitKeyMetaData meta; - }; - -/** - * Run internal invariant checks. For debugging. - */ -void -DH_check_invariants (void); - -/** - * Look up the issue for a unit public key. Note that the result - * must only be used in this thread and only until another key or - * key state is resolved. - * - * @param h_unit_pub hash of donation_unit public key - * @param[in,out] conn used to return status message if NULL is returned - * @param[out] mret set to the MHD status if NULL is returned - * @return the donation_unit key issue, - * or NULL if @a h_unit_pub could not be found - */ -struct DH_DonationUnitKey * -DH_keys_donation_unit_by_hash ( - const struct DONAU_DonationUnitHashP *h_unit_pub, - struct MHD_Connection *conn, - MHD_RESULT *mret); - -/** - * Information needed to derive the CS r_pub. - */ -struct DH_CsDeriveData -{ - /** - * Hash of key to sign with. - */ - const struct DONAU_DonationUnitHashP *h_du_pub; - - /** - * Nonce to use. - */ - const struct DONAU_CsNonce *nonce; }; - -/** - * Request to derive CS @a r_pub using the donation unit and nonce from @a cdd. - * - * @param cdd data to compute @a r_pub from - * @param[out] r_pub where to write the result - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donation_unit_cs_r_pub ( - const struct DH_CsDeriveData *cdd, - struct GNUNET_CRYPTO_CSPublicRPairP *r_pub); - - -/** - * Request to derive a bunch of CS @a r_pubs using the - * donation units and nonces from @a cdds. - * - * @param cdds array to compute @a r_pubs from - * @param cdds_length length of the @a cdds array - * @param[out] r_pubs array where to write the result; must be of length @a cdds_length - * @return #DONAU_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donation_unit_cs_batch_r_pub ( - const struct DH_CsDeriveData *cdds, - unsigned int cdds_length, - struct GNUNET_CRYPTO_CSPublicRPairP *r_pubs); - -/** - * Sign the message in @a purpose with the donau's signing key. - * - * The @a purpose data is the beginning of the data of which the signature is - * to be created. The `size` field in @a purpose must correctly indicate the - * number of bytes of the data structure, including its header. Use - * #DH_keys_donau_sign() instead of calling this function directly! - * - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the donau - * @param[out] sig signature over purpose using current signing key - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donau_sign_ ( - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct DONAU_EddsaPublicKeyP *pub, - struct DONAU_DonauSignatureP *sig); - - -/** - * Sign the message in @a purpose with the donau's signing key. - * - * The @a purpose data is the beginning of the data of which the signature is - * to be created. The `size` field in @a purpose must correctly indicate the - * number of bytes of the data structure, including its header. Use - * #DH_keys_donau_sign() instead of calling this function directly! - * - * @param cls key state state to look in - * @param purpose the message to sign - * @param[out] pub set to the current public signing key of the donau - * @param[out] sig signature over purpose using current signing key - * @return #TALER_EC_NONE on success - */ -enum TALER_ErrorCode -DH_keys_donau_sign2_ ( - void *cls, - const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose, - struct DONAU_EddsaPublicKeyP *pub, - struct DONAU_DonauSignatureP *sig); - - -/** - * @ingroup crypto - * @brief EdDSA sign a given block. - * - * The @a ps data must be a fixed-size struct for which the signature is to be - * created. The `size` field in @a ps->purpose must correctly indicate the - * number of bytes of the data structure, including its header. - * - * @param ps packed struct with what to sign, MUST begin with a purpose - * @param[out] pub where to store the public key to use for the signing - * @param[out] sig where to write the signature - * @return #TALER_EC_NONE on success - */ -#define DH_keys_donau_sign(ps,pub,sig) \ - ({ \ - /* check size is set correctly */ \ - GNUNET_assert (htonl ((ps)->purpose.size) == \ - sizeof (*ps)); \ - /* check 'ps' begins with the purpose */ \ - GNUNET_static_assert (((void*) (ps)) == \ - ((void*) &(ps)->purpose)); \ - DH_keys_donau_sign_ (&(ps)->purpose, \ - pub, \ - sig); \ - }) - - -/** - * @ingroup crypto - * @brief EdDSA sign a given block. - * - * The @a ps data must be a fixed-size struct for which the signature is to be - * created. The `size` field in @a ps->purpose must correctly indicate the - * number of bytes of the data structure, including its header. - * - * This allows requesting multiple donation units with the same @a ksh which - * thus will remain valid until the next call to - * #DH_keys_donation_unit_by_hash() or #DH_keys_get_state() or - * #DH_keys_donau_sign(). - * - * @param ksh key state to use - * @param ps packed struct with what to sign, MUST begin with a purpose - * @param[out] pub where to store the public key to use for the signing - * @param[out] sig where to write the signature - * @return #TALER_EC_NONE on success - */ -#define DH_keys_donau_sign2(ksh,ps,pub,sig) \ - ({ \ - /* check size is set correctly */ \ - GNUNET_assert (htonl ((ps)->purpose.size) == \ - sizeof (*ps)); \ - /* check 'ps' begins with the purpose */ \ - GNUNET_static_assert (((void*) (ps)) == \ - ((void*) &(ps)->purpose)); \ - DH_keys_donau_sign2_ (ksh, \ - &(ps)->purpose, \ - pub, \ - sig); \ - }) - - -/** - * Function to call to handle requests to "/keys" by sending - * back our current key material. - * - * @param rc request context - * @param args array of additional options (must be empty for this function) - * @return MHD result code - */ -MHD_RESULT -DH_keys_get_handler (struct DH_RequestContext *rc, - const char *const args[]); - - -/** - * Initialize keys subsystem. - * - * @return #GNUNET_OK on success - */ -enum GNUNET_GenericReturnValue -DH_keys_init (void); - - -#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am @@ -13,23 +13,20 @@ endif # Libraries -lib_LTLIBRARIES = \ - libtalerdonau.la - -libtalerdonau_la_LDFLAGS = \ - -version-info 5:0:0 \ - -no-undefined - -libtalerdonau_la_SOURCES = \ - donau_api_charities_open.c - -# maybe need libtalercurl -libtalerdonau_la_LIBADD = \ - $(top_builddir)/src/json/libtalerjson.la \ - $(top_builddir)/src/util/libdonauutil.la \ - -lgnunetcurl \ - -lgnunetjson \ - -lgnunetutil \ - -ljansson \ - $(LIBGNURLCURL_LIBS) \ - $(XLIB) +#lib_LTLIBRARIES = \ +# libdonau.la +# +#libdonau_la_LDFLAGS = \ +# -version-info 5:0:0 \ +# -no-undefined +# +## maybe need libtalercurl +#libdonau_la_LIBADD = \ +# $(top_builddir)/src/json/libtalerjson.la \ +# $(top_builddir)/src/util/libdonauutil.la \ +# -lgnunetcurl \ +# -lgnunetjson \ +# -lgnunetutil \ +# -ljansson \ +# $(LIBGNURLCURL_LIBS) \ +# $(XLIB) diff --git a/src/lib/donau_api_charities_close.c b/src/lib/donau_api_charities_close.c @@ -1,84 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_reserves_close.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/close requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP close codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A /reserves/$RID/close Handle - */ -struct DONAU_ReservesCloseHandle -{ - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #DH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Function to call with the result. - */ - DONAU_ReservesCloseCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Our signature. - */ - struct TALER_ReserveSignatureP reserve_sig; - - /** - * When did we make the request. - */ - struct GNUNET_TIME_Timestamp ts; - -}; - -/* end of donau_api_reserves_close.c */ diff --git a/src/lib/donau_api_charities_get.c b/src/lib/donau_api_charities_get.c @@ -1,266 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_reserves_get.c - * @brief Implementation of the GET /reserves/$RESERVE_PUB requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A /reserves/ GET Handle - */ -struct DONAU_ReservesGetHandle -{ - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - DONAU_ReservesGetCallback cb; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Closure for @a cb. - */ - void *cb_cls; - -}; - - -/** - * We received an #MHD_HTTP_OK status code. Handle the JSON - * response. - * - * @param rgh handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_get_ok (struct DONAU_ReservesGetHandle *rgh, - const json_t *j) -{ - struct DONAU_ReserveSummary rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_OK - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &rs.details.ok.balance), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - rgh->cb (rgh->cb_cls, - &rs); - rgh->cb = NULL; - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserves/ GET request. - * - * @param cls the `struct DONAU_ReservesGetHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reserves_get_finished (void *cls, - long response_code, - const void *response) -{ - struct DONAU_ReservesGetHandle *rgh = cls; - const json_t *j = response; - struct DONAU_ReserveSummary rs = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - rgh->job = NULL; - switch (response_code) - { - case 0: - rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - handle_reserves_get_ok (rgh, - j)) - { - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for GET %s\n", - (unsigned int) response_code, - (int) rs.hr.ec, - rgh->url); - break; - } - if (NULL != rgh->cb) - { - rgh->cb (rgh->cb_cls, - &rs); - rgh->cb = NULL; - } - DONAU_reserves_get_cancel (rgh); -} - - -struct DONAU_ReservesGetHandle * -DONAU_reserves_get ( - struct GNUNET_CURL_Context *ctx, - const char *url, - const struct TALER_ReservePublicKeyP *reserve_pub, - struct GNUNET_TIME_Relative timeout, - DONAU_ReservesGetCallback cb, - void *cb_cls) -{ - struct DONAU_ReservesGetHandle *rgh; - CURL *eh; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 16 + 32]; - - { - char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; - char *end; - char timeout_str[32]; - - end = GNUNET_STRINGS_data_to_string ( - reserve_pub, - sizeof (*reserve_pub), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (timeout_str, - sizeof (timeout_str), - "%llu", - (unsigned long long) - (timeout.rel_value_us - / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us)); - if (GNUNET_TIME_relative_is_zero (timeout)) - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s", - pub_str); - else - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s?timeout_ms=%s", - pub_str, - timeout_str); - } - rgh = GNUNET_new (struct DONAU_ReservesGetHandle); - rgh->cb = cb; - rgh->cb_cls = cb_cls; - rgh->reserve_pub = *reserve_pub; - rgh->url = TALER_url_join (url, - arg_str, - NULL); - if (NULL == rgh->url) - { - GNUNET_free (rgh); - return NULL; - } - eh = DONAU_curl_easy_get_ (rgh->url); - if (NULL == eh) - { - GNUNET_break (0); - GNUNET_free (rgh->url); - GNUNET_free (rgh); - return NULL; - } - rgh->job = GNUNET_CURL_job_add (ctx, - eh, - &handle_reserves_get_finished, - rgh); - return rgh; -} - - -void -DONAU_reserves_get_cancel ( - struct DONAU_ReservesGetHandle *rgh) -{ - if (NULL != rgh->job) - { - GNUNET_CURL_job_cancel (rgh->job); - rgh->job = NULL; - } - GNUNET_free (rgh->url); - GNUNET_free (rgh); -} - - -/* end of donau_api_reserves_get.c */ diff --git a/src/lib/donau_api_charities_history.c b/src/lib/donau_api_charities_history.c @@ -1,363 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_reserves_history.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/history requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP history codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A /reserves/$RID/history Handle - */ -struct DONAU_ReservesHistoryHandle -{ - - /** - * The keys of the donau this request handle will use - */ - struct DONAU_Keys *keys; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #DH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Function to call with the result. - */ - DONAU_ReservesHistoryCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Our signature. - */ - struct TALER_ReserveSignatureP reserve_sig; - - /** - * When did we make the request. - */ - struct GNUNET_TIME_Timestamp ts; - -}; - - -/** - * We received an #MHD_HTTP_OK history code. Handle the JSON - * response. - * - * @param rsh handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_history_ok (struct DONAU_ReservesHistoryHandle *rsh, - const json_t *j) -{ - const json_t *history; - unsigned int len; - struct DONAU_ReserveHistory rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_OK, - .ts = rsh->ts, - .reserve_sig = &rsh->reserve_sig - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &rs.details.ok.balance), - GNUNET_JSON_spec_array_const ("history", - &history), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - len = json_array_size (history); - { - struct DONAU_ReserveHistoryEntry *rhistory; - - rhistory = GNUNET_new_array (len, - struct DONAU_ReserveHistoryEntry); - if (GNUNET_OK != - DONAU_parse_reserve_history (rsh->keys, - history, - &rsh->reserve_pub, - rs.details.ok.balance.currency, - &rs.details.ok.total_in, - &rs.details.ok.total_out, - len, - rhistory)) - { - GNUNET_break_op (0); - DONAU_free_reserve_history (len, - rhistory); - return GNUNET_SYSERR; - } - if (NULL != rsh->cb) - { - rs.details.ok.history = rhistory; - rs.details.ok.history_len = len; - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - DONAU_free_reserve_history (len, - rhistory); - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserves/$RID/history request. - * - * @param cls the `struct DONAU_ReservesHistoryHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reserves_history_finished (void *cls, - long response_code, - const void *response) -{ - struct DONAU_ReservesHistoryHandle *rsh = cls; - const json_t *j = response; - struct DONAU_ReserveHistory rs = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - rsh->job = NULL; - switch (response_code) - { - case 0: - rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - handle_reserves_history_ok (rsh, - j)) - { - GNUNET_break_op (0); - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_FORBIDDEN: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_CONFLICT: - /* Insufficient balance to inquire for reserve history */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for reserves history\n", - (unsigned int) response_code, - (int) rs.hr.ec); - break; - } - if (NULL != rsh->cb) - { - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - DONAU_reserves_history_cancel (rsh); -} - - -struct DONAU_ReservesHistoryHandle * -DONAU_reserves_history ( - struct GNUNET_CURL_Context *ctx, - const char *url, - struct DONAU_Keys *keys, - const struct TALER_ReservePrivateKeyP *reserve_priv, - DONAU_ReservesHistoryCallback cb, - void *cb_cls) -{ - struct DONAU_ReservesHistoryHandle *rsh; - CURL *eh; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; - const struct DONAU_GlobalFee *gf; - - rsh = GNUNET_new (struct DONAU_ReservesHistoryHandle); - rsh->cb = cb; - rsh->cb_cls = cb_cls; - rsh->ts = GNUNET_TIME_timestamp_get (); - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &rsh->reserve_pub.eddsa_pub); - { - char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; - char *end; - - end = GNUNET_STRINGS_data_to_string ( - &rsh->reserve_pub, - sizeof (rsh->reserve_pub), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s/history", - pub_str); - } - rsh->url = TALER_url_join (url, - arg_str, - NULL); - if (NULL == rsh->url) - { - GNUNET_free (rsh); - return NULL; - } - eh = DONAU_curl_easy_get_ (rsh->url); - if (NULL == eh) - { - GNUNET_break (0); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - gf = DONAU_get_global_fee (keys, - rsh->ts); - if (NULL == gf) - { - GNUNET_break_op (0); - curl_easy_cleanup (eh); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - TALER_wallet_reserve_history_sign (rsh->ts, - &gf->fees.history, - reserve_priv, - &rsh->reserve_sig); - { - json_t *history_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_timestamp ("request_timestamp", - rsh->ts), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &rsh->reserve_sig)); - - if (GNUNET_OK != - TALER_curl_easy_post (&rsh->post_ctx, - eh, - history_obj)) - { - GNUNET_break (0); - curl_easy_cleanup (eh); - json_decref (history_obj); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - json_decref (history_obj); - } - rsh->keys = DONAU_keys_incref (keys); - rsh->job = GNUNET_CURL_job_add2 (ctx, - eh, - rsh->post_ctx.headers, - &handle_reserves_history_finished, - rsh); - return rsh; -} - - -void -DONAU_reserves_history_cancel ( - struct DONAU_ReservesHistoryHandle *rsh) -{ - if (NULL != rsh->job) - { - GNUNET_CURL_job_cancel (rsh->job); - rsh->job = NULL; - } - TALER_curl_easy_post_finished (&rsh->post_ctx); - GNUNET_free (rsh->url); - DONAU_keys_decref (rsh->keys); - GNUNET_free (rsh); -} - - -/* end of donau_api_reserves_history.c */ diff --git a/src/lib/donau_api_charities_open.c b/src/lib/donau_api_charities_open.c @@ -1,61 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_reserves_open.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/open requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP open codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_common.h" -#include "donau_api_handle.h" -#include "donau_api_curl_defaults.h" - - -/** - * Information we keep per coin to validate the reply. - */ -struct CoinData -{ - /** - * Public key of the coin. - */ - struct TALER_CoinSpendPublicKeyP coin_pub; - - /** - * Signature by the coin. - */ - struct TALER_CoinSpendSignatureP coin_sig; - - /** - * The hash of the denomination's public key - */ - struct TALER_DenominationHashP h_denom_pub; - - /** - * How much did this coin contribute. - */ - struct TALER_Amount contribution; -}; - -/* end of donau_api_reserves_open.c */ diff --git a/src/lib/donau_api_charities_status.c b/src/lib/donau_api_charities_status.c @@ -1,336 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_reserves_status.c - * @brief Implementation of the POST /reserves/$RESERVE_PUB/status requests - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A /reserves/$RID/status Handle - */ -struct DONAU_ReservesStatusHandle -{ - - /** - * The keys of the donau this request handle will use - */ - struct DONAU_Keys *keys; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #DH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Function to call with the result. - */ - DONAU_ReservesStatusCallback cb; - - /** - * Public key of the reserve we are querying. - */ - struct TALER_ReservePublicKeyP reserve_pub; - - /** - * Closure for @a cb. - */ - void *cb_cls; - -}; - - -/** - * We received an #MHD_HTTP_OK status code. Handle the JSON - * response. - * - * @param rsh handle of the request - * @param j JSON response - * @return #GNUNET_OK on success - */ -static enum GNUNET_GenericReturnValue -handle_reserves_status_ok (struct DONAU_ReservesStatusHandle *rsh, - const json_t *j) -{ - const json_t *history; - unsigned int len; - struct DONAU_ReserveStatus rs = { - .hr.reply = j, - .hr.http_status = MHD_HTTP_OK - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &rs.details.ok.balance), - GNUNET_JSON_spec_array_const ("history", - &history), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - len = json_array_size (history); - { - struct DONAU_ReserveHistoryEntry *rhistory; - - rhistory = GNUNET_new_array (len, - struct DONAU_ReserveHistoryEntry); - if (GNUNET_OK != - DONAU_parse_reserve_history (rsh->keys, - history, - &rsh->reserve_pub, - rs.details.ok.balance.currency, - &rs.details.ok.total_in, - &rs.details.ok.total_out, - len, - rhistory)) - { - GNUNET_break_op (0); - DONAU_free_reserve_history (len, - rhistory); - GNUNET_JSON_parse_free (spec); - return GNUNET_SYSERR; - } - if (NULL != rsh->cb) - { - rs.details.ok.history = rhistory; - rs.details.ok.history_len = len; - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - DONAU_free_reserve_history (len, - rhistory); - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserves/$RID/status request. - * - * @param cls the `struct DONAU_ReservesStatusHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reserves_status_finished (void *cls, - long response_code, - const void *response) -{ - struct DONAU_ReservesStatusHandle *rsh = cls; - const json_t *j = response; - struct DONAU_ReserveStatus rs = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - rsh->job = NULL; - switch (response_code) - { - case 0: - rs.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - handle_reserves_status_ok (rsh, - j)) - { - rs.hr.http_status = 0; - rs.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - break; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_FORBIDDEN: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - GNUNET_break (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - rs.hr.ec = TALER_JSON_get_error_code (j); - rs.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for reserves status\n", - (unsigned int) response_code, - (int) rs.hr.ec); - break; - } - if (NULL != rsh->cb) - { - rsh->cb (rsh->cb_cls, - &rs); - rsh->cb = NULL; - } - DONAU_reserves_status_cancel (rsh); -} - - -struct DONAU_ReservesStatusHandle * -DONAU_reserves_status ( - struct GNUNET_CURL_Context *ctx, - const char *url, - struct DONAU_Keys *keys, - const struct TALER_ReservePrivateKeyP *reserve_priv, - DONAU_ReservesStatusCallback cb, - void *cb_cls) -{ - struct DONAU_ReservesStatusHandle *rsh; - CURL *eh; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; - struct TALER_ReserveSignatureP reserve_sig; - struct GNUNET_TIME_Timestamp ts - = GNUNET_TIME_timestamp_get (); - - rsh = GNUNET_new (struct DONAU_ReservesStatusHandle); - rsh->cb = cb; - rsh->cb_cls = cb_cls; - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &rsh->reserve_pub.eddsa_pub); - { - char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; - char *end; - - end = GNUNET_STRINGS_data_to_string ( - &rsh->reserve_pub, - sizeof (rsh->reserve_pub), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s/status", - pub_str); - } - rsh->url = TALER_url_join (url, - arg_str, - NULL); - if (NULL == rsh->url) - { - GNUNET_free (rsh); - return NULL; - } - eh = DONAU_curl_easy_get_ (rsh->url); - if (NULL == eh) - { - GNUNET_break (0); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - TALER_wallet_reserve_status_sign (ts, - reserve_priv, - &reserve_sig); - { - json_t *status_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_timestamp ("request_timestamp", - ts), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &reserve_sig)); - - if (GNUNET_OK != - TALER_curl_easy_post (&rsh->post_ctx, - eh, - status_obj)) - { - GNUNET_break (0); - curl_easy_cleanup (eh); - json_decref (status_obj); - GNUNET_free (rsh->url); - GNUNET_free (rsh); - return NULL; - } - json_decref (status_obj); - } - rsh->keys = DONAU_keys_incref (keys); - rsh->job = GNUNET_CURL_job_add2 (ctx, - eh, - rsh->post_ctx.headers, - &handle_reserves_status_finished, - rsh); - return rsh; -} - - -void -DONAU_reserves_status_cancel ( - struct DONAU_ReservesStatusHandle *rsh) -{ - if (NULL != rsh->job) - { - GNUNET_CURL_job_cancel (rsh->job); - rsh->job = NULL; - } - TALER_curl_easy_post_finished (&rsh->post_ctx); - GNUNET_free (rsh->url); - DONAU_keys_decref (rsh->keys); - GNUNET_free (rsh); -} - - -/* end of donau_api_reserves_status.c */ diff --git a/src/lib/donau_api_csr_issue_receipts.c b/src/lib/donau_api_csr_issue_receipts.c @@ -1,279 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_csr_withdraw.c - * @brief Implementation of /csr-withdraw requests (get R in donau used for Clause Schnorr withdraw and refresh) - * @author Lucien Heuzeveldt - * @author Gian Demarmels - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A Clause Schnorr R Handle - */ -struct DONAU_CsRWithdrawHandle -{ - /** - * Function to call with the result. - */ - DONAU_CsRWithdrawCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Context for #DH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; -}; - - -/** - * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation. - * Extract the coin's signature and return it to the caller. The signature we - * get from the donau is for the blinded value. Thus, we first must - * unblind it and then should verify its validity against our coin's hash. - * - * If everything checks out, we return the unblinded signature - * to the application via the callback. - * - * @param csrh operation handle - * @param av reply from the donau - * @param hr http response details - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static enum GNUNET_GenericReturnValue -csr_ok (struct DONAU_CsRWithdrawHandle *csrh, - const json_t *av, - struct DONAU_HttpResponse *hr) -{ - struct DONAU_CsRWithdrawResponse csrr = { - .hr = *hr, - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_donau_withdraw_values ( - "ewv", - &csrr.details.ok.alg_values), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (av, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - csrh->cb (csrh->cb_cls, - &csrr); - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the HTTP /csr request. - * - * @param cls the `struct DONAU_CsRWithdrawHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_csr_finished (void *cls, - long response_code, - const void *response) -{ - struct DONAU_CsRWithdrawHandle *csrh = cls; - const json_t *j = response; - struct DONAU_HttpResponse hr = { - .reply = j, - .http_status = (unsigned int) response_code - }; - struct DONAU_CsRWithdrawResponse csrr = { - .hr = hr - }; - - csrh->job = NULL; - switch (response_code) - { - case 0: - csrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - { - if (GNUNET_OK != - csr_ok (csrh, - response, - &hr)) - { - GNUNET_break_op (0); - csrr.hr.http_status = 0; - csrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - } - DONAU_csr_withdraw_cancel (csrh); - return; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, the donau basically just says - that it doesn't know the /csr endpoint or denomination. - Can happen if the donau doesn't support Clause Schnorr. - We should simply pass the JSON reply to the application. */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_GONE: - /* could happen if denomination was revoked */ - /* Note: one might want to check /keys for revocation - signature here, alas tricky in case our /keys - is outdated => left to clients */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - csrr.hr.ec = TALER_JSON_get_error_code (j); - csrr.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for CS R request\n", - (unsigned int) response_code, - (int) hr.ec); - break; - } - csrh->cb (csrh->cb_cls, - &csrr); - csrh->cb = NULL; - DONAU_csr_withdraw_cancel (csrh); -} - - -struct DONAU_CsRWithdrawHandle * -DONAU_csr_withdraw ( - struct GNUNET_CURL_Context *curl_ctx, - const char *donau_url, - const struct DONAU_DenomPublicKey *pk, - const struct TALER_CsNonce *nonce, - DONAU_CsRWithdrawCallback res_cb, - void *res_cb_cls) -{ - struct DONAU_CsRWithdrawHandle *csrh; - - if (TALER_DENOMINATION_CS != pk->key.cipher) - { - GNUNET_break (0); - return NULL; - } - csrh = GNUNET_new (struct DONAU_CsRWithdrawHandle); - csrh->cb = res_cb; - csrh->cb_cls = res_cb_cls; - csrh->url = TALER_url_join (donau_url, - "csr-withdraw", - NULL); - if (NULL == csrh->url) - { - GNUNET_free (csrh); - return NULL; - } - - { - CURL *eh; - json_t *req; - - req = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_varsize ("nonce", - nonce, - sizeof(struct TALER_CsNonce)), - GNUNET_JSON_pack_data_varsize ("denom_pub_hash", - &pk->h_key, - sizeof(struct TALER_DenominationHashP))); - GNUNET_assert (NULL != req); - eh = DONAU_curl_easy_get_ (csrh->url); - if ( (NULL == eh) || - (GNUNET_OK != - TALER_curl_easy_post (&csrh->post_ctx, - eh, - req)) ) - { - GNUNET_break (0); - if (NULL != eh) - curl_easy_cleanup (eh); - json_decref (req); - GNUNET_free (csrh->url); - GNUNET_free (csrh); - return NULL; - } - json_decref (req); - csrh->job = GNUNET_CURL_job_add2 (curl_ctx, - eh, - csrh->post_ctx.headers, - &handle_csr_finished, - csrh); - } - return csrh; -} - - -void -DONAU_csr_withdraw_cancel (struct - DONAU_CsRWithdrawHandle *csrh) -{ - if (NULL != csrh->job) - { - GNUNET_CURL_job_cancel (csrh->job); - csrh->job = NULL; - } - GNUNET_free (csrh->url); - TALER_curl_easy_post_finished (&csrh->post_ctx); - GNUNET_free (csrh); -} diff --git a/src/lib/donau_api_issue_receipts.c b/src/lib/donau_api_issue_receipts.c @@ -1,265 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2022 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_withdraw.c - * @brief Implementation of /reserves/$RESERVE_PUB/withdraw requests with blinding/unblinding - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A Withdraw Handle - */ -struct DONAU_WithdrawHandle -{ - - /** - * The curl context to use - */ - struct GNUNET_CURL_Context *curl_ctx; - - /** - * The base-URL to the donau - */ - const char *donau_url; - - /** - * The /keys material from the donau - */ - struct DONAU_Keys *keys; - - /** - * Handle for the actual (internal) withdraw operation. - */ - struct DONAU_Withdraw2Handle *wh2; - - /** - * Function to call with the result. - */ - DONAU_WithdrawCallback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * blinding secret - */ - union TALER_DenominationBlindingKeyP bks; - - /** - * Private key of the coin we are withdrawing. - */ - struct TALER_CoinSpendPrivateKeyP priv; - - /** - * Details of the planchet. - */ - struct TALER_PlanchetDetail pd; - - /** - * Values of the @cipher selected - */ - struct TALER_DonauWithdrawValues alg_values; - - /** - * Denomination key we are withdrawing. - */ - struct DONAU_DenomPublicKey pk; - - /** - * Handler for the CS R request (only used for TALER_DENOMINATION_CS denominations) - */ - struct DONAU_CsRWithdrawHandle *csrh; - -}; - - -/** - * Function called when stage 1 of CS withdraw is finished (request r_pub's) - * - * @param cls the `struct DONAU_WithdrawHandle` - * @param csrr replies from the /csr-withdraw request - */ -static void -withdraw_cs_stage_two_callback ( - void *cls, - const struct DONAU_CsRWithdrawResponse *csrr) -{ - struct DONAU_WithdrawHandle *wh = cls; - struct DONAU_WithdrawResponse wr = { - .hr = csrr->hr - }; - - wh->csrh = NULL; - GNUNET_assert (TALER_DENOMINATION_CS == wh->pk.key.cipher); - switch (csrr->hr.http_status) - { - case MHD_HTTP_OK: - wh->alg_values = csrr->details.ok.alg_values; - TALER_planchet_setup_coin_priv (&wh->ps, - &wh->alg_values, - &wh->priv); - TALER_planchet_blinding_secret_create (&wh->ps, - &wh->alg_values, - &wh->bks); - /* This initializes the 2nd half of the - wh->pd.blinded_planchet! */ - if (GNUNET_OK != - TALER_planchet_prepare (&wh->pk.key, - &wh->alg_values, - &wh->bks, - &wh->priv, - wh->ach, - &wh->c_hash, - &wh->pd)) - { - GNUNET_break (0); - break; - } - wh->wh2 = DONAU_withdraw2 (wh->curl_ctx, - wh->donau_url, - wh->keys, - &wh->pd, - wh->reserve_priv, - &handle_reserve_withdraw_finished, - wh); - return; - default: - break; - } - wh->cb (wh->cb_cls, - &wr); - DONAU_withdraw_cancel (wh); -} - - -struct DONAU_WithdrawHandle * -DONAU_withdraw ( - struct GNUNET_CURL_Context *curl_ctx, - const char *donau_url, - struct DONAU_Keys *keys, - const struct TALER_ReservePrivateKeyP *reserve_priv, - const struct DONAU_WithdrawCoinInput *wci, - DONAU_WithdrawCallback res_cb, - void *res_cb_cls) -{ - struct DONAU_WithdrawHandle *wh; - - wh = GNUNET_new (struct DONAU_WithdrawHandle); - wh->keys = DONAU_keys_incref (keys); - wh->donau_url = donau_url; - wh->curl_ctx = curl_ctx; - wh->cb = res_cb; - wh->cb_cls = res_cb_cls; - wh->reserve_priv = reserve_priv; - wh->ps = *wci->ps; - wh->ach = wci->ach; - wh->pk = *wci->pk; - TALER_denom_pub_deep_copy (&wh->pk.key, - &wci->pk->key); - - switch (wci->pk->key.cipher) - { - case TALER_DENOMINATION_RSA: - { - wh->alg_values.cipher = TALER_DENOMINATION_RSA; - TALER_planchet_setup_coin_priv (&wh->ps, - &wh->alg_values, - &wh->priv); - TALER_planchet_blinding_secret_create (&wh->ps, - &wh->alg_values, - &wh->bks); - if (GNUNET_OK != - TALER_planchet_prepare (&wh->pk.key, - &wh->alg_values, - &wh->bks, - &wh->priv, - wh->ach, - &wh->c_hash, - &wh->pd)) - { - GNUNET_break (0); - GNUNET_free (wh); - return NULL; - } - wh->wh2 = DONAU_withdraw2 (curl_ctx, - donau_url, - keys, - &wh->pd, - wh->reserve_priv, - &handle_reserve_withdraw_finished, - wh); - break; - } - case TALER_DENOMINATION_CS: - { - TALER_cs_withdraw_nonce_derive ( - &wh->ps, - &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce); - /* Note that we only initialize the first half - of the blinded_planchet here; the other part - will be done after the /csr-withdraw request! */ - wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; - wh->csrh = DONAU_csr_withdraw ( - curl_ctx, - donau_url, - &wh->pk, - &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce, - &withdraw_cs_stage_two_callback, - wh); - break; - } - default: - GNUNET_break (0); - GNUNET_free (wh); - return NULL; - } - return wh; -} - - -void -DONAU_withdraw_cancel (struct DONAU_WithdrawHandle *wh) -{ - TALER_blinded_planchet_free (&wh->pd.blinded_planchet); - if (NULL != wh->csrh) - { - DONAU_csr_withdraw_cancel (wh->csrh); - wh->csrh = NULL; - } - if (NULL != wh->wh2) - { - DONAU_withdraw2_cancel (wh->wh2); - wh->wh2 = NULL; - } - DONAU_keys_decref (wh->keys); - TALER_denom_pub_free (&wh->pk.key); - GNUNET_free (wh); -} diff --git a/src/lib/donau_api_issue_receipts2.c b/src/lib/donau_api_issue_receipts2.c @@ -1,498 +0,0 @@ -/* - This file is part of TALER - Copyright (C) 2014-2023 Taler Systems SA - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU 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 CHARITYABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see - <http://www.gnu.org/licenses/> -*/ -/** - * @file lib/donau_api_withdraw2.c - * @brief Implementation of /reserves/$RESERVE_PUB/withdraw requests without blinding/unblinding - * @author Christian Grothoff - */ -#include "taler/platform.h" -#include <jansson.h> -#include <microhttpd.h> /* just for HTTP status codes */ -#include <gnunet/gnunet_util_lib.h> -#include <gnunet/gnunet_json_lib.h> -#include <gnunet/gnunet_curl_lib.h> -#include "taler_donau_service.h" -#include "taler/taler_json_lib.h" -#include "donau_api_handle.h" -#include "taler_signatures.h" -#include "donau_api_curl_defaults.h" - - -/** - * @brief A Withdraw Handle - */ -struct DONAU_Withdraw2Handle -{ - - /** - * The /keys material from the donau - */ - struct DONAU_Keys *keys; - - /** - * The url for this request. - */ - char *url; - - /** - * Handle for the request. - */ - struct GNUNET_CURL_Job *job; - - /** - * Function to call with the result. - */ - DONAU_Withdraw2Callback cb; - - /** - * Closure for @a cb. - */ - void *cb_cls; - - /** - * Context for #DH_curl_easy_post(). Keeps the data that must - * persist for Curl to make the upload. - */ - struct TALER_CURL_PostContext post_ctx; - - /** - * Total amount requested (value plus withdraw fee). - */ - struct TALER_Amount requested_amount; - - /** - * Public key of the reserve we are withdrawing from. - */ - struct TALER_ReservePublicKeyP reserve_pub; - -}; - - -/** - * We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation. - * Extract the coin's signature and return it to the caller. The signature we - * get from the donau is for the blinded value. Thus, we first must - * unblind it and then should verify its validity against our coin's hash. - * - * If everything checks out, we return the unblinded signature - * to the application via the callback. - * - * @param wh operation handle - * @param json reply from the donau - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static enum GNUNET_GenericReturnValue -reserve_withdraw_ok (struct DONAU_Withdraw2Handle *wh, - const json_t *json) -{ - struct DONAU_Withdraw2Response w2r = { - .hr.reply = json, - .hr.http_status = MHD_HTTP_OK - }; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_blinded_denom_sig ("ev_sig", - &w2r.details.ok.blind_sig), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* signature is valid, return it to the application */ - wh->cb (wh->cb_cls, - &w2r); - /* make sure callback isn't called again after return */ - wh->cb = NULL; - GNUNET_JSON_parse_free (spec); - return GNUNET_OK; -} - - -/** - * We got a 409 CONFLICT response for the /reserves/$RESERVE_PUB/withdraw operation. - * Check the signatures on the withdraw transactions in the provided - * history and that the balances add up. We don't do anything directly - * with the information, as the JSON will be returned to the application. - * However, our job is ensuring that the donau followed the protocol, and - * this in particular means checking all of the signatures in the history. - * - * @param wh operation handle - * @param json reply from the donau - * @return #GNUNET_OK on success, #GNUNET_SYSERR on errors - */ -static enum GNUNET_GenericReturnValue -reserve_withdraw_payment_required ( - struct DONAU_Withdraw2Handle *wh, - const json_t *json) -{ - struct TALER_Amount balance; - struct TALER_Amount total_in_from_history; - struct TALER_Amount total_out_from_history; - json_t *history; - size_t len; - struct GNUNET_JSON_Specification spec[] = { - TALER_JSON_spec_amount_any ("balance", - &balance), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - history = json_object_get (json, - "history"); - if (NULL == history) - { - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - - /* go over transaction history and compute - total incoming and outgoing amounts */ - len = json_array_size (history); - { - struct DONAU_ReserveHistoryEntry *rhistory; - - /* Use heap allocation as "len" may be very big and thus this may - not fit on the stack. Use "GNUNET_malloc_large" as a malicious - donau may theoretically try to crash us by giving a history - that does not fit into our memory. */ - rhistory = GNUNET_malloc_large ( - sizeof (struct DONAU_ReserveHistoryEntry) - * len); - if (NULL == rhistory) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (GNUNET_OK != - DONAU_parse_reserve_history (wh->keys, - history, - &wh->reserve_pub, - balance.currency, - &total_in_from_history, - &total_out_from_history, - len, - rhistory)) - { - GNUNET_break_op (0); - DONAU_free_reserve_history (len, - rhistory); - return GNUNET_SYSERR; - } - DONAU_free_reserve_history (len, - rhistory); - } - - /* Check that funds were really insufficient */ - if (0 >= TALER_amount_cmp (&wh->requested_amount, - &balance)) - { - /* Requested amount is smaller or equal to reported balance, - so this should not have failed. */ - GNUNET_break_op (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; -} - - -/** - * Function called when we're done processing the - * HTTP /reserves/$RESERVE_PUB/withdraw request. - * - * @param cls the `struct DONAU_WithdrawHandle` - * @param response_code HTTP response code, 0 on error - * @param response parsed JSON result, NULL on error - */ -static void -handle_reserve_withdraw_finished (void *cls, - long response_code, - const void *response) -{ - struct DONAU_Withdraw2Handle *wh = cls; - const json_t *j = response; - struct DONAU_Withdraw2Response w2r = { - .hr.reply = j, - .hr.http_status = (unsigned int) response_code - }; - - wh->job = NULL; - switch (response_code) - { - case 0: - w2r.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (GNUNET_OK != - reserve_withdraw_ok (wh, - j)) - { - GNUNET_break_op (0); - w2r.hr.http_status = 0; - w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - GNUNET_assert (NULL == wh->cb); - DONAU_withdraw2_cancel (wh); - return; - case MHD_HTTP_BAD_REQUEST: - /* This should never happen, either us or the donau is buggy - (or API version conflict); just pass JSON reply to the application */ - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_FORBIDDEN: - GNUNET_break_op (0); - /* Nothing really to verify, donau says one of the signatures is - invalid; as we checked them, this should never happen, we - should pass the JSON reply to the application */ - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_NOT_FOUND: - /* Nothing really to verify, the donau basically just says - that it doesn't know this reserve. Can happen if we - query before the wire transfer went through. - We should simply pass the JSON reply to the application. */ - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_CONFLICT: - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - - if (TALER_EC_DONAU_RESERVES_AGE_RESTRICTION_REQUIRED == w2r.hr.ec) - break; - - /* The donau says that the reserve has insufficient funds; - check the signatures in the history... */ - if (GNUNET_OK != - reserve_withdraw_payment_required (wh, - j)) - { - GNUNET_break_op (0); - w2r.hr.http_status = 0; - w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - } - break; - case MHD_HTTP_GONE: - /* could happen if denomination was revoked */ - /* Note: one might want to check /keys for revocation - signature here, alas tricky in case our /keys - is outdated => left to clients */ - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - break; - case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: - /* only validate reply is well-formed */ - { - uint64_t ptu; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_uint64 ("requirement_row", - &ptu), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (j, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - w2r.hr.http_status = 0; - w2r.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED; - break; - } - } - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - /* Server had an internal issue; we should retry, but this API - leaves this to the application */ - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - break; - default: - /* unexpected response code */ - GNUNET_break_op (0); - w2r.hr.ec = TALER_JSON_get_error_code (j); - w2r.hr.hint = TALER_JSON_get_error_hint (j); - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d for donau withdraw\n", - (unsigned int) response_code, - (int) w2r.hr.ec); - break; - } - if (NULL != wh->cb) - { - wh->cb (wh->cb_cls, - &w2r); - wh->cb = NULL; - } - DONAU_withdraw2_cancel (wh); -} - - -struct DONAU_Withdraw2Handle * -DONAU_withdraw2 ( - struct GNUNET_CURL_Context *curl_ctx, - const char *donau_url, - struct DONAU_Keys *keys, - const struct TALER_PlanchetDetail *pd, - const struct TALER_ReservePrivateKeyP *reserve_priv, - DONAU_Withdraw2Callback res_cb, - void *res_cb_cls) -{ - struct DONAU_Withdraw2Handle *wh; - const struct DONAU_DenomPublicKey *dk; - struct TALER_ReserveSignatureP reserve_sig; - char arg_str[sizeof (struct TALER_ReservePublicKeyP) * 2 + 32]; - struct TALER_BlindedCoinHashP bch; - - GNUNET_assert (NULL != keys); - dk = DONAU_get_denomination_key_by_hash (keys, - &pd->denom_pub_hash); - if (NULL == dk) - { - GNUNET_break (0); - return NULL; - } - wh = GNUNET_new (struct DONAU_Withdraw2Handle); - wh->keys = DONAU_keys_incref (keys); - wh->cb = res_cb; - wh->cb_cls = res_cb_cls; - /* Compute how much we expected to charge to the reserve */ - if (0 > - TALER_amount_add (&wh->requested_amount, - &dk->value, - &dk->fees.withdraw)) - { - /* Overflow here? Very strange, our CPU must be fried... */ - GNUNET_break (0); - GNUNET_free (wh); - return NULL; - } - - GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, - &wh->reserve_pub.eddsa_pub); - - { - char pub_str[sizeof (struct TALER_ReservePublicKeyP) * 2]; - char *end; - - end = GNUNET_STRINGS_data_to_string ( - &wh->reserve_pub, - sizeof (struct TALER_ReservePublicKeyP), - pub_str, - sizeof (pub_str)); - *end = '\0'; - GNUNET_snprintf (arg_str, - sizeof (arg_str), - "reserves/%s/withdraw", - pub_str); - } - - if (GNUNET_OK != - TALER_coin_ev_hash (&pd->blinded_planchet, - &pd->denom_pub_hash, - &bch)) - { - GNUNET_break (0); - GNUNET_free (wh); - return NULL; - } - - TALER_wallet_withdraw_sign (&pd->denom_pub_hash, - &wh->requested_amount, - &bch, - reserve_priv, - &reserve_sig); - { - json_t *withdraw_obj = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_data_auto ("denom_pub_hash", - &pd->denom_pub_hash), - TALER_JSON_pack_blinded_planchet ("coin_ev", - &pd->blinded_planchet), - GNUNET_JSON_pack_data_auto ("reserve_sig", - &reserve_sig)); - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Attempting to withdraw from reserve %s\n", - TALER_B2S (&wh->reserve_pub)); - wh->url = TALER_url_join (donau_url, - arg_str, - NULL); - if (NULL == wh->url) - { - json_decref (withdraw_obj); - GNUNET_free (wh); - return NULL; - } - { - CURL *eh; - - eh = DONAU_curl_easy_get_ (wh->url); - if ( (NULL == eh) || - (GNUNET_OK != - TALER_curl_easy_post (&wh->post_ctx, - eh, - withdraw_obj)) ) - { - GNUNET_break (0); - if (NULL != eh) - curl_easy_cleanup (eh); - json_decref (withdraw_obj); - GNUNET_free (wh->url); - GNUNET_free (wh); - return NULL; - } - json_decref (withdraw_obj); - wh->job = GNUNET_CURL_job_add2 (curl_ctx, - eh, - wh->post_ctx.headers, - &handle_reserve_withdraw_finished, - wh); - } - } - return wh; -} - - -void -DONAU_withdraw2_cancel (struct DONAU_Withdraw2Handle *wh) -{ - if (NULL != wh->job) - { - GNUNET_CURL_job_cancel (wh->job); - wh->job = NULL; - } - GNUNET_free (wh->url); - TALER_curl_easy_post_finished (&wh->post_ctx); - DONAU_keys_decref (wh->keys); - GNUNET_free (wh); -}