diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am index 5fd506562..9aa295317 100644 --- a/src/exchange-lib/Makefile.am +++ b/src/exchange-lib/Makefile.am @@ -21,6 +21,7 @@ libtalerexchange_la_SOURCES = \ exchange_api_deposit_wtid.c \ exchange_api_refresh.c \ exchange_api_refresh_link.c \ + exchange_api_refund.c \ exchange_api_reserve.c \ exchange_api_wire.c \ exchange_api_wire_deposits.c diff --git a/src/exchange-lib/exchange_api_refund.c b/src/exchange-lib/exchange_api_refund.c index ade070093..f29488fb6 100644 --- a/src/exchange-lib/exchange_api_refund.c +++ b/src/exchange-lib/exchange_api_refund.c @@ -17,7 +17,6 @@ /** * @file exchange-lib/exchange_api_refund.c * @brief Implementation of the /refund request of the exchange's HTTP API - * @author Sree Harsha Totakura * @author Christian Grothoff */ #include "platform.h" @@ -138,8 +137,8 @@ verify_refund_signature_ok (const struct TALER_EXCHANGE_RefundHandle *rh, */ static void handle_refund_finished (void *cls, - long response_code, - const json_t *json) + long response_code, + const json_t *json) { struct TALER_EXCHANGE_RefundHandle *rh = cls; @@ -205,7 +204,7 @@ handle_refund_finished (void *cls, * * @param exchange the exchange handle; the exchange must be ready to operate * @param amount the amount to be refunded; must be larger than the refund fee - * (as that fee is still being subtracted), and smaller than the amount + * (as that fee is still being subtracted), and smaller than the amount * (with deposit fee) of the original deposit contribution of this coin * @param refund_fee fee applicable to this coin for the refund * @param h_contract hash of the contact of the merchant with the customer that is being refunded @@ -226,6 +225,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, const struct TALER_Amount *amount, const struct TALER_Amount *refund_fee, const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, const struct TALER_CoinSpendPublicKeyP *coin_pub, uint64_t rtransaction_id, const struct TALER_MerchantPrivateKeyP *merchant_priv, @@ -234,8 +234,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, { struct TALER_EXCHANGE_RefundHandle *rh; struct GNUNET_CURL_Context *ctx; + struct TALER_RefundRequestPS rr; struct TALER_MerchantSignatureP merchant_sig; - struct TALER_MerchantPublicKeyP merchant_pub; json_t *refund_obj; CURL *eh; @@ -245,8 +245,22 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, GNUNET_break (0); return NULL; } - /* FIXME: create signature! */ - + rr.purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND); + rr.purpose.size = htonl (sizeof (struct TALER_RefundRequestPS)); + rr.h_contract = *h_contract; + rr.transaction_id = GNUNET_htonll (transaction_id); + rr.coin_pub = *coin_pub; + GNUNET_CRYPTO_eddsa_key_get_public (&merchant_priv->eddsa_priv, + &rr.merchant.eddsa_pub); + rr.rtransaction_id = GNUNET_htonll (rtransaction_id); + TALER_amount_hton (&rr.refund_amount, + amount); + TALER_amount_hton (&rr.refund_fee, + refund_fee); + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, + &rr.purpose, + &merchant_sig.eddsa_sig)); refund_obj = json_pack ("{s:o, s:o," /* amount/fee */ " s:o, s:o," /* H_contract, coin_pub */ " s:I, s:I," /* transaction id, rtransaction id */ @@ -259,8 +273,8 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, sizeof (*coin_pub)), "transaction_id", (json_int_t) transaction_id, "rtransaction_id", (json_int_t) rtransaction_id, - "merchant_pub", GNUNET_JSON_from_data (&merchant_pub, - sizeof (merchant_pub)), + "merchant_pub", GNUNET_JSON_from_data (&rr.merchant, + sizeof (struct TALER_MerchantPublicKeyP)), "merchant_sig", GNUNET_JSON_from_data (&merchant_sig, sizeof (merchant_sig)) ); @@ -274,13 +288,13 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, rh->depconf.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND); rh->depconf.h_contract = *h_contract; rh->depconf.transaction_id = GNUNET_htonll (transaction_id); + rh->depconf.coin_pub = *coin_pub; + rh->depconf.merchant = rr.merchant; rh->depconf.rtransaction_id = GNUNET_htonll (rtransaction_id); TALER_amount_hton (&rh->depconf.refund_amount, amount); TALER_amount_hton (&rh->depconf.refund_fee, refund_fee); - rh->depconf.coin_pub = *coin_pub; - rh->depconf.merchant = *merchant_pub; eh = curl_easy_init (); GNUNET_assert (NULL != (rh->json_enc = diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 794051e26..4fbadb79b 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -504,7 +504,7 @@ typedef void * * @param exchange the exchange handle; the exchange must be ready to operate * @param amount the amount to be refunded; must be larger than the refund fee - * (as that fee is still being subtracted), and smaller than the amount + * (as that fee is still being subtracted), and smaller than the amount * (with deposit fee) of the original deposit contribution of this coin * @param refund_fee fee applicable to this coin for the refund * @param h_contract hash of the contact of the merchant with the customer that is being refunded @@ -525,6 +525,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, const struct TALER_Amount *amount, const struct TALER_Amount *refund_fee, const struct GNUNET_HashCode *h_contract, + uint64_t transaction_id, const struct TALER_CoinSpendPublicKeyP *coin_pub, uint64_t rtransaction_id, const struct TALER_MerchantPrivateKeyP *merchant_priv, @@ -534,7 +535,7 @@ TALER_EXCHANGE_refund (struct TALER_EXCHANGE_Handle *exchange, /** * Cancel a refund permission request. This function cannot be used - * on a request handle if a response is already served for it. If + * on a request handle if a response is already served for it. If * this function is called, the refund may or may not have happened. * However, it is fine to try to refund the coin a second time. * diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index e338916e1..c31cc6b93 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -117,6 +117,11 @@ */ #define TALER_SIGNATURE_EXCHANGE_CONFIRM_WIRE_DEPOSIT 1037 +/** + * Signature where the Exchange confirms a refund request. + */ +#define TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND 1038 + /*********************/ /* Wallet signatures */ @@ -453,6 +458,64 @@ struct TALER_RefundRequestPS }; +/** + * @brief Format used to generate the signature on a request to refund + * a coin into the account of the customer. + */ +struct TALER_RefundConfirmationPS +{ + /** + * Purpose must be #TALER_SIGNATURE_EXCHANGE_CONFIRM_REFUND. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the contract which is being refunded. + */ + struct GNUNET_HashCode h_contract GNUNET_PACKED; + + /** + * Merchant-generated transaction ID of the orginal transaction. + */ + uint64_t transaction_id GNUNET_PACKED; + + /** + * The coin's public key. This is the value that must have been + * signed (blindly) by the Exchange. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * The Merchant's public key. Allows the merchant to later refund + * the transaction or to inquire about the wire transfer identifier. + */ + struct TALER_MerchantPublicKeyP merchant; + + /** + * Merchant-generated transaction ID for the refund. + */ + uint64_t rtransaction_id GNUNET_PACKED; + + /** + * Amount to be refunded, including refund fee charged by the + * exchange to the customer. + */ + struct TALER_AmountNBO refund_amount; + + /** + * Refund fee charged by the exchange. This must match the + * Exchange's denomination key's refund fee. If the client puts in + * an invalid refund fee (too high or too low) that does not match + * the Exchange's denomination key, the refund operation is invalid + * and will be rejected by the exchange. The @e amount_with_fee + * minus the @e refund_fee is the amount that will be credited to + * the original coin. + */ + struct TALER_AmountNBO refund_fee; + +}; + + /** * @brief Message signed by a coin to indicate that the coin should be * melted.