summaryrefslogtreecommitdiff
path: root/src/exchange/taler-exchange-httpd_responses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/exchange/taler-exchange-httpd_responses.c')
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c1011
1 files changed, 286 insertions, 725 deletions
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index cb1179d6d..8993ea50f 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014-2021 Taler Systems SA
+ 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
@@ -23,418 +23,34 @@
* @author Christian Grothoff
*/
#include "platform.h"
+#include <gnunet/gnunet_json_lib.h>
+#include <microhttpd.h>
#include <zlib.h>
#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"
-/**
- * Compile the transaction history of a coin into a JSON object.
- *
- * @param coin_pub public key of the coin
- * @param tl transaction history to JSON-ify
- * @return json representation of the @a rh, NULL on error
- */
-json_t *
-TEH_RESPONSE_compile_transaction_history (
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_EXCHANGEDB_TransactionList *tl)
-{
- json_t *history;
-
- history = json_array ();
- if (NULL == history)
- {
- GNUNET_break (0); /* out of memory!? */
- return NULL;
- }
- for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl;
- NULL != pos;
- pos = pos->next)
- {
- switch (pos->type)
- {
- case TALER_EXCHANGEDB_TT_DEPOSIT:
- {
- const struct TALER_EXCHANGEDB_DepositListEntry *deposit =
- pos->details.deposit;
- struct TALER_MerchantWireHash h_wire;
-
- TALER_merchant_wire_signature_hash (deposit->receiver_wire_account,
- &deposit->wire_salt,
- &h_wire);
-#if ENABLE_SANITY_CHECKS
- /* internal sanity check before we hand out a bogus sig... */
- if (GNUNET_OK !=
- TALER_wallet_deposit_verify (&deposit->amount_with_fee,
- &deposit->deposit_fee,
- &h_wire,
- &deposit->h_contract_terms,
- NULL /* h_extensions! */,
- &deposit->h_denom_pub,
- deposit->timestamp,
- &deposit->merchant_pub,
- deposit->refund_deadline,
- coin_pub,
- &deposit->csig))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
-#endif
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "DEPOSIT"),
- TALER_JSON_pack_amount ("amount",
- &deposit->amount_with_fee),
- TALER_JSON_pack_amount ("deposit_fee",
- &deposit->deposit_fee),
- GNUNET_JSON_pack_time_abs ("timestamp",
- deposit->timestamp),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_time_abs ("refund_deadline",
- deposit->refund_deadline)),
- GNUNET_JSON_pack_data_auto ("merchant_pub",
- &deposit->merchant_pub),
- GNUNET_JSON_pack_data_auto ("h_contract_terms",
- &deposit->h_contract_terms),
- GNUNET_JSON_pack_data_auto ("h_wire",
- &h_wire),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &deposit->h_denom_pub),
- GNUNET_JSON_pack_data_auto ("coin_sig",
- &deposit->csig))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- break;
- }
- case TALER_EXCHANGEDB_TT_MELT:
- {
- const struct TALER_EXCHANGEDB_MeltListEntry *melt =
- pos->details.melt;
- struct TALER_RefreshMeltCoinAffirmationPS ms = {
- .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT),
- .purpose.size = htonl (sizeof (ms)),
- .rc = melt->rc,
- .h_denom_pub = melt->h_denom_pub,
- .coin_pub = *coin_pub
- };
-
- TALER_amount_hton (&ms.amount_with_fee,
- &melt->amount_with_fee);
- TALER_amount_hton (&ms.melt_fee,
- &melt->melt_fee);
-#if ENABLE_SANITY_CHECKS
- /* internal sanity check before we hand out a bogus sig... */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
- &ms,
- &melt->coin_sig.eddsa_signature,
- &coin_pub->eddsa_pub))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
-#endif
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "MELT"),
- TALER_JSON_pack_amount ("amount",
- &melt->amount_with_fee),
- TALER_JSON_pack_amount ("melt_fee",
- &melt->melt_fee),
- GNUNET_JSON_pack_data_auto ("rc",
- &melt->rc),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &melt->h_denom_pub),
- GNUNET_JSON_pack_data_auto ("coin_sig",
- &melt->coin_sig))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- }
- break;
- case TALER_EXCHANGEDB_TT_REFUND:
- {
- const struct TALER_EXCHANGEDB_RefundListEntry *refund =
- pos->details.refund;
- struct TALER_Amount value;
- struct TALER_RefundRequestPS rr = {
- .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
- .purpose.size = htonl (sizeof (rr)),
- .h_contract_terms = refund->h_contract_terms,
- .coin_pub = *coin_pub,
- .merchant = refund->merchant_pub,
- .rtransaction_id = GNUNET_htonll (refund->rtransaction_id)
- };
-
- TALER_amount_hton (&rr.refund_amount,
- &refund->refund_amount);
-#if ENABLE_SANITY_CHECKS
- /* internal sanity check before we hand out a bogus sig... */
- if (GNUNET_OK !=
- GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
- &rr,
- &refund->merchant_sig.eddsa_sig,
- &refund->merchant_pub.eddsa_pub))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
-#endif
- if (0 >
- TALER_amount_subtract (&value,
- &refund->refund_amount,
- &refund->refund_fee))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "REFUND"),
- TALER_JSON_pack_amount ("amount",
- &value),
- TALER_JSON_pack_amount ("refund_fee",
- &refund->refund_fee),
- GNUNET_JSON_pack_data_auto ("h_contract_terms",
- &refund->h_contract_terms),
- GNUNET_JSON_pack_data_auto ("merchant_pub",
- &refund->merchant_pub),
- GNUNET_JSON_pack_uint64 ("rtransaction_id",
- refund->rtransaction_id),
- GNUNET_JSON_pack_data_auto ("merchant_sig",
- &refund->merchant_sig))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- }
- break;
- case TALER_EXCHANGEDB_TT_OLD_COIN_RECOUP:
- {
- struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
- pos->details.old_coin_recoup;
- struct TALER_ExchangePublicKeyP epub;
- struct TALER_ExchangeSignatureP esig;
- struct TALER_RecoupRefreshConfirmationPS pc = {
- .purpose.purpose = htonl (
- TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
- .purpose.size = htonl (sizeof (pc)),
- .timestamp = GNUNET_TIME_absolute_hton (pr->timestamp),
- .coin_pub = pr->coin.coin_pub,
- .old_coin_pub = pr->old_coin_pub
- };
-
- TALER_amount_hton (&pc.recoup_amount,
- &pr->value);
- if (TALER_EC_NONE !=
- TEH_keys_exchange_sign (&pc,
- &epub,
- &esig))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- /* NOTE: we could also provide coin_pub's coin_sig, denomination key hash and
- the denomination key's RSA signature over coin_pub, but as the
- wallet should really already have this information (and cannot
- check or do anything with it anyway if it doesn't), it seems
- strictly unnecessary. */
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "OLD-COIN-RECOUP"),
- TALER_JSON_pack_amount ("amount",
- &pr->value),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &esig),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &epub),
- GNUNET_JSON_pack_data_auto ("coin_pub",
- &pr->coin.coin_pub),
- GNUNET_JSON_pack_time_abs ("timestamp",
- pr->timestamp))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- break;
- }
- case TALER_EXCHANGEDB_TT_RECOUP:
- {
- const struct TALER_EXCHANGEDB_RecoupListEntry *recoup =
- pos->details.recoup;
- struct TALER_ExchangePublicKeyP epub;
- struct TALER_ExchangeSignatureP esig;
- struct TALER_RecoupConfirmationPS pc = {
- .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
- .purpose.size = htonl (sizeof (pc)),
- .timestamp = GNUNET_TIME_absolute_hton (recoup->timestamp),
- .coin_pub = *coin_pub,
- .reserve_pub = recoup->reserve_pub
- };
-
- TALER_amount_hton (&pc.recoup_amount,
- &recoup->value);
- if (TALER_EC_NONE !=
- TEH_keys_exchange_sign (&pc,
- &epub,
- &esig))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "RECOUP"),
- TALER_JSON_pack_amount ("amount",
- &recoup->value),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &esig),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &epub),
- GNUNET_JSON_pack_data_auto ("reserve_pub",
- &recoup->reserve_pub),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &recoup->h_denom_pub),
- GNUNET_JSON_pack_data_auto ("coin_sig",
- &recoup->coin_sig),
- GNUNET_JSON_pack_data_auto ("coin_blind",
- &recoup->coin_blind),
- GNUNET_JSON_pack_data_auto ("reserve_pub",
- &recoup->reserve_pub),
- GNUNET_JSON_pack_time_abs ("timestamp",
- recoup->timestamp))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- }
- break;
- case TALER_EXCHANGEDB_TT_RECOUP_REFRESH:
- {
- struct TALER_EXCHANGEDB_RecoupRefreshListEntry *pr =
- pos->details.recoup_refresh;
- struct TALER_ExchangePublicKeyP epub;
- struct TALER_ExchangeSignatureP esig;
- struct TALER_RecoupRefreshConfirmationPS pc = {
- .purpose.purpose = htonl (
- TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH),
- .purpose.size = htonl (sizeof (pc)),
- .timestamp = GNUNET_TIME_absolute_hton (pr->timestamp),
- .coin_pub = *coin_pub,
- .old_coin_pub = pr->old_coin_pub
- };
-
- TALER_amount_hton (&pc.recoup_amount,
- &pr->value);
- if (TALER_EC_NONE !=
- TEH_keys_exchange_sign (&pc,
- &epub,
- &esig))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- /* NOTE: we could also provide coin_pub's coin_sig, denomination key
- hash and the denomination key's RSA signature over coin_pub, but as
- the wallet should really already have this information (and cannot
- check or do anything with it anyway if it doesn't), it seems
- strictly unnecessary. *///
- if (0 !=
- json_array_append_new (
- history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "RECOUP-REFRESH"),
- TALER_JSON_pack_amount ("amount",
- &pr->value),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &esig),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &epub),
- GNUNET_JSON_pack_data_auto ("old_coin_pub",
- &pr->old_coin_pub),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &pr->coin.denom_pub_hash),
- GNUNET_JSON_pack_data_auto ("coin_sig",
- &pr->coin_sig),
- GNUNET_JSON_pack_data_auto ("coin_blind",
- &pr->coin_blind),
- GNUNET_JSON_pack_time_abs ("timestamp",
- pr->timestamp))))
- {
- GNUNET_break (0);
- json_decref (history);
- return NULL;
- }
- break;
- }
- default:
- GNUNET_assert (0);
- }
- }
- return history;
-}
-
-
MHD_RESULT
TEH_RESPONSE_reply_unknown_denom_pub_hash (
struct MHD_Connection *connection,
- const struct TALER_DenominationHash *dph)
+ const struct TALER_DenominationHashP *dph)
{
struct TALER_ExchangePublicKeyP epub;
struct TALER_ExchangeSignatureP esig;
- struct GNUNET_TIME_Absolute now;
+ struct GNUNET_TIME_Timestamp now;
enum TALER_ErrorCode ec;
- now = GNUNET_TIME_absolute_get ();
- GNUNET_TIME_round_abs (&now);
- {
- struct TALER_DenominationUnknownAffirmationPS dua = {
- .purpose.size = htonl (sizeof (dua)),
- .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN),
- .timestamp = GNUNET_TIME_absolute_hton (now),
- .h_denom_pub = *dph,
- };
-
- ec = TEH_keys_exchange_sign (&dua,
- &epub,
- &esig);
- }
+ 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);
@@ -447,8 +63,8 @@ TEH_RESPONSE_reply_unknown_denom_pub_hash (
connection,
MHD_HTTP_NOT_FOUND,
TALER_JSON_pack_ec (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN),
- GNUNET_JSON_pack_time_abs ("timestamp",
- now),
+ GNUNET_JSON_pack_timestamp ("timestamp",
+ now),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&epub),
GNUNET_JSON_pack_data_auto ("exchange_sig",
@@ -461,30 +77,23 @@ TEH_RESPONSE_reply_unknown_denom_pub_hash (
MHD_RESULT
TEH_RESPONSE_reply_expired_denom_pub_hash (
struct MHD_Connection *connection,
- const struct TALER_DenominationHash *dph,
- struct GNUNET_TIME_Absolute now,
+ 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 TALER_DenominationExpiredAffirmationPS dua = {
- .purpose.size = htonl (sizeof (dua)),
- .purpose.purpose = htonl (
- TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED),
- .timestamp = GNUNET_TIME_absolute_hton (now),
- .h_denom_pub = *dph,
- };
-
- /* strncpy would create a compiler warning */
- memcpy (dua.operation,
- oper,
- GNUNET_MIN (sizeof (dua.operation),
- strlen (oper)));
- ecr = TEH_keys_exchange_sign (&dua,
- &epub,
- &esig);
+ 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);
@@ -499,8 +108,8 @@ TEH_RESPONSE_reply_expired_denom_pub_hash (
TALER_JSON_pack_ec (ec),
GNUNET_JSON_pack_string ("oper",
oper),
- GNUNET_JSON_pack_time_abs ("timestamp",
- now),
+ GNUNET_JSON_pack_timestamp ("timestamp",
+ now),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&epub),
GNUNET_JSON_pack_data_auto ("exchange_sig",
@@ -510,338 +119,290 @@ TEH_RESPONSE_reply_expired_denom_pub_hash (
}
-/**
- * Send proof that a request is invalid to client because of
- * insufficient funds. This function will create a message with all
- * of the operations affecting the coin that demonstrate that the coin
- * has insufficient value.
- *
- * @param connection connection to the client
- * @param ec error code to return
- * @param coin_pub public key of the coin
- * @param tl transaction list to use to build reply
- * @return MHD result code
- */
MHD_RESULT
-TEH_RESPONSE_reply_coin_insufficient_funds (
+TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
struct MHD_Connection *connection,
- enum TALER_ErrorCode ec,
- const struct TALER_CoinSpendPublicKeyP *coin_pub,
- const struct TALER_EXCHANGEDB_TransactionList *tl)
+ const struct TALER_DenominationHashP *dph)
{
- json_t *history;
+ struct TALER_ExchangePublicKeyP epub;
+ struct TALER_ExchangeSignatureP esig;
+ struct GNUNET_TIME_Timestamp now;
+ enum TALER_ErrorCode ec;
- history = TEH_RESPONSE_compile_transaction_history (coin_pub,
- tl);
- if (NULL == history)
+ 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,
- TALER_EC_GENERIC_JSON_ALLOCATION_FAILURE,
- "Failed to generated proof of insufficient funds");
+ ec,
+ NULL);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
- MHD_HTTP_CONFLICT,
+ 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_array_steal ("history",
- history));
+ 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));
}
-/**
- * Compile the history of a reserve into a JSON object
- * and calculate the total balance.
- *
- * @param rh reserve history to JSON-ify
- * @param[out] balance set to current reserve balance
- * @return json representation of the @a rh, NULL on error
- */
-json_t *
-TEH_RESPONSE_compile_reserve_history (
- const struct TALER_EXCHANGEDB_ReserveHistory *rh,
- struct TALER_Amount *balance)
+MHD_RESULT
+TEH_RESPONSE_reply_coin_conflicting_contract (
+ struct MHD_Connection *connection,
+ enum TALER_ErrorCode ec,
+ const struct TALER_MerchantWireHashP *h_wire)
{
- struct TALER_Amount credit_total;
- struct TALER_Amount withdraw_total;
- json_t *json_history;
- enum InitAmounts
- {
- /** Nothing initialized */
- IA_NONE = 0,
- /** credit_total initialized */
- IA_CREDIT = 1,
- /** withdraw_total initialized */
- IA_WITHDRAW = 2
- } init = IA_NONE;
-
- json_history = json_array ();
- for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh;
- NULL != pos;
- pos = pos->next)
+ 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)
{
- switch (pos->type)
- {
- case TALER_EXCHANGEDB_RO_BANK_TO_EXCHANGE:
- {
- const struct TALER_EXCHANGEDB_BankTransfer *bank =
- pos->details.bank;
- if (0 == (IA_CREDIT & init))
- {
- credit_total = bank->amount;
- init |= IA_CREDIT;
- }
- else if (0 >
- TALER_amount_add (&credit_total,
- &credit_total,
- &bank->amount))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- if (0 !=
- json_array_append_new (
- json_history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "CREDIT"),
- GNUNET_JSON_pack_time_abs ("timestamp",
- bank->execution_date),
- GNUNET_JSON_pack_string ("sender_account_url",
- bank->sender_account_details),
- GNUNET_JSON_pack_uint64 ("wire_reference",
- bank->wire_reference),
- TALER_JSON_pack_amount ("amount",
- &bank->amount))))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- break;
- }
- case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
- {
- const struct TALER_EXCHANGEDB_CollectableBlindcoin *withdraw
- = pos->details.withdraw;
- struct TALER_Amount value;
-
- value = withdraw->amount_with_fee;
- if (0 == (IA_WITHDRAW & init))
- {
- withdraw_total = value;
- init |= IA_WITHDRAW;
- }
- else
- {
- if (0 >
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- if (0 !=
- json_array_append_new (
- json_history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "WITHDRAW"),
- GNUNET_JSON_pack_data_auto ("reserve_sig",
- &withdraw->reserve_sig),
- GNUNET_JSON_pack_data_auto ("h_coin_envelope",
- &withdraw->h_coin_envelope),
- GNUNET_JSON_pack_data_auto ("h_denom_pub",
- &withdraw->denom_pub_hash),
- TALER_JSON_pack_amount ("withdraw_fee",
- &withdraw->withdraw_fee),
- TALER_JSON_pack_amount ("amount",
- &value))))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- break;
- case TALER_EXCHANGEDB_RO_RECOUP_COIN:
- {
- const struct TALER_EXCHANGEDB_Recoup *recoup
- = pos->details.recoup;
- struct TALER_ExchangePublicKeyP pub;
- struct TALER_ExchangeSignatureP sig;
-
- if (0 == (IA_CREDIT & init))
- {
- credit_total = recoup->value;
- init |= IA_CREDIT;
- }
- else if (0 >
- TALER_amount_add (&credit_total,
- &credit_total,
- &recoup->value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- {
- struct TALER_RecoupConfirmationPS pc = {
- .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP),
- .purpose.size = htonl (sizeof (pc)),
- .timestamp = GNUNET_TIME_absolute_hton (recoup->timestamp),
- .coin_pub = recoup->coin.coin_pub,
- .reserve_pub = recoup->reserve_pub
- };
-
- TALER_amount_hton (&pc.recoup_amount,
- &recoup->value);
- if (TALER_EC_NONE !=
- TEH_keys_exchange_sign (&pc,
- &pub,
- &sig))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
-
- if (0 !=
- json_array_append_new (
- json_history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "RECOUP"),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &pub),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &sig),
- GNUNET_JSON_pack_time_abs ("timestamp",
- recoup->timestamp),
- TALER_JSON_pack_amount ("amount",
- &recoup->value),
- GNUNET_JSON_pack_data_auto ("coin_pub",
- &recoup->coin.coin_pub))))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- break;
- case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
- {
- const struct TALER_EXCHANGEDB_ClosingTransfer *closing =
- pos->details.closing;
- struct TALER_ExchangePublicKeyP pub;
- struct TALER_ExchangeSignatureP sig;
- struct TALER_Amount value;
-
- value = closing->amount;
- if (0 == (IA_WITHDRAW & init))
- {
- withdraw_total = value;
- init |= IA_WITHDRAW;
- }
- else
- {
- if (0 >
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- {
- struct TALER_ReserveCloseConfirmationPS rcc = {
- .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED),
- .purpose.size = htonl (sizeof (rcc)),
- .timestamp = GNUNET_TIME_absolute_hton (closing->execution_date),
- .reserve_pub = pos->details.closing->reserve_pub,
- .wtid = closing->wtid
- };
-
- TALER_amount_hton (&rcc.closing_amount,
- &value);
- TALER_amount_hton (&rcc.closing_fee,
- &closing->closing_fee);
- TALER_payto_hash (closing->receiver_account_details,
- &rcc.h_payto);
- if (TALER_EC_NONE !=
- TEH_keys_exchange_sign (&rcc,
- &pub,
- &sig))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- if (0 !=
- json_array_append_new (
- json_history,
- GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("type",
- "CLOSING"),
- GNUNET_JSON_pack_string ("receiver_account_details",
- closing->receiver_account_details),
- GNUNET_JSON_pack_data_auto ("wtid",
- &closing->wtid),
- GNUNET_JSON_pack_data_auto ("exchange_pub",
- &pub),
- GNUNET_JSON_pack_data_auto ("exchange_sig",
- &sig),
- GNUNET_JSON_pack_time_abs ("timestamp",
- closing->execution_date),
- TALER_JSON_pack_amount ("amount",
- &value),
- TALER_JSON_pack_amount ("closing_fee",
- &closing->closing_fee))))
- {
- GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- }
- break;
- }
+
+ 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);
}
- if (0 == (IA_CREDIT & init))
+ 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)))
{
- /* We should not have gotten here, without credits no reserve
- should exist! */
GNUNET_break (0);
- json_decref (json_history);
- return NULL;
- }
- if (0 == (IA_WITHDRAW & init))
- {
- /* did not encounter any withdraw operations, set withdraw_total to zero */
- GNUNET_assert (GNUNET_OK ==
- TALER_amount_set_zero (credit_total.currency,
- &withdraw_total));
+ return TALER_MHD_reply_with_ec (connection,
+ ec,
+ NULL);
}
- if (0 >
- TALER_amount_subtract (balance,
- &credit_total,
- &withdraw_total))
+ 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);
- json_decref (json_history);
- return NULL;
+ 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));
+}
- return json_history;
+
+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;
}