merchant

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

commit d614bb0b8364751ba8efc563eca4ce964604b7c8
parent 5c0eb14b1b329efc8ad4b7c74ea610a33658684d
Author: Christian Grothoff <grothoff@gnunet.org>
Date:   Mon,  4 Aug 2025 00:23:35 +0200

fix rounding logic for token validity periods

Diffstat:
Msrc/backend/taler-merchant-httpd_private-post-orders.c | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 99 insertions(+), 4 deletions(-)

diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c @@ -1542,6 +1542,85 @@ get_rounded_time_interval (struct GNUNET_TIME_Relative precision, /** + * Get rounded time interval. @a start is calculated by rounding + * @a ts up to the nearest 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 + * @return #GNUNET_OK on success, #GNUNET_SYSERR on error + */ +static enum GNUNET_GenericReturnValue +get_rounded_time_interval_up (struct GNUNET_TIME_Relative precision, + struct GNUNET_TIME_Timestamp ts, + struct GNUNET_TIME_Timestamp *start) +{ + struct tm timeinfo; + time_t seconds; + + seconds = GNUNET_TIME_timestamp_to_s (ts); + GNUNET_break (NULL != + localtime_r (&seconds, + &timeinfo)); + + if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_YEARS, + ==, + precision)) + { + timeinfo.tm_year++; + 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_mon++; + 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_mday++; + 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_hour++; + timeinfo.tm_min = 0; + timeinfo.tm_sec = 0; + } + else if (GNUNET_TIME_relative_cmp (GNUNET_TIME_UNIT_MINUTES, + ==, + precision)) + { + timeinfo.tm_min++; + timeinfo.tm_sec = 0; + } + else + { + return GNUNET_SYSERR; + } + seconds = mktime (&timeinfo); + GNUNET_break (seconds != (time_t) -1); + *start = GNUNET_TIME_timestamp_from_s (seconds); + return GNUNET_OK; +} + + +/** * Find the family entry for the family of the given @a slug * in @a oc. * @@ -1989,10 +2068,26 @@ add_output_token_family (struct OrderContext *oc, key_details.token_family.validity_granularity, key.valid_before, &key_expires)); - GNUNET_assert (GNUNET_TIME_timestamp_cmp ( - key_expires, - !=, - round_start)); + if (GNUNET_TIME_timestamp_cmp ( + key_expires, + ==, + round_start)) + { + /* valid_before does not actually end after the + next rounded validity period would start; + determine next rounded validity period + start point and extend valid_before to cover + the full validity period */ + GNUNET_assert ( + GNUNET_OK == + get_rounded_time_interval_up ( + key_details.token_family.validity_granularity, + key.valid_before, + &key_expires)); + /* This should basically always end up being key_expires */ + key.valid_before = GNUNET_TIME_timestamp_max (key.valid_before, + key_expires); + } if (GNUNET_OK != create_key (key_details.token_family.cipher_spec, &token_priv,