diff options
-rw-r--r-- | src/backend/taler-merchant-httpd_post-orders-ID-pay.c | 66 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-token-families.c | 18 | ||||
-rw-r--r-- | src/backenddb/pg_insert_token_family.c | 4 | ||||
-rw-r--r-- | src/include/taler_merchant_service.h | 7 | ||||
-rw-r--r-- | src/include/taler_merchant_testing_lib.h | 1 | ||||
-rw-r--r-- | src/include/taler_merchantdb_plugin.h | 5 | ||||
-rw-r--r-- | src/lib/merchant_api_post_order_pay.c | 14 | ||||
-rw-r--r-- | src/lib/merchant_api_post_tokenfamilies.c | 3 | ||||
-rw-r--r-- | src/testing/test_merchant_api.c | 2 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_pay_order.c | 17 | ||||
-rw-r--r-- | src/testing/testing_api_cmd_post_tokenfamilies.c | 8 |
11 files changed, 75 insertions, 70 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 888ea0ba..08e4b6d8 100644 --- a/src/backend/taler-merchant-httpd_post-orders-ID-pay.c +++ b/src/backend/taler-merchant-httpd_post-orders-ID-pay.c @@ -256,6 +256,7 @@ struct TokenUseConfirmation /** * Hash of the token issue public key associated with this token. + * Note this is set in the validate_tokens phase. */ struct TALER_TokenIssuePublicKeyHashP h_issue; @@ -278,11 +279,6 @@ struct TokenEnvelope */ struct TALER_TokenEnvelopeP blinded_token; - /** - * Hash of token issue public key. - */ - struct TALER_TokenIssuePublicKeyHashP h_issue; - }; @@ -1515,8 +1511,7 @@ build_token_sigs (struct PayContext *pc) for (unsigned int i = 0; i < pc->output_tokens_len; i++) { json_array_append_new (token_sigs, GNUNET_JSON_PACK ( - GNUNET_JSON_pack_blinded_sig ("blind_sig", pc->output_tokens[i].sig.signature), - GNUNET_JSON_pack_data_auto ("h_issue", &pc->output_tokens[i].h_issue) + GNUNET_JSON_pack_blinded_sig ("blind_sig", pc->output_tokens[i].sig.signature) )); } @@ -2308,20 +2303,16 @@ phase_execute_pay_transaction (struct PayContext *pc) static enum GNUNET_GenericReturnValue find_valid_input_tokens (struct PayContext *pc, struct TALER_MerchantContractTokenFamilyKey *key, + unsigned int index, unsigned int expected_num) { int num_validated = 0; struct TokenUseConfirmation *tuc = NULL; - for (size_t i = 0; i < pc->tokens_cnt; i++) + for (unsigned int j = 0; j < expected_num; j++) { - if (0 != GNUNET_CRYPTO_hash_cmp (&pc->tokens[i].h_issue.hash, - &key->pub.public_key->pub_key_hash)) - { - continue; - } + tuc = &pc->tokens[index + j]; - tuc = &pc->tokens[i]; if (NULL == tuc) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -2338,6 +2329,8 @@ find_valid_input_tokens (struct PayContext *pc, return GNUNET_NO; } + tuc->h_issue.hash = key->pub.public_key->pub_key_hash; + if (GNUNET_OK != TALER_token_issue_verify (&tuc->pub, &key->pub, &tuc->unblinded_sig)) @@ -2399,26 +2392,37 @@ find_valid_input_tokens (struct PayContext *pc, static enum GNUNET_GenericReturnValue sign_token_envelopes (struct PayContext *pc, - const char *token_family_slug, struct TALER_MerchantContractTokenFamilyKey *key, struct TALER_TokenIssuePrivateKeyP *priv, + unsigned int index, unsigned int expected_num) { int num_signed = 0; - for (unsigned int i = 0; i<pc->token_envelopes_cnt; i++) + for (unsigned int j = 0; j<expected_num; j++) { - if (0 != GNUNET_CRYPTO_hash_cmp (&pc->token_envelopes[i].h_issue.hash, - &key->pub.public_key->pub_key_hash)) - { - continue; + unsigned int pos = index + j; + + /* TODO: Handle missing envelopes for non-critical output tokens. */ + if (pos > pc->token_envelopes_cnt || pos > pc->output_tokens_len) { + GNUNET_break (0); + pay_end (pc, + TALER_MHD_reply_with_error (pc->connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "Token envelope array is missing " + "required token envelope")); + return GNUNET_NO; } + struct TokenEnvelope *env = &pc->token_envelopes[index + j]; + struct SignedOutputToken *output = &pc->output_tokens[index + j]; + TALER_token_issue_sign (priv, - &pc->token_envelopes[i].blinded_token, - &pc->output_tokens[i].sig); + &env->blinded_token, + &output->sig); - pc->output_tokens[i].h_issue.hash = pc->token_envelopes[i].h_issue.hash; + output->h_issue.hash = key->pub.public_key->pub_key_hash; num_signed++; } @@ -2498,12 +2502,6 @@ phase_validate_tokens (struct PayContext *pc) selected = pc->choices[pc->choice_index]; - /* 1. Iterate over inputs of selected choice: - 1.1. Get key for each input. - 1.2. Check if token signed by this key are valid at the current time. - 1.3. Iterate over provided tokens and check if required number with matching h_issue are present. - 1.4. Validate ub_sig with the issue public key, validate token_sig using the token_pub key of the request. - 1.5. Sum up validated tokens and check if validated_len == tokens_cnt after loop. */ for (unsigned int i = 0; i<selected.inputs_len; i++) { struct TALER_MerchantContractInput input = selected.inputs[i]; @@ -2557,6 +2555,7 @@ phase_validate_tokens (struct PayContext *pc) if (GNUNET_NO == find_valid_input_tokens (pc, &key, + i, input.details.token.count)) { /* Error is already scheduled from find_valid_input_token. */ @@ -2621,9 +2620,9 @@ phase_validate_tokens (struct PayContext *pc) GNUNET_assert (NULL != details.priv.private_key); if (GNUNET_OK != sign_token_envelopes (pc, - family.slug, &key, &details.priv, + i, output.details.token.count)) { /* Error is already scheduled from sign_token_envelopes. */ @@ -2704,9 +2703,6 @@ input_tokens_paid_check ( struct TokenUseConfirmation *tuc = &pc->tokens[i]; if ( (0 == - GNUNET_CRYPTO_hash_cmp (&tuc->h_issue.hash, - &h_issue_pub->hash)) && - (0 == GNUNET_memcmp (&tuc->pub, use_pub)) && (0 == GNUNET_memcmp (&tuc->sig, use_sig)) && @@ -3375,8 +3371,6 @@ phase_parse_pay (struct PayContext *pc) &tuc->pub), TALER_JSON_spec_token_issue_sig ("ub_sig", &tuc->unblinded_sig), - GNUNET_JSON_spec_fixed_auto ("h_issue", - &tuc->h_issue), GNUNET_JSON_spec_end () }; enum GNUNET_GenericReturnValue res; @@ -3445,8 +3439,6 @@ phase_parse_pay (struct PayContext *pc) struct GNUNET_JSON_Specification ispec[] = { TALER_JSON_spec_token_envelope ("token_ev", &ev->blinded_token), - GNUNET_JSON_spec_fixed_auto ("h_issue", - &ev->h_issue.hash), GNUNET_JSON_spec_end () }; enum GNUNET_GenericReturnValue res; diff --git a/src/backend/taler-merchant-httpd_private-post-token-families.c b/src/backend/taler-merchant-httpd_private-post-token-families.c index 5a342af2..069f6b29 100644 --- a/src/backend/taler-merchant-httpd_private-post-token-families.c +++ b/src/backend/taler-merchant-httpd_private-post-token-families.c @@ -97,6 +97,8 @@ TMH_private_post_token_families (const struct TMH_RequestHandler *rh, &details.valid_before), GNUNET_JSON_spec_relative_time ("duration", &details.duration), + GNUNET_JSON_spec_relative_time ("rounding", + &details.rounding), GNUNET_JSON_spec_end () }; @@ -171,6 +173,22 @@ TMH_private_post_token_families (const struct TMH_RequestHandler *rh, "description_i18n"); } + if ( GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_YEARS, !=, details.rounding) && + GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MONTHS, !=, details.rounding) && + GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_DAYS, !=, details.rounding) && + GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_HOURS, !=, details.rounding) && + GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MINUTES, !=, details.rounding) ) + { + GNUNET_break (0); + GNUNET_JSON_parse_free (spec); + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Received invalid rounding value: %s\n", + GNUNET_STRINGS_relative_time_to_string (details.rounding, GNUNET_YES)); + return TALER_MHD_reply_with_error (connection, + MHD_HTTP_BAD_REQUEST, + TALER_EC_GENERIC_PARAMETER_MALFORMED, + "rounding"); + } /* finally, interact with DB until no serialization error */ for (unsigned int i = 0; i<MAX_RETRIES; i++) diff --git a/src/backenddb/pg_insert_token_family.c b/src/backenddb/pg_insert_token_family.c index bf7159b8..f533a2fb 100644 --- a/src/backenddb/pg_insert_token_family.c +++ b/src/backenddb/pg_insert_token_family.c @@ -56,6 +56,7 @@ TMH_PG_insert_token_family (void *cls, GNUNET_PQ_query_param_timestamp (&details->valid_after), GNUNET_PQ_query_param_timestamp (&details->valid_before), GNUNET_PQ_query_param_relative_time (&details->duration), + GNUNET_PQ_query_param_relative_time (&details->rounding), GNUNET_PQ_query_param_string (kind), GNUNET_PQ_query_param_end }; @@ -72,8 +73,9 @@ TMH_PG_insert_token_family (void *cls, ",valid_after" ",valid_before" ",duration" + ",rounding" ",kind)" - " SELECT merchant_serial, $2, $3, $4, $5, $6, $7, $8, $9" + " SELECT merchant_serial, $2, $3, $4, $5, $6, $7, $8, $9, $10" " FROM merchant_instances" " WHERE merchant_id=$1"); return GNUNET_PQ_eval_prepared_non_select (pg->conn, diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h index dc79303f..52034f63 100644 --- a/src/include/taler_merchant_service.h +++ b/src/include/taler_merchant_service.h @@ -2069,6 +2069,7 @@ typedef void * @param valid_after when the token family becomes valid * @param valid_before when the token family expires * @param duration how long tokens issued by this token family are valid for + * @param rounding rounding duration of token family * @param kind kind of token family, "subscription" or "discount" * @param cb function to call with the backend's result * @param cb_cls closure for @a cb @@ -2085,6 +2086,7 @@ TALER_MERCHANT_token_families_post ( struct GNUNET_TIME_Timestamp valid_after, struct GNUNET_TIME_Timestamp valid_before, struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Relative rounding, const char *kind, TALER_MERCHANT_TokenFamiliesPostCallback cb, void *cb_cls); @@ -3352,11 +3354,6 @@ struct TALER_MERCHANT_OutputToken struct TALER_TokenEnvelopeP envelope; /** - * Hash of the corresponding token issue public key. - */ - struct TALER_TokenIssuePublicKeyHashP h_issue; - - /** * Blinded issue signature made by the merchant. */ struct TALER_TokenIssueBlindSignatureP blinded_sig; diff --git a/src/include/taler_merchant_testing_lib.h b/src/include/taler_merchant_testing_lib.h index 20ac3076..d4b5bd27 100644 --- a/src/include/taler_merchant_testing_lib.h +++ b/src/include/taler_merchant_testing_lib.h @@ -1572,6 +1572,7 @@ TALER_TESTING_cmd_merchant_post_tokenfamilies ( struct GNUNET_TIME_Timestamp valid_after, struct GNUNET_TIME_Timestamp valid_before, struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Relative rounding, const char *kind); /* ****** Webhooks ******* */ diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h index f63fcd99..e7f3090a 100644 --- a/src/include/taler_merchantdb_plugin.h +++ b/src/include/taler_merchantdb_plugin.h @@ -1148,6 +1148,11 @@ struct TALER_MERCHANTDB_TokenFamilyDetails struct GNUNET_TIME_Relative duration; /** + * Rounding duration of the token family. + */ + struct GNUNET_TIME_Relative rounding; + + /** * Token family kind. */ enum TALER_MERCHANTDB_TokenFamilyKind kind; diff --git a/src/lib/merchant_api_post_order_pay.c b/src/lib/merchant_api_post_order_pay.c index 33592c08..b34240b6 100644 --- a/src/lib/merchant_api_post_order_pay.c +++ b/src/lib/merchant_api_post_order_pay.c @@ -155,8 +155,6 @@ parse_tokens (const json_t *token_sigs, struct GNUNET_JSON_Specification spec[] = { TALER_JSON_spec_blinded_token_issue_sig ("blind_sig", &token->blinded_sig), - GNUNET_JSON_spec_fixed_auto ("h_issue", - &token->h_issue), GNUNET_JSON_spec_end () }; @@ -480,10 +478,7 @@ TALER_MERCHANT_order_pay_frontend ( GNUNET_JSON_pack_data_auto ("token_pub", &ut->token_pub), TALER_JSON_pack_token_issue_sig ("ub_sig", - &ut->ub_sig), - /* TODO: Check if we need a more specific hash, similar to TALER_denom_pub_hash () */ - GNUNET_JSON_pack_data_auto ("h_issue", - &ut->issue_pub.public_key->pub_key_hash)); + &ut->ub_sig)); if (0 != json_array_append_new (j_tokens, j_token)) @@ -544,8 +539,6 @@ TALER_MERCHANT_order_pay_frontend ( GNUNET_memcpy (oph->coins, coins, num_coins * sizeof (struct TALER_MERCHANT_PaidCoin)); - /* TODO: Copy tokens_evs to pay handle so they - can be unblinded in the callback. */ eh = TALER_MERCHANT_curl_easy_get_ (oph->url); if (GNUNET_OK != @@ -626,9 +619,8 @@ TALER_MERCHANT_order_pay ( j_token_ev = GNUNET_JSON_PACK ( TALER_JSON_pack_token_envelope ("token_ev", - &ev->envelope), - GNUNET_JSON_pack_data_auto ("h_issue", - &ev->h_issue.hash)); + &ev->envelope)); + if (0 != json_array_append_new (j_output_tokens, j_token_ev)) diff --git a/src/lib/merchant_api_post_tokenfamilies.c b/src/lib/merchant_api_post_tokenfamilies.c index 0c5e18c2..95cbd13b 100644 --- a/src/lib/merchant_api_post_tokenfamilies.c +++ b/src/lib/merchant_api_post_tokenfamilies.c @@ -169,6 +169,7 @@ TALER_MERCHANT_token_families_post ( struct GNUNET_TIME_Timestamp valid_after, struct GNUNET_TIME_Timestamp valid_before, struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Relative rounding, const char *kind, TALER_MERCHANT_TokenFamiliesPostCallback cb, void *cb_cls) @@ -193,6 +194,8 @@ TALER_MERCHANT_token_families_post ( valid_before), GNUNET_JSON_pack_time_rel ("duration", duration), + GNUNET_JSON_pack_time_rel ("rounding", + rounding), GNUNET_JSON_pack_string ("kind", kind)); handle = GNUNET_new (struct TALER_MERCHANT_TokenFamiliesPostHandle); diff --git a/src/testing/test_merchant_api.c b/src/testing/test_merchant_api.c index fdf5e7f4..28c32c2f 100644 --- a/src/testing/test_merchant_api.c +++ b/src/testing/test_merchant_api.c @@ -1698,6 +1698,7 @@ run (void *cls, GNUNET_TIME_absolute_add ( GNUNET_TIME_timestamp_get ().abs_time, GNUNET_TIME_UNIT_YEARS)), GNUNET_TIME_UNIT_MONTHS, + GNUNET_TIME_UNIT_MONTHS, "subscription"), TALER_TESTING_cmd_merchant_post_orders_choices ("create-order-with-upcoming-output", cred.cfg, @@ -1720,6 +1721,7 @@ run (void *cls, GNUNET_TIME_UNIT_ZERO_TS, GNUNET_TIME_relative_to_timestamp (GNUNET_TIME_UNIT_YEARS), GNUNET_TIME_UNIT_MONTHS, + GNUNET_TIME_UNIT_MONTHS, "subscription"), TALER_TESTING_cmd_merchant_post_orders_choices ("create-order-with-output", cred.cfg, diff --git a/src/testing/testing_api_cmd_pay_order.c b/src/testing/testing_api_cmd_pay_order.c index dbcb5b24..97d0b66a 100644 --- a/src/testing/testing_api_cmd_pay_order.c +++ b/src/testing/testing_api_cmd_pay_order.c @@ -512,25 +512,11 @@ pay_cb (void *cls, { struct TALER_MERCHANT_PrivateTokenDetails *details = &ps->issued_tokens[i]; + /* The issued tokens should be in the same order as the provided envelopes. */ - if (1 == GNUNET_CRYPTO_hash_cmp( - &details->issue_pub.public_key->pub_key_hash, - &pr->details.ok.tokens[i].h_issue.hash)) - { - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Unexpected token issued. " - "Expected token with hash %s but got token with hash %s.\n", - GNUNET_h2s (&details->issue_pub.public_key->pub_key_hash), - GNUNET_h2s (&pr->details.ok.tokens[i].h_issue.hash)); - GNUNET_break (0); - TALER_TESTING_interpreter_fail (ps->is); - return; - } - ps->issued_tokens[i].blinded_sig = pr->details.ok.tokens[i].blinded_sig; - if (GNUNET_OK != TALER_token_issue_sig_unblind (&details->issue_sig, &details->blinded_sig, @@ -880,7 +866,6 @@ pay_run (void *cls, ps->num_issued_tokens); for (unsigned int i = 0; i<len_output_tokens; i++) { - output_tokens[i].h_issue.hash = ps->issued_tokens[i].issue_pub.public_key->pub_key_hash; output_tokens[i].envelope.blinded_pub = ps->issued_tokens[i].envelope.blinded_pub; } diff --git a/src/testing/testing_api_cmd_post_tokenfamilies.c b/src/testing/testing_api_cmd_post_tokenfamilies.c index aafff9ef..c24b98db 100644 --- a/src/testing/testing_api_cmd_post_tokenfamilies.c +++ b/src/testing/testing_api_cmd_post_tokenfamilies.c @@ -92,6 +92,11 @@ struct PostTokenFamiliesState struct GNUNET_TIME_Relative duration; /** + * Rounding duation of token family. + */ + struct GNUNET_TIME_Relative rounding; + + /** * Kind of the token family. "subscription" or "discount". */ const char *kind; @@ -166,6 +171,7 @@ post_tokenfamilies_run (void *cls, state->valid_after, state->valid_before, state->duration, + state->rounding, state->kind, &post_tokenfamilies_cb, state); @@ -241,6 +247,7 @@ TALER_TESTING_cmd_merchant_post_tokenfamilies ( struct GNUNET_TIME_Timestamp valid_after, struct GNUNET_TIME_Timestamp valid_before, struct GNUNET_TIME_Relative duration, + struct GNUNET_TIME_Relative rounding, const char *kind) /* "subscription" or "discount" */ { struct PostTokenFamiliesState *state; @@ -257,6 +264,7 @@ TALER_TESTING_cmd_merchant_post_tokenfamilies ( state->valid_after = valid_after; state->valid_before = valid_before; state->duration = duration; + state->rounding = rounding; state->kind = kind; { struct TALER_TESTING_Command cmd = { |