diff options
Diffstat (limited to 'src/exchange/taler-exchange-httpd_coins_get.c')
-rw-r--r-- | src/exchange/taler-exchange-httpd_coins_get.c | 490 |
1 files changed, 488 insertions, 2 deletions
diff --git a/src/exchange/taler-exchange-httpd_coins_get.c b/src/exchange/taler-exchange-httpd_coins_get.c index 9f61b38f6..c5cf6ba56 100644 --- a/src/exchange/taler-exchange-httpd_coins_get.c +++ b/src/exchange/taler-exchange-httpd_coins_get.c @@ -48,6 +48,492 @@ add_response_headers (void *cls, } +/** + * 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 + */ +static json_t * +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_MerchantWireHashP 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... */ + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_wallet_deposit_verify ( + &deposit->amount_with_fee, + &deposit->deposit_fee, + &h_wire, + &deposit->h_contract_terms, + deposit->no_wallet_data_hash + ? NULL + : &deposit->wallet_data_hash, + deposit->no_age_commitment + ? NULL + : &deposit->h_age_commitment, + &deposit->h_policy, + &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 ( + // FIXME: offset missing! (here and in all other cases!) + 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_timestamp ("timestamp", + deposit->timestamp), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_timestamp ("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_allow_null ( + deposit->no_age_commitment ? + GNUNET_JSON_pack_string ( + "h_age_commitment", NULL) : + GNUNET_JSON_pack_data_auto ("h_age_commitment", + &deposit->h_age_commitment)), + 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; + const struct TALER_AgeCommitmentHash *phac = NULL; + +#if ENABLE_SANITY_CHECKS + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_wallet_melt_verify ( + &melt->amount_with_fee, + &melt->melt_fee, + &melt->rc, + &melt->h_denom_pub, + &melt->h_age_commitment, + coin_pub, + &melt->coin_sig)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } +#endif + + /* Age restriction is optional. We communicate a NULL value to + * JSON_PACK below */ + if (! melt->no_age_commitment) + phac = &melt->h_age_commitment; + + 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_allow_null ( + GNUNET_JSON_pack_data_auto ("h_age_commitment", + phac)), + 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; + +#if ENABLE_SANITY_CHECKS + TEH_METRICS_num_verifications[TEH_MT_SIGNATURE_EDDSA]++; + if (GNUNET_OK != + TALER_merchant_refund_verify ( + coin_pub, + &refund->h_contract_terms, + refund->rtransaction_id, + &refund->refund_amount, + &refund->merchant_pub, + &refund->merchant_sig)) + { + 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; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_refresh_sign ( + &TEH_keys_exchange_sign_, + pr->timestamp, + &pr->value, + &pr->coin.coin_pub, + &pr->old_coin_pub, + &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_timestamp ("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; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_sign ( + &TEH_keys_exchange_sign_, + recoup->timestamp, + &recoup->value, + coin_pub, + &recoup->reserve_pub, + &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 ("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_timestamp ("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; + + if (TALER_EC_NONE != + TALER_exchange_online_confirm_recoup_refresh_sign ( + &TEH_keys_exchange_sign_, + pr->timestamp, + &pr->value, + coin_pub, + &pr->old_coin_pub, + &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 ("coin_sig", + &pr->coin_sig), + GNUNET_JSON_pack_data_auto ("coin_blind", + &pr->coin_blind), + GNUNET_JSON_pack_timestamp ("timestamp", + pr->timestamp)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + + case TALER_EXCHANGEDB_TT_PURSE_DEPOSIT: + { + struct TALER_EXCHANGEDB_PurseDepositListEntry *pd + = pos->details.purse_deposit; + const struct TALER_AgeCommitmentHash *phac = NULL; + + if (! pd->no_age_commitment) + phac = &pd->h_age_commitment; + + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "PURSE-DEPOSIT"), + TALER_JSON_pack_amount ("amount", + &pd->amount), + GNUNET_JSON_pack_string ("exchange_base_url", + NULL == pd->exchange_base_url + ? TEH_base_url + : pd->exchange_base_url), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("h_age_commitment", + phac)), + GNUNET_JSON_pack_data_auto ("purse_pub", + &pd->purse_pub), + GNUNET_JSON_pack_bool ("refunded", + pd->refunded), + GNUNET_JSON_pack_data_auto ("coin_sig", + &pd->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + + case TALER_EXCHANGEDB_TT_PURSE_REFUND: + { + const struct TALER_EXCHANGEDB_PurseRefundListEntry *prefund = + pos->details.purse_refund; + struct TALER_Amount value; + enum TALER_ErrorCode ec; + struct TALER_ExchangePublicKeyP epub; + struct TALER_ExchangeSignatureP esig; + + if (0 > + TALER_amount_subtract (&value, + &prefund->refund_amount, + &prefund->refund_fee)) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + ec = TALER_exchange_online_purse_refund_sign ( + &TEH_keys_exchange_sign_, + &value, + &prefund->refund_fee, + coin_pub, + &prefund->purse_pub, + &epub, + &esig); + if (TALER_EC_NONE != ec) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "PURSE-REFUND"), + TALER_JSON_pack_amount ("amount", + &value), + TALER_JSON_pack_amount ("refund_fee", + &prefund->refund_fee), + GNUNET_JSON_pack_data_auto ("exchange_sig", + &esig), + GNUNET_JSON_pack_data_auto ("exchange_pub", + &epub), + GNUNET_JSON_pack_data_auto ("purse_pub", + &prefund->purse_pub)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + } + break; + + case TALER_EXCHANGEDB_TT_RESERVE_OPEN: + { + struct TALER_EXCHANGEDB_ReserveOpenListEntry *role + = pos->details.reserve_open; + + if (0 != + json_array_append_new ( + history, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("type", + "RESERVE-OPEN-DEPOSIT"), + TALER_JSON_pack_amount ("coin_contribution", + &role->coin_contribution), + GNUNET_JSON_pack_data_auto ("reserve_sig", + &role->reserve_sig), + GNUNET_JSON_pack_data_auto ("coin_sig", + &role->coin_sig)))) + { + GNUNET_break (0); + json_decref (history); + return NULL; + } + break; + } + } + } + return history; +} + + MHD_RESULT TEH_handler_coins_get (struct TEH_RequestContext *rc, const struct TALER_CoinSpendPublicKeyP *coin_pub) @@ -118,8 +604,8 @@ TEH_handler_coins_get (struct TEH_RequestContext *rc, sizeof (etagp), "\"%llu\"", (unsigned long long) etag); - history = TEH_RESPONSE_compile_transaction_history (coin_pub, - tl); + history = compile_transaction_history (coin_pub, + tl); TEH_plugin->free_coin_transaction_list (TEH_plugin->cls, tl); tl = NULL; |