challenger

OAuth 2.0-based authentication service that validates user can receive messages at a certain address
Log | Files | Refs | Submodules | README | LICENSE

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:
Msrc/challengerdb/do_insert_token.c | 8+++++---
Msrc/challengerdb/meson.build | 1+
Msrc/challengerdb/test_challenger_db.c | 75+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/include/challenger-database/do_insert_token.h | 3++-
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