diff options
Diffstat (limited to 'src/stasis')
-rw-r--r-- | src/stasis/Makefile.am | 15 | ||||
-rw-r--r-- | src/stasis/anastasis_db_plugin.c | 2 | ||||
-rw-r--r-- | src/stasis/drop.sql (renamed from src/stasis/drop0001.sql) | 25 | ||||
-rw-r--r-- | src/stasis/plugin_anastasis_postgres.c | 617 | ||||
-rw-r--r-- | src/stasis/stasis-0001.sql | 60 | ||||
-rw-r--r-- | src/stasis/test_anastasis_db.c | 14 | ||||
-rw-r--r-- | src/stasis/versioning.sql (renamed from src/stasis/stasis-0000.sql) | 3 |
7 files changed, 439 insertions, 297 deletions
diff --git a/src/stasis/Makefile.am b/src/stasis/Makefile.am index 140f65e..0197f0e 100644 --- a/src/stasis/Makefile.am +++ b/src/stasis/Makefile.am @@ -16,9 +16,9 @@ endif sqldir = $(prefix)/share/anastasis/sql/ sql_DATA = \ - stasis-0000.sql \ + versioning.sql \ stasis-0001.sql \ - drop0001.sql + drop.sql pkgcfgdir = $(prefix)/share/anastasis/config.d/ @@ -59,16 +59,16 @@ libanastasisdb_la_LDFLAGS = \ libanastasis_plugin_db_postgres_la_SOURCES = \ plugin_anastasis_postgres.c -libanastasis_plugin_db_postgres_la_LIBADD = \ - $(LTLIBINTL) libanastasis_plugin_db_postgres_la_LDFLAGS = \ + $(ANASTASIS_PLUGIN_LDFLAGS) +libanastasis_plugin_db_postgres_la_LIBADD = \ + $(LTLIBINTL) \ $(top_builddir)/src/util/libanastasisutil.la \ - $(ANASTASIS_PLUGIN_LDFLAGS) \ - -lgnunetpq \ - -lpq \ -ltalerpq \ -ltalerutil \ + -lgnunetpq \ -lgnunetutil \ + -lpq \ $(XLIB) check_PROGRAMS = \ @@ -83,7 +83,6 @@ test_anastasis_db_postgres_LDFLAGS = \ -lgnunetpq \ -ltalerutil \ -ltalerpq \ - -luuid \ $(XLIB) AM_TESTS_ENVIRONMENT=export ANASTASIS_PREFIX=$${ANASTASIS_PREFIX:-@libdir@};export PATH=$${ANASTASIS_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; diff --git a/src/stasis/anastasis_db_plugin.c b/src/stasis/anastasis_db_plugin.c index 7edca5f..a7e55b9 100644 --- a/src/stasis/anastasis_db_plugin.c +++ b/src/stasis/anastasis_db_plugin.c @@ -3,7 +3,7 @@ Copyright (C) 2015, 2016 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY diff --git a/src/stasis/drop0001.sql b/src/stasis/drop.sql index c7697c0..357fa9d 100644 --- a/src/stasis/drop0001.sql +++ b/src/stasis/drop.sql @@ -1,6 +1,6 @@ -- -- This file is part of ANASTASIS --- Copyright (C) 2014--2020 Anastasis Systems SA +-- Copyright (C) 2014--2022 Anastasis Systems SA -- -- ANASTASIS is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software @@ -17,22 +17,15 @@ -- Everything in one big transaction BEGIN; --- This script DROPs all of the tables we create. --- --- Unlike the other SQL files, it SHOULD be updated to reflect the --- latest requirements for dropping tables. - --- Drops for 0001.sql -DROP TABLE IF EXISTS anastasis_truth CASCADE; -DROP TABLE IF EXISTS anastasis_user CASCADE; -DROP TABLE IF EXISTS anastasis_recdoc_payment; -DROP TABLE IF EXISTS anastasis_recoverydocument; -DROP TABLE IF EXISTS anastasis_challengecode; -DROP TABLE IF EXISTS anastasis_challenge_payment; -DROP TABLE IF EXISTS anastasis_auth_iban_in; +WITH xpatches AS ( + SELECT patch_name + FROM _v.patches + WHERE starts_with(patch_name,'stasis-') +) + SELECT _v.unregister_patch(xpatches.patch_name) + FROM xpatches; --- Unregister patch (0001.sql) -SELECT _v.unregister_patch('stasis-0001'); +DROP SCHEMA anastasis CASCADE; -- And we're out of here... COMMIT; diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c index b1be081..9f4b969 100644 --- a/src/stasis/plugin_anastasis_postgres.c +++ b/src/stasis/plugin_anastasis_postgres.c @@ -1,9 +1,9 @@ /* This file is part of Anastasis - Copyright (C) 2020, 2021 Anastasis SARL + Copyright (C) 2020, 2021, 2022 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY @@ -15,8 +15,7 @@ */ /** * @file stasis/plugin_anastasis_postgres.c - * @brief database helper functions for postgres used by the anastasis - * @author Sree Harsha Totakura <sreeharsha@totakura.in> + * @brief database helper functions for postgres used by GNU Anastasis * @author Christian Grothoff * @author Marcello Stanisci */ @@ -38,12 +37,6 @@ */ #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 @@ -90,16 +83,19 @@ postgres_drop_tables (void *cls) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_Context *conn; + enum GNUNET_GenericReturnValue ret; conn = GNUNET_PQ_connect_with_cfg (pg->cfg, "stasis-postgres", - "drop", + NULL, NULL, NULL); if (NULL == conn) return GNUNET_SYSERR; + ret = GNUNET_PQ_exec_sql (conn, + "drop"); GNUNET_PQ_disconnect (conn); - return GNUNET_OK; + return ret; } @@ -114,11 +110,15 @@ postgres_create_tables (void *cls) { struct PostgresClosure *pc = cls; struct GNUNET_PQ_Context *conn; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO anastasis;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; conn = GNUNET_PQ_connect_with_cfg (pc->cfg, "stasis-postgres", "stasis-", - NULL, + es, NULL); if (NULL == conn) return GNUNET_SYSERR; @@ -134,7 +134,7 @@ postgres_create_tables (void *cls) * @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure */ static enum GNUNET_GenericReturnValue -postgres_connect (void *cls) +prepare_statements (void *cls) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_PreparedStatement ps[] = { @@ -143,54 +143,44 @@ postgres_connect (void *cls) "(user_id" ",expiration_date" ") VALUES " - "($1, $2);", - 2), + "($1, $2);"), GNUNET_PQ_make_prepare ("do_commit", - "COMMIT", - 0), + "COMMIT"), GNUNET_PQ_make_prepare ("user_select", "SELECT" " expiration_date " "FROM anastasis_user" " WHERE user_id=$1" - " FOR UPDATE;", - 1), + " FOR UPDATE;"), GNUNET_PQ_make_prepare ("user_update", "UPDATE anastasis_user" " SET " " expiration_date=$1" - " WHERE user_id=$2;", - 2), + " WHERE user_id=$2;"), GNUNET_PQ_make_prepare ("recdoc_payment_insert", "INSERT INTO anastasis_recdoc_payment " "(user_id" ",post_counter" - ",amount_val" - ",amount_frac" + ",amount" ",payment_identifier" ",creation_date" ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6), + "($1, $2, $3, $4, $5);"), GNUNET_PQ_make_prepare ("challenge_payment_insert", "INSERT INTO anastasis_challenge_payment " "(truth_uuid" - ",amount_val" - ",amount_frac" + ",amount" ",payment_identifier" ",creation_date" ") VALUES " - "($1, $2, $3, $4, $5);", - 5), + "($1, $2, $3, $4);"), GNUNET_PQ_make_prepare ("truth_payment_insert", "INSERT INTO anastasis_truth_payment " "(truth_uuid" - ",amount_val" - ",amount_frac" + ",amount" ",expiration" ") VALUES " - "($1, $2, $3, $4);", - 4), + "($1, $2, $3);"), GNUNET_PQ_make_prepare ("recdoc_payment_done", "UPDATE anastasis_recdoc_payment " "SET" @@ -200,8 +190,7 @@ postgres_connect (void *cls) " AND" " user_id=$2" " AND" - " paid=FALSE;", - 2), + " paid=FALSE;"), GNUNET_PQ_make_prepare ("challenge_refund_update", "UPDATE anastasis_challenge_payment " "SET" @@ -211,8 +200,7 @@ postgres_connect (void *cls) " AND" " paid=TRUE" " AND" - " truth_uuid=$2;", - 2), + " truth_uuid=$2;"), GNUNET_PQ_make_prepare ("challenge_payment_done", "UPDATE anastasis_challenge_payment " "SET" @@ -224,43 +212,36 @@ postgres_connect (void *cls) " AND" " truth_uuid=$2" " AND" - " paid=FALSE;", - 2), + " paid=FALSE;"), GNUNET_PQ_make_prepare ("recdoc_payment_select", "SELECT" " creation_date" ",post_counter" - ",amount_val" - ",amount_frac" + ",amount" ",paid" " FROM anastasis_recdoc_payment" - " WHERE payment_identifier=$1;", - 1), + " WHERE payment_identifier=$1;"), GNUNET_PQ_make_prepare ("truth_payment_select", "SELECT" " expiration" " FROM anastasis_truth_payment" " WHERE truth_uuid=$1" - " AND expiration>$2;", - 2), + " AND expiration>$2;"), GNUNET_PQ_make_prepare ("challenge_payment_select", "SELECT" " creation_date" - ",amount_val" - ",amount_frac" + ",amount" ",paid" " FROM anastasis_challenge_payment" " WHERE payment_identifier=$1" " AND truth_uuid=$2" " AND refunded=FALSE" - " AND counter>0;", - 1), + " AND counter>0;"), GNUNET_PQ_make_prepare ("challenge_pending_payment_select", "SELECT" " creation_date" ",payment_identifier" - ",amount_val" - ",amount_frac" + ",amount" " FROM anastasis_challenge_payment" " WHERE" " paid=FALSE" @@ -269,29 +250,24 @@ postgres_connect (void *cls) " AND" " truth_uuid=$1" " AND" - " creation_date > $2;", - 1), + " creation_date > $2;"), GNUNET_PQ_make_prepare ("recdoc_payments_select", "SELECT" " user_id" ",payment_identifier" - ",amount_val" - ",amount_frac" + ",amount" " FROM anastasis_recdoc_payment" - " WHERE paid=FALSE;", - 0), + " WHERE paid=FALSE;"), GNUNET_PQ_make_prepare ("gc_accounts", "DELETE FROM anastasis_user " "WHERE" - " expiration_date < $1;", - 1), + " expiration_date < $1;"), GNUNET_PQ_make_prepare ("gc_recdoc_pending_payments", "DELETE FROM anastasis_recdoc_payment " "WHERE" " paid=FALSE" " AND" - " creation_date < $1;", - 1), + " creation_date < $1;"), GNUNET_PQ_make_prepare ("gc_challenge_pending_payments", "DELETE FROM anastasis_challenge_payment " "WHERE" @@ -299,8 +275,7 @@ postgres_connect (void *cls) " OR" " refunded=TRUE)" " AND" - " creation_date < $1;", - 1), + " creation_date < $1;"), GNUNET_PQ_make_prepare ("truth_insert", "INSERT INTO anastasis_truth " "(truth_uuid" @@ -310,32 +285,24 @@ postgres_connect (void *cls) ",truth_mime" ",expiration" ") VALUES " - "($1, $2, $3, $4, $5, $6);", - 6), - + "($1, $2, $3, $4, $5, $6);"), GNUNET_PQ_make_prepare ("test_auth_iban_payment", "SELECT" - " credit_val" - ",credit_frac" + " credit" ",wire_subject" " FROM anastasis_auth_iban_in" " WHERE debit_account_details=$1" - " AND execution_date>=$2;", - 2), + " AND execution_date>=$2;"), GNUNET_PQ_make_prepare ("store_auth_iban_payment_details", "INSERT INTO anastasis_auth_iban_in " "(wire_reference" ",wire_subject" - ",credit_val" - ",credit_frac" + ",credit" ",debit_account_details" ",credit_account_details" ",execution_date" ") VALUES " - "($1, $2, $3, $4, $5, $6, $7);", - 7), - - + "($1, $2, $3, $4, $5, $6);"), GNUNET_PQ_make_prepare ("recovery_document_insert", "INSERT INTO anastasis_recoverydocument " "(user_id" @@ -343,17 +310,27 @@ postgres_connect (void *cls) ",account_sig" ",recovery_data_hash" ",recovery_data" + ",recovery_meta_data" + ",creation_date" ") VALUES " - "($1, $2, $3, $4, $5);", - 5), + "($1, $2, $3, $4, $5, $6, $7);"), GNUNET_PQ_make_prepare ("truth_select", "SELECT " " method_name" ",encrypted_truth" ",truth_mime" " FROM anastasis_truth" - " WHERE truth_uuid =$1;", - 1), + " WHERE truth_uuid=$1;"), + GNUNET_PQ_make_prepare ("recoverydocument_select_meta", + "SELECT " + " version" + ",creation_date" + ",recovery_meta_data" + " FROM anastasis_recoverydocument" + " WHERE user_id=$1" + " AND version < $2" + " ORDER BY version DESC" + " LIMIT 1000;"), GNUNET_PQ_make_prepare ("latest_recoverydocument_select", "SELECT " " version" @@ -361,10 +338,9 @@ postgres_connect (void *cls) ",recovery_data_hash" ",recovery_data" " FROM anastasis_recoverydocument" - " WHERE user_id =$1 " + " WHERE user_id=$1" " ORDER BY version DESC" - " LIMIT 1;", - 1), + " LIMIT 1;"), GNUNET_PQ_make_prepare ("latest_recovery_version_select", "SELECT" " version" @@ -374,8 +350,7 @@ postgres_connect (void *cls) " JOIN anastasis_user USING (user_id)" " WHERE user_id=$1" " ORDER BY version DESC" - " LIMIT 1;", - 1), + " LIMIT 1;"), GNUNET_PQ_make_prepare ("recoverydocument_select", "SELECT " " account_sig" @@ -383,30 +358,26 @@ postgres_connect (void *cls) ",recovery_data" " FROM anastasis_recoverydocument" " WHERE user_id=$1" - " AND version=$2;", - 2), + " AND version=$2;"), GNUNET_PQ_make_prepare ("postcounter_select", "SELECT" " post_counter" " FROM anastasis_recdoc_payment" " WHERE user_id=$1" - " AND payment_identifier=$2;", - 2), + " AND payment_identifier=$2;"), GNUNET_PQ_make_prepare ("postcounter_update", - "UPDATE " - "anastasis_recdoc_payment " - "SET " - "post_counter=$1 " - "WHERE user_id =$2 " - "AND payment_identifier=$3;", - 3), + "UPDATE" + " anastasis_recdoc_payment" + " SET" + " post_counter=$1" + " WHERE user_id =$2" + " AND payment_identifier=$3;"), GNUNET_PQ_make_prepare ("key_share_select", "SELECT " "key_share_data " "FROM " "anastasis_truth " - "WHERE truth_uuid =$1;", - 1), + "WHERE truth_uuid =$1;"), GNUNET_PQ_make_prepare ("challengecode_insert", "INSERT INTO anastasis_challengecode " "(truth_uuid" @@ -415,8 +386,7 @@ postgres_connect (void *cls) ",expiration_date" ",retry_counter" ") VALUES " - "($1, $2, $3, $4, $5);", - 5), + "($1, $2, $3, $4, $5);"), GNUNET_PQ_make_prepare ("challengecode_select", "SELECT " " code" @@ -424,8 +394,7 @@ postgres_connect (void *cls) " FROM anastasis_challengecode" " WHERE truth_uuid=$1" " AND expiration_date > $2" - " AND retry_counter != 0;", - 2), + " AND retry_counter != 0;"), GNUNET_PQ_make_prepare ("challengecode_set_satisfied", "UPDATE anastasis_challengecode" " SET satisfied=TRUE" @@ -437,16 +406,14 @@ postgres_connect (void *cls) " WHERE truth_uuid=$1" " AND code=$2" " ORDER BY creation_date DESC" - " LIMIT 1);", - 2), + " LIMIT 1);"), GNUNET_PQ_make_prepare ("challengecode_test_satisfied", "SELECT 1 FROM anastasis_challengecode" " WHERE truth_uuid=$1" " AND satisfied=TRUE" " AND code=$2" " AND creation_date >= $3" - " LIMIT 1;", - 3), + " LIMIT 1;"), GNUNET_PQ_make_prepare ("challengecode_select_meta", "SELECT " " code" @@ -457,22 +424,19 @@ postgres_connect (void *cls) " AND expiration_date > $2" " AND creation_date > $3" " ORDER BY creation_date DESC" - " LIMIT 1;", - 2), + " LIMIT 1;"), GNUNET_PQ_make_prepare ("challengecode_update_retry", "UPDATE anastasis_challengecode" " SET retry_counter=retry_counter - 1" " WHERE truth_uuid=$1" " AND code=$2" - " AND retry_counter != 0;", - 1), + " AND retry_counter != 0;"), GNUNET_PQ_make_prepare ("challengepayment_dec_counter", "UPDATE anastasis_challenge_payment" " SET counter=counter - 1" " WHERE truth_uuid=$1" " AND payment_identifier=$2" - " AND counter > 0;", - 2), + " AND counter > 0;"), GNUNET_PQ_make_prepare ("challengecode_mark_sent", "UPDATE anastasis_challengecode" " SET retransmission_date=$3" @@ -484,32 +448,31 @@ postgres_connect (void *cls) " WHERE truth_uuid=$1" " AND code=$2" " ORDER BY creation_date DESC" - " LIMIT 1);", - 3), + " LIMIT 1);"), GNUNET_PQ_make_prepare ("get_last_auth_iban_payment", "SELECT " " wire_reference" " FROM anastasis_auth_iban_in" " WHERE credit_account_details=$1" " ORDER BY wire_reference DESC" - " LIMIT 1;", - 1), + " LIMIT 1;"), GNUNET_PQ_make_prepare ("gc_challengecodes", "DELETE FROM anastasis_challengecode " "WHERE " - "expiration_date < $1;", - 1), + "expiration_date < $1;"), GNUNET_PQ_PREPARED_STATEMENT_END }; - pg->conn = GNUNET_PQ_connect_with_cfg (pg->cfg, - "stasis-postgres", - NULL, - NULL, - ps); - if (NULL == pg->conn) - return GNUNET_SYSERR; - return GNUNET_OK; + { + enum GNUNET_GenericReturnValue ret; + + ret = GNUNET_PQ_prepare_statements (pg->conn, + ps); + if (GNUNET_OK != ret) + return ret; + pg->init = true; + return GNUNET_OK; + } } @@ -554,15 +517,19 @@ internal_setup (struct PostgresClosure *pg, "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE;"), GNUNET_PQ_make_try_execute ("SET enable_sort=OFF;"), GNUNET_PQ_make_try_execute ("SET enable_seqscan=OFF;"), + GNUNET_PQ_make_execute ("SET search_path TO anastasis;"), GNUNET_PQ_EXECUTE_STATEMENT_END }; #else - struct GNUNET_PQ_ExecuteStatement *es = NULL; + struct GNUNET_PQ_ExecuteStatement es[] = { + GNUNET_PQ_make_execute ("SET search_path TO anastasis;"), + GNUNET_PQ_EXECUTE_STATEMENT_END + }; #endif struct GNUNET_PQ_Context *db_conn; db_conn = GNUNET_PQ_connect_with_cfg (pg->cfg, - "exchangedb-postgres", + "stasis-postgres", NULL, es, NULL); @@ -576,7 +543,7 @@ internal_setup (struct PostgresClosure *pg, return GNUNET_OK; if (skip_prepare) return GNUNET_OK; - return postgres_connect (pg); + return prepare_statements (pg); } @@ -635,7 +602,7 @@ postgres_preflight (void *cls) * must point to a constant * @return #GNUNET_OK on success */ -static int +static enum GNUNET_GenericReturnValue begin_transaction (void *cls, const char *name) { @@ -646,7 +613,8 @@ begin_transaction (void *cls, }; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); pg->transaction_name = name; if (GNUNET_OK != GNUNET_PQ_exec_statements (pg->conn, @@ -802,7 +770,8 @@ postgres_gc (void *cls, enum GNUNET_DB_QueryStatus qs; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "gc_accounts", params); @@ -836,6 +805,8 @@ postgres_store_recovery_document ( const struct GNUNET_HashCode *recovery_data_hash, const void *recovery_data, size_t recovery_data_size, + const void *recovery_meta_data, + size_t recovery_meta_data_size, const struct ANASTASIS_PaymentSecretP *payment_secret, uint32_t *version) { @@ -843,7 +814,8 @@ postgres_store_recovery_document ( enum GNUNET_DB_QueryStatus qs; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); for (unsigned int retry = 0; retry<MAX_RETRIES; retry++) { if (GNUNET_OK != @@ -1011,6 +983,8 @@ postgres_store_recovery_document ( /* finally, actually insert the recovery document */ { + struct GNUNET_TIME_Timestamp now + = GNUNET_TIME_timestamp_get (); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_uint32 (version), @@ -1018,6 +992,9 @@ postgres_store_recovery_document ( GNUNET_PQ_query_param_auto_from_type (recovery_data_hash), GNUNET_PQ_query_param_fixed_size (recovery_data, recovery_data_size), + GNUNET_PQ_query_param_fixed_size (recovery_meta_data, + recovery_meta_data_size), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; @@ -1052,7 +1029,8 @@ retry: /** - * Increment account lifetime. + * Increment account lifetime based on payment having been received. + * Does nothing if the payment is not new. * * @param cls closure * @param account_pub which account received a payment @@ -1067,11 +1045,16 @@ postgres_increment_lifetime ( const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, const struct ANASTASIS_PaymentSecretP *payment_identifier, struct GNUNET_TIME_Relative lifetime, - struct GNUNET_TIME_Absolute *paid_until) + struct GNUNET_TIME_Timestamp *paid_until) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incrementing lifetime of account %s based on payment by %s\n", + TALER_B2S (account_pub), + GNUNET_TIME_relative2s (lifetime, + true)); check_connection (pg); for (unsigned int retries = 0; retries<MAX_RETRIES; retries++) { @@ -1096,14 +1079,16 @@ postgres_increment_lifetime ( { case GNUNET_DB_STATUS_HARD_ERROR: rollback (pg); - *paid_until = GNUNET_TIME_UNIT_ZERO_ABS; + *paid_until = GNUNET_TIME_UNIT_ZERO_TS; return qs; case GNUNET_DB_STATUS_SOFT_ERROR: goto retry; case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: + /* Payment not new or payment request unknown. */ /* continued below */ break; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: + /* Payment just now marked as 'paid' */ /* continued below */ break; } @@ -1115,10 +1100,10 @@ postgres_increment_lifetime ( GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_end }; - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration_date", - &expiration), + GNUNET_PQ_result_spec_timestamp ("expiration_date", + &expiration), GNUNET_PQ_result_spec_end }; @@ -1146,14 +1131,18 @@ postgres_increment_lifetime ( /* user does not exist, create new one */ struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_absolute_time (&expiration), + GNUNET_PQ_query_param_timestamp (&expiration), GNUNET_PQ_query_param_end }; - expiration = GNUNET_TIME_relative_to_absolute (lifetime); - GNUNET_break (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != - expiration.abs_value_us); + expiration = GNUNET_TIME_relative_to_timestamp (lifetime); + GNUNET_break (! GNUNET_TIME_absolute_is_never (expiration.abs_time)); *paid_until = expiration; + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Creating new account %s with initial lifetime of %s\n", + TALER_B2S (account_pub), + GNUNET_TIME_relative2s (lifetime, + true)); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "user_insert", params); @@ -1162,28 +1151,36 @@ postgres_increment_lifetime ( case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs) { - /* existing rec doc payment, return expiration */ + /* existing rec doc payment (payment replay), return + existing expiration */ *paid_until = expiration; rollback (pg); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Payment existed, lifetime of account %s unchanged at %s\n", TALER_B2S (account_pub), - GNUNET_STRINGS_absolute_time_to_string (*paid_until)); + GNUNET_TIME_timestamp2s (*paid_until)); return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } else { - /* user exists, update expiration_date */ + /* user exists, payment is new, update expiration_date */ struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&expiration), + GNUNET_PQ_query_param_timestamp (&expiration), GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_end }; - expiration = GNUNET_TIME_absolute_add (expiration, - lifetime); - GNUNET_break (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != - expiration.abs_value_us); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Incrementing lifetime of account %s by %s\n", + TALER_B2S (account_pub), + GNUNET_TIME_relative2s (lifetime, + true)); + expiration + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_add (expiration.abs_time, + lifetime)); + GNUNET_break (! GNUNET_TIME_absolute_is_never ( + expiration.abs_time)); *paid_until = expiration; qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "user_update", @@ -1215,7 +1212,7 @@ postgres_increment_lifetime ( GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Incremented lifetime of account %s to %s\n", TALER_B2S (account_pub), - GNUNET_STRINGS_absolute_time_to_string (*paid_until)); + GNUNET_TIME_timestamp2s (*paid_until)); return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; retry: rollback (pg); @@ -1239,7 +1236,7 @@ postgres_update_lifetime ( void *cls, const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, const struct ANASTASIS_PaymentSecretP *payment_identifier, - struct GNUNET_TIME_Absolute eol) + struct GNUNET_TIME_Timestamp eol) { struct PostgresClosure *pg = cls; enum GNUNET_DB_QueryStatus qs; @@ -1283,10 +1280,10 @@ postgres_update_lifetime ( GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_end }; - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration_date", - &expiration), + GNUNET_PQ_result_spec_timestamp ("expiration_date", + &expiration), GNUNET_PQ_result_spec_end }; @@ -1306,41 +1303,39 @@ postgres_update_lifetime ( /* user does not exist, create new one */ struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_absolute_time (&eol), + GNUNET_PQ_query_param_timestamp (&eol), GNUNET_PQ_query_param_end }; - GNUNET_break (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != - eol.abs_value_us); + GNUNET_break (! GNUNET_TIME_absolute_is_never (eol.abs_time)); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "user_insert", params); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created new account %s with expiration %s\n", TALER_B2S (account_pub), - GNUNET_STRINGS_absolute_time_to_string (eol)); + GNUNET_TIME_timestamp2s (eol)); } break; case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: { /* user exists, update expiration_date */ struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&expiration), + GNUNET_PQ_query_param_timestamp (&expiration), GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_end }; - expiration = GNUNET_TIME_absolute_max (expiration, - eol); - GNUNET_break (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != - expiration.abs_value_us); + expiration = GNUNET_TIME_timestamp_max (expiration, + eol); + GNUNET_break (! GNUNET_TIME_absolute_is_never (expiration.abs_time)); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "user_update", params); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updated account %s to new expiration %s\n", TALER_B2S (account_pub), - GNUNET_STRINGS_absolute_time_to_string (expiration)); + GNUNET_TIME_timestamp2s (expiration)); } break; } @@ -1394,20 +1389,22 @@ postgres_record_recdoc_payment ( const struct TALER_Amount *amount) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_TIME_Absolute expiration; + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (account_pub), GNUNET_PQ_query_param_uint32 (&post_counter), - TALER_PQ_query_param_amount (amount), + TALER_PQ_query_param_amount (pg->conn, + amount), GNUNET_PQ_query_param_auto_from_type (payment_secret), - GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; enum GNUNET_DB_QueryStatus qs; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); /* because of constraint at user_id, first we have to verify if user exists, and if not, create one */ @@ -1417,8 +1414,8 @@ postgres_record_recdoc_payment ( GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration_date", - &expiration), + GNUNET_PQ_result_spec_timestamp ("expiration_date", + &expiration), GNUNET_PQ_result_spec_end }; @@ -1437,11 +1434,11 @@ postgres_record_recdoc_payment ( case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: { /* create new user with short lifetime */ - struct GNUNET_TIME_Absolute exp - = GNUNET_TIME_relative_to_absolute (TRANSIENT_LIFETIME); + struct GNUNET_TIME_Timestamp exp + = GNUNET_TIME_relative_to_timestamp (TRANSIENT_LIFETIME); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (account_pub), - GNUNET_PQ_query_param_absolute_time (&exp), + GNUNET_PQ_query_param_timestamp (&exp), GNUNET_PQ_query_param_end }; @@ -1463,7 +1460,7 @@ postgres_record_recdoc_payment ( GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Created new account %s with transient life until %s\n", TALER_B2S (account_pub), - GNUNET_STRINGS_absolute_time_to_string (exp)); + GNUNET_TIME_timestamp2s (exp)); break; } } @@ -1497,11 +1494,13 @@ postgres_record_truth_upload_payment ( struct GNUNET_TIME_Relative duration) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute exp = GNUNET_TIME_relative_to_absolute (duration); + struct GNUNET_TIME_Timestamp exp = GNUNET_TIME_relative_to_timestamp ( + duration); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (uuid), - TALER_PQ_query_param_amount (amount), - GNUNET_PQ_query_param_absolute_time (&exp), + TALER_PQ_query_param_amount (pg->conn, + amount), + GNUNET_PQ_query_param_timestamp (&exp), GNUNET_PQ_query_param_end }; @@ -1524,18 +1523,18 @@ static enum GNUNET_DB_QueryStatus postgres_check_truth_upload_paid ( void *cls, const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid, - struct GNUNET_TIME_Absolute *paid_until) + struct GNUNET_TIME_Timestamp *paid_until) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (uuid), - GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration", - paid_until), + GNUNET_PQ_result_spec_timestamp ("expiration", + paid_until), GNUNET_PQ_result_spec_end }; @@ -1564,12 +1563,13 @@ postgres_record_challenge_payment ( const struct TALER_Amount *amount) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), - TALER_PQ_query_param_amount (amount), + TALER_PQ_query_param_amount (pg->conn, + amount), GNUNET_PQ_query_param_auto_from_type (payment_secret), - GNUNET_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; @@ -1628,16 +1628,17 @@ postgres_record_auth_iban_payment ( const struct TALER_Amount *amount, const char *debit_account, const char *credit_account, - struct GNUNET_TIME_Absolute execution_date) + struct GNUNET_TIME_Timestamp execution_date) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_uint64 (&wire_reference), GNUNET_PQ_query_param_string (wire_subject), - TALER_PQ_query_param_amount (amount), + TALER_PQ_query_param_amount (pg->conn, + amount), GNUNET_PQ_query_param_string (debit_account), GNUNET_PQ_query_param_string (credit_account), - GNUNET_PQ_query_param_absolute_time (&execution_date), + GNUNET_PQ_query_param_timestamp (&execution_date), GNUNET_PQ_query_param_end }; @@ -1747,7 +1748,7 @@ static enum GNUNET_DB_QueryStatus postgres_test_auth_iban_payment ( void *cls, const char *debit_account, - struct GNUNET_TIME_Absolute earliest_date, + struct GNUNET_TIME_Timestamp earliest_date, ANASTASIS_DB_AuthIbanTransfercheck cb, void *cb_cls) { @@ -1759,7 +1760,7 @@ postgres_test_auth_iban_payment ( }; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_string (debit_account), - TALER_PQ_query_param_absolute_time (&earliest_date), + GNUNET_PQ_query_param_timestamp (&earliest_date), GNUNET_PQ_query_param_end }; enum GNUNET_DB_QueryStatus qs; @@ -1930,7 +1931,7 @@ postgres_store_truth ( struct GNUNET_TIME_Relative truth_expiration) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute expiration = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp expiration; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), GNUNET_PQ_query_param_auto_from_type (key_share_data), @@ -1938,14 +1939,12 @@ postgres_store_truth ( GNUNET_PQ_query_param_fixed_size (encrypted_truth, encrypted_truth_size), GNUNET_PQ_query_param_string (mime_type), - TALER_PQ_query_param_absolute_time (&expiration), + GNUNET_PQ_query_param_timestamp (&expiration), GNUNET_PQ_query_param_end }; - expiration = GNUNET_TIME_absolute_add (expiration, - truth_expiration); - GNUNET_TIME_round_abs (&expiration); + expiration = GNUNET_TIME_relative_to_timestamp (truth_expiration); check_connection (pg); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "truth_insert", @@ -2045,7 +2044,7 @@ enum ANASTASIS_DB_AccountStatus postgres_lookup_account ( void *cls, const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, - struct GNUNET_TIME_Absolute *paid_until, + struct GNUNET_TIME_Timestamp *paid_until, struct GNUNET_HashCode *recovery_data_hash, uint32_t *version) { @@ -2057,11 +2056,12 @@ postgres_lookup_account ( enum GNUNET_DB_QueryStatus qs; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); { struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration_date", - paid_until), + GNUNET_PQ_result_spec_timestamp ("expiration_date", + paid_until), GNUNET_PQ_result_spec_auto_from_type ("recovery_data_hash", recovery_data_hash), GNUNET_PQ_result_spec_uint32 ("version", @@ -2090,8 +2090,8 @@ postgres_lookup_account ( /* check if account exists */ { struct GNUNET_PQ_ResultSpec rs[] = { - GNUNET_PQ_result_spec_absolute_time ("expiration_date", - paid_until), + GNUNET_PQ_result_spec_timestamp ("expiration_date", + paid_until), GNUNET_PQ_result_spec_end }; @@ -2165,7 +2165,8 @@ postgres_get_latest_recovery_document ( }; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); return GNUNET_PQ_eval_prepared_singleton_select (pg->conn, "latest_recoverydocument_select", params, @@ -2174,6 +2175,129 @@ postgres_get_latest_recovery_document ( /** + * Closure for meta_iterator(). + */ +struct MetaIteratorContext +{ + /** + * Function to call on each result. + */ + ANASTASIS_DB_RecoveryMetaCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Set to true on database failure. + */ + bool db_failure; +}; + + +/** + * Helper function for #postgres_get_recovery_meta_data(). + * To be called with the results of a SELECT statement + * that has returned @a num_results results. + * + * @param cls closure of type `struct MetaIteratorContext *` + * @param result the postgres result + * @param num_results the number of results in @a result + */ +static void +meta_iterator (void *cls, + PGresult *result, + unsigned int num_results) +{ + struct MetaIteratorContext *ctx = cls; + + for (unsigned int i = 0; i<num_results; i++) + { + uint32_t version; + void *meta_data; + size_t meta_data_size; + struct GNUNET_TIME_Timestamp ts; + struct GNUNET_PQ_ResultSpec rs[] = { + GNUNET_PQ_result_spec_uint32 ("version", + &version), + GNUNET_PQ_result_spec_timestamp ("creation_date", + &ts), + GNUNET_PQ_result_spec_variable_size ("recovery_meta_data", + &meta_data, + &meta_data_size), + GNUNET_PQ_result_spec_end + }; + enum GNUNET_GenericReturnValue ret; + + if (GNUNET_OK != + GNUNET_PQ_extract_result (result, + rs, + i)) + { + GNUNET_break (0); + ctx->db_failure = true; + return; + } + ret = ctx->cb (ctx->cb_cls, + version, + ts, + meta_data, + meta_data_size); + GNUNET_PQ_cleanup_result (rs); + if (GNUNET_OK != ret) + break; + } +} + + +/** + * Fetch recovery document meta data for user. Returns + * meta data in descending order from @a max_version. + * The size of the result set may be limited. + * + * @param cls closure + * @param account_pub public key of the user's account + * @param max_version the maximum version number the user requests + * @param cb function to call on each result + * @param cb_cls closure for @a cb + * @return transaction status + */ +static enum GNUNET_DB_QueryStatus +postgres_get_recovery_meta_data ( + void *cls, + const struct ANASTASIS_CRYPTO_AccountPublicKeyP *account_pub, + uint32_t max_version, + ANASTASIS_DB_RecoveryMetaCallback cb, + void *cb_cls) +{ + struct PostgresClosure *pg = cls; + struct MetaIteratorContext ctx = { + .cb = cb, + .cb_cls = cb_cls + }; + struct GNUNET_PQ_QueryParam params[] = { + GNUNET_PQ_query_param_auto_from_type (account_pub), + GNUNET_PQ_query_param_uint32 (&max_version), + GNUNET_PQ_query_param_end + }; + enum GNUNET_DB_QueryStatus qs; + + check_connection (pg); + qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, + "recoverydocument_select_meta", + params, + &meta_iterator, + &ctx); + if (qs < 0) + return qs; + if (ctx.db_failure) + return GNUNET_DB_STATUS_HARD_ERROR; + return qs; +} + + +/** * Fetch recovery document for user according given version. * * @param cls closure @@ -2301,6 +2425,10 @@ check_valid_code (void *cls, cvc->db_failure = true; return; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Found issued challenge %llu (client: %s)\n", + (unsigned long long) server_code, + GNUNET_h2s (cvc->hashed_code)); { struct GNUNET_HashCode shashed_code; @@ -2310,6 +2438,9 @@ check_valid_code (void *cls, GNUNET_memcmp (&shashed_code, cvc->hashed_code)) { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Challenge is valid challenge (%s)\n", + (0 != sat) ? "satisfied" : "not satisfied"); cvc->valid = true; cvc->code = server_code; cvc->satisfied = (0 != sat); @@ -2364,17 +2495,16 @@ postgres_verify_challenge_code ( .hashed_code = hashed_code, .pg = pg }; - struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), - TALER_PQ_query_param_absolute_time (&now), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; enum GNUNET_DB_QueryStatus qs; *satisfied = false; check_connection (pg); - GNUNET_TIME_round_abs (&now); qs = GNUNET_PQ_eval_prepared_multi_select (pg->conn, "challengecode_select", params, @@ -2439,13 +2569,13 @@ postgres_test_challenge_code_satisfied ( void *cls, const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, const uint64_t code, - struct GNUNET_TIME_Absolute after) + struct GNUNET_TIME_Timestamp after) { struct PostgresClosure *pg = cls; struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), GNUNET_PQ_query_param_uint64 (&code), - GNUNET_PQ_query_param_absolute_time (&after), + GNUNET_PQ_query_param_timestamp (&after), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -2475,12 +2605,13 @@ postgres_lookup_challenge_payment ( { struct PostgresClosure *pg = cls; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); - struct GNUNET_TIME_Absolute recent - = GNUNET_TIME_absolute_subtract (now, - ANASTASIS_CHALLENGE_OFFER_LIFETIME); + struct GNUNET_TIME_Timestamp recent + = GNUNET_TIME_absolute_to_timestamp ( + GNUNET_TIME_absolute_subtract (now, + ANASTASIS_CHALLENGE_OFFER_LIFETIME)); struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), - GNUNET_PQ_query_param_absolute_time (&recent), + GNUNET_PQ_query_param_timestamp (&recent), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -2547,20 +2678,18 @@ postgres_create_challenge_code ( struct GNUNET_TIME_Relative rotation_period, struct GNUNET_TIME_Relative validity_period, uint32_t retry_counter, - struct GNUNET_TIME_Absolute *retransmission_date, + struct GNUNET_TIME_Timestamp *retransmission_date, 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_Timestamp now = GNUNET_TIME_timestamp_get (); + struct GNUNET_TIME_Timestamp 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, + expiration_date = GNUNET_TIME_relative_to_timestamp (validity_period); + ex_rot = GNUNET_TIME_absolute_subtract (now.abs_time, rotation_period); for (unsigned int retries = 0; retries<MAX_RETRIES; retries++) { @@ -2576,8 +2705,8 @@ postgres_create_challenge_code ( uint32_t old_retry_counter; 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_timestamp (&now), + GNUNET_PQ_query_param_absolute_time (&ex_rot), GNUNET_PQ_query_param_end }; struct GNUNET_PQ_ResultSpec rs[] = { @@ -2585,8 +2714,8 @@ postgres_create_challenge_code ( code), GNUNET_PQ_result_spec_uint32 ("retry_counter", &old_retry_counter), - GNUNET_PQ_result_spec_absolute_time ("retransmission_date", - retransmission_date), + GNUNET_PQ_result_spec_timestamp ("retransmission_date", + retransmission_date), GNUNET_PQ_result_spec_end }; enum GNUNET_DB_QueryStatus qs; @@ -2613,26 +2742,27 @@ postgres_create_challenge_code ( rollback (pg); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Active challenge %llu has zero tries left, refusing to create another one\n", - (unsigned long long) code); + (unsigned long long) *code); return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; } rollback (pg); GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Active challenge has %u tries left, returning old challenge\n", - (unsigned int) old_retry_counter); + "Active challenge has %u tries left, returning old challenge %llu\n", + (unsigned int) old_retry_counter, + (unsigned long long) *code); return qs; } } *code = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, - NONCE_MAX_VALUE); - *retransmission_date = GNUNET_TIME_UNIT_ZERO_ABS; + ANASTASIS_PIN_MAX_VALUE); + *retransmission_date = GNUNET_TIME_UNIT_ZERO_TS; { 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_timestamp (&now), + GNUNET_PQ_query_param_timestamp (&expiration_date), GNUNET_PQ_query_param_uint32 (&retry_counter), GNUNET_PQ_query_param_end }; @@ -2691,22 +2821,24 @@ postgres_mark_challenge_sent ( check_connection (pg); { - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp now; 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), + GNUNET_PQ_query_param_timestamp (&now), GNUNET_PQ_query_param_end }; - now = GNUNET_TIME_absolute_get (); - GNUNET_TIME_round_abs (&now); + now = GNUNET_TIME_timestamp_get (); qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, "challengecode_mark_sent", params); if (qs <= 0) return qs; } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Marking challenge %llu as issued\n", + (unsigned long long) code); { struct GNUNET_PQ_QueryParam params[] = { GNUNET_PQ_query_param_auto_from_type (truth_uuid), @@ -2733,14 +2865,15 @@ enum GNUNET_DB_QueryStatus postgres_challenge_gc (void *cls) { struct PostgresClosure *pg = cls; - struct GNUNET_TIME_Absolute time_now = GNUNET_TIME_absolute_get (); + struct GNUNET_TIME_Timestamp time_now = GNUNET_TIME_timestamp_get (); struct GNUNET_PQ_QueryParam params[] = { - GNUNET_PQ_query_param_absolute_time (&time_now), + GNUNET_PQ_query_param_timestamp (&time_now), GNUNET_PQ_query_param_end }; check_connection (pg); - postgres_preflight (pg); + GNUNET_break (GNUNET_OK == + postgres_preflight (pg)); return GNUNET_PQ_eval_prepared_non_select (pg->conn, "gc_challengecodes", params); @@ -2777,7 +2910,8 @@ libanastasis_plugin_db_postgres_init (void *cls) } plugin = GNUNET_new (struct ANASTASIS_DatabasePlugin); plugin->cls = pg; - plugin->connect = &postgres_connect; + /* FIXME: Should this be the same? */ + plugin->connect = &postgres_preflight; plugin->create_tables = &postgres_create_tables; plugin->drop_tables = &postgres_drop_tables; plugin->gc = &postgres_gc; @@ -2793,6 +2927,7 @@ libanastasis_plugin_db_postgres_init (void *cls) plugin->get_escrow_challenge = &postgres_get_escrow_challenge; plugin->get_key_share = &postgres_get_key_share; plugin->get_latest_recovery_document = &postgres_get_latest_recovery_document; + plugin->get_recovery_meta_data = &postgres_get_recovery_meta_data; plugin->get_recovery_document = &postgres_get_recovery_document; plugin->lookup_account = &postgres_lookup_account; plugin->check_payment_identifier = &postgres_check_payment_identifier; diff --git a/src/stasis/stasis-0001.sql b/src/stasis/stasis-0001.sql index e0ebfa6..fe08cdc 100644 --- a/src/stasis/stasis-0001.sql +++ b/src/stasis/stasis-0001.sql @@ -1,6 +1,6 @@ -- -- This file is part of Anastasis --- Copyright (C) 2020, 2021 Anastasis SARL SA +-- Copyright (C) 2020, 2021, 2022, 2023 Anastasis SARL SA -- -- ANASTASIS is free software; you can redistribute it and/or modify it under the -- terms of the GNU General Public License as published by the Free Software @@ -20,30 +20,41 @@ BEGIN; -- Check patch versioning is in place. SELECT _v.register_patch('stasis-0001', NULL, NULL); +CREATE SCHEMA anastasis; +COMMENT ON SCHEMA anastasis IS 'anastasis backend data'; + +SET search_path TO anastasis; + + +CREATE TYPE taler_amount + AS + (val INT8 + ,frac INT4 + ); +COMMENT ON TYPE taler_amount + IS 'Stores an amount, fraction is in units of 1/100000000 of the base value'; + CREATE TABLE IF NOT EXISTS anastasis_truth_payment (truth_uuid BYTEA PRIMARY KEY CHECK(LENGTH(truth_uuid)=32), - amount_val INT8 NOT NULL, - amount_frac INT4 NOT NULL, + amount taler_amount NOT NULL, expiration INT8 NOT NULL); COMMENT ON TABLE anastasis_truth_payment IS 'Records about payments for truth uploads'; COMMENT ON COLUMN anastasis_truth_payment.truth_uuid IS 'Identifier of the truth'; -COMMENT ON COLUMN anastasis_truth_payment.amount_val +COMMENT ON COLUMN anastasis_truth_payment.amount IS 'Amount we were paid'; -COMMENT ON COLUMN anastasis_truth_payment.amount_frac - IS 'Amount we were paid fraction'; COMMENT ON COLUMN anastasis_truth_payment.expiration IS 'At which date will the truth payment expire'; CREATE TABLE IF NOT EXISTS anastasis_truth (truth_uuid BYTEA PRIMARY KEY CHECK(LENGTH(truth_uuid)=32), - key_share_data BYTEA CHECK(LENGTH(key_share_data)=80) NOT NULL, - method_name VARCHAR NOT NULL, + key_share_data BYTEA CHECK(LENGTH(key_share_data)=72) NOT NULL, + method_name TEXT NOT NULL, encrypted_truth BYTEA NOT NULL, - truth_mime VARCHAR NOT NULL, + truth_mime TEXT NOT NULL, expiration INT8 NOT NULL); COMMENT ON TABLE anastasis_truth IS 'Truth data is needed to authenticate clients during recovery'; @@ -73,11 +84,10 @@ COMMENT ON COLUMN anastasis_user.expiration_date CREATE TABLE IF NOT EXISTS anastasis_recdoc_payment - (payment_id BIGSERIAL PRIMARY KEY, + (payment_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, user_id BYTEA NOT NULL REFERENCES anastasis_user(user_id), post_counter INT4 NOT NULL DEFAULT 0 CHECK(post_counter >= 0), - amount_val INT8 NOT NULL, - amount_frac INT4 NOT NULL, + amount taler_amount NOT NULL, payment_identifier BYTEA NOT NULL CHECK(LENGTH(payment_identifier)=32), creation_date INT8 NOT NULL, paid BOOLEAN NOT NULL DEFAULT FALSE); @@ -89,10 +99,8 @@ COMMENT ON COLUMN anastasis_recdoc_payment.user_id IS 'Link to the corresponding user who paid'; COMMENT ON COLUMN anastasis_recdoc_payment.post_counter IS 'For how many posts does the user pay'; -COMMENT ON COLUMN anastasis_recdoc_payment.amount_val +COMMENT ON COLUMN anastasis_recdoc_payment.amount IS 'Amount we were paid'; -COMMENT ON COLUMN anastasis_recdoc_payment.amount_frac - IS 'Amount we were paid fraction'; COMMENT ON COLUMN anastasis_recdoc_payment.payment_identifier IS 'Payment identifier which the user has to provide'; COMMENT ON COLUMN anastasis_recdoc_payment.creation_date @@ -102,10 +110,9 @@ COMMENT ON COLUMN anastasis_recdoc_payment.paid CREATE TABLE IF NOT EXISTS anastasis_challenge_payment - (payment_id BIGSERIAL PRIMARY KEY, + (payment_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, truth_uuid BYTEA CHECK(LENGTH(truth_uuid)=32) NOT NULL, - amount_val INT8 NOT NULL, - amount_frac INT4 NOT NULL, + amount taler_amount NOT NULL, payment_identifier BYTEA NOT NULL CHECK(LENGTH(payment_identifier)=32), creation_date INT8 NOT NULL, counter INT4 NOT NULL DEFAULT 3, @@ -118,10 +125,8 @@ COMMENT ON COLUMN anastasis_challenge_payment.payment_id IS 'Serial number which identifies the payment'; COMMENT ON COLUMN anastasis_challenge_payment.truth_uuid IS 'Link to the corresponding challenge which is paid'; -COMMENT ON COLUMN anastasis_challenge_payment.amount_val +COMMENT ON COLUMN anastasis_challenge_payment.amount IS 'Amount we were paid'; -COMMENT ON COLUMN anastasis_challenge_payment.amount_frac - IS 'Amount we were paid fraction'; COMMENT ON COLUMN anastasis_challenge_payment.payment_identifier IS 'Payment identifier which the user has to provide'; COMMENT ON COLUMN anastasis_challenge_payment.counter @@ -140,6 +145,8 @@ CREATE TABLE IF NOT EXISTS anastasis_recoverydocument account_sig BYTEA NOT NULL CHECK(LENGTH(account_sig)=64), recovery_data_hash BYTEA NOT NULL CHECK(length(recovery_data_hash)=64), recovery_data BYTEA NOT NULL, + recovery_meta_data BYTEA NOT NULL, + creation_date INT8 NOT NULL, PRIMARY KEY (user_id, version)); COMMENT ON TABLE anastasis_recoverydocument IS 'Stores a recovery document which contains the policy and the encrypted core secret'; @@ -151,8 +158,12 @@ COMMENT ON COLUMN anastasis_recoverydocument.account_sig IS 'Signature of the recovery document'; COMMENT ON COLUMN anastasis_recoverydocument.recovery_data_hash IS 'Hash of the recovery document to prevent unnecessary uploads'; +COMMENT ON COLUMN anastasis_recoverydocument.creation_date + IS 'Creation date of the recovery document (when it was uploaded)'; COMMENT ON COLUMN anastasis_recoverydocument.recovery_data IS 'Contains the encrypted policy and core secret'; +COMMENT ON COLUMN anastasis_recoverydocument.recovery_meta_data + IS 'Contains an encrypted human-readable and sometimes user-generated description of the backup'; CREATE TABLE IF NOT EXISTS anastasis_challengecode @@ -194,11 +205,10 @@ COMMENT ON INDEX anastasis_challengecode_expiration_index CREATE TABLE IF NOT EXISTS anastasis_auth_iban_in - (auth_in_serial_id BIGSERIAL UNIQUE + (auth_in_serial_id BIGINT GENERATED BY DEFAULT AS IDENTITY UNIQUE ,wire_reference INT8 NOT NULL PRIMARY KEY ,wire_subject TEXT NOT NULL - ,credit_val INT8 NOT NULL - ,credit_frac INT4 NOT NULL + ,credit taler_amount NOT NULL ,debit_account_details TEXT NOT NULL ,credit_account_details TEXT NOT NULL ,execution_date INT8 NOT NULL @@ -209,6 +219,8 @@ COMMENT ON COLUMN anastasis_auth_iban_in.wire_reference IS 'Unique number identifying the wire transfer in LibEuFin/Nexus'; COMMENT ON COLUMN anastasis_auth_iban_in.wire_subject IS 'For authentication, this contains the code, but also additional text'; +COMMENT ON COLUMN anastasis_auth_iban_in.credit + IS 'Amount we were credited'; COMMENT ON COLUMN anastasis_auth_iban_in.execution_date IS 'Used both for (theoretical) garbage collection and to see if the transfer happened on time'; COMMENT ON COLUMN anastasis_auth_iban_in.credit_account_details diff --git a/src/stasis/test_anastasis_db.c b/src/stasis/test_anastasis_db.c index 1ec9770..5ad29bc 100644 --- a/src/stasis/test_anastasis_db.c +++ b/src/stasis/test_anastasis_db.c @@ -3,7 +3,7 @@ Copyright (C) 2020, 2021 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY @@ -151,7 +151,7 @@ run (void *cls) &paymentSecretP, &amount)); { - struct GNUNET_TIME_Absolute res_time; + struct GNUNET_TIME_Timestamp res_time; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->increment_lifetime (plugin->cls, @@ -192,11 +192,13 @@ run (void *cls) &recoveryDataHash, recovery_data, strlen (recovery_data), + "meta-data", + strlen ("meta-data"), &paymentSecretP, &docVersion)); { uint32_t vrs; - struct GNUNET_TIME_Absolute exp; + struct GNUNET_TIME_Timestamp exp; FAILIF (ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED != plugin->lookup_account (plugin->cls, @@ -240,7 +242,7 @@ run (void *cls) GNUNET_free (res_recovery_data); { - struct GNUNET_TIME_Absolute rt; + struct GNUNET_TIME_Timestamp rt; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != plugin->create_challenge_code (plugin->cls, @@ -250,10 +252,10 @@ run (void *cls) 3, /* retry counter */ &rt, &challenge_code)); - FAILIF (0 != rt.abs_value_us); + FAILIF (! GNUNET_TIME_absolute_is_zero (rt.abs_time)); } { - struct GNUNET_TIME_Absolute rt; + struct GNUNET_TIME_Timestamp rt; uint64_t c2; FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != diff --git a/src/stasis/stasis-0000.sql b/src/stasis/versioning.sql index 116f409..444cf95 100644 --- a/src/stasis/stasis-0000.sql +++ b/src/stasis/versioning.sql @@ -146,12 +146,13 @@ BEGIN; + -- This file adds versioning support to database it will be loaded to. -- It requires that PL/pgSQL is already loaded - will raise exception otherwise. -- All versioning "stuff" (tables, functions) is in "_v" schema. -- All functions are defined as 'RETURNS SETOF INT4' to be able to make them to RETURN literally nothing (0 rows). --- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling. +-- >> RETURNS VOID<< IS similar, but it still outputs "empty line" in psql when calling CREATE SCHEMA IF NOT EXISTS _v; COMMENT ON SCHEMA _v IS 'Schema for versioning data and functionality.'; |