diff options
Diffstat (limited to 'src/backend/taler-merchant-httpd_private-post-orders.c')
-rw-r--r-- | src/backend/taler-merchant-httpd_private-post-orders.c | 212 |
1 files changed, 137 insertions, 75 deletions
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c index 6974e367..4ac997ae 100644 --- a/src/backend/taler-merchant-httpd_private-post-orders.c +++ b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -35,6 +35,7 @@ #include <taler/taler_error_codes.h> #include <taler/taler_signatures.h> #include <taler/taler_json_lib.h> +#include <time.h> #include "taler-merchant-httpd.h" #include "taler-merchant-httpd_private-post-orders.h" #include "taler-merchant-httpd_exchanges.h" @@ -690,6 +691,7 @@ clean_order (void *cls) oc->parse_choices.choices[i].outputs_len, 0); } + // TODO: Free token family public keys GNUNET_array_grow (oc->parse_request.inventory_products, oc->parse_request.inventory_products_length, 0); @@ -1319,6 +1321,96 @@ get_exchange_keys (void *cls, } /** + * Get rounded time interval. @a start is calculated by rounding + * @a ts down to the nearest multiple of @a precision. @a end is + * the next higher multiple of @a precision. + * + * @param precision rounding precision. + * year, month, day, hour, minute are supported. + * @param ts timestamp to round + * @param[out] start start of the interval + * @param[out] end end of the interval + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static enum GNUNET_GenericReturnValue +get_rounded_time_interval (struct GNUNET_TIME_Relative precision, + struct GNUNET_TIME_Timestamp ts, + struct GNUNET_TIME_Timestamp *start, + struct GNUNET_TIME_Timestamp *end) +{ + struct tm* timeinfo; + time_t seconds; + + seconds = GNUNET_TIME_timestamp_to_s (ts); + timeinfo = localtime (&seconds); + + if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_YEARS, ==, precision)) + { + timeinfo->tm_mon = 0; + timeinfo->tm_mday = 1; + timeinfo->tm_hour = 0; + timeinfo->tm_min = 0; + timeinfo->tm_sec = 0; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MONTHS, ==, precision)) + { + timeinfo->tm_mday = 1; + timeinfo->tm_hour = 0; + timeinfo->tm_min = 0; + timeinfo->tm_sec = 0; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_DAYS, ==, precision)) + { + timeinfo->tm_hour = 0; + timeinfo->tm_min = 0; + timeinfo->tm_sec = 0; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_HOURS, ==, precision)) + { + timeinfo->tm_min = 0; + timeinfo->tm_sec = 0; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MINUTES, ==, precision)) + { + timeinfo->tm_sec = 0; + } + else + { + return GNUNET_SYSERR; + } + + *start = GNUNET_TIME_timestamp_from_s (mktime (timeinfo)); + + if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_YEARS, ==, precision)) + { + timeinfo->tm_year++; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MONTHS, ==, precision)) + { + timeinfo->tm_mon = (timeinfo->tm_mon + 1) % 12; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_DAYS, ==, precision)) + { + timeinfo->tm_mday++; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_HOURS, ==, precision)) + { + timeinfo->tm_hour++; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MINUTES, ==, precision)) + { + timeinfo->tm_min++; + } + else + { + return GNUNET_SYSERR; + } + + *end = GNUNET_TIME_timestamp_from_s (mktime (timeinfo)); + return GNUNET_OK; +} + +/** * Check if the token family with the given @a slug is already present in * the list of token families for this order. If not, fetch its details and * add it to the list. Then check if there is a public key with a matching @@ -1328,8 +1420,9 @@ get_exchange_keys (void *cls, * @param[in,out] oc order context * @param slug slug of the token family * @param valid_after validity start date of the token, subject to rounding + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error */ -static MHD_RESULT +static enum GNUNET_GenericReturnValue set_token_family (struct OrderContext *oc, const char *slug, struct GNUNET_TIME_Timestamp valid_after) @@ -1339,16 +1432,22 @@ set_token_family (struct OrderContext *oc, enum GNUNET_DB_QueryStatus qs; // TODO: make this configurable. This is the granularity of token // expiration dates. - struct GNUNET_TIME_Relative rounding = GNUNET_TIME_UNIT_YEARS; + struct GNUNET_TIME_Relative precision = GNUNET_TIME_UNIT_MONTHS; + struct GNUNET_TIME_Timestamp min_valid_after; + struct GNUNET_TIME_Timestamp max_valid_after; - struct GNUNET_TIME_Timestamp min_valid_after = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_round_down ( - valid_after.abs_time, - rounding)); - struct GNUNET_TIME_Timestamp max_valid_after = GNUNET_TIME_absolute_to_timestamp ( - GNUNET_TIME_absolute_add( - min_valid_after.abs_time, - rounding)); + if ( GNUNET_OK != get_rounded_time_interval (precision, + valid_after, + &min_valid_after, + &max_valid_after)) + { + GNUNET_break (0); + reply_with_error (oc, + MHD_HTTP_INTERNAL_SERVER_ERROR, + TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, + "valid_after"); + return GNUNET_SYSERR; + } for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++) { @@ -1364,13 +1463,15 @@ set_token_family (struct OrderContext *oc, { for (unsigned int i = 0; i<family->keys_len; i++) { - if (family->keys[i].valid_after.abs_time.abs_value_us >= - min_valid_after.abs_time.abs_value_us - && family->keys[i].valid_after.abs_time.abs_value_us < - max_valid_after.abs_time.abs_value_us) + if (GNUNET_TIME_timestamp_cmp (family->keys[i].valid_after, + >=, + min_valid_after) + && GNUNET_TIME_timestamp_cmp (family->keys[i].valid_after, + <, + max_valid_after)) { /* The token family and a matching key is already added. */ - return MHD_YES; + return GNUNET_OK; } } } @@ -1414,15 +1515,15 @@ set_token_family (struct OrderContext *oc, http_status, ec, "token_family_slug"); - return MHD_NO; + return GNUNET_SYSERR; } - if (NULL == key_details.pub) + if (GNUNET_CRYPTO_BSA_INVALID == key_details.pub.public_key.cipher) { /* There is no matching key for this token family yet. */ /* We have to generate one. */ - /* If public key is NULL, private key must also be NULL */ - GNUNET_assert (NULL == key_details.priv); + /* If public key is invalid, private key must also be invalid */ + GNUNET_assert (GNUNET_CRYPTO_BSA_INVALID == key_details.priv.private_key.cipher); enum GNUNET_DB_QueryStatus iqs; struct GNUNET_CRYPTO_BlindSignPrivateKey *priv; @@ -1446,6 +1547,7 @@ set_token_family (struct OrderContext *oc, }; // TODO: Check if I have to decref pub and priv here. + // GNUNET_CRYPTO_blind_sign_pub_decref (pub); iqs = TMH_db->insert_token_family_key (TMH_db->cls, slug, @@ -1454,10 +1556,9 @@ set_token_family (struct OrderContext *oc, min_valid_after, valid_before); - /* private key is no longer needed */ - // GNUNET_CRYPTO_blind_sign_priv_decref (&token_priv.private_key); + GNUNET_CRYPTO_blind_sign_priv_decref (priv); - if (iqs < 0) + if (iqs <= 0) { enum TALER_ErrorCode ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; unsigned int http_status = 0; @@ -1469,23 +1570,21 @@ set_token_family (struct OrderContext *oc, ec = TALER_EC_GENERIC_DB_STORE_FAILED; break; case GNUNET_DB_STATUS_SOFT_ERROR: + case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: http_status = MHD_HTTP_INTERNAL_SERVER_ERROR; ec = TALER_EC_GENERIC_DB_SOFT_FAILURE; break; - case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: /* case listed to make compilers happy */ GNUNET_assert (0); } - // GNUNET_CRYPTO_blind_sign_pub_decref (&token_pub.public_key); - GNUNET_break (0); reply_with_error (oc, http_status, ec, "token_family_slug"); - return MHD_NO; + return GNUNET_SYSERR; } { @@ -1501,7 +1600,7 @@ set_token_family (struct OrderContext *oc, } } else { struct TALER_MerchantContractTokenFamilyKey key = { - .pub = *key_details.pub, + .pub = key_details.pub, .valid_after = key_details.valid_before, .valid_before = key_details.valid_before, }; @@ -1517,9 +1616,6 @@ set_token_family (struct OrderContext *oc, 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: @@ -1538,7 +1634,7 @@ set_token_family (struct OrderContext *oc, oc->parse_choices.token_families_len, *family); - return MHD_YES; + return GNUNET_OK; } /** @@ -2496,29 +2592,12 @@ parse_choices (struct OrderContext *oc) continue; } - bool found = false; - - for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++) - { - if (0 == strcmp (oc->parse_choices.token_families[i].slug, - input.details.token.token_family_slug)) - { - found = true; - break; - } - } - - if (! found) + if (GNUNET_OK != set_token_family (oc, + input.details.token.token_family_slug, + input.details.token.valid_after)) { - MHD_RESULT res; - res = set_token_family (oc, - input.details.token.token_family_slug, - input.details.token.valid_after); - - if (MHD_NO == res) - { - return; - } + /* error is already scheduled, return. */ + return; } GNUNET_array_append (oc->parse_choices.choices[i].inputs, @@ -2592,29 +2671,12 @@ parse_choices (struct OrderContext *oc) continue; } - bool found = false; - - for (unsigned int i = 0; i<oc->parse_choices.token_families_len; i++) + if (GNUNET_OK != set_token_family (oc, + output.details.token.token_family_slug, + output.details.token.valid_after)) { - if (0 == strcmp (oc->parse_choices.token_families[i].slug, - output.details.token.token_family_slug)) - { - found = true; - break; - } - } - - if (! found) - { - MHD_RESULT res; - res = set_token_family (oc, - output.details.token.token_family_slug, - output.details.token.valid_after); - - if (MHD_NO == res) - { - return; - } + /* error is already scheduled, return. */ + return; } GNUNET_array_append (oc->parse_choices.choices[i].outputs, |