/* 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 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with TALER; see the file COPYING. If not, see */ /** * @file taler-exchange-httpd_responses.c * @brief API for generating generic replies of the exchange; these * functions are called TEH_RESPONSE_reply_ and they generate * and queue MHD response objects for a given connection. * @author Florian Dold * @author Benedikt Mueller * @author Christian Grothoff */ #include "platform.h" #include #include #include #include "taler-exchange-httpd_responses.h" #include "taler_exchangedb_plugin.h" #include "taler_util.h" #include "taler_json_lib.h" #include "taler_mhd_lib.h" #include "taler-exchange-httpd_keys.h" MHD_RESULT TEH_RESPONSE_reply_unknown_denom_pub_hash ( struct MHD_Connection *connection, const struct TALER_DenominationHashP *dph) { struct TALER_ExchangePublicKeyP epub; struct TALER_ExchangeSignatureP esig; struct GNUNET_TIME_Timestamp now; enum TALER_ErrorCode ec; now = GNUNET_TIME_timestamp_get (); ec = TALER_exchange_online_denomination_unknown_sign ( &TEH_keys_exchange_sign_, now, dph, &epub, &esig); if (TALER_EC_NONE != ec) { GNUNET_break (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, ec, NULL); } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_NOT_FOUND, TALER_JSON_pack_ec (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN), GNUNET_JSON_pack_timestamp ("timestamp", now), GNUNET_JSON_pack_data_auto ("exchange_pub", &epub), GNUNET_JSON_pack_data_auto ("exchange_sig", &esig), GNUNET_JSON_pack_data_auto ("h_denom_pub", dph)); } MHD_RESULT TEH_RESPONSE_reply_expired_denom_pub_hash ( struct MHD_Connection *connection, const struct TALER_DenominationHashP *dph, enum TALER_ErrorCode ec, const char *oper) { struct TALER_ExchangePublicKeyP epub; struct TALER_ExchangeSignatureP esig; enum TALER_ErrorCode ecr; struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); ecr = TALER_exchange_online_denomination_expired_sign ( &TEH_keys_exchange_sign_, now, dph, oper, &epub, &esig); if (TALER_EC_NONE != ecr) { GNUNET_break (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, ec, NULL); } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_GONE, TALER_JSON_pack_ec (ec), GNUNET_JSON_pack_string ("oper", oper), GNUNET_JSON_pack_timestamp ("timestamp", now), GNUNET_JSON_pack_data_auto ("exchange_pub", &epub), GNUNET_JSON_pack_data_auto ("exchange_sig", &esig), GNUNET_JSON_pack_data_auto ("h_denom_pub", dph)); } MHD_RESULT TEH_RESPONSE_reply_invalid_denom_cipher_for_operation ( struct MHD_Connection *connection, const struct TALER_DenominationHashP *dph) { struct TALER_ExchangePublicKeyP epub; struct TALER_ExchangeSignatureP esig; struct GNUNET_TIME_Timestamp now; enum TALER_ErrorCode ec; now = GNUNET_TIME_timestamp_get (); ec = TALER_exchange_online_denomination_unknown_sign ( &TEH_keys_exchange_sign_, now, dph, &epub, &esig); if (TALER_EC_NONE != ec) { GNUNET_break (0); return TALER_MHD_reply_with_error (connection, MHD_HTTP_INTERNAL_SERVER_ERROR, ec, NULL); } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_NOT_FOUND, TALER_JSON_pack_ec ( TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION), GNUNET_JSON_pack_timestamp ("timestamp", now), GNUNET_JSON_pack_data_auto ("exchange_pub", &epub), GNUNET_JSON_pack_data_auto ("exchange_sig", &esig), GNUNET_JSON_pack_data_auto ("h_denom_pub", dph)); } MHD_RESULT TEH_RESPONSE_reply_coin_insufficient_funds ( struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub) { return TALER_MHD_REPLY_JSON_PACK ( connection, TALER_ErrorCode_get_http_status_safe (ec), TALER_JSON_pack_ec (ec), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub), // FIXME - #7267: to be kept only for some of the error types! GNUNET_JSON_pack_data_auto ("h_denom_pub", h_denom_pub)); } MHD_RESULT TEH_RESPONSE_reply_coin_conflicting_contract ( struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct TALER_MerchantWireHashP *h_wire) { return TALER_MHD_REPLY_JSON_PACK ( connection, TALER_ErrorCode_get_http_status_safe (ec), GNUNET_JSON_pack_data_auto ("h_wire", h_wire), TALER_JSON_pack_ec (ec)); } MHD_RESULT TEH_RESPONSE_reply_coin_denomination_conflict ( struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_DenominationPublicKey *prev_denom_pub, const struct TALER_DenominationSignature *prev_denom_sig) { return TALER_MHD_REPLY_JSON_PACK ( connection, TALER_ErrorCode_get_http_status_safe (ec), TALER_JSON_pack_ec (ec), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub), TALER_JSON_pack_denom_pub ("prev_denom_pub", prev_denom_pub), TALER_JSON_pack_denom_sig ("prev_denom_sig", prev_denom_sig) ); } MHD_RESULT TEH_RESPONSE_reply_coin_age_commitment_conflict ( struct MHD_Connection *connection, enum TALER_ErrorCode ec, enum TALER_EXCHANGEDB_CoinKnownStatus status, const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_AgeCommitmentHash *h_age_commitment) { const char *conflict_detail; switch (status) { case TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NULL: conflict_detail = "expected NULL age commitment hash"; h_age_commitment = NULL; break; case TALER_EXCHANGEDB_CKS_AGE_CONFLICT_EXPECTED_NON_NULL: conflict_detail = "expected non-NULL age commitment hash"; break; case TALER_EXCHANGEDB_CKS_AGE_CONFLICT_VALUE_DIFFERS: conflict_detail = "expected age commitment hash differs"; break; default: GNUNET_assert (0); } return TALER_MHD_REPLY_JSON_PACK ( connection, TALER_ErrorCode_get_http_status_safe (ec), TALER_JSON_pack_ec (ec), GNUNET_JSON_pack_data_auto ("coin_pub", coin_pub), GNUNET_JSON_pack_data_auto ("h_denom_pub", h_denom_pub), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_data_auto ("expected_age_commitment_hash", h_age_commitment)), GNUNET_JSON_pack_string ("conflict_detail", conflict_detail) ); } MHD_RESULT TEH_RESPONSE_reply_reserve_insufficient_balance ( struct MHD_Connection *connection, enum TALER_ErrorCode ec, const struct TALER_Amount *reserve_balance, const struct TALER_Amount *balance_required, const struct TALER_ReservePublicKeyP *reserve_pub) { return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_CONFLICT, TALER_JSON_pack_ec (ec), TALER_JSON_pack_amount ("balance", reserve_balance), TALER_JSON_pack_amount ("requested_amount", balance_required)); } MHD_RESULT TEH_RESPONSE_reply_reserve_age_restriction_required ( struct MHD_Connection *connection, uint16_t maximum_allowed_age) { return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_CONFLICT, TALER_JSON_pack_ec (TALER_EC_EXCHANGE_RESERVES_AGE_RESTRICTION_REQUIRED), GNUNET_JSON_pack_uint64 ("maximum_allowed_age", maximum_allowed_age)); } MHD_RESULT TEH_RESPONSE_reply_purse_created ( struct MHD_Connection *connection, struct GNUNET_TIME_Timestamp exchange_timestamp, const struct TALER_Amount *purse_balance, const struct TEH_PurseDetails *pd) { struct TALER_ExchangePublicKeyP pub; struct TALER_ExchangeSignatureP sig; enum TALER_ErrorCode ec; if (TALER_EC_NONE != (ec = TALER_exchange_online_purse_created_sign ( &TEH_keys_exchange_sign_, exchange_timestamp, pd->purse_expiration, &pd->target_amount, purse_balance, &pd->purse_pub, &pd->h_contract_terms, &pub, &sig))) { GNUNET_break (0); return TALER_MHD_reply_with_ec (connection, ec, NULL); } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_OK, TALER_JSON_pack_amount ("total_deposited", purse_balance), GNUNET_JSON_pack_timestamp ("exchange_timestamp", exchange_timestamp), GNUNET_JSON_pack_data_auto ("exchange_sig", &sig), GNUNET_JSON_pack_data_auto ("exchange_pub", &pub)); } MHD_RESULT TEH_RESPONSE_reply_kyc_required (struct MHD_Connection *connection, const struct TALER_PaytoHashP *h_payto, const struct TALER_EXCHANGEDB_KycStatus *kyc) { return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, TALER_JSON_pack_ec (TALER_EC_EXCHANGE_GENERIC_KYC_REQUIRED), GNUNET_JSON_pack_data_auto ("h_payto", h_payto), GNUNET_JSON_pack_uint64 ("requirement_row", kyc->requirement_row)); } MHD_RESULT TEH_RESPONSE_reply_aml_blocked (struct MHD_Connection *connection, enum TALER_AmlDecisionState status) { enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; switch (status) { case TALER_AML_NORMAL: GNUNET_break (0); return MHD_NO; case TALER_AML_PENDING: ec = TALER_EC_EXCHANGE_GENERIC_AML_PENDING; break; case TALER_AML_FROZEN: ec = TALER_EC_EXCHANGE_GENERIC_AML_FROZEN; break; } return TALER_MHD_REPLY_JSON_PACK ( connection, MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS, TALER_JSON_pack_ec (ec)); } MHD_RESULT TEH_RESPONSE_reply_not_modified ( struct MHD_Connection *connection, const char *etags, TEH_RESPONSE_SetHeaders cb, void *cb_cls) { MHD_RESULT ret; struct MHD_Response *resp; resp = MHD_create_response_from_buffer (0, NULL, MHD_RESPMEM_PERSISTENT); cb (cb_cls, resp); GNUNET_break (MHD_YES == MHD_add_response_header (resp, MHD_HTTP_HEADER_ETAG, etags)); ret = MHD_queue_response (connection, MHD_HTTP_NOT_MODIFIED, resp); GNUNET_break (MHD_YES == ret); MHD_destroy_response (resp); return ret; } /* end of taler-exchange-httpd_responses.c */