From d1461b2485cb8a633e93f4ed59c560619f08af72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Bl=C3=A4ttler?= Date: Mon, 6 May 2024 21:08:58 +0200 Subject: work on tokens --- .../taler-merchant-httpd_post-orders-ID-pay.c | 33 ++++++-- src/include/taler_merchant_service.h | 10 +-- src/lib/merchant_api_post_order_pay.c | 89 ++++++++++++---------- src/testing/testing_api_cmd_pay_order.c | 15 +--- 4 files changed, 81 insertions(+), 66 deletions(-) diff --git a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c index 0dad53db..c56fa63b 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -451,7 +451,7 @@ struct PayContext struct GNUNET_HashCode h_wallet_data; /** - * Output commitment hash. + * Output commitment hash calculated from the 'tokens_evs' field of the request. */ struct GNUNET_HashCode h_outputs; @@ -2644,6 +2644,7 @@ phase_contract_paid (struct PayContext *pc) TALER_merchant_pay_sign (&pc->h_contract_terms, &pc->hc->instance->merchant_priv, &sig); + /* TODO: Add token_sigs to response body. */ pay_end (pc, TALER_MHD_REPLY_JSON_PACK ( pc->connection, @@ -2938,6 +2939,7 @@ phase_check_contract (struct PayContext *pc) static void phase_parse_wallet_data (struct PayContext *pc) { + struct GNUNET_HashCode h_outputs_req; pc->choice_index = -1; if (NULL == pc->wallet_data) @@ -2951,11 +2953,10 @@ phase_parse_wallet_data (struct PayContext *pc) GNUNET_JSON_spec_int64 ("choice_index", &pc->choice_index), NULL), - /* TODO: Add h_outputs to wallet_data */ - // GNUNET_JSON_spec_mark_optional( - // GNUNET_JSON_spec_fixed_auto ("h_outputs", - // &pc->h_outputs), - // NULL), + GNUNET_JSON_spec_mark_optional( + GNUNET_JSON_spec_fixed_auto ("h_outputs", + &h_outputs_req), + NULL), GNUNET_JSON_spec_end () }; @@ -2974,6 +2975,17 @@ phase_parse_wallet_data (struct PayContext *pc) return; } + if (0 != GNUNET_CRYPTO_hash_cmp(&h_outputs_req, &pc->h_outputs)) + { + GNUNET_break_op (0); + pay_end (pc, + TALER_MHD_reply_with_error (pc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "'wallet_data.h_outputs' does not match hash of tokens_evs")); + return; + } + TALER_json_hash (pc->wallet_data, &pc->h_wallet_data); @@ -3253,9 +3265,16 @@ phase_parse_pay (struct PayContext *pc) pc->connection, MHD_HTTP_BAD_REQUEST, TALER_EC_GENERIC_PARAMETER_MALFORMED, - "'token_evs' array too long")); + "'tokens_evs' array too long")); return; } + if (0 < pc->token_envelopes_cnt) + { + /* Calculate output commitment to be verified later. */ + TALER_json_hash (tokens_evs, + &pc->h_outputs); + + } pc->token_envelopes = GNUNET_new_array (pc->token_envelopes_cnt, struct TokenEnvelope); diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index 1907f88f..24f5e61c 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -3344,8 +3344,7 @@ struct TALER_MERCHANT_OutputToken * @param coins array of coins to pay with * @param num_tokens length of the @a tokens array * @param tokens array of tokens used - * @param num_output_tokens length of the @a output_tokens array - * @param output_tokens array of output token to be issued by the merchant + * @param j_output_tokens json array of token envelopes, NULL for none * @param pay_cb the callback to call when a reply for this request is available * @param pay_cb_cls closure for @a pay_cb * @return a handle for this request @@ -3361,8 +3360,7 @@ TALER_MERCHANT_order_pay_frontend ( const struct TALER_MERCHANT_PaidCoin coins[static num_coins], unsigned int num_tokens, const struct TALER_MERCHANT_UsedToken tokens[static num_tokens], - unsigned int num_output_tokens, - const struct TALER_MERCHANT_OutputToken output_tokens[static num_output_tokens], + json_t *j_output_tokens, TALER_MERCHANT_OrderPayCallback pay_cb, void *pay_cb_cls); @@ -3449,7 +3447,7 @@ struct TALER_MERCHANT_UseToken * @param merchant_url base URL of the merchant * @param session_id session to pay for, or NULL for none * @param h_contract hash of the contact of the merchant with the customer - * @param wallet_data inputs from the wallet for the contract, NULL for none + * @param choice_index index of the selected contract coice, -1 for none * @param amount total value of the contract to be paid to the merchant * @param max_fee maximum fee covered by the merchant (according to the contract) * @param merchant_pub the public key of the merchant (used to identify the merchant for refund requests) @@ -3475,7 +3473,7 @@ TALER_MERCHANT_order_pay ( const char *merchant_url, const char *session_id, const struct TALER_PrivateContractHashP *h_contract, - const json_t *wallet_data, + int choice_index, const struct TALER_Amount *amount, const struct TALER_Amount *max_fee, const struct TALER_MerchantPublicKeyP *merchant_pub, diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c index 39e4e35b..ca4e8a18 100644 --- a/src/lib/merchant_api_post_order_pay.c +++ b/src/lib/merchant_api_post_order_pay.c @@ -384,8 +384,7 @@ TALER_MERCHANT_order_pay_frontend ( const struct TALER_MERCHANT_PaidCoin coins[static num_coins], unsigned int num_tokens, const struct TALER_MERCHANT_UsedToken tokens[static num_tokens], - unsigned int num_output_tokens, - const struct TALER_MERCHANT_OutputToken output_tokens[static num_output_tokens], + json_t *j_output_tokens, TALER_MERCHANT_OrderPayCallback pay_cb, void *pay_cb_cls) { @@ -393,7 +392,6 @@ TALER_MERCHANT_order_pay_frontend ( json_t *pay_obj; json_t *j_coins; json_t *j_tokens = NULL; - json_t *j_output_tokens = NULL; CURL *eh; struct TALER_Amount total_fee; struct TALER_Amount total_amount; @@ -502,31 +500,6 @@ TALER_MERCHANT_order_pay_frontend ( } } - if (0 < num_output_tokens) - { - j_output_tokens = json_array (); - GNUNET_assert (NULL != j_output_tokens); - for (unsigned int i = 0; ienvelope), - GNUNET_JSON_pack_data_auto ("h_issue", - &ev->h_issue.hash)); - if (0 != - json_array_append_new (j_output_tokens, - j_token_ev)) - { - GNUNET_break (0); - json_decref (j_output_tokens); - return NULL; - } - } - } - pay_obj = GNUNET_JSON_PACK ( GNUNET_JSON_pack_array_steal ("coins", j_coins), @@ -534,8 +507,8 @@ TALER_MERCHANT_order_pay_frontend ( GNUNET_JSON_pack_array_steal ("tokens", j_tokens)), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_steal ("tokens_evs", - j_output_tokens)), + GNUNET_JSON_pack_array_incref ("tokens_evs", + j_output_tokens)), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_incref ("wallet_data", (json_t *) wallet_data)), @@ -576,7 +549,7 @@ TALER_MERCHANT_order_pay_frontend ( GNUNET_memcpy (oph->coins, coins, num_coins * sizeof (struct TALER_MERCHANT_PaidCoin)); - /* TODO: Copy token_evs to pay handle so they + /* TODO: Copy tokens_evs to pay handle so they can be unblinded in the callback. */ eh = TALER_MERCHANT_curl_easy_get_ (oph->url); @@ -608,7 +581,7 @@ TALER_MERCHANT_order_pay ( const char *merchant_url, const char *session_id, const struct TALER_PrivateContractHashP *h_contract_terms, - const json_t *wallet_data, + int choice_index, const struct TALER_Amount *amount, const struct TALER_Amount *max_fee, const struct TALER_MerchantPublicKeyP *merchant_pub, @@ -627,6 +600,9 @@ TALER_MERCHANT_order_pay ( TALER_MERCHANT_OrderPayCallback pay_cb, void *pay_cb_cls) { + json_t *j_output_tokens = NULL; + const json_t *wallet_data = NULL; + struct GNUNET_HashCode h_outputs; struct GNUNET_HashCode wallet_data_hash; if (GNUNET_YES != @@ -636,17 +612,51 @@ TALER_MERCHANT_order_pay ( GNUNET_break (0); return NULL; } - if (0 < num_tokens && NULL == wallet_data) + if ((0 < num_tokens || 0 < num_output_tokens) && 0 > choice_index) { - /* Since the wallet has to sign over the wallet_data_hash - to use tokens, wallet data must not be NULL if input - tokens are provided */ + /* Tokens (input or output) require a valid choice_index to be set. + Only contracts with coices can use or issue tokens. */ GNUNET_break (0); return NULL; } - if (NULL != wallet_data) + if (0 < num_output_tokens) + { + /* Build token envelopes json array. */ + j_output_tokens = json_array (); + GNUNET_assert (NULL != j_output_tokens); + for (unsigned int i = 0; ienvelope), + GNUNET_JSON_pack_data_auto ("h_issue", + &ev->h_issue.hash)); + if (0 != + json_array_append_new (j_output_tokens, + j_token_ev)) + { + GNUNET_break (0); + json_decref (j_output_tokens); + return NULL; + } + } + + TALER_json_hash (j_output_tokens, &h_outputs); + } + if (0 <= choice_index) + { + wallet_data = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_int64 ("choice_index", + choice_index), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_data_auto ("h_outputs", + &h_outputs))); TALER_json_hash (wallet_data, - &wallet_data_hash); + &wallet_data_hash); + } { struct TALER_MERCHANT_PaidCoin pc[num_coins]; struct TALER_MERCHANT_UsedToken ut[num_tokens]; @@ -720,8 +730,7 @@ TALER_MERCHANT_order_pay ( pc, num_tokens, ut, - num_output_tokens, - output_tokens, + j_output_tokens, pay_cb, pay_cb_cls); if (NULL == oph) diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c index 143540e9..a356d327 100644 --- a/src/testing/testing_api_cmd_pay_order.c +++ b/src/testing/testing_api_cmd_pay_order.c @@ -130,11 +130,6 @@ struct PayState */ enum TALER_MerchantConfirmationAlgorithm pos_alg; - /** - * Wallet data json object. Used in the pay request if not NULL. - */ - const json_t *wallet_data; - /** * Index of the choice to be used in the payment. -1 for orders without choices. */ @@ -849,7 +844,7 @@ pay_run (void *cls, GNUNET_assert (GNUNET_CRYPTO_BSA_RSA == details->issue_pub.public_key->cipher); TALER_token_blind_input_copy (&details->blinding_inputs, - TALER_token_bling_input_rsa_singleton ()); + TALER_token_blind_input_rsa_singleton ()); /* TODO: Where to get details->blinding_inputs from? */ TALER_token_use_setup_random (&details->master); TALER_token_use_setup_priv (&details->master, @@ -904,7 +899,7 @@ pay_run (void *cls, ps->merchant_url, ps->session_id, h_proposal, - ps->wallet_data, + ps->choice_index, &ps->total_amount, &max_fee, &merchant_pub, @@ -1066,12 +1061,6 @@ TALER_TESTING_cmd_merchant_pay_order_choices (const char *label, ps->session_id = session_id; ps->token_reference = token_reference; ps->choice_index = choice_index; - if (0 <= choice_index) - { - ps->wallet_data = json_pack ("{s:i}", - "choice_index", - choice_index); - } { struct TALER_TESTING_Command cmd = { .cls = ps, -- cgit v1.2.3