summaryrefslogtreecommitdiff
path: root/src/stasis/plugin_anastasis_postgres.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stasis/plugin_anastasis_postgres.c')
-rw-r--r--src/stasis/plugin_anastasis_postgres.c135
1 files changed, 134 insertions, 1 deletions
diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c
index 8c06243..506c304 100644
--- a/src/stasis/plugin_anastasis_postgres.c
+++ b/src/stasis/plugin_anastasis_postgres.c
@@ -38,6 +38,12 @@
*/
#define MAX_RETRIES 3
+/**
+ * Maximum value allowed for nonces. Limited to 2^52 to ensure the
+ * numeric value survives a conversion to float by JavaScript.
+ */
+#define NONCE_MAX_VALUE (1LLU << 52)
+
/**
* Type of the "cls" argument given to each of the functions in
@@ -2125,7 +2131,7 @@ postgres_create_challenge_code (
}
*code = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE,
- INT64_MAX);
+ NONCE_MAX_VALUE);
*retransmission_date = GNUNET_TIME_UNIT_ZERO_ABS;
{
struct GNUNET_PQ_QueryParam params[] = {
@@ -2169,6 +2175,132 @@ retry:
/**
+ * Setup challenge code for a given challenge identified by the
+ * challenge public key. The function will first check if there is
+ * already a valid code for this challenge present and won't insert
+ * a new one in this case. This variant is not rate-limited, will
+ * return the existing challenge if it has not yet expired and will
+ * simply create new challenges when the old ones need to be
+ * rotated.
+ *
+ * @param cls closure
+ * @param truth_uuid the identifier for the challenge
+ * @param rotation_period for how long is the code available
+ * @param validity_period for how long is the code available
+ * @param[out] code set to the code which will be checked for later
+ * @return transaction status,
+ * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB
+ */
+static enum GNUNET_DB_QueryStatus
+postgres_get_unlimited_challenge_code (
+ void *cls,
+ const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
+ struct GNUNET_TIME_Relative rotation_period,
+ struct GNUNET_TIME_Relative validity_period,
+ uint64_t *code)
+{
+ struct PostgresClosure *pg = cls;
+ enum GNUNET_DB_QueryStatus qs;
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_TIME_Absolute expiration_date;
+ struct GNUNET_TIME_Absolute ex_rot;
+
+ check_connection (pg);
+ GNUNET_TIME_round_abs (&now);
+ expiration_date = GNUNET_TIME_absolute_add (now,
+ validity_period);
+ ex_rot = GNUNET_TIME_absolute_subtract (now,
+ rotation_period);
+ for (unsigned int retries = 0; retries<MAX_RETRIES; retries++)
+ {
+ if (GNUNET_OK !=
+ begin_transaction (pg,
+ "get_unlimited_challenge_code"))
+ {
+ GNUNET_break (0);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ }
+
+ {
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ TALER_PQ_query_param_absolute_time (&now),
+ TALER_PQ_query_param_absolute_time (&ex_rot),
+ GNUNET_PQ_query_param_end
+ };
+ struct GNUNET_PQ_ResultSpec rs[] = {
+ GNUNET_PQ_result_spec_uint64 ("code",
+ code),
+ GNUNET_PQ_result_spec_end
+ };
+ enum GNUNET_DB_QueryStatus qs;
+
+ qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn,
+ "challengecode_select_meta",
+ params,
+ rs);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ GNUNET_break (0);
+ rollback (pg);
+ return qs;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ /* no active challenge, create fresh one (below) */
+ break;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ rollback (pg);
+ return qs;
+ }
+ }
+
+ *code = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE,
+ NONCE_MAX_VALUE);
+ {
+ uint32_t retry_counter = UINT32_MAX;
+ struct GNUNET_PQ_QueryParam params[] = {
+ GNUNET_PQ_query_param_auto_from_type (truth_uuid),
+ GNUNET_PQ_query_param_uint64 (code),
+ TALER_PQ_query_param_absolute_time (&now),
+ TALER_PQ_query_param_absolute_time (&expiration_date),
+ GNUNET_PQ_query_param_uint32 (&retry_counter),
+ GNUNET_PQ_query_param_end
+ };
+
+ qs = GNUNET_PQ_eval_prepared_non_select (pg->conn,
+ "challengecode_insert",
+ params);
+ switch (qs)
+ {
+ case GNUNET_DB_STATUS_HARD_ERROR:
+ rollback (pg);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SOFT_ERROR:
+ goto retry;
+ case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
+ GNUNET_break (0);
+ rollback (pg);
+ return GNUNET_DB_STATUS_HARD_ERROR;
+ case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
+ break;
+ }
+ }
+ qs = commit_transaction (pg);
+ if (GNUNET_DB_STATUS_SOFT_ERROR == qs)
+ goto retry;
+ if (qs < 0)
+ return qs;
+ return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT;
+retry:
+ rollback (pg);
+ }
+ return GNUNET_DB_STATUS_SOFT_ERROR;
+}
+
+
+/**
* Remember in the database that we successfully sent a challenge.
*
* @param cls closure
@@ -2675,6 +2807,7 @@ libanastasis_plugin_db_postgres_init (void *cls)
plugin->test_challenge_code_satisfied =
&postgres_test_challenge_code_satisfied;
plugin->create_challenge_code = &postgres_create_challenge_code;
+ plugin->get_unlimited_challenge_code = &postgres_get_unlimited_challenge_code;
plugin->mark_challenge_sent = &postgres_mark_challenge_sent;
plugin->challenge_gc = &postgres_challenge_gc;
plugin->record_truth_upload_payment = &postgres_record_truth_upload_payment;