aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/exchange-lib/exchange_api_common.c147
-rw-r--r--src/exchange-lib/exchange_api_reserve.c68
-rw-r--r--src/exchange/taler-exchange-httpd_responses.c311
-rw-r--r--src/include/taler_exchangedb_plugin.h57
-rw-r--r--src/include/taler_json_lib.h12
-rw-r--r--src/include/taler_signatures.h5
-rw-r--r--src/json/json_helper.c89
7 files changed, 406 insertions, 283 deletions
diff --git a/src/exchange-lib/exchange_api_common.c b/src/exchange-lib/exchange_api_common.c
index 29d0f6d1c..d9d0a6d56 100644
--- a/src/exchange-lib/exchange_api_common.c
+++ b/src/exchange-lib/exchange_api_common.c
@@ -89,13 +89,22 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
"DEPOSIT"))
{
struct TALER_DepositRequestPS dr;
- struct TALER_Amount dr_amount;
struct TALER_CoinSpendSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("signature",
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
&sig),
- GNUNET_JSON_spec_fixed_auto ("details",
- &dr),
+ GNUNET_JSON_spec_fixed_auto ("h_proposal_data",
+ &dr.h_proposal_data),
+ GNUNET_JSON_spec_fixed_auto ("h_wire",
+ &dr.h_wire),
+ GNUNET_JSON_spec_absolute_time_nbo ("timestamp",
+ &dr.timestamp),
+ GNUNET_JSON_spec_absolute_time_nbo ("refund_deadline",
+ &dr.refund_deadline),
+ TALER_JSON_spec_amount_nbo ("deposit_fee",
+ &dr.deposit_fee),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+ &dr.merchant),
GNUNET_JSON_spec_end()
};
@@ -107,12 +116,11 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- /* TODO #4980 */
- if (sizeof (dr) != ntohl (dr.purpose.size))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ dr.purpose.size = htonl (sizeof (dr));
+ dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
+ TALER_amount_hton (&dr.amount_with_fee,
+ &amount);
+ dr.coin_pub = *coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
&dr.purpose,
@@ -122,28 +130,22 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- TALER_amount_ntoh (&dr_amount,
- &dr.amount_with_fee);
- /* TODO #4980 */
- if (0 != TALER_amount_cmp (&dr_amount,
- &amount))
- {
- GNUNET_break (0);
- return GNUNET_SYSERR;
- }
+ /* TODO: check that deposit fee and coin value match
+ our expectations from /keys! */
add = GNUNET_YES;
}
else if (0 == strcasecmp (type,
"MELT"))
{
struct TALER_RefreshMeltCoinAffirmationPS rm;
- struct TALER_Amount rm_amount;
struct TALER_CoinSpendSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("signature",
+ GNUNET_JSON_spec_fixed_auto ("coin_sig",
&sig),
- GNUNET_JSON_spec_fixed_auto ("details",
- &rm),
+ GNUNET_JSON_spec_fixed_auto ("session_hash",
+ &rm.session_hash),
+ TALER_JSON_spec_amount_nbo ("melt_fee",
+ &rm.melt_fee),
GNUNET_JSON_spec_end()
};
@@ -155,12 +157,11 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- /* TODO #4980 */
- if (sizeof (rm) != ntohl (rm.purpose.size))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ rm.purpose.size = htonl (sizeof (rm));
+ rm.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
+ TALER_amount_hton (&rm.amount_with_fee,
+ &amount);
+ rm.coin_pub = *coin_pub;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
&rm.purpose,
@@ -170,30 +171,26 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- TALER_amount_ntoh (&rm_amount,
- &rm.amount_with_fee);
- /* TODO #4980 */
- if (0 != TALER_amount_cmp (&rm_amount,
- &amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ /* TODO: check that deposit fee and coin value match
+ our expectations from /keys! */
add = GNUNET_YES;
}
else if (0 == strcasecmp (type,
"REFUND"))
{
struct TALER_RefundRequestPS rr;
- struct TALER_Amount rr_amount;
- struct TALER_Amount rr_fee;
- struct TALER_Amount rr_delta;
- struct TALER_CoinSpendSignatureP sig;
+ struct TALER_MerchantSignatureP sig;
struct GNUNET_JSON_Specification spec[] = {
- GNUNET_JSON_spec_fixed_auto ("signature",
+ GNUNET_JSON_spec_fixed_auto ("merchant_sig",
&sig),
- GNUNET_JSON_spec_fixed_auto ("details",
- &rr),
+ GNUNET_JSON_spec_fixed_auto ("h_proposal_data",
+ &rr.h_proposal_data),
+ GNUNET_JSON_spec_fixed_auto ("merchant_pub",
+ &rr.merchant),
+ GNUNET_JSON_spec_uint64 ("rtransaction_id",
+ &rr.rtransaction_id),
+ TALER_JSON_spec_amount_nbo ("refund_fee",
+ &rr.refund_fee),
GNUNET_JSON_spec_end()
};
@@ -205,38 +202,20 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- /* TODO #4980 */
- if (sizeof (rr) != ntohl (rr.purpose.size))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ rr.purpose.size = htonl (sizeof (rr));
+ rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND);
+ rr.coin_pub = *coin_pub;
+ TALER_amount_hton (&rr.refund_amount,
+ &amount);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
&rr.purpose,
- &sig.eddsa_signature,
+ &sig.eddsa_sig,
&rr.merchant.eddsa_pub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- TALER_amount_ntoh (&rr_amount,
- &rr.refund_amount);
- if (GNUNET_OK !=
- TALER_amount_subtract (&rr_delta,
- &rr_amount,
- &rr_fee))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
- /* TODO #4980 */
- if (0 != TALER_amount_cmp (&rr_delta,
- &amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
/* NOTE: theoretically, we could also check that the given
merchant_pub and h_proposal_data appear in the
history under deposits. However, there is really no benefit
@@ -244,13 +223,14 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
(an auditor ought to check, though). Then again, we similarly
had no reason to check the merchant's signature (other than a
well-formendess check). */
+ /* TODO: check that deposit fee and coin value match
+ our expectations from /keys! */
add = GNUNET_NO;
}
else if (0 == strcasecmp (type,
"PAYBACK"))
{
struct TALER_PaybackConfirmationPS pc;
- struct TALER_Amount pc_amount;
struct TALER_ExchangePublicKeyP exchange_pub;
struct TALER_ExchangeSignatureP exchange_sig;
struct GNUNET_JSON_Specification spec[] = {
@@ -258,8 +238,10 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
&exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&exchange_pub),
- GNUNET_JSON_spec_fixed_auto ("details",
- &pc),
+ GNUNET_JSON_spec_fixed_auto ("reserve_pub",
+ &pc.reserve_pub),
+ GNUNET_JSON_spec_absolute_time_nbo ("timestamp",
+ &pc.timestamp),
GNUNET_JSON_spec_end()
};
@@ -271,13 +253,11 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
-
- /* TODO #4980 */
- if (sizeof (pc) != ntohl (pc.purpose.size))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
+ pc.purpose.size = htonl (sizeof (pc));
+ pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
+ pc.coin_pub = *coin_pub;
+ TALER_amount_hton (&pc.payback_amount,
+ &amount);
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK,
&pc.purpose,
@@ -287,15 +267,6 @@ TALER_EXCHANGE_verify_coin_history (const char *currency,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
- TALER_amount_ntoh (&pc_amount,
- &pc.payback_amount);
- /* TODO #4980 */
- if (0 != TALER_amount_cmp (&pc_amount,
- &amount))
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
add = GNUNET_YES;
}
else
diff --git a/src/exchange-lib/exchange_api_reserve.c b/src/exchange-lib/exchange_api_reserve.c
index 0ed8cca00..98f15dcda 100644
--- a/src/exchange-lib/exchange_api_reserve.c
+++ b/src/exchange-lib/exchange_api_reserve.c
@@ -184,12 +184,15 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
{
struct TALER_ReserveSignatureP sig;
struct TALER_WithdrawRequestPS withdraw_purpose;
- struct TALER_Amount amount_from_purpose;
struct GNUNET_JSON_Specification withdraw_spec[] = {
- GNUNET_JSON_spec_fixed_auto ("signature",
+ GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&sig),
- GNUNET_JSON_spec_fixed_auto ("details",
- &withdraw_purpose),
+ TALER_JSON_spec_amount_nbo ("withdraw_fee",
+ &withdraw_purpose.withdraw_fee),
+ GNUNET_JSON_spec_fixed_auto ("h_denom_pub",
+ &withdraw_purpose.h_denomination_pub),
+ GNUNET_JSON_spec_fixed_auto ("h_coin_envelope",
+ &withdraw_purpose.h_coin_envelope),
GNUNET_JSON_spec_end()
};
unsigned int i;
@@ -203,6 +206,13 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
+ withdraw_purpose.purpose.size
+ = htonl (sizeof (withdraw_purpose));
+ withdraw_purpose.purpose.purpose
+ = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
+ withdraw_purpose.reserve_pub = *reserve_pub;
+ TALER_amount_hton (&withdraw_purpose.amount_with_fee,
+ &amount);
/* Check that the signature is a valid withdraw request */
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
@@ -214,18 +224,10 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_JSON_parse_free (withdraw_spec);
return GNUNET_SYSERR;
}
- TALER_amount_ntoh (&amount_from_purpose,
- &withdraw_purpose.amount_with_fee);
- /* TODO #4980 */
- if (0 != TALER_amount_cmp (&amount,
- &amount_from_purpose))
- {
- GNUNET_break_op (0);
- GNUNET_JSON_parse_free (withdraw_spec);
- return GNUNET_SYSERR;
- }
- rhistory[off].details.out_authorization_sig = json_object_get (transaction,
- "signature");
+ /* TODO: check that withdraw fee matches expectations! */
+ rhistory[off].details.out_authorization_sig
+ = json_object_get (transaction,
+ "signature");
/* Check check that the same withdraw transaction
isn't listed twice by the exchange. We use the
"uuid" array to remember the hashes of all
@@ -263,25 +265,22 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
"PAYBACK"))
{
struct TALER_PaybackConfirmationPS pc;
- struct TALER_Amount amount_from_purpose;
- struct GNUNET_TIME_Absolute timestamp_from_purpose;
struct GNUNET_TIME_Absolute timestamp;
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification payback_spec[] = {
- GNUNET_JSON_spec_fixed_auto ("details",
- &pc),
+ GNUNET_JSON_spec_fixed_auto ("coin_pub",
+ &pc.coin_pub),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&rhistory[off].details.payback_details.exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
&rhistory[off].details.payback_details.exchange_pub),
- GNUNET_JSON_spec_absolute_time ("timestamp",
- &timestamp),
- TALER_JSON_spec_amount ("amount",
- &rhistory[off].amount),
+ GNUNET_JSON_spec_absolute_time_nbo ("timestamp",
+ &pc.timestamp),
GNUNET_JSON_spec_end()
};
rhistory[off].type = TALER_EXCHANGE_RTT_PAYBACK;
+ rhistory[off].amount = amount;
if (GNUNET_OK !=
GNUNET_JSON_parse (transaction,
payback_spec,
@@ -291,22 +290,13 @@ parse_reserve_history (struct TALER_EXCHANGE_Handle *exchange,
return GNUNET_SYSERR;
}
rhistory[off].details.payback_details.coin_pub = pc.coin_pub;
- TALER_amount_ntoh (&amount_from_purpose,
- &pc.payback_amount);
+ TALER_amount_hton (&pc.payback_amount,
+ &amount);
+ pc.purpose.size = htonl (sizeof (pc));
+ pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
+ pc.reserve_pub = *reserve_pub;
+ timestamp = GNUNET_TIME_absolute_ntoh (pc.timestamp);
rhistory[off].details.payback_details.timestamp = timestamp;
- timestamp_from_purpose = GNUNET_TIME_absolute_ntoh (pc.timestamp);
- /* TODO #4980 */
- if ( (0 != memcmp (&pc.reserve_pub,
- reserve_pub,
- sizeof (*reserve_pub))) ||
- (timestamp_from_purpose.abs_value_us !=
- timestamp.abs_value_us) ||
- (0 != TALER_amount_cmp (&amount_from_purpose,
- &rhistory[off].amount)) )
- {
- GNUNET_break_op (0);
- return GNUNET_SYSERR;
- }
key_state = TALER_EXCHANGE_get_keys (exchange);
if (GNUNET_OK !=
diff --git a/src/exchange/taler-exchange-httpd_responses.c b/src/exchange/taler-exchange-httpd_responses.c
index c67c885ec..a335e440c 100644
--- a/src/exchange/taler-exchange-httpd_responses.c
+++ b/src/exchange/taler-exchange-httpd_responses.c
@@ -307,7 +307,7 @@ TEH_RESPONSE_reply_arg_missing (struct MHD_Connection *connection,
{
return TEH_RESPONSE_reply_json_pack (connection,
MHD_HTTP_BAD_REQUEST,
- "{ s:s, s:I, s:s}",
+ "{s:s, s:I, s:s}",
"error", "missing parameter",
"code", (json_int_t) ec,
"parameter", param_name);
@@ -524,20 +524,15 @@ TEH_RESPONSE_reply_deposit_success (struct MHD_Connection *connection,
static json_t *
compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
{
- json_t *details;
- const char *type;
- struct TALER_Amount value;
json_t *history;
- const struct GNUNET_CRYPTO_EddsaSignature *sig;
- const struct TALER_EXCHANGEDB_TransactionList *pos;
-
+
history = json_array ();
if (NULL == history)
{
GNUNET_break (0); /* out of memory!? */
return NULL;
}
- for (pos = tl; NULL != pos; pos = pos->next)
+ for (const struct TALER_EXCHANGEDB_TransactionList *pos = tl; NULL != pos; pos = pos->next)
{
switch (pos->type)
{
@@ -546,8 +541,6 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
struct TALER_DepositRequestPS dr;
const struct TALER_EXCHANGEDB_Deposit *deposit = pos->details.deposit;
- type = "DEPOSIT";
- value = deposit->amount_with_fee;
dr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_DEPOSIT);
dr.purpose.size = htonl (sizeof (struct TALER_DepositRequestPS));
dr.h_proposal_data = deposit->h_proposal_data;
@@ -560,12 +553,11 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
&deposit->deposit_fee);
dr.merchant = deposit->merchant_pub;
dr.coin_pub = deposit->coin.coin_pub;
- sig = &deposit->csig.eddsa_signature;
/* internal sanity check before we hand out a bogus sig... */
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_DEPOSIT,
&dr.purpose,
- sig,
+ &deposit->csig.eddsa_signature,
&deposit->coin.coin_pub.eddsa_pub))
{
GNUNET_break (0);
@@ -573,16 +565,25 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
return NULL;
}
- details = GNUNET_JSON_from_data_auto (&dr);
- break;
+ GNUNET_assert (0 ==
+ json_array_append_new (history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o, s:o, s:o, s:o}",
+ "type", "DEPOSIT",
+ "amount", TALER_JSON_from_amount (&deposit->amount_with_fee),
+ "deposit_fee", TALER_JSON_from_amount (&deposit->deposit_fee),
+ "timestamp", GNUNET_JSON_from_time_abs (deposit->timestamp),
+ "refund_deadline", GNUNET_JSON_from_time_abs (deposit->refund_deadline),
+ "merchant_pub", GNUNET_JSON_from_data_auto (&deposit->merchant_pub),
+ "h_proposal_data", GNUNET_JSON_from_data_auto (&deposit->h_proposal_data),
+ "h_wire", GNUNET_JSON_from_data_auto (&deposit->h_wire),
+ "coin_sig", GNUNET_JSON_from_data_auto (&deposit->csig))));
+ break;
}
case TALER_EXCHANGEDB_TT_REFRESH_MELT:
{
struct TALER_RefreshMeltCoinAffirmationPS ms;
const struct TALER_EXCHANGEDB_RefreshMelt *melt = pos->details.melt;
- type = "MELT";
- value = melt->amount_with_fee;
ms.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_MELT);
ms.purpose.size = htonl (sizeof (struct TALER_RefreshMeltCoinAffirmationPS));
ms.session_hash = melt->session_hash;
@@ -591,12 +592,11 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
TALER_amount_hton (&ms.melt_fee,
&melt->melt_fee);
ms.coin_pub = melt->coin.coin_pub;
- sig = &melt->coin_sig.eddsa_signature;
/* internal sanity check before we hand out a bogus sig... */
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WALLET_COIN_MELT,
&ms.purpose,
- sig,
+ &melt->coin_sig.eddsa_signature,
&melt->coin.coin_pub.eddsa_pub))
{
GNUNET_break (0);
@@ -604,15 +604,22 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
return NULL;
}
- details = GNUNET_JSON_from_data_auto (&ms);
+ GNUNET_assert (0 ==
+ json_array_append_new (history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o}",
+ "type", "MELT",
+ "amount", TALER_JSON_from_amount (&melt->amount_with_fee),
+ "melt_fee", TALER_JSON_from_amount (&melt->melt_fee),
+ "session_hash", GNUNET_JSON_from_data_auto (&melt->session_hash),
+ "coin_sig", GNUNET_JSON_from_data_auto (&melt->coin_sig))));
}
break;
case TALER_EXCHANGEDB_TT_REFUND:
{
struct TALER_RefundRequestPS rr;
const struct TALER_EXCHANGEDB_Refund *refund = pos->details.refund;
+ struct TALER_Amount value;
- type = "REFUND";
if (GNUNET_OK !=
TALER_amount_subtract (&value,
&refund->refund_amount,
@@ -633,18 +640,27 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
TALER_amount_hton (&rr.refund_fee,
&refund->refund_fee);
/* internal sanity check before we hand out a bogus sig... */
- sig = &refund->merchant_sig.eddsa_sig;
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND,
&rr.purpose,
- sig,
+ &refund->merchant_sig.eddsa_sig,
&refund->merchant_pub.eddsa_pub))
{
GNUNET_break (0);
json_decref (history);
return NULL;
}
- details = GNUNET_JSON_from_data_auto (&rr);
+
+ GNUNET_assert (0 ==
+ json_array_append_new (history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o, s:I, s:o}",
+ "type", "REFUND",
+ "amount", TALER_JSON_from_amount (&value),
+ "refund_fee", TALER_JSON_from_amount (&refund->refund_fee),
+ "h_proposal_data", GNUNET_JSON_from_data_auto (&refund->h_proposal_data),
+ "merchant_pub", GNUNET_JSON_from_data_auto (&refund->merchant_pub),
+ "rtransaction_id", (json_int_t) refund->rtransaction_id,
+ "merchant_sig", GNUNET_JSON_from_data_auto (&refund->merchant_sig))));
}
break;
case TALER_EXCHANGEDB_TT_PAYBACK:
@@ -654,8 +670,6 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
struct TALER_ExchangePublicKeyP epub;
struct TALER_ExchangeSignatureP esig;
- type = "PAYBACK";
- value = payback->value;
pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
pc.purpose.size = htonl (sizeof (pc));
pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp);
@@ -666,28 +680,20 @@ compile_transaction_history (const struct TALER_EXCHANGEDB_TransactionList *tl)
TEH_KS_sign (&pc.purpose,
&epub,
&esig);
- details = GNUNET_JSON_from_data_auto (&pc);
GNUNET_assert (0 ==
json_array_append_new (history,
- json_pack ("{s:s, s:o, s:o, s:o, s:o}",
- "type", type,
- "amount", TALER_JSON_from_amount (&value),
+ json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o}",
+ "type", "PAYBACK",
+ "amount", TALER_JSON_from_amount (&payback->value),
"exchange_sig", GNUNET_JSON_from_data_auto (&esig),
"exchange_pub", GNUNET_JSON_from_data_auto (&epub),
- "details", details)));
+ "reserve_pub", GNUNET_JSON_from_data_auto (&payback->reserve_pub),
+ "timestamp", GNUNET_JSON_from_time_abs (payback->timestamp))));
}
- /* do not go to the default handler, we already appended! */
- continue;
+ break;
default:
GNUNET_assert (0);
}
- GNUNET_assert (0 ==
- json_array_append_new (history,
- json_pack ("{s:s, s:o, s:o, s:o}",
- "type", type,
- "amount", TALER_JSON_from_amount (&value),
- "signature", GNUNET_JSON_from_data_auto (sig),
- "details", details)));
}
return history;
}
@@ -739,20 +745,12 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
{
struct TALER_Amount deposit_total;
struct TALER_Amount withdraw_total;
- struct TALER_Amount value;
json_t *json_history;
int ret;
- const struct TALER_EXCHANGEDB_ReserveHistory *pos;
- struct TALER_WithdrawRequestPS wr;
- const struct TALER_EXCHANGEDB_Payback *payback;
- struct TALER_PaybackConfirmationPS pc;
- struct TALER_ReserveCloseConfirmationPS rcc;
- struct TALER_ExchangePublicKeyP pub;
- struct TALER_ExchangeSignatureP sig;
json_history = json_array ();
ret = 0;
- for (pos = rh; NULL != pos; pos = pos->next)
+ for (const struct TALER_EXCHANGEDB_ReserveHistory *pos = rh; NULL != pos; pos = pos->next)
{
switch (pos->type)
{
@@ -778,115 +776,130 @@ compile_reserve_history (const struct TALER_EXCHANGEDB_ReserveHistory *rh,
"amount", TALER_JSON_from_amount (&pos->details.bank->amount))));
break;
case TALER_EXCHANGEDB_RO_WITHDRAW_COIN:
- value = pos->details.withdraw->amount_with_fee;
- if (0 == (2 & ret))
{
- withdraw_total = value;
- }
- else
- {
- if (GNUNET_OK !=
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- json_decref (json_history);
- return NULL;
- }
+ struct GNUNET_HashCode h_denom_pub;
+ struct TALER_Amount value;
+
+ value = pos->details.withdraw->amount_with_fee;
+ if (0 == (2 & ret))
+ {
+ withdraw_total = value;
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
+ }
+ ret |= 2;
+ GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key,
+ &h_denom_pub);
+ GNUNET_assert (0 ==
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o}",
+ "type", "WITHDRAW",
+ "reserve_sig", GNUNET_JSON_from_data_auto (&pos->details.withdraw->reserve_sig),
+ "h_coin_envelope", GNUNET_JSON_from_data_auto (&pos->details.withdraw->h_coin_envelope),
+ "h_denom_pub", GNUNET_JSON_from_data_auto (&h_denom_pub),
+ "withdraw_fee", TALER_JSON_from_amount (&pos->details.withdraw->withdraw_fee),
+ "amount", TALER_JSON_from_amount (&value))));
}
- ret |= 2;
- wr.purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
- wr.purpose.size = htonl (sizeof (struct TALER_WithdrawRequestPS));
- wr.reserve_pub = pos->details.withdraw->reserve_pub;
- TALER_amount_hton (&wr.amount_with_fee,
- &value);
- TALER_amount_hton (&wr.withdraw_fee,
- &pos->details.withdraw->withdraw_fee);
- GNUNET_CRYPTO_rsa_public_key_hash (pos->details.withdraw->denom_pub.rsa_public_key,
- &wr.h_denomination_pub);
- wr.h_coin_envelope = pos->details.withdraw->h_coin_envelope;
- GNUNET_assert (0 ==
- json_array_append_new (json_history,
- json_pack ("{s:s, s:o, s:o, s:o}",
- "type", "WITHDRAW",
- "signature", GNUNET_JSON_from_data_auto (&pos->details.withdraw->reserve_sig),
- "details", GNUNET_JSON_from_data_auto (&wr),
-
- "amount", TALER_JSON_from_amount (&value))));
break;
case TALER_EXCHANGEDB_RO_PAYBACK_COIN:
- payback = pos->details.payback;
- if (0 == (1 & ret))
- deposit_total = payback->value;
- else
- if (GNUNET_OK !=
- TALER_amount_add (&deposit_total,
- &deposit_total,
- &payback->value))
- {
- json_decref (json_history);
- return NULL;
- }
- ret |= 1;
- pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
- pc.purpose.size = htonl (sizeof (struct TALER_PaybackConfirmationPS));
- pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp);
- TALER_amount_hton (&pc.payback_amount,
- &payback->value);
- pc.coin_pub = payback->coin.coin_pub;
- pc.reserve_pub = payback->reserve_pub;
- TEH_KS_sign (&pc.purpose,
- &pub,
- &sig);
-
- GNUNET_assert (0 ==
- json_array_append_new (json_history,
- json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o}",
- "type", "PAYBACK",
- "exchange_pub", GNUNET_JSON_from_data_auto (&pub),
- "exchange_sig", GNUNET_JSON_from_data_auto (&sig),
- "timestamp", GNUNET_JSON_from_time_abs (payback->timestamp),
- "amount", TALER_JSON_from_amount (&payback->value),
- "details", GNUNET_JSON_from_data_auto (&pc))));
- break;
- case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
- value = pos->details.bank->amount;
- if (0 == (2 & ret))
{
- withdraw_total = value;
+ const struct TALER_EXCHANGEDB_Payback *payback;
+ struct TALER_PaybackConfirmationPS pc;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+
+ payback = pos->details.payback;
+ if (0 == (1 & ret))
+ deposit_total = payback->value;
+ else
+ if (GNUNET_OK !=
+ TALER_amount_add (&deposit_total,
+ &deposit_total,
+ &payback->value))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
+ ret |= 1;
+ pc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_PAYBACK);
+ pc.purpose.size = htonl (sizeof (struct TALER_PaybackConfirmationPS));
+ pc.timestamp = GNUNET_TIME_absolute_hton (payback->timestamp);
+ TALER_amount_hton (&pc.payback_amount,
+ &payback->value);
+ pc.coin_pub = payback->coin.coin_pub;
+ pc.reserve_pub = payback->reserve_pub;
+ TEH_KS_sign (&pc.purpose,
+ &pub,
+ &sig);
+
+ GNUNET_assert (0 ==
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o, s:o}",
+ "type", "PAYBACK",
+ "exchange_pub", GNUNET_JSON_from_data_auto (&pub),
+ "exchange_sig", GNUNET_JSON_from_data_auto (&sig),
+ "timestamp", GNUNET_JSON_from_time_abs (payback->timestamp),
+ "amount", TALER_JSON_from_amount (&payback->value),
+ "coin_pub", GNUNET_JSON_from_data_auto (&payback->coin.coin_pub))));
}
- else
+ break;
+ case TALER_EXCHANGEDB_RO_EXCHANGE_TO_BANK:
{
- if (GNUNET_OK !=
- TALER_amount_add (&withdraw_total,
- &withdraw_total,
- &value))
- {
- json_decref (json_history);
- return NULL;
- }
+ struct TALER_ReserveCloseConfirmationPS rcc;
+ struct TALER_ExchangePublicKeyP pub;
+ struct TALER_ExchangeSignatureP sig;
+ struct TALER_Amount value;
+
+ value = pos->details.closing->amount;
+ if (0 == (2 & ret))
+ {
+ withdraw_total = value;
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ TALER_amount_add (&withdraw_total,
+ &withdraw_total,
+ &value))
+ {
+ json_decref (json_history);
+ return NULL;
+ }
+ }
+ ret |= 2;
+ rcc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED);
+ rcc.purpose.size = htonl (sizeof (struct TALER_ReserveCloseConfirmationPS));
+ rcc.timestamp = GNUNET_TIME_absolute_hton (pos->details.closing->execution_date);
+ TALER_amount_hton (&rcc.closing_amount,
+ &value);
+ TALER_amount_hton (&rcc.closing_fee,
+ &pos->details.closing->closing_fee);
+ rcc.reserve_pub = pos->details.closing->reserve_pub;
+ TALER_JSON_hash (pos->details.closing->receiver_account_details,
+ &rcc.h_wire);
+ TEH_KS_sign (&rcc.purpose,
+ &pub,
+ &sig);
+ GNUNET_assert (0 ==
+ json_array_append_new (json_history,
+ json_pack ("{s:s, s:o, s:o, s:o, s:o}",
+ "type", "CLOSING",
+ "exchange_pub", GNUNET_JSON_from_data_auto (&pub),
+ "exchange_sig", GNUNET_JSON_from_data_auto (&sig),
+ "timestamp", GNUNET_JSON_from_time_abs (pos->details.closing->execution_date),
+ "h_wire", GNUNET_JSON_from_data_auto (&rcc.h_wire),
+ "amount", TALER_JSON_from_amount (&value),
+ "closing_fee", TALER_JSON_from_amount (&pos->details.closing->closing_fee))));
}
- ret |= 2;
-
- rcc.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_RESERVE_CLOSED);
- rcc.purpose.size = htonl (sizeof (struct TALER_ReserveCloseConfirmationPS));
- rcc.timestamp = GNUNET_TIME_absolute_hton (pos->details.bank->execution_date);
- TALER_amount_hton (&rcc.closing_amount,
- &value);
- rcc.reserve_pub = pos->details.bank->reserve_pub;
- TALER_JSON_hash (pos->details.bank->sender_account_details,
- &rcc.h_wire);
- TEH_KS_sign (&rcc.purpose,
- &pub,
- &sig);
- GNUNET_assert (0 ==
- json_array_append_new (json_history,
- json_pack ("{s:s, s:o, s:o, s:o, s:o}",
- "type", "CLOSING",
- "exchange_pub", GNUNET_JSON_from_data_auto (&pub),
- "exchange_sig", GNUNET_JSON_from_data_auto (&sig),
- "details", GNUNET_JSON_from_data_auto (&rcc),
- "amount", TALER_JSON_from_amount (&value))));
break;
}
}
diff --git a/src/include/taler_exchangedb_plugin.h b/src/include/taler_exchangedb_plugin.h
index fe08bd27e..b9c3d79e6 100644
--- a/src/include/taler_exchangedb_plugin.h
+++ b/src/include/taler_exchangedb_plugin.h
@@ -28,14 +28,13 @@
/**
- * @brief Information we keep on bank transfer(s) that established or
- * closed a reserve.
+ * @brief Information we keep on bank transfer(s) that established a reserve.
*/
struct TALER_EXCHANGEDB_BankTransfer
{
/**
- * Public key of the reserve that was filled or depleted.
+ * Public key of the reserve that was filled.
*/
struct TALER_ReservePublicKeyP reserve_pub;
@@ -52,7 +51,7 @@ struct TALER_EXCHANGEDB_BankTransfer
struct GNUNET_TIME_Absolute execution_date;
/**
- * Detailed wire information about the sending (or receiving) account.
+ * Detailed wire information about the sending account.
*/
json_t *sender_account_details;
@@ -66,6 +65,47 @@ struct TALER_EXCHANGEDB_BankTransfer
/**
+ * @brief Information we keep on bank transfer(s) that
+ * closed a reserve.
+ */
+struct TALER_EXCHANGEDB_ClosingTransfer
+{
+
+ /**
+ * Public key of the reserve that was depleted.
+ */
+ struct TALER_ReservePublicKeyP reserve_pub;
+
+ /**
+ * Amount that was transferred to the exchange.
+ */
+ struct TALER_Amount amount;
+
+ /**
+ * Amount that was charged by the exchange.
+ */
+ struct TALER_Amount closing_fee;
+
+ /**
+ * When did the exchange execute the transaction?
+ */
+ struct GNUNET_TIME_Absolute execution_date;
+
+ /**
+ * Detailed wire information about the receiving account.
+ */
+ json_t *receiver_account_details;
+
+ /**
+ * Detailed wire transfer information that uniquely identifies the
+ * wire transfer.
+ */
+ json_t *transfer_details;
+
+};
+
+
+/**
* @brief A summary of a Reserve
*/
struct TALER_EXCHANGEDB_Reserve
@@ -244,8 +284,7 @@ struct TALER_EXCHANGEDB_ReserveHistory
/**
* Details about a bank transfer to the exchange (reserve
- * was established) or from the exchange (reserve was
- * closed).
+ * was established).
*/
struct TALER_EXCHANGEDB_BankTransfer *bank;
@@ -259,6 +298,12 @@ struct TALER_EXCHANGEDB_ReserveHistory
*/
struct TALER_EXCHANGEDB_Payback *payback;
+ /**
+ * Details about a bank transfer from the exchange (reserve
+ * was closed).
+ */
+ struct TALER_EXCHANGEDB_ClosingTransfer *closing;
+
} details;
};
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index b247ba1f5..248de9c45 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -59,6 +59,18 @@ TALER_JSON_spec_amount (const char *name,
/**
+ * Provide specification to parse given JSON object to an amount
+ * in network byte order.
+ *
+ * @param name name of the amount field in the JSON
+ * @param[out] r_amount where the amount has to be written
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount_nbo (const char *name,
+ struct TALER_AmountNBO *r_amount);
+
+
+/**
* Generate line in parser specification for denomination public key.
*
* @param field name of the field
diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h
index 70560b4b3..0b1c7ac33 100644
--- a/src/include/taler_signatures.h
+++ b/src/include/taler_signatures.h
@@ -1254,6 +1254,11 @@ struct TALER_ReserveCloseConfirmationPS
struct TALER_AmountNBO closing_amount;
/**
+ * How much did the exchange charge for closing the reserve?
+ */
+ struct TALER_AmountNBO closing_fee;
+
+ /**
* Public key of the reserve that received the payback.
*/
struct TALER_ReservePublicKeyP reserve_pub;
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
index f964f8f17..1d2a33156 100644
--- a/src/json/json_helper.c
+++ b/src/json/json_helper.c
@@ -119,7 +119,6 @@ parse_amount (void *cls,
}
-
/**
* Provide specification to parse given JSON object to an amount.
*
@@ -144,6 +143,94 @@ TALER_JSON_spec_amount (const char *name,
/**
+ * Parse given JSON object to Amount in NBO.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static int
+parse_amount_nbo (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ struct TALER_AmountNBO *r_amount = spec->ptr;
+ struct TALER_Amount amount;
+ json_int_t value;
+ json_int_t fraction;
+ const char *currency;
+
+ memset (&amount,
+ 0,
+ sizeof (struct TALER_Amount));
+ if (0 != json_unpack (root,
+ "{s:I, s:I, s:s}",
+ "value", &value,
+ "fraction", &fraction,
+ "currency", &currency))
+ {
+ char *json_enc;
+
+ if (NULL == (json_enc = json_dumps (root,
+ JSON_COMPACT | JSON_ENCODE_ANY)))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Malformed JSON amount: %s\n",
+ json_enc);
+ free (json_enc);
+ return GNUNET_SYSERR;
+ }
+ if ( (value < 0) ||
+ (fraction < 0) ||
+ (value > UINT64_MAX) ||
+ (fraction > UINT32_MAX) )
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (strlen (currency) >= TALER_CURRENCY_LEN)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ amount.value = (uint64_t) value;
+ amount.fraction = (uint32_t) fraction;
+ strcpy (amount.currency, currency);
+ (void) TALER_amount_normalize (&amount);
+ TALER_amount_hton (r_amount,
+ &amount);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Provide specification to parse given JSON object to an amount.
+ *
+ * @param name name of the amount field in the JSON
+ * @param[out] r_amount where the amount has to be written
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_amount_nbo (const char *name,
+ struct TALER_AmountNBO *r_amount)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_amount_nbo,
+ .cleaner = NULL,
+ .cls = NULL,
+ .field = name,
+ .ptr = r_amount,
+ .ptr_size = 0,
+ .size_ptr = NULL
+ };
+ return ret;
+}
+
+
+/**
* Generate line in parser specification for denomination public key.
*
* @param field name of the field