commit c63b925b9ddaf440d044dd7e881096e45ff7c950
parent 2d3413e76e6c44f10808a2d31be31ea65f4ae6bb
Author: Christian Grothoff <christian@grothoff.org>
Date: Thu, 6 Aug 2026 14:38:11 +0200
convert time C-side and ensure we do not end up in the past
Diffstat:
4 files changed, 83 insertions(+), 4 deletions(-)
diff --git a/src/challengerdb/do_insert_token.c b/src/challengerdb/do_insert_token.c
@@ -35,11 +35,13 @@ CHALLENGERDB_do_insert_token (struct CHALLENGERDB_PostgresContext *ctx,
{
struct GNUNET_TIME_Absolute ge
= GNUNET_TIME_relative_to_absolute (token_expiration);
+ struct GNUNET_TIME_Absolute ae
+ = GNUNET_TIME_relative_to_absolute (address_expiration);
struct GNUNET_PQ_QueryParam params[] = {
GNUNET_PQ_query_param_auto_from_type (nonce),
GNUNET_PQ_query_param_auto_from_type (token),
GNUNET_PQ_query_param_absolute_time (&ge),
- GNUNET_PQ_query_param_relative_time (&address_expiration),
+ GNUNET_PQ_query_param_absolute_time (&ae),
GNUNET_PQ_query_param_end
};
@@ -59,7 +61,7 @@ CHALLENGERDB_do_insert_token (struct CHALLENGERDB_PostgresContext *ctx,
" WHERE nonce=$1"
" AND address IS NOT NULL"
" AND auth_attempts_left < 0"
- " RETURNING address, last_tx_time"
+ " RETURNING address"
") INSERT INTO tokens"
" (access_token"
" ,address"
@@ -69,7 +71,7 @@ CHALLENGERDB_do_insert_token (struct CHALLENGERDB_PostgresContext *ctx,
" $2"
" ,address"
" ,$3"
- " ,LEAST($4, 9223372036854775807::BIGINT - last_tx_time) + last_tx_time"
+ " ,$4"
" FROM consumed;");
return GNUNET_PQ_eval_prepared_non_select (ctx->conn,
"do_insert_token",
diff --git a/src/challengerdb/meson.build b/src/challengerdb/meson.build
@@ -108,6 +108,7 @@ test_challenger_db_postgres = executable(
libchallengerdb_dep,
gnunetpq_dep,
talerutil_dep,
+ pq_dep,
json_dep,
],
include_directories: [incdir, configuration_inc],
diff --git a/src/challengerdb/test_challenger_db.c b/src/challengerdb/test_challenger_db.c
@@ -20,6 +20,7 @@
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_pq_lib.h>
#include <taler/taler_util.h>
#include "challenger_database_lib.h"
#include "challenger-database/drop_tables.h"
@@ -31,8 +32,10 @@
#include "challenger-database/do_challenge_address.h"
#include "challenger-database/do_solve_challenge.h"
#include "challenger-database/do_insert_token.h"
+#include "challenger-database/get_token.h"
#include "challenger-database/get_validation_pkce.h"
#include "challenger_util.h"
+#include "pg_helper.h"
#define FAILIF(cond) \
@@ -323,6 +326,76 @@ test_solved_redeemable (void)
/**
+ * Test that the address expiration stored with a freshly minted token is
+ * in the future, and in particular that it does *not* depend on the
+ * validation's ``last_tx_time``. The regression this guards against
+ * computed the expiration as ``address_expiration + last_tx_time``, which
+ * lands in 1970 whenever that column was never written. We force the
+ * column back to 0 to pin the property down without relying on any
+ * particular code path leaving it there.
+ *
+ * @return #GNUNET_OK on success
+ */
+static enum GNUNET_GenericReturnValue
+test_address_expiry_is_in_the_future (void)
+{
+ struct GNUNET_PQ_ExecuteStatement es[] = {
+ GNUNET_PQ_make_execute ("UPDATE validations SET last_tx_time=0;"),
+ GNUNET_PQ_EXECUTE_STATEMENT_END
+ };
+ struct CHALLENGER_ValidationNonceP nonce;
+ struct CHALLENGER_AccessTokenP token;
+ struct GNUNET_TIME_Timestamp address_expiration;
+ struct GNUNET_TIME_Absolute now;
+ json_t *address = NULL;
+ uint64_t rowid;
+ uint32_t pin;
+ enum GNUNET_GenericReturnValue ret;
+
+ if ( (GNUNET_OK !=
+ challenge_validation (&nonce,
+ &pin)) ||
+ (GNUNET_OK !=
+ solve_validation (&nonce,
+ pin)) )
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_PQ_exec_statements (pg->conn,
+ es))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ now = GNUNET_TIME_absolute_get ();
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ insert_token (&nonce,
+ &token))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
+ CHALLENGERDB_get_token (pg,
+ &token,
+ &rowid,
+ &address,
+ &address_expiration))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ ret = GNUNET_OK;
+ if (address_expiration.abs_time.abs_value_us <= now.abs_value_us)
+ {
+ GNUNET_break (0);
+ ret = GNUNET_SYSERR;
+ }
+ json_decref (address);
+ return ret;
+}
+
+
+/**
* Main function that will be run by the scheduler.
*
* @param cls closure with config
@@ -369,6 +442,8 @@ run (void *cls)
test_unsolved_not_redeemable ());
FAILIF (GNUNET_OK !=
test_solved_redeemable ());
+ FAILIF (GNUNET_OK !=
+ test_address_expiry_is_in_the_future ());
result = 0;
drop:
GNUNET_break (GNUNET_OK ==
diff --git a/src/include/challenger-database/do_insert_token.h b/src/include/challenger-database/do_insert_token.h
@@ -39,7 +39,8 @@
* @param nonce validation process to grant access to
* @param grant grant token that grants access
* @param grant_expiration for how long should the grant be valid
- * @param address_expiration for how long after validation do we consider addresses to be valid
+ * @param address_expiration for how long from now do we consider the address
+ * to be valid
* @return transaction status:
* #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if the token was minted
* #GNUNET_DB_STATUS_SUCCESS_NO_RESULTS if there is no solved validation