merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 08ce214e695e73a79e8344eed0e648a870121f61
parent 04b3192dbba7262bfa2714ff15cf44b55185bd89
Author: bohdan-potuzhnyi <bohdan.potuzhnyi@gmail.com>
Date:   Tue, 15 Jul 2025 13:00:41 +0200

fixing errors, and a bit of restructuring

Diffstat:
Msrc/backend/taler-merchant-httpd_post-orders-ID-pay.c | 261++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/backend/taler-merchant-httpd_private-post-orders.c | 66++++++++++++++++++++++++++++++++++++------------------------------
Msrc/backenddb/pg_upsert_donau_keys.c | 49++++++++++++++++++++++++++-----------------------
Msrc/lib/taler_merchant_pay_service.c | 665+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/util/contract_parse.c | 1-
5 files changed, 573 insertions(+), 469 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 @@ -374,6 +374,10 @@ struct ExchangeGroup }; +/** + * Information about donau, that can be fetched even + * if the merhchant doesn't support donau + */ struct DonauData { /** @@ -706,6 +710,27 @@ struct PayContext } charity; + /** + * Struct to hold the clients bkps + donau request handler + */ + struct + { + /** + * Number of the blinded key pairs + */ + unsigned int num_bkps; + + /** + * Blinded key pairs received from the wallet + */ + struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps; + + /** + * Handler of the donau request + */ + struct DONAU_BatchIssueReceiptHandle *birh; + } donau_handler; + struct { /** @@ -1888,17 +1913,13 @@ merchant_donau_issue_receipt_cb (void *cls, return; } - /* Extract overall HTTP status and Taler error code from 'resp->hr' */ - unsigned int http_status = resp->hr.http_status; - enum TALER_ErrorCode ec = resp->hr.ec; - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Donau responded with status=%u, ec=%u\n", - http_status, - ec); + resp->hr.http_status, + resp->hr.ec); /* If Donau gave 0 => means the reply was malformed or invalid. */ - if (0 == http_status) + if (0 == resp->hr.http_status) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Donau replied with status 0 => invalid or parse error\n"); @@ -1909,33 +1930,28 @@ merchant_donau_issue_receipt_cb (void *cls, } /* If Taler error code is non-zero => Donau signaled an error. */ - if (TALER_EC_NONE != ec) + if (TALER_EC_NONE != resp->hr.ec) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Donau responded with Taler error code %u\n", - ec); + resp->hr.ec); resume_pay_with_error (pc, - ec, + resp->hr.ec, "Donau returned an error"); return; } - /* If the HTTP status is 201 (CREATED), we can read the union contents. */ - if (MHD_HTTP_CREATED == http_status) + if (MHD_HTTP_CREATED == resp->hr.http_status) { pc->donau_receipt.sigs = - resp->details.ok.blinded_sigs; /* array of signatures */ + resp->details.ok.blinded_sigs; - // TODO: For each output we have one signature(or rather for the selected donau_output_token), - // we need to put them into the output token. - // sigs.blinded_sig to the output_tokens[i].sig.signature for (size_t i = 0; i<pc->validate_tokens.output_tokens_len; i++) { const struct TALER_MERCHANT_ContractChoice *choice = &pc->check_contract.contract_terms->details.v1 .choices[pc->parse_wallet_data.choice_index]; - /* If the matching contract-output is a donation-receipt, we skip it. */ if (i < choice->outputs_len && TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT == choice->outputs[i].type) @@ -1969,7 +1985,7 @@ merchant_donau_issue_receipt_cb (void *cls, GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Donau responded with HTTP code %u\n", - http_status); + resp->hr.http_status); resume_pay_with_error (pc, TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR, @@ -2022,11 +2038,11 @@ merchant_parse_json_bkp (struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp, static void phase_generate_donation_receipt (struct PayContext *pc) { - #ifndef HAVE_DONAU_DONAU_SERVICE_H +#ifndef HAVE_DONAU_DONAU_SERVICE_H /* If Donau is disabled at compile-time, skip. */ pc->phase = PP_PAYMENT_NOTIFICATION; return; - #else +#else /* 1) Parse the BUDIs array from JSON into an array of * DONAU_BlindedUniqueDonorIdentifierKeyPair. */ const json_t *budikeypairs = pc->parse_wallet_data.donau.budikeypairs; @@ -2098,7 +2114,7 @@ phase_generate_donation_receipt (struct PayContext *pc) /* As we do in the batch_issue for the exchange*/ MHD_suspend_connection (pc->connection); pc->suspended = GNUNET_YES; - #endif +#endif } @@ -2742,7 +2758,6 @@ phase_execute_pay_transaction (struct PayContext *pc) } // REVIEW: insert donau blinded inputs (into DB here!) - // REVIEW: fetching the charity private key and ID from the DB if (NULL != pc->parse_wallet_data.donau.budikeypairs) { enum GNUNET_DB_QueryStatus qs; @@ -2767,42 +2782,6 @@ phase_execute_pay_transaction (struct PayContext *pc) return; } } - - pc->charity.charity_priv = GNUNET_new (struct DONAU_CharityPrivateKeyP); - - /* Part where we fetch info about the charity*/ - qs = TMH_db->lookup_order_charity ( - TMH_db->cls, - pc->parse_wallet_data.donau.donau_url, - &pc->charity.charity_id, - pc->charity.charity_priv); - - if (0 > qs) - { - TMH_db->rollback (TMH_db->cls); - - /* just fail. */ - pay_end (pc, - TALER_MHD_reply_with_error ( - pc->connection, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_DB_FETCH_FAILED, - "lookup_order_charity")); - return; - } - else if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) - { - /* The given donau_url was not found in merchant_donau_instances - or the corresponding merchant_keys for the private key. */ - TMH_db->rollback (TMH_db->cls); - pay_end (pc, - TALER_MHD_reply_with_error ( - pc->connection, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "No matching Donau charity found for the given URL")); - return; - } } @@ -3847,9 +3826,7 @@ static void phase_parse_wallet_data (struct PayContext *pc) { const json_t *tokens_evs; - const json_t *budikeypairs = NULL; - const char *donau_url_tmp = NULL; - uint64_t donation_year_tmp = 0; + const json_t *donau_obj; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_mark_optional ( @@ -3860,30 +3837,10 @@ phase_parse_wallet_data (struct PayContext *pc) GNUNET_JSON_spec_array_const ("tokens_evs", &tokens_evs), NULL), - - /* FIELDS for DONAU ------------------------------------- */ - /* "donau_url" is optional (a JSON string) */ - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("donau_url", - &donau_url_tmp), - NULL), - /* "donation_year" is optional (parsed as uint64_t) */ GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint64 ("donau_year", - &donation_year_tmp), + GNUNET_JSON_spec_object_const ("donau", + &donau_obj), NULL), - /* "budikeypairs" is optional (a JSON array) */ - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_array_const ("donau_budikeypairs", - &budikeypairs), - NULL), - /* ---------------------------------------------------------- */ - // REVIEW: extend spec for wallet to submit - // - URL of selected donau - // - year - // - BUDIs with blinded donation receipts (donau-key-hash, blinded value) - // + check in later phase (once we have the contract) - // that the selected donau was offered and the BUDIs are below the allowed amount GNUNET_JSON_spec_end () }; @@ -3980,29 +3937,139 @@ phase_parse_wallet_data (struct PayContext *pc) } } - pc->parse_wallet_data.donau.donau_url = NULL; +#ifdef HAVE_DONAU_DONAU_SERVICE_H + pc->parse_wallet_data.donau.donau_url = NULL; + pc->parse_wallet_data.donau.donation_year = 0; + pc->parse_wallet_data.donau.budikeypairs = NULL; + pc->donau_handler.num_bkps = 0; + pc->donau_handler.bkps = NULL; + + if (NULL != donau_obj) { - if (NULL != donau_url_tmp) - pc->parse_wallet_data.donau.donau_url = GNUNET_strdup (donau_url_tmp); + const char *donau_url_tmp = NULL; + uint64_t donation_year_tmp = 0; + const json_t *budikeypairs = NULL; + + /* All three fields inside the object are required together. */ + struct GNUNET_JSON_Specification dspec[] = { + GNUNET_JSON_spec_string ("url", + &donau_url_tmp), + GNUNET_JSON_spec_uint64 ("year", + &donation_year_tmp), + GNUNET_JSON_spec_array_const ("budikeypairs", + &budikeypairs), + GNUNET_JSON_spec_end () + }; + enum GNUNET_GenericReturnValue res; - // FIXME: Probably some error handling could happen here - } + res = TALER_MHD_parse_json_data (pc->connection, + donau_obj, + dspec); + if (GNUNET_YES != res) + { + GNUNET_break_op (0); + pay_end (pc, + (GNUNET_NO == res) + ? MHD_YES + : MHD_NO); + return; + } - pc->parse_wallet_data.donau.donation_year = 0; - { - pc->parse_wallet_data.donau.donation_year = donation_year_tmp; + if (! json_is_array (budikeypairs) || (0 == json_array_size (budikeypairs))) + { + resume_pay_with_error (pc, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Missing or empty 'budikeypairs' array"); + return; + } - // FIXME: What if the url is set but the year is not? - // add error throwing + // Fetchning the charity information from the database based on the selected donau_url + { + enum GNUNET_DB_QueryStatus qs; + pc->charity.charity_priv = GNUNET_new (struct DONAU_CharityPrivateKeyP); + + /* Part where we fetch info about the charity*/ + qs = TMH_db->lookup_order_charity ( + TMH_db->cls, + donau_url_tmp, + &pc->charity.charity_id, + pc->charity.charity_priv); + + // TODO: Change to switch + if (0 > qs) + { + TMH_db->rollback (TMH_db->cls); - } + /* just fail. */ + pay_end (pc, + TALER_MHD_reply_with_error ( + pc->connection, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_DB_FETCH_FAILED, + "lookup_order_charity")); + return; + } + else if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + { + /* The given donau_url was not found in merchant_donau_instances + or the corresponding merchant_keys for the private key. */ + TMH_db->rollback (TMH_db->cls); + pay_end (pc, + TALER_MHD_reply_with_error ( + pc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "No matching Donau charity found for the given URL")); + return; + } + } - pc->parse_wallet_data.donau.budikeypairs = NULL; - { + pc->parse_wallet_data.donau.donau_url = GNUNET_strdup (donau_url_tmp); + pc->parse_wallet_data.donau.donation_year = donation_year_tmp; pc->parse_wallet_data.donau.budikeypairs = budikeypairs; - // FIXME: What if the url is set but the budis not? + // Stage to parse the budikeypairs from json to struct + { + size_t num_bkps = json_array_size (budikeypairs); + struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkps = + GNUNET_new_array (num_bkps, + struct DONAU_BlindedUniqueDonorIdentifierKeyPair); + + for (size_t i = 0; i < num_bkps; i++) + { + const json_t *bkp_obj = json_array_get (budikeypairs, i); + if (GNUNET_SYSERR == merchant_parse_json_bkp (&bkps[i], bkp_obj)) + { + GNUNET_break_op (0); + GNUNET_free (bkps); + resume_pay_with_error (pc, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Failed to parse budikeypairs"); + return; + } + } + + pc->donau_handler.num_bkps = num_bkps; + pc->donau_handler.bkps = bkps; + } + + // FIXME: BUG #### Check the amount of the bkps, versus amount in the contract and maximum allowed for donau + { + + } + } +#else + /* Donau not compiled in: reject request if a donau object was given. */ + if (NULL != donau_obj) + { + pay_end (pc, + TALER_MHD_reply_with_error (pc->connection, + MHD_HTTP_NOT_IMPLEMENTED, + TALER_EC_MERCHANT_GENERIC_FEATURE_NOT_AVAILABLE, + "donau support disabled")); + return; } +#endif /* HAVE_DONAU_DONAU_SERVICE_H */ TALER_json_hash (pc->parse_pay.wallet_data, &pc->parse_wallet_data.h_wallet_data); diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -78,7 +78,7 @@ * refuses a forced download. */ #define MAX_KEYS_WAIT \ - GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500) + GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 2500) /** * Generate the base URL for the given merchant instance. @@ -2209,6 +2209,7 @@ set_max_fee (struct OrderContext *oc) oc->phase++; } + /** * Exchange `/keys` processing is done, resume handling * the order. @@ -3353,24 +3354,26 @@ add_donau_url (void *cls, const json_t *donau_keys_json) { json_t *json_instances = cls; - GNUNET_assert(0 == json_array_append_new(json_instances, json_string(donau_url))); + GNUNET_assert (0 == json_array_append_new (json_instances, json_string ( + donau_url))); } + static void parse_donau_instances (struct OrderContext *oc, struct TALER_MERCHANT_ContractOutput *output) { - json_t *json_donau_instances = json_array(); + json_t *json_donau_instances = json_array (); enum GNUNET_DB_QueryStatus qs; /* Invoke the database call, accumulating URLs in a JSON array */ - qs = TMH_db->select_donau_instance(TMH_db->cls, - &add_donau_url, - json_donau_instances); + qs = TMH_db->select_donau_instance (TMH_db->cls, + &add_donau_url, + json_donau_instances); if (qs < 0) { - json_decref(json_donau_instances); + json_decref (json_donau_instances); GNUNET_break_op (0); reply_with_error (oc, MHD_HTTP_INTERNAL_SERVER_ERROR, @@ -3380,33 +3383,36 @@ parse_donau_instances (struct OrderContext *oc, } /* Convert the JSON array of strings into a C array of URLs */ - size_t num_instances = json_array_size(json_donau_instances); - if (num_instances > 0) { - output->details.donation_receipt.donau_urls = malloc(num_instances * sizeof(char *)); - if (!output->details.donation_receipt.donau_urls) + size_t num_instances = json_array_size (json_donau_instances); + if (num_instances > 0) { - json_decref(json_donau_instances); - GNUNET_break_op (0); - reply_with_error (oc, - MHD_HTTP_INTERNAL_SERVER_ERROR, - TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR, - "donau url parsing allocating memory"); - return; - } - output->details.donation_receipt.donau_urls_len = num_instances; + output->details.donation_receipt.donau_urls = malloc (num_instances + * sizeof(char *)); + if (! output->details.donation_receipt.donau_urls) + { + json_decref (json_donau_instances); + GNUNET_break_op (0); + reply_with_error (oc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_CLIENT_INTERNAL_ERROR, + "donau url parsing allocating memory"); + return; + } + output->details.donation_receipt.donau_urls_len = num_instances; - for (size_t i = 0; i < num_instances; i++) - { - json_t *url_json = json_array_get(json_donau_instances, i); - const char *url_str = json_string_value(url_json); - output->details.donation_receipt.donau_urls[i] = strdup(url_str); + for (size_t i = 0; i < num_instances; i++) + { + json_t *url_json = json_array_get (json_donau_instances, i); + const char *url_str = json_string_value (url_json); + output->details.donation_receipt.donau_urls[i] = strdup (url_str); + } } } - - json_decref(json_donau_instances); + json_decref (json_donau_instances); } + #endif /** @@ -3603,8 +3609,8 @@ parse_choices (struct OrderContext *oc) output.details.donation_receipt.amount.currency); /* If amount wasn't set, we need to get it from the overall amount */ - if(GNUNET_OK != - TALER_amount_is_valid (&output.details.donation_receipt.amount)) + if (GNUNET_OK != + TALER_amount_is_valid (&output.details.donation_receipt.amount)) { output.details.donation_receipt.amount = choice->amount; } @@ -3615,7 +3621,7 @@ parse_choices (struct OrderContext *oc) /* If the system was complied with donau support, we can parse the donau instances */ #ifdef HAVE_DONAU_DONAU_SERVICE_H - parse_donau_instances (oc, &output); + parse_donau_instances (oc, &output); #endif GNUNET_log (GNUNET_ERROR_TYPE_WARNING, diff --git a/src/backenddb/pg_upsert_donau_keys.c b/src/backenddb/pg_upsert_donau_keys.c @@ -39,33 +39,36 @@ TMH_PG_upsert_donau_keys ( if (NULL == jkeys) return GNUNET_DB_STATUS_HARD_ERROR; - struct GNUNET_PQ_QueryParam params[] = { - TALER_PQ_query_param_json (jkeys), - GNUNET_PQ_query_param_string (keys->donau_url), - GNUNET_PQ_query_param_end - }; + { + struct GNUNET_PQ_QueryParam params[] = { + TALER_PQ_query_param_json (jkeys), + GNUNET_PQ_query_param_string (keys->donau_url), + GNUNET_PQ_query_param_end + }; - check_connection (pg); - PREPARE (pg, - "insert_donau_keys", - "INSERT INTO merchant_donau_keys" - "(keys_json" - ",donau_url" - ") VALUES ($1, $2);"); - PREPARE (pg, - "update_donau_keys", - "UPDATE merchant_donau_keys SET" - " keys_json=$1" - " WHERE" - " donau_url=$2;"); + check_connection (pg); + PREPARE (pg, + "insert_donau_keys", + "INSERT INTO merchant_donau_keys" + "(keys_json" + ",donau_url" + ") VALUES ($1, $2);"); + PREPARE (pg, + "update_donau_keys", + "UPDATE merchant_donau_keys SET" + " keys_json=$1" + " WHERE" + " donau_url=$2;"); - qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "update_donau_keys", - params); - if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, - "insert_donau_keys", + "update_donau_keys", params); + if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) + qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, + "insert_donau_keys", + params); + } + json_decref (jkeys); return qs; } \ No newline at end of file diff --git a/src/lib/taler_merchant_pay_service.c b/src/lib/taler_merchant_pay_service.c @@ -71,7 +71,7 @@ struct TALER_MERCHANT_OrderPayHandle struct TALER_PrivateContractHashP h_contract_terms; bool has_merchant_pub; - struct TALER_MerchantPublicKeyP merchant_pub; + struct TALER_MerchantPublicKeyP merchant_pub; bool has_choice_index; int choice_index; @@ -81,17 +81,20 @@ struct TALER_MERCHANT_OrderPayHandle const struct TALER_Amount *max_fee; /* raw arrays as passed in via set_options(): */ - struct { + struct + { unsigned int num_coins; const struct TALER_MERCHANT_PayCoin *coins; } coins; - struct { + struct + { unsigned int num_tokens; const struct TALER_MERCHANT_UseToken *tokens; } input_tokens; - struct { + struct + { unsigned int num_output_tokens; const struct TALER_MERCHANT_OutputToken *output_tokens; } output_tokens; @@ -114,16 +117,18 @@ struct TALER_MERCHANT_OrderPayHandle bool am_wallet; + json_t *donau_data; + // TODO: Remove this block; /* --- Donau (optional) ------------------------------------------------- */ #ifdef HAVE_DONAU_DONAU_SERVICE_H - bool has_donau_url; - char *donau_url; + bool has_donau_url; + char *donau_url; - bool has_donau_year; - uint64_t donau_year; + bool has_donau_year; + uint64_t donau_year; - bool has_donau_budis; - json_t *donau_budikeypairs; /* array we’ll own */ + bool has_donau_budis; + json_t *donau_budikeypairs; /* array we’ll own */ #endif }; @@ -173,6 +178,7 @@ parse_tokens (const json_t *token_sigs, return GNUNET_YES; } + /** * Function called when we're done processing the * HTTP /pay request. @@ -183,8 +189,8 @@ parse_tokens (const json_t *token_sigs, */ static void handle_finished (void *cls, - long response_code, - const void *resp) + long response_code, + const void *resp) { struct TALER_MERCHANT_OrderPayHandle *oph = cls; const json_t *json = resp; @@ -207,123 +213,123 @@ handle_finished (void *cls, (unsigned int) response_code); switch (response_code) { - case 0: - pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - break; - case MHD_HTTP_OK: - if (oph->am_wallet) + case 0: + pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + break; + case MHD_HTTP_OK: + if (oph->am_wallet) + { + const json_t *token_sigs = NULL; + struct GNUNET_JSON_Specification spec[] = { + GNUNET_JSON_spec_fixed_auto ("sig", + &pr.details.ok.merchant_sig), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_string ("pos_confirmation", + &pr.details.ok.pos_confirmation), + NULL), + GNUNET_JSON_spec_mark_optional ( + GNUNET_JSON_spec_array_const ("token_sigs", + &token_sigs), + NULL), + GNUNET_JSON_spec_end () + }; + + if (GNUNET_OK != + GNUNET_JSON_parse (json, + spec, + NULL, NULL)) { - const json_t *token_sigs = NULL; - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_fixed_auto ("sig", - &pr.details.ok.merchant_sig), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_string ("pos_confirmation", - &pr.details.ok.pos_confirmation), - NULL), - GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_array_const ("token_sigs", - &token_sigs), - NULL), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (json, - spec, - NULL, NULL)) - { - GNUNET_break_op (0); - pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - pr.hr.http_status = 0; - pr.hr.hint = "sig field missing in response"; - break; - } + GNUNET_break_op (0); + pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + pr.hr.http_status = 0; + pr.hr.hint = "sig field missing in response"; + break; + } - if (GNUNET_OK != - parse_tokens (token_sigs, - &pr.details.ok.tokens, - &pr.details.ok.num_tokens)) - { - GNUNET_break_op (0); - pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - pr.hr.http_status = 0; - pr.hr.hint = "failed to parse token_sigs field in response"; - break; - } + if (GNUNET_OK != + parse_tokens (token_sigs, + &pr.details.ok.tokens, + &pr.details.ok.num_tokens)) + { + GNUNET_break_op (0); + pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + pr.hr.http_status = 0; + pr.hr.hint = "failed to parse token_sigs field in response"; + break; + } - if (GNUNET_OK != - TALER_merchant_pay_verify (&oph->h_contract_terms, - &oph->merchant_pub, - &pr.details.ok.merchant_sig)) - { - GNUNET_break_op (0); - pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; - pr.hr.http_status = 0; - pr.hr.hint = "signature invalid"; - } + if (GNUNET_OK != + TALER_merchant_pay_verify (&oph->h_contract_terms, + &oph->merchant_pub, + &pr.details.ok.merchant_sig)) + { + GNUNET_break_op (0); + pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; + pr.hr.http_status = 0; + pr.hr.hint = "signature invalid"; } - break; - /* Tolerating Not Acceptable because sometimes - * - especially in tests - we might want to POST - * coins one at a time. */ - case MHD_HTTP_NOT_ACCEPTABLE: - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_BAD_REQUEST: - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - /* This should never happen, either us - * or the merchant is buggy (or API version conflict); - * just pass JSON reply to the application */ - break; - case MHD_HTTP_PAYMENT_REQUIRED: - /* was originally paid, but then refunded */ - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_FORBIDDEN: - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - break; - case MHD_HTTP_NOT_FOUND: - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - /* Nothing really to verify, this should never - happen, we should pass the JSON reply to the - application */ - break; - case MHD_HTTP_REQUEST_TIMEOUT: - pr.hr.ec = TALER_JSON_get_error_code (json); - pr.hr.hint = TALER_JSON_get_error_hint (json); - /* The merchant couldn't generate a timely response, likely because - it itself waited too long on the exchange. - Pass on to application. */ - break; - case MHD_HTTP_CONFLICT: - TALER_MERCHANT_parse_error_details_ (json, - MHD_HTTP_CONFLICT, - &pr.hr); - break; - case MHD_HTTP_GONE: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* The merchant says we are too late, the offer has expired or some - denomination key of a coin involved has expired. - Might be a disagreement in timestamps? Still, pass on to application. */ - break; - case MHD_HTTP_PRECONDITION_FAILED: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* Nothing really to verify, the merchant is blaming us for failing to - satisfy some constraint (likely it does not like our exchange because - of some disagreement on the PKI). We should pass the JSON reply to the - application */ - break; - case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: + } + break; + /* Tolerating Not Acceptable because sometimes + * - especially in tests - we might want to POST + * coins one at a time. */ + case MHD_HTTP_NOT_ACCEPTABLE: + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_BAD_REQUEST: + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + /* This should never happen, either us + * or the merchant is buggy (or API version conflict); + * just pass JSON reply to the application */ + break; + case MHD_HTTP_PAYMENT_REQUIRED: + /* was originally paid, but then refunded */ + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_FORBIDDEN: + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + break; + case MHD_HTTP_NOT_FOUND: + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + /* Nothing really to verify, this should never + happen, we should pass the JSON reply to the + application */ + break; + case MHD_HTTP_REQUEST_TIMEOUT: + pr.hr.ec = TALER_JSON_get_error_code (json); + pr.hr.hint = TALER_JSON_get_error_hint (json); + /* The merchant couldn't generate a timely response, likely because + it itself waited too long on the exchange. + Pass on to application. */ + break; + case MHD_HTTP_CONFLICT: + TALER_MERCHANT_parse_error_details_ (json, + MHD_HTTP_CONFLICT, + &pr.hr); + break; + case MHD_HTTP_GONE: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* The merchant says we are too late, the offer has expired or some + denomination key of a coin involved has expired. + Might be a disagreement in timestamps? Still, pass on to application. */ + break; + case MHD_HTTP_PRECONDITION_FAILED: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* Nothing really to verify, the merchant is blaming us for failing to + satisfy some constraint (likely it does not like our exchange because + of some disagreement on the PKI). We should pass the JSON reply to the + application */ + break; + case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS: { json_t *ebus = json_object_get (json, "exchange_base_urls"); @@ -363,54 +369,54 @@ handle_finished (void *cls, pr.details.unavailable_for_legal_reasons.exchanges = ebua; oph->cb (oph->cb_cls, - &pr); + &pr); TALER_MERCHANT_order_pay_cancel1 (oph); return; } } - break; - case MHD_HTTP_INTERNAL_SERVER_ERROR: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* Server had an internal issue; we should retry, - but this API leaves this to the application */ - break; - case MHD_HTTP_BAD_GATEWAY: - /* Nothing really to verify, the merchant is blaming the exchange. - We should pass the JSON reply to the application */ - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - break; - case MHD_HTTP_SERVICE_UNAVAILABLE: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* Exchange couldn't respond properly; the retry is - left to the application */ - break; - case MHD_HTTP_GATEWAY_TIMEOUT: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* Exchange couldn't respond in a timely fashion; - the retry is left to the application */ - break; - default: - TALER_MERCHANT_parse_error_details_ (json, - response_code, - &pr.hr); - /* unexpected response code */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected response code %u/%d\n", - (unsigned int) response_code, - (int) pr.hr.ec); - GNUNET_break_op (0); - break; + break; + case MHD_HTTP_INTERNAL_SERVER_ERROR: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* Server had an internal issue; we should retry, + but this API leaves this to the application */ + break; + case MHD_HTTP_BAD_GATEWAY: + /* Nothing really to verify, the merchant is blaming the exchange. + We should pass the JSON reply to the application */ + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + break; + case MHD_HTTP_SERVICE_UNAVAILABLE: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* Exchange couldn't respond properly; the retry is + left to the application */ + break; + case MHD_HTTP_GATEWAY_TIMEOUT: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* Exchange couldn't respond in a timely fashion; + the retry is left to the application */ + break; + default: + TALER_MERCHANT_parse_error_details_ (json, + response_code, + &pr.hr); + /* unexpected response code */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected response code %u/%d\n", + (unsigned int) response_code, + (int) pr.hr.ec); + GNUNET_break_op (0); + break; } oph->cb (oph->cb_cls, - &pr); + &pr); if (pr.details.ok.tokens) { @@ -422,13 +428,15 @@ handle_finished (void *cls, TALER_MERCHANT_order_pay_cancel1 (oph); } + struct TALER_MERCHANT_OrderPayHandle * TALER_MERCHANT_order_pay_create (struct GNUNET_CURL_Context *ctx, TALER_MERCHANT_OrderPayCallback cb, - TALER_MERCHANT_ORDER_PAY_CALLBACK_CLOSURE_TYPE *cb_cls) + TALER_MERCHANT_ORDER_PAY_CALLBACK_CLOSURE_TYPE + *cb_cls) { struct TALER_MERCHANT_OrderPayHandle *ph = - GNUNET_new (struct TALER_MERCHANT_OrderPayHandle); + GNUNET_new (struct TALER_MERCHANT_OrderPayHandle); ph->ctx = ctx; ph->cb = cb; ph->cb_cls = cb_cls; @@ -437,6 +445,7 @@ TALER_MERCHANT_order_pay_create (struct GNUNET_CURL_Context *ctx, return ph; } + void TALER_MERCHANT_order_pay_cancel1 (struct TALER_MERCHANT_OrderPayHandle *ph) { @@ -458,12 +467,9 @@ TALER_MERCHANT_order_pay_cancel1 (struct TALER_MERCHANT_OrderPayHandle *ph) json_decref (ph->tokens_evs); ph->tokens_evs = NULL; - #ifdef HAVE_DONAU_DONAU_SERVICE_H - GNUNET_free (ph->donau_url); - if (ph->donau_budikeypairs) - json_decref (ph->donau_budikeypairs); - #endif - + GNUNET_free (ph->donau_url); + if (ph->donau_budikeypairs) + json_decref (ph->donau_budikeypairs); GNUNET_free (ph->url); GNUNET_free (ph->merchant_url); @@ -472,12 +478,14 @@ TALER_MERCHANT_order_pay_cancel1 (struct TALER_MERCHANT_OrderPayHandle *ph) GNUNET_free (ph); } + static enum TALER_MERCHANT_OrderPayOptionErrorCode store_json_option (struct TALER_MERCHANT_OrderPayHandle *ph, enum TALER_MERCHANT_OrderPayOptionType ot, json_t *snippet) { - if (ph->field_seen[ot]) { + if (ph->field_seen[ot]) + { json_decref (snippet); return TALER_MERCHANT_OPOEC_DUPLICATE_OPTION; } @@ -487,39 +495,46 @@ store_json_option (struct TALER_MERCHANT_OrderPayHandle *ph, return TALER_MERCHANT_OPOEC_OK; } + enum TALER_MERCHANT_OrderPayOptionErrorCode TALER_MERCHANT_order_pay_set_options (struct TALER_MERCHANT_OrderPayHandle *ph, - const struct TALER_MERCHANT_OrderPayOption options[], + const struct TALER_MERCHANT_OrderPayOption + options[], size_t max_options) { for (size_t i = 0; i < max_options - && options[i].ot != TALER_MERCHANT_OrderPayOptionType_END; i++) + && options[i].ot != TALER_MERCHANT_OrderPayOptionType_END; i++) { const struct TALER_MERCHANT_OrderPayOption *o = &options[i]; switch (o->ot) { - case TALER_MERCHANT_OrderPayOptionType_MERCHANT_URL: - ph->merchant_url = GNUNET_strdup(o->details.merchant_url); - break; + case TALER_MERCHANT_OrderPayOptionType_MERCHANT_URL: + ph->merchant_url = GNUNET_strdup (o->details.merchant_url); + break; - case TALER_MERCHANT_OrderPayOptionType_SESSION_ID: - ph->session_id = GNUNET_strdup(o->details.session_id); - /* add straight into JSON body */ - { - json_t *js = GNUNET_JSON_PACK(GNUNET_JSON_pack_string("session_id", o->details.session_id)); - enum TALER_MERCHANT_OrderPayOptionErrorCode ec = store_json_option(ph, o->ot, js); - if (TALER_MERCHANT_OPOEC_OK != ec) - return ec; - break; - } + case TALER_MERCHANT_OrderPayOptionType_SESSION_ID: + ph->session_id = GNUNET_strdup (o->details.session_id); + /* add straight into JSON body */ + { + json_t *js = GNUNET_JSON_PACK (GNUNET_JSON_pack_string ("session_id", + o->details. + session_id)); + enum TALER_MERCHANT_OrderPayOptionErrorCode ec = store_json_option (ph, + o-> + ot, + js); + if (TALER_MERCHANT_OPOEC_OK != ec) + return ec; + break; + } - case TALER_MERCHANT_OrderPayOptionType_ORDER_ID: + case TALER_MERCHANT_OrderPayOptionType_ORDER_ID: { - ph->order_id = GNUNET_strdup(o->details.order_id); + ph->order_id = GNUNET_strdup (o->details.order_id); break; } - case TALER_MERCHANT_OrderPayOptionType_H_CONTRACT: + case TALER_MERCHANT_OrderPayOptionType_H_CONTRACT: { ph->h_contract_terms = *o->details.h_contract; ph->has_h_contract = true; @@ -527,24 +542,24 @@ TALER_MERCHANT_order_pay_set_options (struct TALER_MERCHANT_OrderPayHandle *ph, break; } - case TALER_MERCHANT_OrderPayOptionType_CHOICE_INDEX: - ph->choice_index = o->details.choice_index; - ph->has_choice_index = true; - break; + case TALER_MERCHANT_OrderPayOptionType_CHOICE_INDEX: + ph->choice_index = o->details.choice_index; + ph->has_choice_index = true; + break; - case TALER_MERCHANT_OrderPayOptionType_AMOUNT: + case TALER_MERCHANT_OrderPayOptionType_AMOUNT: { ph->amount = &o->details.amount; break; } - case TALER_MERCHANT_OrderPayOptionType_MAX_FEE: + case TALER_MERCHANT_OrderPayOptionType_MAX_FEE: { ph->max_fee = &o->details.max_fee; break; } - case TALER_MERCHANT_OrderPayOptionType_MERCHANT_PUB: + case TALER_MERCHANT_OrderPayOptionType_MERCHANT_PUB: { ph->merchant_pub = o->details.merchant_pub; ph->has_merchant_pub = true; @@ -552,26 +567,26 @@ TALER_MERCHANT_order_pay_set_options (struct TALER_MERCHANT_OrderPayHandle *ph, break; } - case TALER_MERCHANT_OrderPayOptionType_TIMESTAMP: + case TALER_MERCHANT_OrderPayOptionType_TIMESTAMP: { ph->timestamp = o->details.timestamp; break; } - case TALER_MERCHANT_OrderPayOptionType_REFUND_DEADLINE: + case TALER_MERCHANT_OrderPayOptionType_REFUND_DEADLINE: { ph->refund_deadline = o->details.refund_deadline; break; } - case TALER_MERCHANT_OrderPayOptionType_PAY_DEADLINE: + case TALER_MERCHANT_OrderPayOptionType_PAY_DEADLINE: { - //FIXME: This one comes from the merchant_api_post_order_pay + // FIXME: This one comes from the merchant_api_post_order_pay // no idea do we still need it or not? break; } - case TALER_MERCHANT_OrderPayOptionType_H_WIRE: + case TALER_MERCHANT_OrderPayOptionType_H_WIRE: { ph->h_wire = o->details.h_wire; ph->has_h_wire = true; @@ -579,79 +594,93 @@ TALER_MERCHANT_order_pay_set_options (struct TALER_MERCHANT_OrderPayHandle *ph, break; } - case TALER_MERCHANT_OrderPayOptionType_COINS: - /* stash for later signing */ - GNUNET_assert(o->details.coins.num_coins >= 0); - ph->coins.num_coins = o->details.coins.num_coins; - ph->coins.coins = o->details.coins.coins; - //ph->field_seen[o->ot] = true; - break; + case TALER_MERCHANT_OrderPayOptionType_COINS: + /* stash for later signing */ + GNUNET_assert (o->details.coins.num_coins >= 0); + ph->coins.num_coins = o->details.coins.num_coins; + ph->coins.coins = o->details.coins.coins; + // ph->field_seen[o->ot] = true; + break; - case TALER_MERCHANT_OrderPayOptionType_INPUT_TOKENS: - /* stash for later signing */ - ph->input_tokens.num_tokens = o->details.input_tokens.num_tokens; - ph->input_tokens.tokens = o->details.input_tokens.tokens; - break; + case TALER_MERCHANT_OrderPayOptionType_INPUT_TOKENS: + /* stash for later signing */ + ph->input_tokens.num_tokens = o->details.input_tokens.num_tokens; + ph->input_tokens.tokens = o->details.input_tokens.tokens; + break; - case TALER_MERCHANT_OrderPayOptionType_OUTPUT_TOKENS: - /* store JSON array directly, *and* stash for hash */ - ph->output_tokens.num_output_tokens = o->details.output_tokens.num_output_tokens; - ph->output_tokens.output_tokens = o->details.output_tokens.output_tokens; + case TALER_MERCHANT_OrderPayOptionType_OUTPUT_TOKENS: + /* store JSON array directly, *and* stash for hash */ + ph->output_tokens.num_output_tokens = + o->details.output_tokens.num_output_tokens; + ph->output_tokens.output_tokens = o->details.output_tokens.output_tokens; + { + /* build and store tokens_evs */ + json_t *arr = json_array (); + for (unsigned j = 0; j < ph->output_tokens.num_output_tokens; j++) { - /* build and store tokens_evs */ - json_t *arr = json_array(); - for (unsigned j = 0; j < ph->output_tokens.num_output_tokens; j++) - { - const struct TALER_MERCHANT_OutputToken *otk = &ph->output_tokens.output_tokens[j]; - json_t *je = GNUNET_JSON_PACK(TALER_JSON_pack_token_envelope(NULL, &otk->envelope)); - json_array_append_new(arr, je); - } + const struct TALER_MERCHANT_OutputToken *otk = + &ph->output_tokens.output_tokens[j]; + json_t *je = GNUNET_JSON_PACK (TALER_JSON_pack_token_envelope (NULL, + &otk-> + envelope)); + json_array_append_new (arr, je); + } - ph->tokens_evs = arr; + ph->tokens_evs = arr; - ph->field_seen[o->ot] = true; - } + ph->field_seen[o->ot] = true; + } + break; + + case TALER_MERCHANT_OrderPayOptionType_DONAU_URL: + { + if (ph->donau_data == NULL) + ph->donau_data = json_object (); + GNUNET_assert (0 == json_object_set_new ( + ph->donau_data, + "url", + json_string (o->details.donau_url))); + break; + } + + case TALER_MERCHANT_OrderPayOptionType_DONAU_YEAR: + { + // TODO: As the donau_year is part of the donau object, we can already put it inside the json_t donau_data + if (ph->donau_data == NULL) + ph->donau_data = json_object (); + GNUNET_assert (0 == json_object_set_new ( + ph->donau_data, + "year", + json_integer ((json_int_t) o->details.donau_year))); + break; + } + + case TALER_MERCHANT_OrderPayOptionType_DONAU_BUDIS: + { + if (ph->donau_data == NULL) + ph->donau_data = json_object (); + GNUNET_assert (0 == json_object_set_new ( + ph->donau_data, + "budikeypairs", + json_incref (o->details.donau_budis_json))); break; + } -#ifdef HAVE_DONAU_DONAU_SERVICE_H - /* ---------- Donau ------------ */ - case TALER_MERCHANT_OrderPayOptionType_DONAU_URL: - { - ph->has_donau_url = true; - ph->donau_url = GNUNET_strdup (o->details.donau_url); - break; - } - - case TALER_MERCHANT_OrderPayOptionType_DONAU_YEAR: - { - ph->has_donau_year = true; - ph->donau_year = o->details.donau_year; - break; - } - - case TALER_MERCHANT_OrderPayOptionType_DONAU_BUDIS: - { - ph->has_donau_budis = true; - ph->donau_budikeypairs = o->details.donau_budis_json; - json_incref (ph->donau_budikeypairs); - break; - } -#endif /* HAVE_DONAU_DONAU_SERVICE_H */ - - default: - return TALER_MERCHANT_OPOEC_UNKNOWN_OPTION; + default: + return TALER_MERCHANT_OPOEC_UNKNOWN_OPTION; } } return TALER_MERCHANT_OPOEC_OK; } + enum TALER_MERCHANT_OrderPayOptionErrorCode TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) { /* all the old mandatory checks */ - if (!ph->merchant_url || !ph->order_id) + if (! ph->merchant_url || ! ph->order_id) return TALER_MERCHANT_OPOEC_MISSING_MANDATORY; - if ( !(ph->coins.num_coins >= 0) ) + if (! (ph->coins.num_coins >= 0) ) return TALER_MERCHANT_OPOEC_MISSING_MANDATORY; if (GNUNET_YES != @@ -662,31 +691,21 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) } /* --- build wallet_data hash for signing coins & tokens --- */ - if (ph->has_choice_index) { - /* base fields */ - json_t *wd = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_int64 ("choice_index", ph->choice_index), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_array_incref ("tokens_evs", ph->tokens_evs)) + if (ph->has_choice_index) + { + /* base fields */ + json_t *wd = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_int64 ("choice_index", ph->choice_index), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_array_incref ("tokens_evs", ph->tokens_evs)) ); - #ifdef HAVE_DONAU_DONAU_SERVICE_H - /* Donau extras (optional) */ - if (ph->has_donau_url) - GNUNET_assert (0 == json_object_set_new (wd, - "donau_url", - json_string (ph->donau_url))); - - if (ph->has_donau_year) - GNUNET_assert (0 == json_object_set_new (wd, - "donau_year", - json_integer ((json_int_t) ph->donau_year))); - - if (ph->has_donau_budis) - GNUNET_assert (0 == json_object_set_new (wd, - "donau_budikeypairs", - json_incref (ph->donau_budikeypairs))); - #endif + // Putting prepared donau_data into the wallet_data + if (ph->donau_data) + GNUNET_assert (0 == json_object_set_new ( + wd, + "donau", + json_incref (ph->donau_data))); ph->wallet_data = wd; @@ -714,26 +733,27 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) struct TALER_Amount fee; struct TALER_DenominationHashP h_denom_pub; - TALER_denom_pub_hash(&c->denom_pub, &h_denom_pub); - if (0 > TALER_amount_subtract(&fee, &c->amount_with_fee, &c->amount_without_fee)) + TALER_denom_pub_hash (&c->denom_pub, &h_denom_pub); + if (0 > TALER_amount_subtract (&fee, &c->amount_with_fee, + &c->amount_without_fee)) return TALER_MERCHANT_OPOEC_INVALID_VALUE; - TALER_wallet_deposit_sign(&c->amount_with_fee, - &fee, - &ph->h_wire, - &ph->h_contract_terms, - (NULL != ph->wallet_data) + TALER_wallet_deposit_sign (&c->amount_with_fee, + &fee, + &ph->h_wire, + &ph->h_contract_terms, + (NULL != ph->wallet_data) ? &ph->wallet_data_hash : NULL, - c->h_age_commitment, - NULL, - &h_denom_pub, - ph->timestamp, - &ph->merchant_pub, - ph->refund_deadline, - &c->coin_priv, - &pc.coin_sig); + c->h_age_commitment, + NULL, + &h_denom_pub, + ph->timestamp, + &ph->merchant_pub, + ph->refund_deadline, + &c->coin_priv, + &pc.coin_sig); pc.denom_pub = c->denom_pub; pc.denom_sig = c->denom_sig; @@ -741,17 +761,23 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) pc.amount_with_fee = c->amount_with_fee; pc.amount_without_fee = c->amount_without_fee; pc.exchange_url = c->exchange_url; - GNUNET_CRYPTO_eddsa_key_get_public(&c->coin_priv.eddsa_priv, - &pc.coin_pub.eddsa_pub); + GNUNET_CRYPTO_eddsa_key_get_public (&c->coin_priv.eddsa_priv, + &pc.coin_pub.eddsa_pub); /* JSON ------------------------------------------------------------ */ - json_t *je = GNUNET_JSON_PACK(TALER_JSON_pack_amount("contribution", &pc.amount_with_fee), - GNUNET_JSON_pack_data_auto("coin_pub", &pc.coin_pub), - GNUNET_JSON_pack_string("exchange_url", pc.exchange_url), - GNUNET_JSON_pack_data_auto("h_denom", &h_denom_pub), - TALER_JSON_pack_denom_sig("ub_sig", &pc.denom_sig), - GNUNET_JSON_pack_data_auto("coin_sig", &pc.coin_sig)); - json_array_append_new(arr, je); + json_t *je = GNUNET_JSON_PACK (TALER_JSON_pack_amount ("contribution", + &pc.amount_with_fee), + GNUNET_JSON_pack_data_auto ("coin_pub", + &pc.coin_pub), + GNUNET_JSON_pack_string ("exchange_url", + pc.exchange_url), + GNUNET_JSON_pack_data_auto ("h_denom", + &h_denom_pub), + TALER_JSON_pack_denom_sig ("ub_sig", + &pc.denom_sig), + GNUNET_JSON_pack_data_auto ("coin_sig", + &pc.coin_sig)); + json_array_append_new (arr, je); /* optional totals if you need them later (kept here because they existed in the legacy code) */ @@ -759,7 +785,8 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) { total_fee = fee; total_amount = pc.amount_with_fee; - } else + } + else { if ( (0 > TALER_amount_add (&total_fee, @@ -777,9 +804,9 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) enum TALER_MERCHANT_OrderPayOptionErrorCode ec = store_json_option (ph, - TALER_MERCHANT_OrderPayOptionType_COINS, - GNUNET_JSON_PACK ( - GNUNET_JSON_pack_array_steal ("coins", arr) + TALER_MERCHANT_OrderPayOptionType_COINS, + GNUNET_JSON_PACK ( + GNUNET_JSON_pack_array_steal ("coins", arr) )); if (TALER_MERCHANT_OPOEC_OK != ec) { @@ -788,10 +815,12 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) } /* --- sign & pack input_tokens into used_tokens array in body --- */ - if (ph->input_tokens.num_tokens > 0) { + if (ph->input_tokens.num_tokens > 0) + { struct TALER_MERCHANT_UsedToken ut[ph->input_tokens.num_tokens]; json_t *arr = json_array (); - for (unsigned i = 0; i < ph->input_tokens.num_tokens; i++) { + for (unsigned i = 0; i < ph->input_tokens.num_tokens; i++) + { const struct TALER_MERCHANT_UseToken *in = &ph->input_tokens.tokens[i]; struct TALER_MERCHANT_UsedToken *t = &ut[i]; @@ -813,7 +842,7 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) GNUNET_JSON_pack_data_auto ("h_issue", &t->issue_pub.public_key->pub_key_hash), GNUNET_JSON_pack_data_auto ("token_pub", &t->token_pub) - ); + ); json_array_append_new (arr, je); } @@ -821,8 +850,8 @@ TALER_MERCHANT_order_pay_start (struct TALER_MERCHANT_OrderPayHandle *ph) TALER_MERCHANT_OrderPayOptionType_INPUT_TOKENS, GNUNET_JSON_PACK ( GNUNET_JSON_pack_array_steal ("tokens", arr) - ) - ); + ) + ); } diff --git a/src/util/contract_parse.c b/src/util/contract_parse.c @@ -241,7 +241,6 @@ TALER_MERCHANT_parse_choice_output ( break; case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_TOKEN: { - output->details.token.count = 1; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("token_family_slug", &output->details.token.token_family_slug),