diff options
author | Christian Blättler <blatc2@bfh.ch> | 2024-04-10 07:50:56 +0200 |
---|---|---|
committer | Christian Blättler <blatc2@bfh.ch> | 2024-04-10 07:50:56 +0200 |
commit | 983ad0943b4f0b9ddf7d1b7a14693e4b69395ea6 (patch) | |
tree | b925a0058d56b43ac4aa2bcad45c24572c92c58d | |
parent | 53cdcd6cb3aadbeac7d878e817c1314c6fc7c63c (diff) |
serialize v1 orders
-rw-r--r-- | src/backend/Makefile.am | 1 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_contract.c | 182 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_contract.h | 39 | ||||
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-orders.c | 495 |
4 files changed, 260 insertions, 457 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am index d521608d..dbc7cde8 100644 --- a/src/backend/Makefile.am +++ b/src/backend/Makefile.am @@ -25,6 +25,7 @@ bin_PROGRAMS = \ taler_merchant_httpd_SOURCES = \ taler-merchant-httpd.c taler-merchant-httpd.h \ taler-merchant-httpd_config.c taler-merchant-httpd_config.h \ + taler-merchant-httpd_contract.c taler-merchant-httpd_contract.h \ taler-merchant-httpd_exchanges.c taler-merchant-httpd_exchanges.h \ taler-merchant-httpd_get-orders-ID.c \ taler-merchant-httpd_get-orders-ID.h \ diff --git a/src/backend/taler-merchant-httpd_contract.c b/src/backend/taler-merchant-httpd_contract.c index f850f94d..38c82e70 100644 --- a/src/backend/taler-merchant-httpd_contract.c +++ b/src/backend/taler-merchant-httpd_contract.c @@ -45,185 +45,3 @@ TMH_string_to_contract_output_type (const char *str) return TALER_MCOT_INVALID; } - -enum GNUNET_GenericReturnValue -TMH_serialize_contract (const struct TALER_MerchantContract *contract, - const struct TMH_MerchantInstance *instance, - json_t *exchanges, - json_t **out) -{ - if (TALER_MCV_V0 == contract->version) - { - return TMH_serialize_contract_v0 (contract, instance, exchanges, out); - } - - if (TALER_MCV_V1 == contract->version) - { - return TMH_serialize_contract_v1 (contract, instance, exchanges, out); - } - - GNUNET_break (0); - return GNUNET_SYSERR; -} - -enum GNUNET_GenericReturnValue -TMH_serialize_contract_v0 (const struct TALER_MerchantContract *contract, - const struct TMH_MerchantInstance *instance, - json_t *exchanges, - json_t **out) -{ - json_t *merchant; - - { - merchant = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("name", - instance->settings.name), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("website", - instance->settings.website)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("email", - instance->settings.email)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("logo", - instance->settings.logo))); - GNUNET_assert (NULL != merchant); - { - json_t *loca; - - /* Handle merchant address */ - loca = instance->settings.address; - if (NULL != loca) - { - loca = json_deep_copy (loca); - GNUNET_assert (NULL != loca); - GNUNET_assert (0 == - json_object_set_new (merchant, - "address", - loca)); - } - } - { - json_t *juri; - - /* Handle merchant jurisdiction */ - juri = instance->settings.jurisdiction; - if (NULL != juri) - { - juri = json_deep_copy (juri); - GNUNET_assert (NULL != juri); - GNUNET_assert (0 == - json_object_set_new (merchant, - "jurisdiction", - juri)); - } - } - } - - if (1 != contract->choices_len || NULL == contract->choices) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - if (1 != contract->limits_len || NULL == contract->limits) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - - struct TALER_MerchantContractChoice *choice = contract->choices; - - *out = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("summary", - choice->summary), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref ("summary_i18n", - choice->summary_i18n)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("public_reorder_url", - contract->public_reorder_url)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("fulfillment_message", - choice->fulfillment_message)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref ("fulfillment_message_i18n", - choice->fulfillment_message_i18n)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_string ("fulfillment_url", - choice->fulfillment_url)), - GNUNET_JSON_pack_array_incref ("products", - choice->products), - GNUNET_JSON_pack_data_auto ("h_wire", - &contract->limits->h_wire), - GNUNET_JSON_pack_string ("wire_method", - contract->limits->wire_method), - GNUNET_JSON_pack_string ("order_id", - contract->order_id), - GNUNET_JSON_pack_timestamp ("timestamp", - contract->timestamp), - GNUNET_JSON_pack_timestamp ("pay_deadline", - contract->pay_deadline), - GNUNET_JSON_pack_timestamp ("wire_transfer_deadline", - contract->wire_deadline), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_timestamp ("delivery_date", - contract->delivery_date)), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref ("delivery_location", - contract->delivery_location)), - GNUNET_JSON_pack_string ("merchant_base_url", - contract->merchant_base_url), - GNUNET_JSON_pack_object_incref ("merchant", - merchant), - GNUNET_JSON_pack_data_auto ("merchant_pub", - &instance->merchant_pub), - GNUNET_JSON_pack_array_incref ("exchanges", - exchanges), - TALER_JSON_pack_amount ("max_fee", - &contract->limits->max_fee), - TALER_JSON_pack_amount ("amount", - &contract->brutto), - GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref ("extra", - (json_t *) contract->extra)) - ); - - /* Pack does not work here, because it doesn't set zero-values for timestamps */ - GNUNET_assert (0 == - json_object_set_new (*out, - "refund_deadline", - GNUNET_JSON_from_timestamp ( - contract->refund_deadline))); - GNUNET_log ( - GNUNET_ERROR_TYPE_INFO, - "Refund deadline for contact is %llu\n", - (unsigned long long) contract->refund_deadline.abs_time.abs_value_us); - GNUNET_log ( - GNUNET_ERROR_TYPE_INFO, - "Wallet timestamp for contact is %llu\n", - (unsigned long long) contract->timestamp.abs_time.abs_value_us); - - /* Pack does not work here, because it sets zero-values for relative times */ - /* auto_refund should only be set if it is not 0 */ - if (! GNUNET_TIME_relative_is_zero (contract->auto_refund)) - { - GNUNET_assert (0 == - json_object_set_new (*out, - "auto_refund", - GNUNET_JSON_from_time_rel ( - contract->auto_refund))); - } - - return GNUNET_OK; -} - -enum GNUNET_GenericReturnValue -TMH_serialize_contract_v1 (const struct TALER_MerchantContract *contract, - const struct TMH_MerchantInstance *instance, - json_t *exchanges, - json_t **out) -{ - // TODO: Implement v1 serializer - return GNUNET_SYSERR; -} diff --git a/src/backend/taler-merchant-httpd_contract.h b/src/backend/taler-merchant-httpd_contract.h index 06cc8bfe..defe6479 100644 --- a/src/backend/taler-merchant-httpd_contract.h +++ b/src/backend/taler-merchant-httpd_contract.h @@ -19,6 +19,7 @@ * @author Christian Blättler */ #include "taler-merchant-httpd.h" +#include <gnunet/gnunet_time_lib.h> #include <jansson.h> @@ -112,16 +113,21 @@ struct TALER_MerchantContractInput struct { /** - * Label of the token authority in the 'token_authorities' - * array on the top-level. + * Slug of the token family to be used. */ - const char *token_authority_label; + const char *token_family_slug; + + /** + * Start time of the validity period of the token. Base on this timestamp + * the wallet can find the correct key for this token in token_authorities. + */ + struct GNUNET_TIME_Timestamp valid_after; /** * Number of tokens of this type required. Defaults to one if the * field is not provided. */ - unsigned int number; + unsigned int count; } token; } details; }; @@ -198,16 +204,21 @@ struct TALER_MerchantContractOutput struct { /** - * Label of the token authority in the 'token_authorities' - * array on the top-level. + * Slug of the token family to be issued. */ - const char *token_authority_label; + const char *token_family_slug; + + /** + * Start time of the validity period of the token. Base on this timestamp + * the wallet can find the correct key for this token in token_authorities. + */ + struct GNUNET_TIME_Timestamp valid_after; /** * Number of tokens of this type required. Defaults to one if the * field is not provided. */ - unsigned int number; + unsigned int count; } token; } details; }; @@ -277,17 +288,17 @@ struct TALER_MerchantContractTokenAuthority * Human-readable description of the semantics of the tokens issued by * this authority. */ - char *summary; + char *description; /** - * Map from IETF BCP 47 language tags to localized summaries. + * Map from IETF BCP 47 language tags to localized description. */ - json_t *summary_i18n; + json_t *description_i18n; /** * Public key used to validate tokens signed by this authority. */ - struct TALER_TokenFamilyPublicKey key; + struct TALER_TokenFamilyPublicKey *pub; /** * When will tokens signed by this key expire? @@ -318,12 +329,12 @@ struct TALER_MerchantContractTokenAuthority /** * When does the subscription period start? */ - struct GNUNET_TIME_Absolute start_date; + struct GNUNET_TIME_Timestamp start_date; /** * When does the subscription period end? */ - struct GNUNET_TIME_Absolute end_date; + struct GNUNET_TIME_Timestamp end_date; /** * Array of domain names where this subscription can be safely used diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c index 1488fe0d..8a093813 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.c +++ b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -29,6 +29,7 @@ #include <gnunet/gnunet_json_lib.h> #include <gnunet/gnunet_time_lib.h> #include <jansson.h> +#include <microhttpd.h> #include <string.h> #include <taler/taler_error_codes.h> #include <taler/taler_signatures.h> @@ -283,11 +284,6 @@ struct OrderContext const json_t *choices; /** - * Maps authority labels to token details. Is null for v0 contracts. - */ - const json_t *token_types; - - /** * Merchant base URL. */ char *merchant_base_url; @@ -353,22 +349,6 @@ struct OrderContext } parse_order; /** - * Information set in the ORDER_PHASE_PARSE_TOKEN_TYPES phase. - */ - struct - { - /** - * Array of token types referenced in the contract. - */ - struct TALER_MerchantContractTokenAuthority *authorities; - - /** - * Length of the @e authorities array. - */ - unsigned int authorities_len; - } parse_token_types; - - /** * Information set in the ORDER_PHASE_PARSE_CHOICES phase. */ struct @@ -384,6 +364,16 @@ struct OrderContext * Length of the @e choices array. */ unsigned int choices_len; + + /** + * Array of token types referenced in the contract. + */ + struct TALER_MerchantContractTokenAuthority *authorities; + + /** + * Length of the @e authorities array. + */ + unsigned int authorities_len; } parse_choices; /** @@ -503,7 +493,6 @@ struct OrderContext { ORDER_PHASE_PARSE_REQUEST, ORDER_PHASE_PARSE_ORDER, - ORDER_PHASE_PARSE_TOKEN_TYPES, ORDER_PHASE_PARSE_CHOICES, ORDER_PHASE_MERGE_INVENTORY, ORDER_PHASE_ADD_PAYMENT_DETAILS, @@ -1296,6 +1285,146 @@ get_exchange_keys (void *cls, } /** + * Fetch details about the token family with the given @a slug + * and add them to the list of token authorities. Check if the + * token family already has a valid key configured and if not, + * create a new one. + * + * @param[in,out] oc order context + * @param slug slug of the token family + * @param start_date validity start date of the token + */ +static MHD_RESULT +set_token_authority (struct OrderContext *oc, + const char *slug, + struct GNUNET_TIME_Timestamp start_date) +{ + struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details; + struct TALER_MerchantContractTokenAuthority authority; + enum GNUNET_DB_QueryStatus qs; + struct GNUNET_TIME_Absolute min_start_date = GNUNET_TIME_absolute_subtract ( + start_date.abs_time, + // TODO: make this configurable. This is the granularity of token + // expiration dates. + GNUNET_TIME_UNIT_DAYS + ); + + qs = TMH_db->lookup_token_family_key (TMH_db->cls, + oc->hc->instance->settings.id, + slug, + GNUNET_TIME_absolute_to_timestamp (min_start_date), + start_date, + &key_details); + + if (qs <= 0) + { + enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + unsigned int http_status = 0; + + switch (qs) + { + case GNUNET_DB_STATUS_HARD_ERROR: + http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + ec = TALER_EC_GENERIC_DB_FETCH_FAILED; + break; + case GNUNET_DB_STATUS_SOFT_ERROR: + http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; + ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; + break; + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Token family slug unknown\n"); + http_status = MHD_HTTP_NOT_FOUND; + /* TODO: Add specific error code */ + ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; + break; + case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* case listed to make compilers happy */ + GNUNET_assert (0); + } + GNUNET_break (0); + reply_with_error (oc, + http_status, + ec, + "authority_label"); + return MHD_NO; + } + + if (NULL == key_details.pub) + { + /* If public key is NULL, private key must also be NULL */ + GNUNET_assert (NULL == key_details.priv); + + struct GNUNET_CRYPTO_BlindSignPrivateKey *priv; + struct GNUNET_CRYPTO_BlindSignPublicKey *pub; + struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp valid_before = GNUNET_TIME_absolute_to_timestamp( + GNUNET_TIME_absolute_add (now, + key_details.token_family.duration)); + + // TODO: Should I add a wrapper around this, so it directly accepts structs of type + // TALER_TokenFamilyPublicKey and TALER_TokenFamilyPrivateKey? + GNUNET_CRYPTO_blind_sign_keys_create (&priv, + &pub, + // TODO: Make cipher and key length configurable + GNUNET_CRYPTO_BSA_RSA, + 4096); + + struct TALER_TokenFamilyPublicKey token_pub = { + .public_key = *pub, + }; + struct TALER_TokenFamilyPrivateKey token_priv = { + .private_key = *priv, + }; + + qs = TMH_db->insert_token_family_key (TMH_db->cls, + slug, + &token_pub, + &token_priv, + GNUNET_TIME_absolute_to_timestamp (now), + valid_before); + + authority.token_expiration = valid_before; + authority.pub = &token_pub; + // GNUNET_CRYPTO_blind_sign_priv_decref (&token_priv.private_key); + } else { + authority.token_expiration = key_details.valid_before; + authority.pub = key_details.pub; + } + + authority.label = slug; + authority.description = key_details.token_family.description; + authority.description_i18n = key_details.token_family.description_i18n; + + GNUNET_free (key_details.token_family.slug); + GNUNET_free (key_details.token_family.name); + if (NULL != key_details.priv) { + GNUNET_CRYPTO_blind_sign_priv_decref (&key_details.priv->private_key); + } + + switch (key_details.token_family.kind) { + case TALER_MERCHANTDB_TFK_Subscription: + authority.kind = TALER_MCTK_SUBSCRIPTION; + authority.details.subscription.start_date = key_details.valid_after; + authority.details.subscription.end_date = key_details.valid_before; + authority.critical = true; + // TODO: Set trusted domains + break; + case TALER_MERCHANTDB_TFK_Discount: + authority.kind = TALER_MCTK_DISCOUNT; + authority.critical = false; + // TODO: Set expected domains + break; + } + + GNUNET_array_append (oc->parse_choices.authorities, + oc->parse_choices.authorities_len, + authority); + + return MHD_YES; +} + +/** * Serialize order into @a oc->serialize_order.contract, * ready to be stored in the database. Upon success, continue * processing with check_contract(). @@ -1308,8 +1437,8 @@ serialize_order (struct OrderContext *oc) const struct TALER_MERCHANTDB_InstanceSettings *settings = &oc->hc->instance->settings; json_t *merchant = NULL; - json_t *token_types = NULL; - json_t *choices = NULL; + json_t *token_types = json_object (); + json_t *choices = json_array (); { merchant = GNUNET_JSON_PACK ( @@ -1358,21 +1487,37 @@ serialize_order (struct OrderContext *oc) } { - for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++) + for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++) { - struct TALER_MerchantContractTokenAuthority *authority = &oc->parse_token_types.authorities[i]; - - // TODO: What information about a token family do we want to store in the db? + struct TALER_MerchantContractTokenAuthority *authority = &oc->parse_choices.authorities[i]; + + // TODO: Finish spec to clearly define how token families are stored in + // ContractTerms. + // Here are some thoughts: + // - Multiple keys of the same token family can be referrenced in + // one contract. E.g. exchanging old subscription for new. + // - TokenAuthority should be renamed to TokenFamily for consistency. + // - TokenFamilySlug can be used instead of TokenAuthorityLabel, but + // every token-based in- or ouput needs to have a valid_after date, + // so it's clear with key is referenced. json_t *jauthority = GNUNET_JSON_PACK ( - GNUNET_JSON_pack_string ("summary", - authority->summary), + GNUNET_JSON_pack_string ("description", + authority->description), + GNUNET_JSON_pack_allow_null ( + GNUNET_JSON_pack_object_incref ("description_i18n", + authority->description_i18n)), GNUNET_JSON_pack_data_auto ("h_pub", - &authority->key.public_key.pub_key_hash), + &authority->pub->public_key.pub_key_hash), + GNUNET_JSON_pack_data_auto ("pub", + &authority->pub->public_key.pub_key_hash), GNUNET_JSON_pack_timestamp ("token_expiration", authority->token_expiration) ); - json_object_set_new (token_types, authority->label, jauthority); + GNUNET_assert (0 == + json_object_set_new (token_types, + authority->label, + jauthority)); } } @@ -1381,8 +1526,8 @@ serialize_order (struct OrderContext *oc) { struct TALER_MerchantContractChoice *choice = &oc->parse_choices.choices[i]; - json_t *inputs = NULL; - json_t *outputs = NULL; + json_t *inputs = json_array (); + json_t *outputs = json_array (); for (unsigned int j = 0; j<choice->inputs_len; j++) { @@ -1399,15 +1544,15 @@ serialize_order (struct OrderContext *oc) json_object_set_new(jinput, "number", json_integer ( - input->details.token.number))); + input->details.token.count))); GNUNET_assert(0 == json_object_set_new(jinput, - "token_authority_label", + "token_family_slug", json_string ( - input->details.token.token_authority_label))); + input->details.token.token_family_slug))); } - json_array_append_new (inputs, jinput); + GNUNET_assert (0 == json_array_append_new (inputs, jinput)); } for (unsigned int j = 0; j<choice->outputs_len; j++) @@ -1425,16 +1570,16 @@ serialize_order (struct OrderContext *oc) json_object_set_new(joutput, "number", json_integer ( - output->details.token.number))); + output->details.token.count))); GNUNET_assert(0 == json_object_set_new(joutput, - "token_authority_label", + "token_family_slug", json_string ( - output->details.token.token_authority_label))); + output->details.token.token_family_slug))); } - json_array_append_new (outputs, joutput); + GNUNET_assert (0 == json_array_append (outputs, joutput)); } json_t *jchoice = GNUNET_JSON_PACK ( @@ -1444,7 +1589,7 @@ serialize_order (struct OrderContext *oc) outputs) ); - json_array_append_new (choices, jchoice); + GNUNET_assert (0 == json_array_append (choices, jchoice)); } } @@ -1501,12 +1646,12 @@ serialize_order (struct OrderContext *oc) TALER_JSON_pack_amount ("amount", &oc->parse_order.brutto), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref("choices", - choices) + GNUNET_JSON_pack_array_incref ("choices", + choices) ), GNUNET_JSON_pack_allow_null ( - GNUNET_JSON_pack_object_incref("token_types", - token_types) + GNUNET_JSON_pack_object_incref ("token_types", + token_types) ), GNUNET_JSON_pack_allow_null ( GNUNET_JSON_pack_object_incref ("extra", @@ -1644,7 +1789,7 @@ set_exchanges (struct OrderContext *oc) /** * Parse the order field of the request. Upon success, continue - * processing with parse_token_types(). + * processing with parse_choices(). * * @param[in,out] oc order context */ @@ -1710,10 +1855,6 @@ parse_order (struct OrderContext *oc) &jmerchant), NULL), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_object_const ("token_types", - &oc->parse_order.token_types), - NULL), - GNUNET_JSON_spec_mark_optional ( GNUNET_JSON_spec_timestamp ("timestamp", &oc->parse_order.timestamp), NULL), @@ -1779,17 +1920,6 @@ parse_order (struct OrderContext *oc) "choices array must be null for v0 contracts"); return; } - - if (NULL != oc->parse_order.token_types) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - reply_with_error (oc, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_UNEXPECTED_REQUEST_ERROR, - "token_types object must be null for v0 contracts"); - return; - } } else if (0 == strcmp("1", version)) { @@ -1805,18 +1935,6 @@ parse_order (struct OrderContext *oc) "order.choices is not a valid array"); return; } - - if (oc->parse_order.token_types != NULL && - ! json_is_object(oc->parse_order.token_types)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - reply_with_error (oc, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "order.token_types is not a valid object"); - return; - } } else { @@ -2120,153 +2238,6 @@ parse_order (struct OrderContext *oc) } /** - * Parse the token_types map of the request. Upon success, continue - * processing with parse_choices(). - */ -static void -parse_token_types (struct OrderContext *oc) -{ - if (NULL == oc->parse_order.token_types) - { - oc->phase++; - return; - } - - const char *key; - json_t *value; - - json_object_foreach ((json_t*) oc->parse_order.token_types, - key, - value) - { - struct TALER_MerchantContractTokenAuthority authority; - const char *error_name; - unsigned int error_line; - // const json_t *jpublic_key = NULL; - - { - struct GNUNET_JSON_Specification spec[] = { - // GNUNET_JSON_spec_object_const ("key", &jpublic_key), - GNUNET_JSON_spec_bool ("critical", &authority.critical), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (value, - spec, - &error_name, - &error_line)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - reply_with_error (oc, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - error_name); - return; - } - } - - - { - struct GNUNET_JSON_Specification spec[] = { - GNUNET_JSON_spec_rsa_public_key ("rsa_pub", &authority.key.public_key.details.rsa_public_key), - GNUNET_JSON_spec_end () - }; - - if (GNUNET_OK != - GNUNET_JSON_parse (jpublic_key, - spec, - NULL, - NULL)) - { - GNUNET_break_op (0); - GNUNET_JSON_parse_free (spec); - reply_with_error (oc, - MHD_HTTP_BAD_REQUEST, - TALER_EC_GENERIC_PARAMETER_MALFORMED, - "key object of token type is invalid"); - return; - } - } - - authority.key.public_key.cipher = GNUNET_CRYPTO_BSA_RSA; - - GNUNET_CRYPTO_rsa_public_key_hash ( - authority.key.public_key.details.rsa_public_key, - &authority.key.public_key.pub_key_hash); - - { - struct TALER_MERCHANTDB_TokenFamilyKeyDetails key_details; - enum GNUNET_DB_QueryStatus qs; - - qs = TMH_db->lookup_token_family_key (TMH_db->cls, - oc->hc->instance->settings.id, - &authority.key.public_key.pub_key_hash, - &key_details); - - if (qs <= 0) - { - enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - unsigned int http_status = 0; - - switch (qs) - { - case GNUNET_DB_STATUS_HARD_ERROR: - GNUNET_break (0); - http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - ec = TALER_EC_GENERIC_DB_FETCH_FAILED; - break; - case GNUNET_DB_STATUS_SOFT_ERROR: - GNUNET_break (0); - http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; - ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; - break; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Token family public key unknown\n"); - http_status = MHD_HTTP_NOT_FOUND; - // TODO: Add error code - ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; - break; - case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: - /* case listed to make compilers happy */ - GNUNET_assert (0); - } - reply_with_error (oc, - http_status, - ec, - "token type public key unknown"); - return; - } - - // TODO: Copy relevant fields from key_details to authority - // TODO: Don't free key_details.token_family, because we steal the references here - authority.label = key; - authority.summary = key_details.token_family.description; - authority.summary_i18n = key_details.token_family.description_i18n; - - switch (key_details.token_family.kind) { - case TALER_MERCHANTDB_TFK_Subscription: - authority.kind = TALER_MCTK_SUBSCRIPTION; - break; - case TALER_MERCHANTDB_TFK_Discount: - authority.kind = TALER_MCTK_DISCOUNT; - break; - } - - // TODO: Free members of key_details which I didn't steal (private key) - } - - GNUNET_array_append (oc->parse_token_types.authorities, - oc->parse_token_types.authorities_len, - authority); - } - - oc->phase++; -} - -/** * Parse contract choices. Upon success, continue * processing with merge_inventory(). * @@ -2305,7 +2276,6 @@ parse_choices (struct OrderContext *oc) &error_line); if (GNUNET_OK != ret) { - GNUNET_JSON_parse_free (spec); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Choice parsing failed: %s:%u\n", error_name, @@ -2320,7 +2290,6 @@ parse_choices (struct OrderContext *oc) if (! json_is_array (jinputs) || ! json_is_array (joutputs)) { - GNUNET_JSON_parse_free (spec); GNUNET_break_op (0); reply_with_error (oc, MHD_HTTP_BAD_REQUEST, @@ -2339,7 +2308,7 @@ parse_choices (struct OrderContext *oc) // Or should i use GNUNET_grow first and then get the element using the index? // Assuming you add a field in the future, it's easier to that way, so you don't // free it. - struct TALER_MerchantContractInput input = {.details.token.number = 1}; + struct TALER_MerchantContractInput input = {.details.token.count = 1}; const char *kind; const char *ierror_name; unsigned int ierror_line; @@ -2347,11 +2316,13 @@ parse_choices (struct OrderContext *oc) struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_string ("kind", &kind), - GNUNET_JSON_spec_string ("authority_label", - &input.details.token.token_authority_label), + GNUNET_JSON_spec_string ("token_family_slug", + &input.details.token.token_family_slug), + GNUNET_JSON_spec_timestamp ("valid_after", + &input.details.token.valid_after), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("number", - &input.details.token.number), + GNUNET_JSON_spec_uint32 ("count", + &input.details.token.count), NULL), GNUNET_JSON_spec_end() }; @@ -2362,10 +2333,6 @@ parse_choices (struct OrderContext *oc) &ierror_name, &ierror_line)) { - // TODO: I have to call free here beucase the input is not yet appended to the array. - // So its lifecycle ends here. - GNUNET_JSON_parse_free (spec); - GNUNET_JSON_parse_free (ispec); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid input #%u for field %s\n", (unsigned int) idx, @@ -2378,12 +2345,9 @@ parse_choices (struct OrderContext *oc) } input.type = TMH_string_to_contract_input_type (kind); - // TODO: Where / when do I have to free kind? if (TALER_MCIT_INVALID == input.type) { - GNUNET_JSON_parse_free (spec); - GNUNET_JSON_parse_free (ispec); GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Field 'kind' invalid in input #%u\n", (unsigned int) idx); @@ -2394,7 +2358,7 @@ parse_choices (struct OrderContext *oc) return; } - if (0 == input.details.token.number) + if (0 == input.details.token.count) { /* Ignore inputs with 'number' field set to 0 */ continue; @@ -2402,10 +2366,10 @@ parse_choices (struct OrderContext *oc) bool found = false; - for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++) + for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++) { - if (0 == strcmp (oc->parse_token_types.authorities[i].label, - input.details.token.token_authority_label)) + if (0 == strcmp (oc->parse_choices.authorities[i].label, + input.details.token.token_family_slug)) { found = true; break; @@ -2414,8 +2378,15 @@ parse_choices (struct OrderContext *oc) if (! found) { - // TODO: Lookup token family by token_authority_label (slug), - // append to authorities array. + MHD_RESULT res; + res = set_token_authority (oc, + input.details.token.token_family_slug, + input.details.token.valid_after); + + if (MHD_NO == res) + { + return; + } } GNUNET_array_append (oc->parse_choices.choices[i].inputs, @@ -2429,19 +2400,21 @@ parse_choices (struct OrderContext *oc) size_t idx; json_array_foreach ((json_t *) joutputs, idx, joutput) { - struct TALER_MerchantContractOutput output = { .details.token.number = 1 }; + struct TALER_MerchantContractOutput output = { .details.token.count = 1 }; const char *kind; const char *ierror_name; unsigned int ierror_line; struct GNUNET_JSON_Specification ispec[] = { GNUNET_JSON_spec_string ("kind", - &kind), - GNUNET_JSON_spec_string ("authority_label", - &output.details.token.token_authority_label), + &kind), + GNUNET_JSON_spec_string ("token_family_slug", + &output.details.token.token_family_slug), + GNUNET_JSON_spec_timestamp ("valid_after", + &output.details.token.valid_after), GNUNET_JSON_spec_mark_optional ( - GNUNET_JSON_spec_uint32 ("number", - &output.details.token.number), + GNUNET_JSON_spec_uint32 ("count", + &output.details.token.count), NULL), GNUNET_JSON_spec_end() }; @@ -2481,7 +2454,7 @@ parse_choices (struct OrderContext *oc) return; } - if (0 == output.details.token.number) + if (0 == output.details.token.count) { /* Ignore outputs with 'number' field set to 0 */ continue; @@ -2489,10 +2462,10 @@ parse_choices (struct OrderContext *oc) bool found = false; - for (unsigned int i = 0; i<oc->parse_token_types.authorities_len; i++) + for (unsigned int i = 0; i<oc->parse_choices.authorities_len; i++) { - if (0 == strcmp (oc->parse_token_types.authorities[i].label, - output.details.token.token_authority_label)) + if (0 == strcmp (oc->parse_choices.authorities[i].label, + output.details.token.token_family_slug)) { found = true; break; @@ -2501,8 +2474,15 @@ parse_choices (struct OrderContext *oc) if (! found) { - // TODO: Lookup token family by token_authority_label (slug), - // append to authorities array. + MHD_RESULT res; + res = set_token_authority (oc, + output.details.token.token_family_slug, + output.details.token.valid_after); + + if (MHD_NO == res) + { + return; + } } GNUNET_array_append (oc->parse_choices.choices[i].outputs, @@ -2510,8 +2490,6 @@ parse_choices (struct OrderContext *oc) output); } } - - // TODO: Do I have to free spec here? } oc->phase++; @@ -2719,8 +2697,6 @@ parse_request (struct OrderContext *oc) spec); if (GNUNET_OK != ret) { - // TODO: Question: Why no GNUNET_JSON_parse_free (spec) here? - // How are e.g. oc->parse_request.payment_target or otp_id freed? GNUNET_break_op (0); finalize_order2 (oc, ret); @@ -2900,9 +2876,6 @@ TMH_private_post_orders ( case ORDER_PHASE_PARSE_ORDER: parse_order (oc); break; - case ORDER_PHASE_PARSE_TOKEN_TYPES: - parse_token_types (oc); - break; case ORDER_PHASE_PARSE_CHOICES: parse_choices (oc); break; |